摘要
本文主要介绍了LeetCode贪心算法的几个题目,包括1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果。
1、1005.K次取反后最大化的数组和
1.1 思路
- 第一步贪心:寻找绝对值最大的负数优先对其取反
- 第二步贪心:优先取数组中最小的正数,对其进行取反
1.2 代码
public int largestSumAfterKNegations(int[] nums, int k) {
// 第一步贪心:寻找绝对值最大的负数优先对其取反
Arrays.sort(nums);
for(int i=0; i<nums.length; i++) {
if(nums[i] < 0 && k > 0) {
nums[i] = -nums[i];
k--;
}
}
// 第二步贪心:优先取数组中最小的正数,对其进行取反
Arrays.sort(nums);
if(k % 2 == 1) {
nums[0] = -nums[0];
}
return Arrays.stream(nums).sum();
}
2、134. 加油站
2.1 思路
curSum用于跟踪从起始加油站到当前加油站的汽油差值。totalSum用于跟踪整个行程的汽油差值。- 从第一个加油站开始遍历数组。对于每个加油站,计算该加油站的汽油剩余量
gas[i] - cost[i],并累加到curSum和totalSum中。 - 如果
curSum变为负数,说明从当前起始加油站出发无法到达当前加油站,需要重新选择下一个加油站作为新的起始点,同时将curSum重置为0。 - 继续遍历直到完成整个数组。
- 如果
totalSum大于等于0,说明从某个起始加油站出发,可以绕行一圈回到该起始加油站,返回该起始加油站的索引;否则,返回-1,表示无法绕行一圈。
2.2 代码
public int canCompleteCircuit(int[] gas, int[] cost) {
int curSum = 0;
int totalSum = 0;
int start = 0;
for(int i=0; i<gas.length; i++) {
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if(curSum < 0) {
start = i+1;
curSum = 0;
}
}
if(totalSum < 0) {
return -1;
}
return start;
}
3、135. 分发糖果
3.1 思路
-
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
-
先确定右边评分大于左边的情况(也就是从前向后遍历)
- 局部最优:只要右边评分比左边大,右边的孩子就多一个糖果
- 全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
-
再确定左孩子大于右孩子的情况(从后向前遍历)
- 局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的
- 全局最优:相邻的孩子中,评分高的孩子获得更多的糖果
3.2 代码
public int candy(int[] ratings) {
int len = ratings.length;
int[] candy = new int[ratings.length];
Arrays.fill(candy, 1);
// 右-左
for(int i=1; i<len; i++) {
if(ratings[i] > ratings[i-1]) {
candy[i] = candy[i-1] + 1;
}
}
// 左-右
for(int i=len-2; i>=0; i--) {
if(ratings[i] > ratings[i+1]) {
candy[i] = Math.max(candy[i+1] + 1, candy[i]);
}
}
int count = 0;
for(int i=0; i<len; i++) {
count += candy[i];
}
return count;
}