#LeetCode 1005. Maximise Sum Of Array After K Negations
#LeetCode 1005. 视频讲解:贪心算法,这不就是常识?还能叫贪心?LeetCode:1005.K次取反后最大化的数组和_哔哩哔哩_bilibili
这个题目中用到了两次局部最优,第一次是在先用k 将数组中绝对值大的负数转换为正数,这样保证了局部最优。之后又使用k 剩余的次数用在绝对值最小的数值上,这是第二次局部最优。为了提高代码的运行效率,使用k % 2 是否存在余数来快速判断,是否需要给绝对值最小的数目 * (-1) 来消耗掉k 的数值。
这里还用到了流式操作来实现对整数数组 nums 的绝对值大小排序,IntStream.of(array) 先将给定的整数数组转换为一个 IntStream 对象。 .boxed()是将 IntStream 转换为一个包装类型的 Stream,即 Stream<Integer>,这样可以使用 Stream 的各种方法。 .sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1)) 这对流中的元素进行排序。排序的方式是通过比较元素的绝对值大小来实现的。Comparator 接口的 lambda 表达式 (o1, o2) -> Math.abs(o2) - Math.abs(o1) 指定了排序规则,这个排序方式会将绝对值较大的元素排在前面。 .mapToInt(Integer::intValue) 这将 Stream<Integer> 转换为一个 IntStream,将流中的 Integer 元素转换为其对应的基本类型 int。 .toArray()最后将排序后的 IntStream 转换回一个整数数组,则排序完成。
贪心算法代码:
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
nums = IntStream.of(nums)
.boxed()
.sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1))
.mapToInt(Integer::intValue).toArray();
int len = nums.length;
for (int i = 0; i < len; i++) {
if (nums[i] < 0 && k > 0) {
nums[i] *= -1;
k--;
}
}
if (k % 2 == 1) {
nums[len - 1] *= -1;
}
return Arrays.stream(nums).sum();
}
}
#LeetCode 134. Gas Station
#LeetCode 134. 视频讲解:贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站_哔哩哔哩_bilibili
贪心算法的一个要点是:找到最优方案,也就是找到贪心的考虑角度。这个题目是考虑全局最优。如果是增加的油量大于消耗的油量,那么这是优化的方向。设置一个currentSum 这个参数记录从startIndex 到目前的位置中,净增的油量,如果currentSum 变为了负数,则说明已经无法到达目前的位置,那么下次就考虑从这个位置后一个数组开始继续考虑,这个位置之前的所有位置都不会再考虑。
贪心算法代码:
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int currentSum = 0;
int totalSum = 0;
int startIndex = 0;
for (int i = 0; i < gas.length; i++) {
currentSum += (gas[i] - cost[i]);
totalSum += (gas[i] - cost[i]);
if (currentSum < 0) {
startIndex = i + 1;
currentSum = 0;
}
}
if (totalSum < 0) {
return -1;
} else {
return startIndex;
}
}
}
#LeetCode 135. Candy
#LeetCode 135. 视频讲解:贪心算法,两者兼顾很容易顾此失彼!LeetCode:135.分发糖果_哔哩哔哩_bilibili
需要比较两边的情况,需要分为左右两种情况来考虑。
在第一种情况中:是左边的评分高于右侧评分,从左向后遍历,此时的局部最优是只要右边评分比左边评分高,右边的孩子就多一个糖果。
第二种情况是:左孩子大于右孩子的情况需要考虑从右往左的遍历顺序。在这里需要再次考虑贪心,从左向后遍历和从右向左遍历的结果进行比较,选择最大的糖果数目。
贪心算法代码:
class Solution {
public int candy(int[] ratings) {
int[] candy = new int[ratings.length];
for (int i = 0; i < ratings.length; i++) {
candy[i] = 1;
}
for (int i = 1; i < ratings.length; i++) {
if (ratings[i] > ratings[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
for (int j = ratings.length - 2; j >= 0; j--) {
if (ratings[j] > ratings[j + 1]) {
candy[j] = Math.max(candy[j], candy[j + 1] + 1);
}
}
int sum = 0;
for (int k = 0; k < ratings.length; k++) {
sum += candy[k];
}
return sum;
}
}
优化贪心算法:
class Solution {
public int candy(int[] ratings) {
int[] candy = new int[ratings.length];
candy[0] = 1;
for (int i = 1; i < ratings.length; i++) {
candy[i] = (ratings[i] > ratings[i - 1]) ? candy[i - 1] + 1 : 1;
}
for (int i = ratings.length - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candy[i] = Math.max(candy[i], candy[i + 1] + 1);
}
}
int sum = 0;
for (int num : candy) {
sum += num;
}
return sum;
}
}