一、题目打卡
1.1 k次取反后最大化的数组和
题目链接:. - 力扣(LeetCode)
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(),nums.end()); // 首先需要排序一下
for(auto &it : nums){
if(it<=0){
it = it * -1;
k--;
}
if(k==0) break;
}
sort(nums.begin(),nums.end());
// for(auto &it:nums){
// cout << it << endl;
// }
while(k > 0){
nums[0] = nums[0] * -1;
k--;
}
int res = 0;
for(auto &it : nums){
res += it;
}
return res;
}
};
整体的思路是,先进行排序,然后在 k 次数大于0的情况下,尽可能多的去取反绝对值比较大的负数,如果没有负数了,并且反转的次数也还没有用完,那就再次进行扭转,这时候就一直反转最小的正数或者是0就行了。
1.2 加油站
题目链接:. - 力扣(LeetCode)
// 尝试的第一版,直接贪心找到差值最大的位置,这样会出现问题:
/*
[5,8,2,8]
[6,5,6,6]
*/
// class Solution {
// public:
// int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
// int diff = INT_MIN;
// int startInd;
// int size = gas.size(); // 这里必须要提前统计,否则会不断循环
// for(int i = 0 ; i < size;i++){
// gas.push_back(gas[i]);
// cost.push_back(cost[i]);
// if(diff < gas[i] - cost[i]){
// diff = gas[i] - cost[i];
// startInd = i;
// }
// }
// // queue<int> q;
// // for(int i = 0 ; i < gas.size();i++){
// // // if(gas[i] - cost[i] > max_diff){
// // // 方便后面继续进行搜索
// // gas.push_back(gas[i]);
// // cost.push_back(cost[i]);
// // diff = gas[i] - cost[i];
// // if(diff > 0) q.push(i); // 存储所有可以作为起点的位置
// // // }
// // }
// // while(!q.empty()){
// // startInd = q.front();
// // q.pop();
// // // 初始化油量
// // int fuel = 0;
// // for(int ind = startInd; ind < startInd + gas.size(); ind++){
// // fuel = fuel + gas[ind] - cost[ind];
// // if(fuel < 0 ) break;
// // if(fuel >= 0 && ind + 1 == startInd + gas.size()) return startInd;
// // }
// // }
// // 初始化油量
// int fuel = 0;
// for(int ind = startInd; ind < startInd + size; ind++){
// fuel = fuel + gas[ind] - cost[ind];
// if(fuel < 0 ) break;
// if(fuel >= 0 && ind + 1 == startInd + size) return startInd;
// }
// return -1;
// }
// };
// class Solution {
// public:
// int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
// // int diff = INT_MIN;
// // int startInd;
// if(gas.size() == 1 && gas[0] >= cost[0]) return 0;
// if(gas.size() == 1 && gas[0] < cost[0]) return -1;
// int size = gas.size(); // 这里必须要提前统计,否则会不断循环
// vector<int> startInds;
// for(int i = 0 ; i < size;i++){
// gas.push_back(gas[i]);
// cost.push_back(cost[i]);
// if(gas[i] - cost[i] > 0){
// startInds.push_back(i);
// }
// }
// // 初始化油量
// for(auto &startInd : startInds){
// int fuel = 0;
// for(int ind = startInd; ind < startInd + size; ind++){
// fuel = fuel + gas[ind] - cost[ind];
// if(fuel < 0 ) break;
// if(fuel >= 0 && ind + 1 == startInd + size) return startInd;
// }
// }
// return -1;
// }
// };
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int totalSum = 0;
int startInd = 0;
for(int i = 0 ; i < gas.size() ; i++){
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if(curSum < 0){
startInd = i + 1;
curSum = 0;
}
}
if(totalSum < 0) return -1;
return startInd;
}
};
题目我用暴力解法做了做,勉强通过了,暴力的思路也很简单,就是遇到差值是正的时候就进行检验,这时候就肯定是一个双层循环了,答案是用while写的,我感觉那种方法自己一直不太适应,我用的是增加列表的方法,还是答案方法更好一点:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
for (int i = 0; i < cost.size(); i++) {
int rest = gas[i] - cost[i]; // 记录剩余油量
int index = (i + 1) % cost.size();
while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)
rest += gas[index] - cost[index];
index = (index + 1) % cost.size();
}
// 如果以i为起点跑一圈,剩余油量>=0,返回该起始位置
if (rest >= 0 && index == i) return i;
}
return -1;
}
};
不过这个题目本身还是考察贪心的解法,我看了下答案的两个解法,感觉第二个稍微好理解一点,然后看了答案自己写了一次,我感觉这个关键的一个思路就是:如果当前累加的和为负数了,那么开始的位置一定是在这个位置的后面,这个思想虽然证明的过程我理解不了,但是代码过程还是比较好理解的,这里注意需要维护一个整体的和,最终用来判断是否可以完成闭环。
1.3 分发糖果
题目链接:. - 力扣(LeetCode)
// class Solution {
// public:
// int candy(vector<int>& ratings) {
// if(ratings.size() == 1) return 1;
// if(ratings.size() == 2) return ratings[0] == ratings[1] ? 2 : 3;
// vector<bool> flag(ratings.size(),false);
// for(int i = 1 ; i < ratings.size() - 1 ; i++){
// // if(!flag[i - 1] && ratings[i] > ratings[i - 1]){
// if(ratings[i] > ratings[i - 1]){
// flag[i] = true;
// }
// }
// // if(ratings[0] > ratings[1]) flag[0] = true;
// // if(ratings.back() > ratings[ratings.size() - 2]) flag[ratings.size() - 1] = true;
// if(ratings[0] > ratings[1]) flag[0] = true;
// else if (ratings[0] < ratings[1]) flag[1] = true;
// if(ratings.back() > ratings[ratings.size() - 2]) flag[ratings.size() - 1] = true;
// else if(ratings.back() < ratings[ratings.size() - 2]) flag[ratings.size() - 2] = true;
// int res = ratings.size();
// for(const auto &it : flag){
// if(it) res++;
// }
// return res;
// }
// };
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> ahead(ratings.size(),1);
vector<int> back(ratings.size(),1);
for(int i = 1 ; i < ratings.size() ; i++){
if(ratings[i] > ratings[i - 1]){
// ahead[i]++;
ahead[i] = ahead[i-1] + 1;
}
}
for(int i = ratings.size() - 2; i > -1 ; i--){
if(ratings[i] > ratings[i + 1]){
// back[i]++;
back[i] = back[i+1] + 1;
}
}
int res = 0;
for(int i = 0; i < ratings.size();i++){
res += max(ahead[i],back[i]);
}
return res;
}
};
一开始思路的大方向是没有问题的,不过我是只考虑了单边也就是从左到右,而且我忘记处理了累加的情况,只是用bool判断是否相邻的更大,这个也算是贪心的一个方向了,只是我没有考虑的很完整。
答案思路看了以后发现这个题目其实挺清晰的。