贪婪算法
1005. K 次取反后最大化的数组和
思路:把负数变为正数
第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
第二步:从前向后遍历,遇到负数将其变为正数,同时K–
第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
第四步:求和
代码
class Solution {
public:
static bool cmp(int a, int b){
return abs(a) > abs(b);
}
int minnum = INT_MAX;
int count = 0;
int sum = 0;
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end(), cmp);
for(int i = 0;i < nums.size(); i++){
if(nums[i] < 0 && k > 0) {
nums[i] = -1* nums[i];
k--;
}
if(nums[i] < minnum){
count = i;
minnum = nums[i];
}
sum += nums[i];
}
if( k %2 == 0 ) return sum ;
else
return sum - nums[count] * 2;
}
};
134. 加油站
思路:暴力跑一圈把每个点都当成起点
遍历每一个加油站为起点的情况,模拟一圈。
如果跑了一圈,中途没有断油,而且最后油量大于等于0,说明这个起点是ok的。
代码:超时
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curgas = 0;
int index = 0;
for(int i = 0; i < gas.size(); i++)
{
curgas = gas[i];
index = i;
int j = i;
int pointsum = gas.size();
while(pointsum) {
cout<<j<<endl;
if(j + 1 < gas.size()){
if(curgas >= cost[j])curgas = curgas - cost[j] + gas[j+1];
else {
curgas = curgas - cost[j];
break;
}
// cout<<curgas<<endl;
}
else{ //从最后加油站到第一个加油站
if(curgas >= cost[j]){
curgas = curgas - cost[j] + gas[0];
j = -1;
}
else {
curgas = curgas - cost[j];
break;
}
}
j++;
pointsum--;
}
// cout<<" "<<curgas<<" "<<index<<endl;
if(curgas >= 0) return index;
}
if(curgas < 0)return -1;
else return index;
}
};
思路:贪心算法
直接从全局进行贪心选择,情况如下:
情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的
情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。
情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。
代码:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int min = INT_MAX;//从起点出发最小油量
int gassum = 0;//所有油量
for(int i = 0; i < gas.size(); i++){
int gasrest = gas[i] - cost[i];//当前剩的油量
gassum += gasrest;
if(min > gassum) min = gassum;
}
cout<<min<<endl;
if(gassum < 0)return -1;//情况一
if(min >= 0)return 0;//可以从0出发
//情况3
for(int i = gas.size() - 1; i >= 0; i--){
int gasrest = gas[i] - cost[i];
min += gasrest;
if(min >=0)return i;
}
return -1;
}
};
135. 分发糖果
思路:确定一边后,再确定另一边
局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
1.右孩子比左孩子好,从前向后遍历
//比较前一个,右孩子比左孩子好
for(int i = 1; i < ratings.size(); i++){
if(ratings[i] > ratings[i - 1]){
casum[i] = casum[i - 1] + 1;
}
}
2.左孩子比右孩子好,从后向前遍历
//比较后一个,左孩子比右孩子好,从后向前遍历
for(int i = ratings.size() - 1; i >= 0; i--){
if(i - 1 >= 0 && ratings[i - 1] > ratings[i]){
if(casum[i - 1] <= casum[i]) casum[i - 1] = casum[i] + 1;
}
}
完整代码
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int>casum(ratings.size(),1);//分糖果总数,每个人先分一颗
int sum = 0;
//比较前一个,右孩子比左孩子好
for(int i = 1; i < ratings.size(); i++){
if(ratings[i] > ratings[i - 1]){
casum[i] = casum[i - 1] + 1;
}
}
//比较后一个,左孩子比右孩子好,从后向前遍历
for(int i = ratings.size() - 1; i >= 0; i--){
if(i - 1 >= 0 && ratings[i - 1] > ratings[i]){
if(casum[i - 1] <= casum[i]) casum[i - 1] = casum[i] + 1;
}
}
for(int i = 0; i < casum.size(); i++){
sum +=casum[i];
}
return sum;
}
};