1005.K次取反后最大化的数组和
这道题是我自己独立思考出来的,我写的代码还蛮冗余的哈哈哈。我发现自己写代码永远是想一出是一出,不会一次想出结果然后把代码精简一下哈哈哈。
解题思路:
先对数组进行排序,然后比较负数个数与k的大小。
①若k大,则翻转所有负数,此时所有元素都是正数。然后判断最小负数和最小正数哪个小,哪个小哪个就对和的影响更小,翻转这个数k-count次即可。
②若count大于等于k,则翻转前count个数,因为数组是经过排序的,前面count个数都是较小的负数,反转后变绝对值和会更大。
Arrays.sort(nums);
int count;
for (count = 0; count < nums.length; count++) {
if (nums[count] > 0) {
break;
}
} //count:小于0的数量
if (count == 0) {
for (int i = 0; i < k; i++) {
nums[count] = nums[count] * -1;
}
}
if (k <= count) {
for (int i = 0; i < k; i++) {
nums[i] = nums[i] * -1;
}
} else if (count > 0 && k > count) {
int cha = k - count;
for (int i = 0; i < count; i++) {
nums[i] = nums[i] * -1;
}
if (count < nums.length) {
if (nums[count] > nums[count - 1]) {
for (int i = 1; i <= k - count; i++)
nums[count - 1] = nums[count - 1] * -1;
} else {
for (int i = 1; i <= k - count; i++) {
nums[count] = nums[count] * -1;
}
}
}else{
for (int i = 1; i <= k - count; i++)
nums[count - 1] = nums[count - 1] * -1;
}
}
int sum = 0;
for (int i : nums) {
sum += i;
}
return sum;
134. 加油站
这道题。。难。。嗯嗯。。
首先明确如何判断这道题是否有解?
定义sum值,遍历结点每次收集gas-cost的值,若最后sum>=0,则说明最后的油量有剩余,有解。否则无解,返回-1即可。
方法一:
定义min表示从0出发的油量总和最小值。初值为0,遍历结点每次取min与sum的小值。
本题有三种情况:
①无解,sum<0,返回-1.
②min>=0,说明有解,且在i=0处开始出发油量一直为正数,则i=0即为解。
③min<0,说明有解,则i从最后一个加油站往前遍历,每次给min添加rest[i],看哪个点能将油量填平使min>=0,则说明从这个点出发油量可以一直大于0。否则无解。
public int canCompleteCircuit(int[] gas, int[] cost) {
int sum=0;
int min=0;
for(int i=0;i<gas.length;i++){
sum+=gas[i]-cost[i];
min=Math.min(sum,min); //min:从起点出发的油量最小值
}
if(sum<0){return -1;}
if(min>=0){return 0;}
for(int i=gas.length-1;i>=0;i--){
int rest=gas[i]-cost[i];
min+=rest;
if(min>=0){ //将油量填满即为答案
return i;
}
}
return -1;
}
方法二(贪心):
定义起点start=0,curSum,记录i从0开始到i的剩余油量。当curSum<0时,首先说明rest[i]在此处小于0,且[0,i-1]curSum是大于0的。若有解,解一定不会在[0,i]这个区间,一定是i+1。
因此当curSum小于0时,记录i+1的值为新起点并将curSum值清零重新累加。
最后判断若sum<0,无解。若sum=0,返回start值即可。
public int canCompleteCircuit(int[] gas, int[] cost) {
int sum = 0;
int curSum = 0;
int start = 0;
for (int i = 0; i < gas.length; i++) {
int rest = gas[i] - cost[i];
sum += rest;
curSum += rest;
if (curSum < 0) {
curSum=0;
start = i + 1;
}
}
if (sum < 0) {
return -1;
} else {
return start;
}
}
35. 分发糖果
看到题目第一眼:这也叫困难?
开始写:哦,原来是我没理解题意。。。果然是我高攀了。
本题要进行两次遍历,分别判断当前值与左右两边的大小。我一开始只想从左往右遍历一遍即可,之和自己的左边比较,漏掉了还要和自己的右边比较(哈哈)。
贪心解题思路:
首先从左往右遍历,candy[0]=0,从1开始若比左边大则为左边candy+1。
然后从右往左比较,最右边值不变,判断i是否比右边i+1大,candy[i]的值若比右边小则保持当前值,若比右边大则为candy[i+1]+1,最后取这两者的大值,既满足原来的条件(比左边大),又满足了当前遍历比右边大的条件。
最后返回sum值即可。
int[] candy=new int[ratings.length];
candy[0]=1;
//比较左边
//从左往右遍历,每次看前一个是不是比自己小
for(int i=1;i<ratings.length;i++){
if(ratings[i]>ratings[i-1]){
candy[i]=candy[i-1]+1;
}else{
candy[i]=1;
}
}
//比较右边
//从右往左遍历,看右边的是不是比自己小
for(int i=ratings.length-2;i>=0;i--){
if(ratings[i]>ratings[i+1]){
//如果当前的比右边大(此时已经比左边大),则取当前candy和右边candy+1的大值,满足既比左边大,也比右边大、
candy[i]=Math.max(candy[i+1]+1,candy[i]);
}
}
int sum=0;
for(int i:candy){
sum+=i;
}
return sum;