一句话总结:找到窍门答对一半。
原题链接:1005 K次取反后最大化的数组和
先排序,然后对负值计数,之后对K与这个负值的进行判断,对不同情况进行分类再求和计算答案。
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
int n = nums.length;
Arrays.sort(nums);
int ans = 0;
int cntNegative = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] <= 0) cntNegative++;
}
if (cntNegative >= k) {
for (int i = 0; i < k; ++i) {
ans -= nums[i];
}
for (int i = k; i < n; ++i) {
ans += nums[i];
}
return ans;
} else {
for (int i = 0; i < cntNegative; ++i) {
nums[i] = -nums[i];
}
Arrays.sort(nums);
for (int i = 0; i < k - cntNegative; ++i) {
nums[0] = -nums[0];
}
for (int x : nums) ans += x;
return ans;
}
}
}
还有一种利用哈希表的解法,思想大致一样,但少了额外排序的时间,因此时间复杂度更低。解法来源于0ms版本。
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
int[] arr = new int[201];//hash表,这道题的范围是-100到100,正好需要201个位置存储。下标0表示-100
int sum = 0;//保存当前nums数组的和
for(int n : nums){
arr[n+100]++;//统计元素出现次数
sum += n;//统计当前所有元素的和
}
for(int i = 0; i < 100 && k > 0; i++){//从小到大遍历hash表中的负数
if(arr[i] != 0){//如果当前数字还有剩余
//如果当前数字i出现次数 < k ,则获取i的出现次数
//如果当前数字i的出现次数 > k, 则获取k,表示剩余可以取负的次数
int min = Math.min(arr[i],k);//获取当前数字的出现次数和k,较小的一个
k -= min;//对当前数字i,每一个都取负,k表示可取负的次数,需要对min个i取负
//负数取负后,变为正数,i = 0表示的是-100,取负变为100,应该存储在i = 200的位置,
//i = 200表示的是正100
arr[200-i] += min;//对min个i取负,则变为min个正i。存放到相应位置
sum += (200-2*i)*min;//
}
}
if(k % 2 != 0){
for(int i = 100; i <= 200; i++){
if(arr[i] != 0){
sum -= (i-100)*2;
return sum;
}
}
}
return sum;
}
}
原题链接:134 加油站
该算法思想符合贪心。一次遍历数组,找到其中累计可加油量减去与此同时路上耗费油量的最大差值,该位置一定要放在最后一段走,是为贪心思想,而需要返回的即是该位置的后一个位置,从该位置出发可保证。同时设置rem计算总油量与耗费的差值,小于0即说明永远到不了终点,返回-1。
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
int rem = 0;
int minGas = Integer.MAX_VALUE;
int minIndex = 0;
for (int i = 0; i < n; i++) {
rem += gas[i] - cost[i];
if (rem < minGas) {
minGas = rem;
minIndex = i;
}
}
if (minGas > 0) return 0;
return rem < 0 ? -1 : (minIndex + 1) % n;
}
}
原题链接:135 分发糖果
利用一个数组left计算从左边来看应当给多少糖果,即如果ratings[i] > ratings[i - 1]即使得left[i] = left[i - 1] +1,否则left[i] = 1。然后再遍历一遍数组,一边遍历一遍计算右值,最后答案即是left[i]和right的较大者。
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] left = new int[n];
for (int i = 0; i < n; ++i) {
if (i > 0 && ratings[i] > ratings[i - 1]) left[i] = left[i - 1] + 1;
else left[i] = 1;
}
int right = 0, ans = 0;
for (int i = n - 1; i >= 0; --i) {
if (i < n - 1 && ratings[i] > ratings[i + 1]) right++;
else right = 1;
ans += Math.max(left[i], right);
}
return ans;
}
}
另有更精彩的解法。
代码如下:
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int ret = 1;
int inc = 1, dec = 0, pre = 1;
for (int i = 1; i < n; i++) {
if (ratings[i] >= ratings[i - 1]) {
dec = 0;
pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1;
ret += pre;
inc = pre;
} else {
dec++;
if (dec == inc) {
dec++;
}
ret += dec;
pre = 1;
}
}
return ret;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/candy/solutions/533150/fen-fa-tang-guo-by-leetcode-solution-f01p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。