• LeetCode——贪心篇(一)


    刷题顺序及思路来源于代码随想录,网站地址https://programmercarl.com

    目录

    455. 分发饼干

    376. 摆动序列

    53. 最大子数组和

    122. 买卖股票的最佳时机 II

    55. 跳跃游戏

    45. 跳跃游戏 II

    1005. K 次取反后最大化的数组和


    455. 分发饼干

    假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

    对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

    1. 输入: g = [1,2,3], s = [1,1]
    2. 输出: 1
    3. 解释:
    4. 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3
    5. 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
    6. 所以你应该输出1
    1. import java.util.Arrays;
    2. import java.util.Scanner;
    3. /**
    4. * @author light
    5. * @Description 分发饼干
    6. *
    7. * (思路:1.利用大饼干尽量先去满足胃口大的小孩/2.小饼干尽量先去满足胃口小的小孩
    8. * @create 2023-09-04 9:39
    9. */
    10. public class FindContentChildrenTest {
    11. public static void main(String[] args) {
    12. Scanner input=new Scanner(System.in);
    13. int n=input.nextInt();
    14. int[] g=new int[n]; //胃口
    15. for (int i = 0; i < n; i++) {
    16. g[i]=input.nextInt();
    17. }
    18. n=input.nextInt();
    19. int[] s=new int[n]; //饼干尺寸
    20. for (int i = 0; i < n; i++) {
    21. s[i]=input.nextInt();
    22. }
    23. System.out.println(findContentChildren(g, s));
    24. }
    25. public static int findContentChildren(int[] g, int[] s) {
    26. Arrays.sort(g);
    27. Arrays.sort(s);
    28. int count=0;
    29. int index=0;
    30. //小饼干尽量先去满足胃口小的小孩
    31. for (int i = 0; i < s.length; i++) { //先遍历饼干
    32. if(index= g[index]){
    33. count++;
    34. index++;
    35. }
    36. }
    37. return count;
    38. }
    39. }

    376. 摆动序列

    如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

    • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

    • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

    子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

    给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

    1. 输入:nums = [1,7,4,9,2,5]
    2. 输出:6
    3. 解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
    1. import java.util.Scanner;
    2. /**
    3. * @author light
    4. * @Description 摆动序列
    5. *
    6. *
    7. * (思路:删除单调坡度上的节点,只保留两端节点,这个坡度就有两个局部峰值
    8. * 考虑三种情况:
    9. * 1.上下坡中有平坡 1-2-2-1 删除左边的元素或删除右边的元素
    10. * 2.首尾元素 给最左端元素向前延伸一个值,默认最右端有摆动不列入计算
    11. * 3.单调坡中有平坡 1-2-2-3-4
    12. * @create 2023-09-04 10:17
    13. */
    14. public class WiggleMaxLengthTest {
    15. public static void main(String[] args) {
    16. Scanner input=new Scanner(System.in);
    17. int n=input.nextInt();
    18. int[] nums=new int[n]; //胃口
    19. for (int i = 0; i < n; i++) {
    20. nums[i]=input.nextInt();
    21. }
    22. System.out.println(wiggleMaxLength(nums));
    23. }
    24. public static int wiggleMaxLength(int[] nums) {
    25. if(nums.length==1){
    26. return 1;
    27. }
    28. int prediff=0; //上一个差值
    29. int curdiff=0; //当前差值
    30. int result=1; //默认最右端有摆动
    31. for (int i = 1; i < nums.length; i++) {//不遍历最后一个元素,默认最后一个元素有摆动
    32. curdiff=nums[i]-nums[i-1];
    33. if(prediff>=0&&curdiff<0||prediff<=0&&curdiff>0){
    34. result++;
    35. prediff=curdiff; //prediff跟着curdiff去变化,但没必要实时跟着curdiff去变化,只需要当坡度有变化是去记录一下坡度的原始方向---解决情况三
    36. }
    37. }
    38. return result;
    39. }
    40. }

    53. 最大子数组和

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    子数组 是数组中的一个连续部分。

    1. 输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
    2. 输出:6
    3. 解释:连续子数组 [4,-1,2,1] 的和最大,为 6
    1. import java.util.Scanner;
    2. /**
    3. * @author light
    4. * @Description 最大子数组和
    5. *
    6. *
    7. * (思路:当连续和为负数的时候抛弃当前元素,从下一个元素开始重新计算连续和
    8. * @create 2023-09-04 11:24
    9. */
    10. public class MaxSubArrayTest {
    11. public static void main(String[] args) {
    12. Scanner input=new Scanner(System.in);
    13. int n=input.nextInt();
    14. int[] nums=new int[n];
    15. for (int i = 0; i < n; i++) {
    16. nums[i]=input.nextInt();
    17. }
    18. System.out.println(maxSubArray(nums));
    19. }
    20. public static int maxSubArray(int[] nums) {
    21. int count=0;
    22. int sum=Integer.MIN_VALUE;
    23. for (int i = 0; i < nums.length; i++) {
    24. count+=nums[i];
    25. sum=Math.max(sum,count);
    26. if(count<=0){
    27. count=0;
    28. }
    29. }
    30. return sum;
    31. }
    32. }

    122. 买卖股票的最佳时机 II

    给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

    在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

    返回 你能获得的 最大 利润 。

    1. 输入:prices = [7,1,5,3,6,4]
    2. 输出:7
    3. 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4
    4. 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3
    5. 总利润为 4 + 3 = 7
    1. import java.util.Scanner;
    2. /**
    3. * @author light
    4. * @Description 股票买卖最佳时机II
    5. *
    6. * (思路:把利润拆解成以每天的维度
    7. * 如:第2天买入第4天卖出: price[4]-price[2]=price[4]-price[3]+price[3]-price[2]
    8. *
    9. * 贪心:获取正利润已达到全局最大利润
    10. * @create 2023-09-05 9:52
    11. */
    12. public class MaxProfitTest {
    13. public static void main(String[] args) {
    14. Scanner input=new Scanner(System.in);
    15. int n=input.nextInt();
    16. int[] nums=new int[n];
    17. for (int i = 0; i < n; i++) {
    18. nums[i]=input.nextInt();
    19. }
    20. System.out.println(maxProfit(nums));
    21. }
    22. public static int maxProfit(int[] prices) {
    23. int result=0;
    24. for (int i = 1; i < prices.length; i++) {
    25. result+=Math.max(prices[i]-prices[i-1],0); //只获取正利润
    26. }
    27. return result;
    28. }
    29. }

    55. 跳跃游戏

    给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

    判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

    1. 输入:nums = [2,3,1,1,4]
    2. 输出:true
    3. 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。
    1. import java.util.Scanner;
    2. /**
    3. * @author light
    4. * @Description 跳跃游戏
    5. *
    6. * (思路:问题关键不在到底跳跃几步,而是在于跳跃的覆盖范围,
    7. * 那个这个问题就转化为覆盖范围能否覆盖终点
    8. * 每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。
    9. * 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),
    10. * 整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
    11. * @create 2023-09-05 10:09
    12. */
    13. public class CanJumpTest {
    14. public static void main(String[] args) {
    15. Scanner input=new Scanner(System.in);
    16. int n=input.nextInt();
    17. int[] nums=new int[n];
    18. for (int i = 0; i < n; i++) {
    19. nums[i]=input.nextInt();
    20. }
    21. System.out.println(canJump(nums));
    22. }
    23. public static boolean canJump(int[] nums) {
    24. if(nums.length==1){
    25. return true;
    26. }
    27. int coverRang=0; //记录覆盖范围---记录的是下标值
    28. for (int i = 0; i <=coverRang; i++) {
    29. coverRang=Math.max(coverRang,i+nums[i]);
    30. if (coverRang>=nums.length-1){
    31. return true;
    32. }
    33. }
    34. return false;
    35. }
    36. }

    45. 跳跃游戏 II

    给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

    每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

    • 0 <= j <= nums[i] 
    • i + j < n

    返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

    1. 输入: nums = [2,3,1,1,4]
    2. 输出: 2
    3. 解释: 跳到最后一个位置的最小跳跃数是 2
    4. 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
    1. import java.util.Scanner;
    2. /**
    3. * @author light
    4. * @Description 跳跃游戏II
    5. *
    6. * (思路:还是要看覆盖范围,如果当前覆盖范围未达到终点,则步数+1;
    7. * 若当前覆盖范围达到最大值,步数不用+1
    8. *
    9. * @create 2023-09-05 10:30
    10. */
    11. public class JumpTest {
    12. public static void main(String[] args) {
    13. Scanner input=new Scanner(System.in);
    14. int n=input.nextInt();
    15. int[] nums=new int[n];
    16. for (int i = 0; i < n; i++) {
    17. nums[i]=input.nextInt();
    18. }
    19. System.out.println(jump(nums));
    20. }
    21. public static int jump(int[] nums) {
    22. if(nums.length==1){
    23. return 0;
    24. }
    25. int count=0;
    26. int coverRange=0; //当前覆盖范围---下标值
    27. int nextCoverRange=0; //下一步覆盖范围
    28. for (int i = 0; i < nums.length; i++) {
    29. //coverRange=i+nums[i];
    30. nextCoverRange=Math.max(nextCoverRange,i+nums[i]);
    31. if(i==coverRange){
    32. if(coverRange!= nums.length-1){
    33. count++;
    34. coverRange=nextCoverRange;
    35. if(coverRange>= nums.length-1){
    36. break;
    37. }
    38. }else {
    39. break;
    40. }
    41. }
    42. }
    43. return count;
    44. }
    45. }

    1005. K 次取反后最大化的数组和

    给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

    • 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

    重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

    以这种方式修改数组后,返回数组 可能的最大和 。

    1. 输入:nums = [4,2,3], k = 1
    2. 输出:5
    3. 解释:选择下标 1 ,nums 变为 [4,-2,3] 。
    1. import java.util.Arrays;
    2. import java.util.Scanner;
    3. import java.util.stream.IntStream;
    4. /**
    5. * @author light
    6. * @Description K 次取反后最大化的数组和
    7. *
    8. * (思路:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
    9. * 那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让 数组和达到最大。
    10. * 那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值和可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个数组和达到最大。
    11. *
    12. * 那么本题的解题步骤为:
    13. * 第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
    14. * 第二步:从前向后遍历,遇到负数将其变为正数,同时K--
    15. * 第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
    16. * 第四步:求和
    17. * @create 2023-09-05 15:51
    18. */
    19. public class LargestSumAfterKNegationsTest {
    20. public static void main(String[] args) {
    21. Scanner input=new Scanner(System.in);
    22. int n=input.nextInt();
    23. int[] nums=new int[n];
    24. for (int i = 0; i < n; i++) {
    25. nums[i]=input.nextInt();
    26. }
    27. int k=input.nextInt();
    28. System.out.println(largestSumAfterKNegations(nums, k));
    29. }
    30. public static int largestSumAfterKNegations(int[] nums, int k) {
    31. //1.将数组按照绝对值大小从大到小排序
    32. //Integer[] integers=new Integer[nums.length];
    33. //for (int i = 0; i < nums.length; i++) {
    34. // integers[i]=nums[i];
    35. //}
    36. //Arrays.sort(integers, new Comparator() {
    37. // @Override
    38. // public int compare(Integer o1, Integer o2) {
    39. // return Math.abs(o2)-Math.abs(o1);
    40. // }
    41. //});
    42. nums= IntStream.of(nums)
    43. .boxed()
    44. .sorted((a,b)->Math.abs(b)-Math.abs(a))
    45. .mapToInt(Integer::intValue).toArray();
    46. //从前向后遍历,遇到负数将其变为正数,同时K--
    47. for (int i = 0; i < nums.length&&k>0; i++) {
    48. if(nums[i]<0){
    49. nums[i]=-nums[i];
    50. k--;
    51. }
    52. }
    53. //如果K还大于0,那么反复转变数值最小的元素,将K用完
    54. if(k%2==1){ //若剩余k为奇数进行更改,若k为偶数次则不进行取反
    55. nums[nums.length-1]=-nums[nums.length-1];
    56. }
    57. //求和
    58. //int sum=0;
    59. //for (int i = 0; i < nums.length; i++) {
    60. // sum+=nums[i];
    61. //}
    62. //return sum;
    63. return Arrays.stream(nums).sum();
    64. }
    65. }

  • 相关阅读:
    Springboot策略模式实现文件上传功能(Windows/Linux本地,oss,cos)
    流式编程 stream
    Docker安装
    鲲鹏开发者创享日2022:鲲鹏全栈创新 与开发者共建数字湖南
    CentOS7.9安装
    BRLWON Cobra
    新手如何入门Web3?
    redis序列化协议RESP
    【原理篇】WebView 实现嵌套滑动,丝滑般实现吸顶效果,完美兼容 X5 webview
    介绍下官网Redis编程模式
  • 原文地址:https://blog.csdn.net/zssxcj/article/details/132662401