贪心算法(又叫贪婪算法)Greedy Algorithm

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


文章目录

  • 一、贪心算法的思想

  • 二、贪心算法的过程

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


一、贪心算法的思想

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

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

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

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

二、贪心算法的过程

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<int>& prices) {
        //贪心策略:如果想要获得最大利润,可以每天购买或者出售股票使得每一天的利润最大化
        int profit=0;
        for(int i=1;i<prices.size();i++)
        {
            if(prices[i]>prices[i-1])
              profit+=prices[i]-prices[i-1];
        }
        return profit;

    }
};

3.跳跃游戏OJ链接

贪心算法:

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

动态规划:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        //子状态:每个元素能够到达的最大位置
        //状态间的转移方程;F(i)=max(F(i-1),i+nums[i]);
        //初始化:F(0)=nums[0];
        //返回结果:
        vector<int> 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<nums.size()-1;i++)
        {
            dp[i]=max(dp[i-1],i+nums[i]);
            if(dp[i]==i)
              return false;
        }
        return true;
    }
};
class Solution {
public:
    bool canJump(vector<int>& nums) {
        vector<bool> F(nums.size());
        F[0]=true;
        if(nums.size()==1)
        return true;
        for(int i=0;i<nums.size();i++)
        {
            if(F[i])
            {
                for(int j=i+1;j<nums.size()&&j<=nums[i]+i;j++)
                {
                    F[j]=true;
                }
                if(F[nums.size()-1])
                return true;
            }
            else
               return false;
            
        }
        return true;
    }
};

class Solution {
public:
    bool canJump(vector<int>& nums) {
        //子状态:从数组中第i个能否到达最后一个下标
        //状态间的转移方程:j=i+1;j<nums.size()&&j<=nums[i]+i;判断F(j)的状态
        //初始化:F(0)=true;
        //返回结果:F(nums.size()-1);
        vector<bool> F(nums.size());
        F[0]=true;
        if(nums.size()==1)
        return true;
        for(int i=0;i<nums.size();i++)
        {
            if(F[i])
            {
                for(int j=i+1;j<nums.size()&&j<=nums[i]+i;j++)
                {
                    F[j]=true;
                }
                if(F[nums.size()-1])
                return true;
            }
            else
               return false;
            
        }
        return true;
    }
};

4.钱币找零

/*
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct cmp
{
	 bool operator()(vector<int>arry1, vector<int>arry2)
	{
		return arry1[0] > arry2[0];
	}
};
int MaxNum(vector<vector<int>>& 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<int>> 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<iostream>
#include<vector>
#include<algorithm>
using namespace std;

struct cmp
{
	bool operator ()(pair<int, int>& p1, pair<int, int>& p2)
	{
		return p1.first > p2.first;
	}
};
template<class K, class V>
int MaxNum(vector<pair<K, V>>& 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<pair<int, int>> 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<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//贪心策略:每次选择结束时间最早的活动
struct cmp
{
	bool operator()(vector<int>&v1, vector<int>&v2)
	{
		return v1[1]<v2[1];
	}
};
int getMaxNum(vector<vector<int>>& 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<vector<int>> 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<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct cmp
{
	bool operator()(pair<int, int>& p1, pair<int, int>& p2)
	{
		return p1.second < p2.second;
	}
};
template<class K,class V>
int getMaxNum(vector<pair<K, V>>& 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<pair<int, int>> 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<int>&v1,vector<int>&v2)
    {
        return v1[1]<v2[1];
    }
};
class Solution {
public:
//贪心策略:每一步都选取右区间中最小的
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int num=1;
        int i=0;
        sort(intervals.begin(),intervals.end(),cmp());
        for(int j=1;j<intervals.size();j++)
    {
        //将不重复的区间先找出来再减去就剩下没有重复的区间了
        if(intervals[j][0]>=intervals[i][1])
        {
            num++;
            i=j;
        }
    }
    return intervals.size()-num;
        
    }
};

 第二种方式:

struct cmp
{
    bool operator()(vector<int>&v1,vector<int>&v2)
    {
        return v1[1]<v2[1];
    }
};
class Solution {
public:
//贪心策略:每一步都选取右区间中最小的
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int num=0;
        int i=0;
        sort(intervals.begin(),intervals.end(),cmp());
        for(int j=1;j<intervals.size();j++)
    {
        //将不重复的区间先找出来再分重叠情况
        if(intervals[j][0]>=intervals[i][1])
        {
            i=j;
        }
        else
        {
            if(intervals[j][1]<intervals[i][1])
           {
                i=j;
           }
            num++;

        }
    }
    return num;
        
    }
};

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

‘(尐儍苽-℡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值