1005.K次取反后最大化的数组和
思路:
先将数组排序(小→大),从第一个位置开始,比较本位置与下一个位置元素的大小,谁小翻转谁,遇到0停止。到最后一个位置时,如果还没翻转完K步,只翻转最后一个数。
代码:
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
Arrays.sort(nums);
int res = 0;
int index = 0;
for(int i = 0; i < k; i++){//最多翻转k次,碰到0就停
if(nums[index] == 0){
break;
//当比后一个数小时,翻转此数
}else if(index < nums.length -1 && nums[index] <= nums[index + 1]){
nums[index] = -nums[index];
//只有index位置由-变+才会出现这种情况,说明该翻转下一个数了
}else if(index < nums.length -1 && nums[index] > nums[index + 1]){
++index;
nums[index] = -nums[index];
//特殊情况,当index到数组的最后一个位置,不论正负,这个位置的数翻转对和的影响最小
}else if(index == nums.length - 1){
nums[index] = -nums[index];
}
}
for(int num : nums){
res+=num;
}
return res;
}
}
需要注意的点:
1、当index到最后一个位置,没有下一个数可以比较,只对该位置翻转。因为index移动到最后一个位置,说明index-1已经翻转过了,变成正数,无论index的正负,其绝对值都比index-1小,翻转后能最大化数组和。
134. 加油站
思路:
计算走每个加油站增加/减少的油,累加>=0说明能跑完一圈。从i位置累加cursum,记作从i出发剩余的油,一但<0说明从i到目前循环的位置的加油站都不行,重置cursum,从后一个位置重新开始算。
代码:
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int cursum = 0;//检查从某点出发是否
int total = 0;//检查是否能跑完一周
int index = 0;
for(int i = 0; i < gas.length; i++){
cursum += gas[i] - cost[i];
total += gas[i] - cost[i];
if(cursum < 0){//说明从i出发图中油会不够
//精简写法,记录新的起点,如果i到数组末尾,
index = i + 1;
cursum = 0;//重置
}
}
if(total < 0) return -1;
return index;
}
}
需要注意的点:
1、代码的简洁性,循环一次就能解决问题。
135. 分发糖果
思路:
1、右边元素>左边元素,右边 = 左边+1,从前往后遍历。
2、左边元素>右边元素,左边 = 右边+1、已有左边中的最大值。
代码:
class Solution {
public int candy(int[] ratings) {
int[] candynum = new int[ratings.length];
candynum[0] = 1;
//右边比左边元素大就+1(左边元素奖励的基础上)
for(int i = 1; i < ratings.length; i++){
if(ratings[i] > ratings[i - 1]){
candynum[i] = candynum[i - 1] + 1;
}else{
candynum[i] = 1;//就算右边不比左边大,也要填上1(初始化,每个人都有奖励)
}
}
for(int i = ratings.length - 2; i >= 0; i--){
if(ratings[i] > ratings[i + 1]){
candynum[i] = Math.max(candynum[i + 1] + 1, candynum[i]);
}
}
int res = 0;
for(int num : candynum){
res += num;
}
return res;
}
}
需要注意的点:
1、比较并更新两个元素的奖励关系时,要用到已经更新的数据,所以,比较右>左要从前往后更新,比较左>右要从后往前更新。
2、第二次更新时,要取+1和已有的最大值,能保证同时满足与左右比较的条件。