目录
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次取反后最大化的数组和
简单
给你一个整数数组 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.柠檬水找零
简单
在柠檬水摊上,每一杯柠檬水的售价为 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;
// 需要的找零金额,初始值为当前纸币面额减去5
int 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;
}
}