1005.K次取反后最大化的数组
思路
1.从小到大开始排序,然后将负数全部变成正数,每变一次就k--一次。
2.再次排序,如果此时k已经等于0了,那么直接返回就可以了,如果k此时还不等于0,就看看是奇数还是偶数,如果是偶数,也可以直接返回,如果是奇数,那么反转最前面的那一个(最小的一个)。
代码实现
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int res = 0;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] < 0 && k > 0) {
nums[i] *= -1;
k--;
}
}
sort(nums.begin(), nums.end()); //再次排序
if (k%2 != 0) nums[0] *= -1; // 如果 k 是奇数, 反转最小的元素
for(int i = 0; i < nums.size(); i++) res += nums[i];
return res;
}
};
134.加油站
思路
1.首先应该想到的是,如果总gas-总cost小于0的话,那么注定是没有办法行驶完一圈的。
2.除此之外的话,我们假设从第i个加油站开始出发,然后一直加当前的gas-cost,如果i+k的时候, 当前小于0了,那么说明从i个加油站开始,无法走到i+k,此时就要从i+k+1个加油站重新开始当前的相加。
代码实现
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int res = 0;
int cur_tank = 0;
int sum_tank = 0;
for(int i = 0; i < gas.size(); i++)
{
cur_tank += gas[i]-cost[i];
sum_tank += gas[i]-cost[i];
if(cur_tank<0)
{
cur_tank = 0;
res = i+1;
}
}
if(sum_tank>=0) return res;
return -1;
}
};
反思
一开始的时候,我没有用cur_tank,而是使用了gas-cost,然后记录哪一段路程的结果最大,那么就要他从这一站出发,其实这样做是错误的,因为我们需要的是过程,保证这个那个过程油不会耗尽。
135.分发糖果
思路
这道题目虽然是一道困难题,但是如果想明白了,这个题还是非常简单的。
我们先从左到右比较,如果i<i+1,那么就让当前的i孩子糖果加一,然后从右到左再来一遍就可以了。
代码实现
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candyVec(ratings.size(), 1);
// 从前向后
for (int i = 1; i < ratings.size(); i++) {
if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
}
// 从后向前
for (int i = ratings.size() - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] ) {
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
}
}
// 统计结果
int result = 0;
for (int i = 0; i < candyVec.size(); i++) result += candyVec[i];
return result;
}
};
860.柠檬水找零
思路
设一个sum_5,sum_10,如果碰到了10元的,那么就是sum_5减一,sum_10加一,如果碰到了20元的,那么就先判断一下10元的还有没有,如果没有了,那么就减少三张5元的,如果有,就减少一张10元的,一张5元的。最后统计一下如果sum_5小于0,就说明无法正确找零。
代码实现
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0, twenty = 0;
for (int bill : bills) {
// 情况一
if (bill == 5) five++;
// 情况二
if (bill == 10) {
if (five <= 0) return false;
ten++;
five--;
}
// 情况三
if (bill == 20) {
// 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着
if (five > 0 && ten > 0) {
five--;
ten--;
twenty++; // 其实这行代码可以删了,因为记录20已经没有意义了,不会用20来找零
} else if (five >= 3) {
five -= 3;
twenty++; // 同理,这行代码也可以删了
} else return false;
}
}
return true;
}
};
435.无重叠区间
思路
按照右边界排序,然后如果当前的右边界大于下一个的左边界,那么就说明要多移除一个区间,
如果不大于,那么就继续。
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if(intervals.empty()) return 0;
sort(intervals.begin(), intervals.end(),[](const auto& u, const auto& v){
return u[1]<v[1];
});
int cur = intervals[0][1];
int res = 0;
for(int i = 1; i < intervals.size(); i ++)
{
if(cur > intervals[i][0])
{
res ++;
}
else
{
cur = intervals[i][1];
}
}
return res;
}
};
738.单调递增的数字
思路
从右到左,如果前一个比当前的大,那么就要将前一个减1,当前的位数变为9。最后,将最前面改变位置的后面的搜索有数字变为9。
代码实现
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strNum = to_string(n);
int flag = strNum.size();
for(int i= strNum.size() -1; i > 0; i --)
{
if(strNum[i]<strNum[i-1])
{
flag = i;
//strNum[i] = '9';
strNum[i-1] -= 1;
}
}
for(int i = flag; i <strNum.size(); i ++)
{
strNum[i] = '9';
}
return stoi(strNum);
}
};