• 代码随想录 贪心算法-简单题目


    目录

    455.分发饼干 

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

    860.柠檬水找零


    455.分发饼干 

    455. 分发饼干

    简单

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

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

    示例 1:

    输入: g = [1,2,3], s = [1,1]
    输出: 1
    解释: 
    你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
    虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
    所以你应该输出1。
    

    示例 2:

    输入: g = [1,2], s = [1,2,3]
    输出: 2
    解释: 
    你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
    你拥有的饼干数量和尺寸都足以让所有孩子满足。
    所以你应该输出2.
    

    提示:

    • 1 <= g.length <= 3 * 104
    • 0 <= s.length <= 3 * 104
    • 1 <= g[i], s[j] <= 231 - 1

    用可满足该孩子的最小饼干去喂该孩子 

    1. class Solution {
    2. // 方法用于找到可以匹配的孩子和饼干的数量
    3. public int findContentChildren(int[] g, int[] s) {
    4. // 对孩子的胃口大小数组和饼干大小数组进行排序
    5. Arrays.sort(g);
    6. Arrays.sort(s);
    7. // begin变量用于记录饼干数组当前检查的起始位置
    8. int begin = 0;
    9. // count变量用于记录成功匹配的孩子和饼干的数量
    10. int count = 0;
    11. // 遍历孩子的胃口大小数组
    12. for(int i = 0; i < g.length; i++){
    13. // 从begin开始遍历饼干大小数组
    14. for(int j = begin; j < s.length; j++){
    15. // 如果找到一块饼干的大小大于等于当前孩子的胃口
    16. if(s[j] >= g[i]){
    17. // 更新begin为当前饼干的后一个位置,这样下次就不需要再检查这块饼干
    18. begin = j + 1;
    19. // 匹配成功,count加1
    20. count++;
    21. // 跳出内层循环,继续检查下一个孩子的胃口
    22. break;
    23. }
    24. }
    25. }
    26. // 返回成功匹配的孩子和饼干的数量
    27. return count;
    28. }
    29. }

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

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

    简单

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

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

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

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

    示例 1:

    输入:nums = [4,2,3], k = 1
    输出:5
    解释:选择下标 1 ,nums 变为 [4,-2,3] 。
    

    示例 2:

    输入:nums = [3,-1,0,2], k = 3
    输出:6
    解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
    

    示例 3:

    输入:nums = [2,-3,-1,5,-4], k = 2
    输出:13
    解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
    

    提示:

    • 1 <= nums.length <= 104
    • -100 <= nums[i] <= 100
    • 1 <= k <= 104

    排序后取反k次,优先取反负数,负数全部取反后,排序得到最小的非负数,对其进行k次取反后得到最大的sum 

    1. class Solution {
    2. // 方法用于计算在数组nums上进行k次取反操作后可能得到的最大和
    3. public int largestSumAfterKNegations(int[] nums, int k) {
    4. int sum = 0;
    5. // 先对数组进行排序,这样负数会排在前面
    6. Arrays.sort(nums);
    7. // 遍历数组,将负数取反(如果k还有剩余并且当前数字是负数)
    8. for(int i = 0; i < nums.length; i++){
    9. if(k > 0 && nums[i] < 0){
    10. nums[i] = -nums[i]; // 取反当前负数
    11. k--; // k剩余次数减1
    12. }
    13. }
    14. // 再次对数组进行排序,因为取反操作可能改变了数组的顺序
    15. Arrays.sort(nums);
    16. // 如果k还有剩余且为奇数,则将最小的数取反(这样可以得到最大和)
    17. if(k > 0 && k % 2 == 1){
    18. nums[0] = -nums[0];
    19. }
    20. // 计算排序后数组的总和
    21. for(int i = 0; i < nums.length; i++){
    22. sum += nums[i];
    23. }
    24. // 返回计算得到的最大和
    25. return sum;
    26. }
    27. }

     笨蛋写法,每次取反都取最小的

    1. class Solution {
    2. public int largestSumAfterKNegations(int[] nums, int k) {
    3. int sum = 0;
    4. for(int i = 0; i < k; i++){
    5. Arrays.sort(nums);
    6. nums[0] = -nums[0];
    7. }
    8. for(int i = 0; i < nums.length; i++){
    9. sum += nums[i];
    10. }
    11. return sum;
    12. }
    13. }

    860.柠檬水找零

    860. 柠檬水找零

    简单

    在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

    每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

    注意,一开始你手头没有任何零钱。

    给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

    示例 1:

    输入:bills = [5,5,5,10,20]
    输出:true
    解释:
    前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
    第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
    第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
    由于所有客户都得到了正确的找零,所以我们输出 true。
    

    示例 2:

    输入:bills = [5,5,10,10,20]
    输出:false
    解释:
    前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
    对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
    对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
    由于不是每位顾客都得到了正确的找零,所以答案是 false。
    

    提示:

    • 1 <= bills.length <= 105
    • bills[i] 不是 5 就是 10 或是 20 

    我的思路:因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!所以找零优先用10元面值 

    1. class Solution {
    2. // 判断是否能通过5元和10元找零满足所有顾客
    3. public boolean lemonadeChange(int[] bills) {
    4. // 使用一个数组来统计各个面额的纸币数量,数组下标代表纸币面额,从1到20
    5. int[] count = new int[21];
    6. // 遍历每张纸币
    7. for(int i = 0; i < bills.length; i++){
    8. // 当前纸币的面额出现次数加1
    9. count[bills[i]] += 1;
    10. // 需要的找零金额,初始值为当前纸币面额减去5
    11. int change = bills[i] - 5;
    12. // 当需要找零的金额大于等于10,并且还有10元纸币可用时
    13. while(change >= 10 && count[10] > 0){
    14. // 使用一张10元纸币找零
    15. count[10] -= 1;
    16. // 更新找零金额,减去10
    17. change -= 10;
    18. }
    19. // 当剩余的找零金额大于等于5,并且还有5元纸币可用时
    20. while(change >= 5 && count[5] > 0){
    21. // 使用一张5元纸币找零
    22. count[5] -= 1;
    23. // 更新找零金额,减去5
    24. change -= 5;
    25. }
    26. // 如果找零金额仍然不为0,说明当前纸币无法找零
    27. if(change != 0){
    28. return false;
    29. }
    30. }
    31. // 如果所有纸币都能成功找零,返回true
    32. return true;
    33. }
    34. }

     找零有如下三种情况:

    • 情况一:账单是5,直接收下。
    • 情况二:账单是10,消耗一个5,增加一个10
    • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

    此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。

    而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。

    账单是20的情况,为什么要优先消耗一个10和一个5呢?

    因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!

    所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。

    1. class Solution {
    2. public boolean lemonadeChange(int[] bills) {
    3. // five表示当前拥有的5元纸币数量
    4. int five = 0;
    5. // ten表示当前拥有的10元纸币数量
    6. int ten = 0;
    7. // 遍历顾客支付的每张纸币
    8. for (int i = 0; i < bills.length; i++) {
    9. // 如果当前纸币是5元
    10. if (bills[i] == 5) {
    11. // 增加5元纸币的数量
    12. five++;
    13. }
    14. // 如果当前纸币是10元
    15. else if (bills[i] == 10) {
    16. // 需要找零5元,因此减少5元纸币的数量
    17. five--;
    18. // 增加10元纸币的数量
    19. ten++;
    20. }
    21. // 如果当前纸币是20元
    22. else if (bills[i] == 20) {
    23. // 优先使用10元和5元纸币找零
    24. if (ten > 0) {
    25. // 如果有10元纸币,则使用一张10元纸币找零
    26. ten--;
    27. // 同时使用一张5元纸币找零
    28. five--;
    29. } else {
    30. // 如果没有10元纸币,则使用三张5元纸币找零
    31. five -= 3;
    32. }
    33. }
    34. // 如果在找零过程中5元或10元纸币数量变为负数,说明无法找零,返回false
    35. if (five < 0 || ten < 0) return false;
    36. }
    37. // 如果所有纸币都能成功找零,返回true
    38. return true;
    39. }
    40. }

  • 相关阅读:
    VPP创建接口
    PLC-Recorder以2ms的高速采集西门子S7-1500数据的方法
    部署 TiDB Lightning
    C++中使用嵌套循环遍历多维数组
    [1]-VIO概述
    投影矩阵、NDC 空间与 Reversed-Z
    Tomcat8启动闪退解决办法
    git仓库的基本使用
    DVWA靶场搭建
    Goosehill大G桨板|潮流水上运动,这个夏天带你一起去
  • 原文地址:https://blog.csdn.net/m0_74267125/article/details/136606338