【leetcode】贪心问题刷题记录(一)

【leetcode】贪心问题刷题记录(一)


前言

本文是基于leetcode贪心问题例题的学习记录

455. 分发饼干

链接
先从简单的开始,贪心问题顾名思义取最优,但是具体怎样做还是得从易到难慢慢积累

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());sort(s.begin(), s.end());
        int ans = 0;
        int size = s.size();
        for(int i = g.size() - 1; i >= 0; i -- )
        {
            if(size > 0 && g[i] <= s[size - 1])
            {
                ans ++;
                size --;
            }
        }
        return ans;
    }
};

376. 摆动序列

链接
一开始完全看错了,以为是连续序列
错误版本:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int flag = 0, last_number = nums[0];
        int res = 0, ans = 0;
        for(int i = 1; i < nums.size(); i ++ )
        {
            if(nums[i] > last_number)
            {
                if(flag == 0 || flag == -1)
                {
                    last_number = nums[i];
                    flag = 1;
                    res ++;
                }
                else 
                {
                    last_number = nums[i];
                    ans = max(ans, res);
                    res = 0;
                    flag = 1;
                }
            }
            else if(nums[i] < last_number)
            {
                if(flag == 0 || flag == 1)
                {
                    last_number = nums[i];
                    flag = -1;
                    res ++;
                }
                else 
                {
                    last_number = nums[i - 1];
                    ans = max(ans, res);
                    res = 0;
                    flag = -1;
                }
            }
            else
            {
                ans = max(ans, res);
                last_number = nums[i - 1];
                res = 0;
                flag = 0;
            }
        }
        return ans;
    }
};

正确版本:
题解

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size() <= 1)return nums.size();
        int pre = 0, cur = 0;
        int ans = 1;
        for(int i = 0; i < nums.size() - 1; i ++ )
        {
            int cur = nums[i + 1] - nums[i];
            if((pre <= 0 && cur > 0) || (pre >= 0 && cur < 0))
            {
                ans ++;
                pre = cur;
            }
        }
        return ans;
    }   
};

53. 最大子数组和

链接
做过的题,先用动态规划做一次

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        vector<int> dp(nums.size(), 0);
        dp[0] = nums[0];
        int ans = dp[0];
        for(int i = 1; i < nums.size(); i ++ )
        {
            dp[i] = max(dp[i - 1] + nums[i], nums[i]);
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

从dp也能透到一些贪心的做法

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ans = 0, res = 0;
        for(int num : nums)
        {
            res += num;
            if(res < 0)res = 0;
            ans = max(ans, res);
        }
        return ans;
    }
};

第一次写的有些过不了,忘了数组里全是负数的情况,修改之后通过

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ans = INT_MIN, res = 0;
        for(int num : nums)
        {
            res += num;
            ans = max(ans, res);
            if(res < 0)res = 0;
        }
        return ans;
    }
};

122. 买卖股票的最佳时机 II

链接
还是先用dp做一遍

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int size = prices.size();
        if(size == 0)return 0;
        vector<vector<int>> dp(size, vector<int>(2));
        dp[0][0] = 0;
        dp[0][1] = - prices[0];
        for(int i = 1; i < size; i ++ )
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[size - 1][0];
    }
};

贪心的做法是:只要涨价了就卖

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans = 0;
        for(int i = 0; i < prices.size() - 1; i ++ )
            ans += max(prices[i + 1] - prices[i], 0);
        return ans;
    }
};

55. 跳跃游戏

链接
跟上一题很像,把连续的一段拆成小段,把跳三格拆成跳三次一格

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() <= 1)return true;
        int steps = 0;
        for(auto num : nums)
        {
            steps --;
            if(num > steps)steps = num;
            if(steps == 0)return false;
        }
        return true;
    }
};

这一个解法有错误,忽略了刚好跳完的情况
正确写法:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() <= 1)return true;
        int steps = 0;
        for(int i = 0; i < nums.size(); i ++ )
        {
            steps --;
            if(nums[i] > steps)steps = nums[i];
            if(steps == 0 && i != nums.size() - 1)return false;
        }
        return true;
    }
};

45. 跳跃游戏 II

