【贪心算法】day2

📝前言说明:

  • 本专栏主要记录本人的贪心算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话);(4)贪心策略正确性的 “证明”
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础python入门基础C++学习笔记Linux
🎀CSDN主页 愚润泽

你可以点击下方链接,进行其他贪心算法题目的学习

点击链接开始学习
贪心day1贪心day2
贪心day3贪心day4
贪心day5贪心day6
贪心day7贪心day8
贪心day9贪心day10

也可以点击下面连接,学习其他算法

点击链接开始学习
优选专题动态规划
递归、搜索与回溯贪心算法


179. 最大数

题目链接:https://leetcode.cn/problems/largest-number/description/
在这里插入图片描述


优质解

思路:

  • 该题其实就是一个排序问题,排序问题本质是:选择两个数,然后按规则决定两个数的先后顺序
  • 本题:对于ab,我们尝试获得 abba 的组合,哪个组合大,则为正确的排序(这就是本题的贪心策略)
  • 然后,sort的时候按我们的规则排序即可

细节:

  • 我们可以先把数字转换成字符串,然后拼接字符串,比较字典序
  • 全为 0 的特殊情况

代码:

class Solution {
public:
    string largestNumber(vector<int>& nums) 
    {
        vector<string> strs;
        for(auto x: nums) strs.emplace_back(to_string(x));
        auto rule = [](const string& s1, const string& s2){
            return s1 + s2 > s2 + s1; // 返回true代表优先级高
        };
        sort(strs.begin(), strs.end(), rule);
        string ans = "";
        for(auto s: strs)
            ans += s;
        return ans[0] == '0'? string("0") : ans;
    }
};

时间复杂度 O ( k ⋅ n l o g n ) O(k⋅nlogn) O(knlogn),k 为字符串平均长度,拼接操作时间复杂度为 O ( k ) O(k) O(k)
空间复杂度: O ( n k ) O(nk) O(nk)

证明

来自Leetcode官方题解答案:
在这里插入图片描述


376. 摆动序列

题目链接:https://leetcode.cn/problems/wiggle-subsequence/description/
在这里插入图片描述


优质解

思路:

  • 贪心策略:以序列结束位置为基准,每次只考虑下一个元素是否会让此序列变得更长
  • 下一个位置有两种情况 >< ,代表两个不同状态结尾的序列
  • >up 序列的是在前一个 down 序列的长度上 +1,如果出现连续的 >,只会 +1 一次(正确性保证 1)
  • 因为我们始终记录了两种状态的序列(即:全部状态),并且每次都是在原来最优解的基础上+1,所以每次的局部最优就是全局最优

代码:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if(n == 1) return 1;
        int up = 1, down = 1;
        for(int i = 1; i < nums.size(); i++)
        {
            if(nums[i] > nums[i - 1])
                up = down + 1;
            if(nums[i] < nums[i - 1])
                down = up + 1;
        }
        return max(up, down);
    }
};

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)


300. 最长递增子序列

题目链接:https://leetcode.cn/problems/longest-increasing-subsequence/description/
在这里插入图片描述


优质解

思路:

贪心 + 二分

  • 回想动态规划:如果新插入的数字比原来最长子序列的最后一个数字大,则可以接入(所以我们只关注子序列的最后一个元素和新插入的元素的大小)
  • end[i] 表示:长度为 i 的子序列的最后一个元素的大小
  • 每次插入数时,用二分查找找到最佳的插入位置
    • 如果可以接在目前最长的子序列后面,则代表:变得更长
    • 如果不能,则可能更新(变小)前面某一子序列的结尾的数

代码:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> end; // end[i]: 长度为 i 的序列的结尾的元素
        end.push_back(nums[0]);
        for(int i = 1; i < n; i++)
        {
            if(nums[i] > end.back())
                end.push_back(nums[i]);
            else
            {
                // 二分查找
                int left = 0, right = end.size() - 1;
                while(left < right)
                {
                    int mid = (left + right) >> 1;
                    if(end[mid] < nums[i])
                        left = mid + 1;
                    else
                        right = mid;
                }
                end[left] = nums[i];
            }
        } 
        return end.size();
    }
};

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( n ) O(n) O(n)


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚润泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值