算法入门(六):贪心算法 - 基础入门(Leetcode 121/455/860/376/738)

阅读完本文,你将对贪心算法有初步的认知和刷题能力。

贪心算法

用一句话概括:每一步都选局部最优解。

对于结果是不是最优解并不关心。因为对于全局来说,局部的每一步最优解累计起来,可能是最优解,也可能不是最优解。

因为贪心算法没有固定的模板,只是一种思想,所以本文收录了几道简单和中等难度的题目,用于认识和理解贪心算法。

贪心算法和贪吃蛇

我们用贪吃蛇的例子来感受贪心算法:

如果每一步都选择最优解,蓝色路线是贪心算法选出来的路线,而作为人类,我们一眼就能看出,红色路线是最优解。这个例子就是贪心算法不是最优解的例子。

Easy / 简单

Leetcode 121 - 买卖股票的最佳时机

Leetcode 121 - 买卖股票的最佳时机

首先来一道HOT100上贪心算法板块的简单题目。

本题的想法是,找最低的价格买入,找最高的价格卖出,求局部最优解,以获得全局最优解。

cpp 复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int minPrice = INT_MAX;
        int maxProfit = 0;
        for(int i = 0;i<n;i++){
            minPrice = min(minPrice,prices[i]);
            maxProfit = max(maxProfit,prices[i] - minPrice); 
        }
        return maxProfit;
    }
};

Leetcode 455 - 分发饼干

Leetcode 455 - 分发饼干

两列数据按照顺序排列后,注意越界判断,可以写在for循环里:

cpp 复制代码
 for (; ck < cookies.size() && cd < childs.size(); ck++)

也可以写在if里,但注意要在判断大小之前。如下:

cpp 复制代码
class Solution {
public:
    int findContentChildren(vector<int>& childs, vector<int>& cookies) {
        sort(cookies.begin(), cookies.end(), less<int>());
        sort(childs.begin(), childs.end(), less<int>());
        int ck = 0;
        int cd = 0;
        for( ;ck<cookies.size();ck++){
            if(cd <childs.size() && childs[cd] <= cookies[ck]){
                cd++;
            }
        }
        return cd;
    }
};

Leetcode 860 - 柠檬水找零

Leetcode 860 - 柠檬水找零

找零场景分为三种情况,顾客支付5,10,20 。5和10都比较简单,注意20时,当10的值为0时,考虑找零3张5 。

cpp 复制代码
class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0;
        int ten = 0;
        for (int bill : bills) {
            if (bill == 5) {
                five++;
            } else if (bill == 10) {
                ten++;
                if (five) {
                    five--;
                } else {
                    return false;
                }
            } else {
                if (ten && five) {
                    ten--;
                    five--;
                } else if (five >= 3) {
                    five -= 3;
                } else {
                    return false;
                }
            }
        }
        return 1;
    }
}
;

Medium / 中等

Leetcode 376 摆动序列

cpp 复制代码
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        if(n<2){
            return n;
        }
        int preDiff = nums[1] - nums[0];
        int res = preDiff != 0? 2:1;
        for(int i = 2;i<n;i++){
            int diff = nums[i] - nums[i-1];
            if((diff > 0 && preDiff <=0)|| (diff < 0 && preDiff >=0)){
                res++;
                preDiff = diff;
            }
        }
        return res;
    }
};

Leetcode 738 - 单调增加的数字

首先尝试暴力法:

cpp 复制代码
class Solution {
public:
    bool isMono(int n){
        int pre = 10;
        while(n){
            int dig = n % 10;
            if(dig > pre) return false;
            pre = dig;
            n = n / 10;
        }
        return true;
    }
    int monotoneIncreasingDigits(int n) {
       while(n){
            if(isMono(n)){
                return n;
            }
            n--;
       } 
       return 0;
    }
};

发现不转换为字符串,是非常难解决的,尝试转换为字符串,例如85,最后结果是79,可以发现是if(si-1>si),需要把si-1--,且si=9。

再多举几个例子,例如8765,其中的过程是:8765->8759->8699->7999。故写出以下代码:

cpp 复制代码
class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string s = to_string(n);
        for(int i = s.size()-1;i>0;i--){
            if(s[i-1]> s[i]){
                s[i-1]--;
                for(int j = i;j<s.size();j++) s[j] = '9';
            }
        }
        return stoi(s);
    }
};
相关推荐
青山木1 小时前
Hot 100 --- 岛屿数量
java·数据结构·算法·leetcode·深度优先·广度优先
不会就选b1 小时前
算法日常・每日刷题--<归并排序>1
数据结构·算法
啦啦啦啦啦zzzz2 小时前
算法:回溯算法
c++·算法·leetcode
IT探索2 小时前
Linux 查找文件指令总结
linux·算法
Lumos1863 小时前
51单片机从零到实战(完结)——后续学习路线建议
算法
稚南城才子,乌衣巷风流3 小时前
DFS序详解:原理、应用与实现
算法·深度优先·图论
稚南城才子,乌衣巷风流3 小时前
动态树(Dynamic Tree)数据结构详解
数据结构·算法
变量未定义~4 小时前
最小生成树1(Prim模板)、最小生成树2(kruskal模板)、最近公共祖先(模板)
算法