链接
自己写的,思路错了,只过了一半

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() <= 1)return 0;
        int steps = 0;
        int ans = 0;
        for(int i = 0; i < nums.size(); i ++ )
        {
            steps --;
            if(i + steps + 1 >= nums.size())break;
            if(nums[i] > steps)
            {
                steps = nums[i];
                ans ++;
            }
        }
        return ans;
    }
};

正确的解法是,只有当走到底走不了的时候才加一步,所以在之前就要保存多走一步能到达的最远距离
题解

class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) return 0;
        int curDistance = 0;    // 当前覆盖最远距离下标
        int ans = 0;            // 记录走的最大步数
        int nextDistance = 0;   // 下一步覆盖最远距离下标
        for (int i = 0; i < nums.size(); i++) {
            nextDistance = max(nums[i] + i, nextDistance);  // 更新下一步覆盖最远距离下标
            if (i == curDistance) {                         // 遇到当前覆盖最远距离下标
                ans++;                                  // 需要走下一步
                curDistance = nextDistance;             // 更新当前覆盖最远距离下标(相当于加油了)
                if (nextDistance >= nums.size() - 1) break;  // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束
            }
        }
        return ans;
    }
};
// 版本二
class Solution {
public:
    int jump(vector<int>& nums) {
        int curDistance = 0;    // 当前覆盖的最远距离下标
        int ans = 0;            // 记录走的最大步数
        int nextDistance = 0;   // 下一步覆盖的最远距离下标
        for (int i = 0; i < nums.size() - 1; i++) { // 注意这里是小于nums.size() - 1,这是关键所在
            nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖的最远距离下标
            if (i == curDistance) {                 // 遇到当前覆盖的最远距离下标
                curDistance = nextDistance;         // 更新当前覆盖的最远距离下标
                ans++;
            }
        }
        return ans;
    }
};

34. 加油站

链接
写得有些冗长了

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int sum = 0;
        for(int i = 0; i < gas.size(); i ++ )
        {
            gas[i] -= cost[i];
            sum += gas[i];
        }
        if(sum < 0)return -1;
        int ans = 0, res = 0;
        int size = gas.size();
        for(int i = 0; i < 2 * size; i ++ )
        {
            res += gas[i % size];
            if(res < 0)
            {
                res = 0;
                ans = (i % size) + 1;
            }
        }
        return ans;
    }
};

看看题解
题解

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int totalSum = 0;
        int start = 0;
        for (int i = 0; i < gas.size(); i++) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if (curSum < 0) {   // 当前累加rest[i]和 curSum一旦小于0
                start = i + 1;  // 起始位置更新为i+1
                curSum = 0;     // curSum从0开始
            }
        }
        if (totalSum < 0) return -1; // 说明怎么走都不可能跑一圈了
        return start;
    }
};

明显简化了很多,学习学习~

135. 分发糖果

链接
枯了,又是看错了题,看成相邻高几分就多分多少糖果
错误代码:

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> res(ratings.size(), 0);
        int m = INT_MAX;
        for(int i = 1; i < ratings.size(); i ++ )
        {
            res[i] = ratings[i] - ratings[i - 1];
            m = min(m, res[i]);
        }
        int ans = 0;
        for(auto rate : res)
        {
            ans += 1 + rate - m;
            cout << ans << ' ';
        }
        return ans;
    }
};

正确解法:

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.柠檬水找零

链接
基本上就是模拟,加了一点点贪心,直接cv了~
题解

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;
    }
};

406. 根据身高重建队列

链接
二维的方式没想出来,看看题解
题解

class Solution {
public:
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort (people.begin(), people.end(), cmp);
        vector<vector<int>> que;
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1];
            que.insert(que.begin() + position, people[i]);
        }
        return que;
    }
};

435. 无重叠区间

链接
这种区间问题要么就是排序头要么就是排序尾

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) return 0;
        sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b){
            return a[1] < b[1];
        });
        int cnt = 1;
        int end = intervals[0][1];
        for(int i = 1; i < intervals.size(); i ++ )
        {
            if(intervals[i][0] >= end)
            {
                end = intervals[i][1];
                cnt++;
            }
        }
        return intervals.size() - cnt;
    }
};

今天就先练到这里了,贪心问题其实也是熟能生巧,多练多积累就会了。吃月饼去咯,中秋快乐~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值