贪心算法(又叫贪婪算法)Greedy Algorithm
作者:mmseoamin日期:2024-04-30

本篇主要是介绍贪心算法:所谓贪心算法是用计算机来模拟一个“贪心”的人做出决策的过程。这个人十分贪婪,每一步行动总是按某种指标选取最优的操作。而且他目光短浅,总是只看眼前,并不考虑以后可能造成的影响


文章目录

  • 一、贪心算法的思想

  • 二、贪心算法的过程

  • 三、关于贪心算法的一些基本模型


    一、贪心算法的思想

    定义:贪心算法(又称贪婪算法)是指,在对于问题求解时总是能做出在当前看来是最好的选择,也就是说,不是从整体最优上加以考虑,他所指出的是在某种意义上的局部最优解。

    贪心选择是所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素。

    当一个问题的最优解包含其子问题的最优解时,称此问题提具有最优子结构性质,运用贪心策略在每一次转化时都取得了最优解。问题的最优子结构性质是该问题可用贪心算法求解的关键特征。贪心算法的每一次操作都对结果产生影响。贪心算法的每一次操作都对结果产生直接影响,贪心算法对每个子问体的解决方案都做出选择,不能回退。

    贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止。

    二、贪心算法的过程

    1.将求解的问题分为若干个子问题;

    2.将每一子问体求解,得到子问题的局部最优解;

    3.将子问题的局部最优解合成原来解问题的一个解;


    三、关于贪心算法的一些基本模型

    1.分割平衡字符串OJ链接

    class Solution {
    public:
        int balancedStringSplit(string s) {
            //贪心策略:只需要将问题分为若干个子问题,
            //每个子问题中只要达到了平衡就分割
            //如果出先R字符那么将平衡左移,如果出现了L字符那么平衡将进行右移,如果平衡一旦达到平衡就进行分割
            int count=0;//统计分割的次数
            int balance=0;//达到平衡的标志
            for(auto ch:s)
            {
                if(ch=='R')
                --balance;
                else
                ++balance;
                if(balance==0)
                count++;
            }
            return count;
        }
    };

    2.买卖股票的最佳时机IIOJ链接

    class Solution {
    public:
        int maxProfit(vector& prices) {
            //贪心策略:如果想要获得最大利润,可以每天购买或者出售股票使得每一天的利润最大化
            int profit=0;
            for(int i=1;iprices[i-1])
                  profit+=prices[i]-prices[i-1];
            }
            return profit;
        }
    };

    3.跳跃游戏OJ链接

    贪心算法:

    class Solution {
    public:
        bool canJump(vector& nums) {
            //贪心策略:从每一个元素开始如果该位置最远位置可以达到的话则将该位置上的数组与最远位置上的
            //数进行比较更新最大位置
            int MaxDistance=0;
            int pos=nums.size()-1;
            for(int i=0;i=i)
                   MaxDistance=max(MaxDistance,nums[i]+i);
                else
                   return false;
                if(MaxDistance>=pos)
                return true;
            }
            return true;
        }
    };

    动态规划:

    class Solution {
    public:
        bool canJump(vector& nums) {
            //子状态:每个元素能够到达的最大位置
            //状态间的转移方程;F(i)=max(F(i-1),i+nums[i]);
            //初始化:F(0)=nums[0];
            //返回结果:
            vector dp(nums.size(),0);
            dp[0]=nums[0];
            if(nums.size()==1)
            return true;
            if(dp[0]==0)
            return false;
            for(int i=1;i 
    
    class Solution {
    public:
        bool canJump(vector& nums) {
            vector F(nums.size());
            F[0]=true;
            if(nums.size()==1)
            return true;
            for(int i=0;i 
     
    
    class Solution {
    public:
        bool canJump(vector& nums) {
            //子状态:从数组中第i个能否到达最后一个下标
            //状态间的转移方程:j=i+1;j F(nums.size());
            F[0]=true;
            if(nums.size()==1)
            return true;
            for(int i=0;i 
    

    4.钱币找零

    /*
    #include
    #include
    #include
    using namespace std;
    struct cmp
    {
    	 bool operator()(vectorarry1, vectorarry2)
    	{
    		return arry1[0] > arry2[0];
    	}
    };
    int MaxNum(vector>& MoneyCut, int& money)
    {
    	//贪心策略:每一次都是使用最大面值的进行。
    	int count = 0;
    	//根据面值进行递减排序
    	sort(MoneyCut.begin(), MoneyCut.end(), cmp());
    	for (auto arr : MoneyCut)
    	{
    		//0表示面值 1表示个数
    		int c = money / arr[0];
    		c = min(c, arr[1]);
    		money -= c * arr[0];
    		count += c;
    		if (money == 0)
    			return count;
    	}
    	if (money != 0)
    		return -1;
    	return count;
    }
    int main()
    {
    	vector < vector> moneycut = { {1,3},{2,1},{5,4},{10,3},{20,0},{50,1},{100,10} };
    	int money = 0;
    	cin >> money;
    	cout << MaxNum(moneycut, money);
    }
    */
    #include
    #include
    #include
    using namespace std;
    struct cmp
    {
    	bool operator ()(pair& p1, pair& p2)
    	{
    		return p1.first > p2.first;
    	}
    };
    template
    int MaxNum(vector>& MoneyCut, int money)
    {
    	int count = 0;
    	sort(MoneyCut.begin(), MoneyCut.end(), cmp());
    	for (auto arr : MoneyCut)
    	{
    		K c = money / arr.first;
    		c = min(arr.second, c);
    		money -= c * arr.first;
    		count += c;
    		if (money == 0)
    			return count;
    	}
    	if (money != 0)
    		return -1;
    	return count;
    }
    int main()
    {
    	vector> moneycut = { {1,3},{2,13},{5,4 }, {10,3}, {20,0}, {50,1},{100,10} };
    	int money = 0;
    	cin >> money;
    	cout << MaxNum(moneycut, money);
    }

    5.活动选择

    /*#include
    #include
    #include
    using namespace std;
    //贪心策略:每次选择结束时间最早的活动
    struct cmp
    {
    	bool operator()(vector&v1, vector&v2)
    	{
    		return v1[1]>& events)
    {
    	int num = 1;
    	int i = 0;
    	sort(events.begin(), events.end(), cmp());
    	for (int j = 1; j < events.size(); j++)
    	{
    		//按照截止时间的顺序
    		if (events[j][0] >= events[i][1])
    		{
    			num++;
    			i = j;
    		}
    	}
    	return num;
    }
    int main()
    {
    	vector> events = { {1,4},{3,5},{0,6},{5,7},{3,8},{3,8},{5,9},{6,10},{8,11},{8,12},{2,13},{12,14} };
    	cout << getMaxNum(events);
    }
    */
    #include
    #include
    #include
    using namespace std;
    struct cmp
    {
    	bool operator()(pair& p1, pair& p2)
    	{
    		return p1.second < p2.second;
    	}
    };
    template
    int getMaxNum(vector>& events)
    {
    	sort(events.begin(), events.end(), cmp());
    	int num = 1;
    	int i = 0;
    	for (int j = 1; j < events.size(); j++)
    	{
    		if (events[j].first >= events[i].second)
    		{
    			num++;
    			i = j;
    		}
    	}
    	return num;
    }
    int main()
    {
    	vector> events = { {1,4},{3,5},{0,6},{5,7},{3,8},{5,9},{6,10},{8,11},{8,12},{2,13},{12,14} };
    	cout << getMaxNum(events);
    }

    6.无重叠区间OJ链接

    第一种方式:

    struct cmp
    {
        bool operator()(vector&v1,vector&v2)
        {
            return v1[1]>& intervals) {
            int num=1;
            int i=0;
            sort(intervals.begin(),intervals.end(),cmp());
            for(int j=1;j=intervals[i][1])
            {
                num++;
                i=j;
            }
        }
        return intervals.size()-num;
            
        }
    };

     第二种方式:

    struct cmp
    {
        bool operator()(vector&v1,vector&v2)
        {
            return v1[1]>& intervals) {
            int num=0;
            int i=0;
            sort(intervals.begin(),intervals.end(),cmp());
            for(int j=1;j=intervals[i][1])
            {
                i=j;
            }
            else
            {
                if(intervals[j][1]