目录
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
用可满足该孩子的最小饼干去喂该孩子
class Solution { // 方法用于找到可以匹配的孩子和饼干的数量 public int findContentChildren(int[] g, int[] s) { // 对孩子的胃口大小数组和饼干大小数组进行排序 Arrays.sort(g); Arrays.sort(s); // begin变量用于记录饼干数组当前检查的起始位置 int begin = 0; // count变量用于记录成功匹配的孩子和饼干的数量 int count = 0; // 遍历孩子的胃口大小数组 for(int i = 0; i < g.length; i++){ // 从begin开始遍历饼干大小数组 for(int j = begin; j < s.length; j++){ // 如果找到一块饼干的大小大于等于当前孩子的胃口 if(s[j] >= g[i]){ // 更新begin为当前饼干的后一个位置,这样下次就不需要再检查这块饼干 begin = j + 1; // 匹配成功,count加1 count++; // 跳出内层循环,继续检查下一个孩子的胃口 break; } } } // 返回成功匹配的孩子和饼干的数量 return count; }
}
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
class Solution { // 方法用于计算在数组nums上进行k次取反操作后可能得到的最大和 public int largestSumAfterKNegations(int[] nums, int k) { int sum = 0; // 先对数组进行排序,这样负数会排在前面 Arrays.sort(nums); // 遍历数组,将负数取反(如果k还有剩余并且当前数字是负数) for(int i = 0; i < nums.length; i++){ if(k > 0 && nums[i] < 0){ nums[i] = -nums[i]; // 取反当前负数 k--; // k剩余次数减1 } } // 再次对数组进行排序,因为取反操作可能改变了数组的顺序 Arrays.sort(nums); // 如果k还有剩余且为奇数,则将最小的数取反(这样可以得到最大和) if(k > 0 && k % 2 == 1){ nums[0] = -nums[0]; } // 计算排序后数组的总和 for(int i = 0; i < nums.length; i++){ sum += nums[i]; } // 返回计算得到的最大和 return sum; }
}
笨蛋写法,每次取反都取最小的
class Solution {public int largestSumAfterKNegations(int[] nums, int k) {int sum = 0;for(int i = 0; i < k; i++){Arrays.sort(nums);nums[0] = -nums[0]; }for(int i = 0; i < nums.length; i++){sum += nums[i];}return sum;}
}
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元面值
class Solution { // 判断是否能通过5元和10元找零满足所有顾客 public boolean lemonadeChange(int[] bills) { // 使用一个数组来统计各个面额的纸币数量,数组下标代表纸币面额,从1到20 int[] count = new int[21]; // 遍历每张纸币 for(int i = 0; i < bills.length; i++){ // 当前纸币的面额出现次数加1 count[bills[i]] += 1; // 需要的找零金额,初始值为当前纸币面额减去5int change = bills[i] - 5; // 当需要找零的金额大于等于10,并且还有10元纸币可用时 while(change >= 10 && count[10] > 0){ // 使用一张10元纸币找零 count[10] -= 1; // 更新找零金额,减去10 change -= 10; } // 当剩余的找零金额大于等于5,并且还有5元纸币可用时 while(change >= 5 && count[5] > 0){ // 使用一张5元纸币找零 count[5] -= 1; // 更新找零金额,减去5 change -= 5; } // 如果找零金额仍然不为0,说明当前纸币无法找零 if(change != 0){ return false; } } // 如果所有纸币都能成功找零,返回true return true; }
}
找零有如下三种情况:
- 情况一:账单是5,直接收下。
- 情况二:账单是10,消耗一个5,增加一个10
- 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5
此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。
而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。
账单是20的情况,为什么要优先消耗一个10和一个5呢?
因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!
所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
class Solution { public boolean lemonadeChange(int[] bills) { // five表示当前拥有的5元纸币数量 int five = 0; // ten表示当前拥有的10元纸币数量 int ten = 0; // 遍历顾客支付的每张纸币 for (int i = 0; i < bills.length; i++) { // 如果当前纸币是5元 if (bills[i] == 5) { // 增加5元纸币的数量 five++; } // 如果当前纸币是10元 else if (bills[i] == 10) { // 需要找零5元,因此减少5元纸币的数量 five--; // 增加10元纸币的数量 ten++; } // 如果当前纸币是20元 else if (bills[i] == 20) { // 优先使用10元和5元纸币找零 if (ten > 0) { // 如果有10元纸币,则使用一张10元纸币找零 ten--; // 同时使用一张5元纸币找零 five--; } else { // 如果没有10元纸币,则使用三张5元纸币找零 five -= 3; } } // 如果在找零过程中5元或10元纸币数量变为负数,说明无法找零,返回false if (five < 0 || ten < 0) return false; } // 如果所有纸币都能成功找零,返回true return true; }
}