1005. K 次取反后最大化的数组和
要求:给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:
- 选择某个下标
i并将nums[i]替换为-nums[i]。
重复这个过程恰好 k 次。可以多次选择同一个下标 i 。
以这种方式修改数组后,返回数组 可能的最大和 。
思路
将nums数组按照绝对值大小排序,在遍历数组时如果遇到负数且k>0时,将负数转为正值,如果k>0,就反复转变数值最小的元素,将K用完。
var largestSumAfterKNegations = function(nums, k) {
nums.sort((a,b) => Math.abs(b)-Math.abs(a))
for(let i=0; i<nums.length; i++){
if(nums[i]<0 && k>0){
nums[i] = -nums[i]
k--
}
}
while(k >0){
nums[nums.length-1] = -nums[nums.length-1]
k--
}
return nums.reduce((a,b)=> a+b)
};
134. 加油站
要求:在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] **升。
你有一辆油箱容量无限的的汽车,从第 **i **个加油站开往第 **i+1 **个加油站需要消耗汽油 cost[i] **升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
思路
首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈,说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。
每个加油站的剩余量rest[i]为gas[i] - cost[i]。
i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。
var canCompleteCircuit = function(gas, cost) {
//暴力
for(let i=0; i<gas.length; i++){ //遍历起点加油站
let rest = gas[i] - cost[i] //剩余油量
let index = (i+1) % cost.length //下一个加油站
while(rest > 0 && index != i){ //模拟以i为起点行驶一圈是否可行
rest += gas[index] - cost[index]
index = (index+1) % cost.length
}
if(rest >=0 && index == i) return i
}
return -1
};
//贪心
var canCompleteCircuit = function(gas, cost) {
let curSum = 0 //每站剩余油量
let totalSum = 0
let start = 0 //起点
for(let i=0; i<gas.length; i++){
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i] //计算整个路程是否能跑完
if(curSum < 0){
//一旦剩余油量小于0,那么只能从下一个站出发,并且只要整体油量是够用的一定能走完
start = i+1
curSum = 0
}
}
if(totalSum < 0){
return -1
}
return start
};
135. 分发糖果
要求:n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
- 每个孩子至少分配到
1个糖果。 - 相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
思路
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
先确定右边评分大于左边的情况(也就是从前向后遍历)
此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
再确定左孩子大于右孩子的情况(从后向前遍历)
如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
var candy = function(ratings) {
let candy = new Array(ratings.length).fill(1)
//从前向后,后面的评分比前面高则糖 +1 (遍历都从第二个开始)
for(let i=1; i<ratings.length; i++){
if(ratings[i] > ratings[i-1]){
candy[i] = candy[i-1] + 1
}
}
//从后向前
for(let i=ratings.length-2; i>=0; i--){
if(ratings[i] > ratings[i+1]){
candy[i] = Math.max(candy[i+1] + 1, candy[i])
}
}
let res = 0
candy.forEach(item => {
res += item
})
return res
};