广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++算法精讲之贪心算法
  • 181
分享到

C++算法精讲之贪心算法

2024-04-02 19:04:59 181人浏览 安东尼
摘要

目录选择排序平衡字符串买股票的最佳时机跳跃游戏钱币找零多机调度问题活动选择无重叠区间选择排序 我们熟知的选择排序,其采用的就是贪心策略。 它所采用的贪心策略即为每次从未排序的数据中选

选择排序

我们熟知的选择排序,其采用的就是贪心策略。 它所采用的贪心策略即为每次从未排序的数据中选取最小值,并把最小值放在未排序数据的起始位置,直到未排序的数据为0,则结束排序。


void swap(int* arr, int i, int j)
{
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

void selectSort(int* arr, int n)
{
	//降序
	for (int i = 0; i < n; i++)
	{
		int maxIndex = i;
		for (int j = i+1; j < n; j++)
		{
			if (arr[j] >= arr[maxIndex])
				maxIndex = j;
		}
		swap(arr, i, maxIndex);
	}
}

平衡字符串

问题描述:

在一个 平衡字符串 中,‘L' 和 ‘R' 字符的数量是相同的。

给你一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

注意:分割得到的每个字符串都必须是平衡字符串,且分割得到的平衡字符串是原平衡字符串的连续子串。

返回可以通过分割得到的平衡字符串的 最大数量 。

贪心策略:从左往右扫描,只要达到平衡,就立即分割,不要有嵌套的平衡。

故可以定义一个变量balance,在遇到不同的字符时,向不同的方向变化,当balance为0时达到平衡,分割数更新。

比如:从左往右扫描字符串s,遇到L,balance-1,遇到R,balance+1.当balance为0时,更新cnt++ 如果最终cnt==0,说明s只需要保持原样,返回1

代码实现:


class Solution {
public:
    int balancedStringSplit(string s) {
        if(s.size() == 1)
            return 0;
        int cnt = 0;
        int balance = 0;
        for(int i = 0; i < s.size(); i++)
        {
            if(s[i] == 'R')
                --balance;
            else 
                ++balance;
            if(balance == 0)
                cnt++;
        }
        if(cnt == 0)
            return 1;

        return cnt;
    }
};

买股票的最佳时机

问题描述:

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

贪心策略:

连续上涨交易日:第一天买最后一天卖收益最大,等价于每天都买卖。

连续下降交易日:不买卖收益最大,即不会亏钱。

故可以遍历整个股票交易日价格列表,在所有上涨交易日都买卖(赚到所有利润),所有下降交易日都不买卖(永不亏钱)

例如从10到50是连续上涨的5天,可以第一天买入,最后一天卖出,利润为40,等价于第一天买入第二天卖出,第二天再买入。。。以此类推

代码实现:


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

        return profit;
    }
};

跳跃游戏

问题描述:

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

贪心策略:

根据题目描述,对于数组中的任意一个位置y,只要存在一个位置x,它本身可以到达,并且它跳跃的最大长度为x+nums[x],这个值大于等于y,即x+nums[x] >= y,那么位置y也可以到达。即对于每一个可以到达的位置x,它使得x+1,x+2,…,x+nums[x] >= y,那么位置y也可以到达。 一次遍历数组中的每一个位置,并实时更新最远可以到达的位置。对于当前遍历到的位置x,如果它在最远可以到达的位置范围内,那么我们就可以从起点通过若干次跳跃达到该位置,因此我们可以用x+nums[x]更新最远可以到达的位置。

在遍历的过程中,如果最远可以到达的位置大于等于数组中的最后一个位置,那就说明最后一个位置可到达,直接返回true。遍历结束后,最后一个位置仍不可达,返回false。

例如:[2, 3, 1, 1, 4]

一开始在位置0,可跳跃的最大长度为2,因此最远可以到达的位置倍更新为2;继续遍历到位置1,由于1<=2,因此位置1可达。用1加上它最大可跳跃的长度3,将最远可以到达的位置更新为4,4大于最后一个位置4,返回true

代码实现:


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

        return false;
    }
};

钱币找零

问题描述:

假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?

贪心策略: 显然,每一步尽可能用面值大的纸币即可。在日常生活中我们也是这么做的。

代码实现:


//按面值降序
struct cmp {
	bool operator()(vector<int>& a1, vector<int>& a2) {
		return a1[0] > a2[0];
	}
};

int solve(vector<vector<int>>& moneyCount, int money)
{
	int num = 0;
	sort(moneyCount.begin(), moneyCount.end(), cmp());
	//首先选择最大面值的纸币
	for (int i = 0; i < moneyCount.size() - 1; i++)
	{
		//选择需要的当前面值和该面值有的数量中的较小值
		int c = min(money / moneyCount[i][0], moneyCount[i][1]);
		money -= c * moneyCount[i][0];
		num += c;
	}
	if (money > 0)
		num = -1;
	return num;
}

多机调度问题

问题描述:

某工厂有n个独立的作业,由m台相同的机器进行加工处理。作业i所需的加工时间为ti,任何作业在被处理时不能中断,也不能进行拆分处理。现厂长请你给他写一个程序:算出n个作业由m台机器加工处理的最短时间。

输入:第一行T(1<T<100)表示有T组测试数据。每组测试数据的第一行分别是整数n,m(1<=n<=10000,1<=m<=100),接下来的一行是n个整数ti(1<=t<=100)。

输出:所需的最短时间

贪心策略:

这个问题还没有最优解,但是用贪心选择策略可设计出较好的近似算法(求次优解) 当n<=m时,只要将作业分给每一个机器即可;当n>m时,首先将n个作业时间从大到小排序,然后依此顺序将作业分配给下一个作业马上结束的处理机。也就是说从剩下的作业中选择需要处理时间最长的,然后依次选择处理时间次长的,直到所有作业全部处理完毕,或者机器不能再处理其他作业为止。如果我们每次是将需要处理时间最短的作业分配给空闲的机器,那么可能就会储秀安其它所有作业都处理完了只剩下所需时间最长的作业在处理的情况,这样势必效率较低。

代码实现:


struct cmp{
	bool operator()(const int& x, const int& y){
		return x > y;
	}
};

int findMax(vector<int>& Machines)
{
	int ret = 0;
	for (int i = 0; i < machines.size(); i++)
	{
		if (machines[i] > machines[ret])
			ret = i;
	}

	return machines[ret];
}

int greedStrategy(vector<int>& works, vector<int>& machines)
{
	//降序
	sort(works.begin(), works.end(), cmp());
	int n = works.size();
	int m = machines.size();
	for (int i = 0; i < n; i++)
	{
		int finish = 0;
		int machineTime = machines[finish];
		for (int j = 1; j < m; j++)
		{
			if (machines[j] < machines[finish])
			{
				finish = j;
			}
		}
		machines[finish] += works[i];
	}

	return findMax(machines);
}

活动选择

问题描述:

有n个需要在同一天使用同一个教室的活动a1, a2, …, an,教室同一时刻只能由一个活动使用。每个活动a[i]都有一个开始时间s[i]和结束时间f[i]。一旦被选择后,活动a[i]就占据半开时间区间[s[i],f[i])。如果[s[i],f[i])和[s[j],f[j])互不重叠,a[i]和a[j]两个活动就可以被安排在这一天。求使得尽量多的活动能不冲突的举行的最大数量。

贪心策略:

1.每次都选择开始时间最早的活动,不能得到最优解。

2.每次都选择持续时间最短的活动,不能得到最优解。

3.每次选取结束时间最早的活动(结束时间最早意味着开始时间也早),可以得到最优解。按这种方法选择,可以为未安排的活动留下尽可能多的时间。如下图的活动集合S,其中各项活动按照结束时间单调递增排序。

代码实现:


struct cmp{
	bool operator()(vector<int>& s1, vector<int>& s2){
		return s1[1] < s2[1];
	}
};

int getMaxNum(vector<vector<int>>& events)
{
	sort(events.begin(), events.end(), cmp());
	int num = 1;
	int i = 0;
	for (int j = 1; j < events.size();j++)
	{
		if (events[j][0] >= events[i][1])
		{
			++num;
			i = j;
		}
	}

	return num;
}

无重叠区间

问题描述:

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。

区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

贪心策略:

法一:与上题活动选择类似,用总区间数减去最大可同时进行的区间数即为结果。

法二: 当按照起点先后顺序考虑区间时,利用一个prev指针追踪刚刚添加到最终列表中的区间。遍历时,可能遇到三种情况:

情况1:当前考虑的两个区间不重叠。这种情况下不移除任何区间,将prev赋值为后面的区间,移除区间数量不变。

情况2:两个区间重叠,后一个区间的终点在前一个区间的终点之前。由于后一个区间的长度更小,可以留下更多空间,容纳更多区间,将prev更新为当前区间,移除区间的数量+1

情况3:两个区间重叠,后一个区间的终点在前一个区间的终点之后。直接移除后一个区间,留下更多空间。因此,prev不变,移除区间的数量+1

代码实现: 法一:


struct cmp{
	bool operator()(vector<int>& s1, vector<int>& s2){
		return s1[1] < s2[1];
	}
};

class Solution {
public:
    int eraseOverlapintervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp());
        int num = 1;
        int i = 0;
        for(int j = 1; j < intervals.size(); j++)
        {
            if(intervals[j][0] >= intervals[i][1])
            {
                i = j;
                num++;
            }
        }

        return intervals.size() - num;
    }
};

法二:


struct cmp{
	bool operator()(vector<int>& s1, vector<int>& s2){
		return s1[1] < s2[1];
	}
};

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if(intervals.empty())
            return 0;
        sort(intervals.begin(), intervals.end(), cmp());
        int prev = 0;
        int num = 0;
        for(int i = 1; i < intervals.size(); i++)
        {
            //情况1 不冲突
            if(intervals[i][0] >= intervals[prev][1])
            {
                prev = i;
            }
            else
            {
                if(intervals[i][1] < intervals[prev][1])
                {
                    //情况2
                    prev = i;
                }
                num++;
            }
        }

        return num;
    }
};

到此这篇关于c++ 算法精讲之贪心算法的文章就介绍到这了,更多相关C++ 贪心算法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++算法精讲之贪心算法

本文链接: https://www.lsjlt.com/news/143836.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++算法精讲之贪心算法
    目录选择排序平衡字符串买股票的最佳时机跳跃游戏钱币找零多机调度问题活动选择无重叠区间选择排序 我们熟知的选择排序,其采用的就是贪心策略。 它所采用的贪心策略即为每次从未排序的数据中选...
    99+
    2022-11-13
  • Java 数据结构与算法系列精讲之贪心算法
    概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. 贪心算法 贪心算法 (Greedy Algorithm) 指的是在每一步选择中都采取在当前状...
    99+
    2022-11-13
  • C++算法学习之贪心算法的应用
    目录贪心1实验题目:减肥的小K1实验题目:最小跳数实验题目:排队接水贪心-堂练实验题目: 区间问题1实验题目:种树实验题目:智力大冲实验题目:删除数字II贪心1 实验题目:减肥的小K...
    99+
    2022-11-13
  • 贪心算法(贪婪算法)
    贪心算法(贪婪算法) 文章目录 **贪心算法思想**选择排序平衡字符串买卖股票的最佳时机跳跃游戏钱币找零多机器调度问题举办活动数量最多无重叠区间 贪心算法思想 ​ 1.贪心算法(又称贪婪算法)是指,在对问题求解时,总是...
    99+
    2023-08-21
    贪心算法 算法 java 数据结构
  • Java贪心算法超详细讲解
    目录什么是贪心算法通过场景理解算法问题分析总结什么是贪心算法 在分析和求解某个问题时,在每一步的计算选择上都是最优的或者最好的,通过这种方式期望最终的计算的结果也是最优的。也就是说,...
    99+
    2022-11-13
  • C++贪心算法怎么应用
    今天小编给大家分享一下C++贪心算法怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。选择排序我们熟知的选择排序,其采用...
    99+
    2023-06-29
  • 【算法】反悔贪心
    文章目录 反悔贪心力扣题目列表630. 课程表 III871. 最低加油次数LCP 30. 魔塔游戏2813. 子序列最大优雅度 洛谷题目列表P2949 [USACO09OPEN] Wor...
    99+
    2023-09-12
    算法 反悔贪心 贪心
  • Python 经典贪心算法之Prim算法案例详解
    最小生成树的Prim算法也是贪心算法的一大经典应用。Prim算法的特点是时刻维护一棵树,算法不断加边,加的过程始终是一棵树。 Prim算法过程: 一条边一条边地加, 维护一棵树。 初...
    99+
    2022-11-12
  • C++BoostGraph算法超详细精讲
    Boost.Graph 中的算法类似于标准库中的算法——它们是通用的并且非常灵活。但是,并不总是很清楚应该如何使用它们。 示例 31.8。使用breadth_...
    99+
    2022-11-13
    C++ Boost Graph C++ Boost Graph算法
  • C++BoostAlgorithm算法超详细精讲
    目录一、说明Boost.Algorithm二、示例练习一、说明Boost.Algorithm Boost.Algorithm 请注意,其他 Boost 库提供了许多算法。例如,您会在...
    99+
    2022-11-13
    C++ Boost Algorithm C++ Boost Algorithm算法
  • C++贪心算法实现马踏棋盘
    本文实例为大家分享了C++贪心算法实现马踏棋盘的具体代码,供大家参考,具体内容如下 算法实现流程: 步骤1:初始化马的位置(结构体horse {x, y}) 步骤2:确定马从当前点...
    99+
    2022-11-13
  • 贪心算法是什么
    本篇文章给大家分享的是有关贪心算法是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1 概念贪心的意思在于在作出选择时,每次都要选择对自身最为有利的结果,保证自身利益的最大化...
    99+
    2023-06-19
  • Java贪心算法之Prime算法原理与实现方法详解
    本文实例讲述了Java贪心算法之Prime算法原理与实现方法。分享给大家供大家参考,具体如下:Prime算法:是一种穷举查找算法来从一个连通图中构造一棵最小生成树。利用始终找到与当前树中节点权重最小的边,找到节点,加到最小生成树的节点集合中...
    99+
    2023-05-31
    java 贪心算法 prime算法
  • 贪心算法①--使用贪心算法思想解活动安排问题-python
    '''一、具有贪心选择结构 复杂问题可以划分成小问题解决二、具有贪心选择性质 是否能够用贪心选择开始一个最优起点,使用贪心选择能否得到一个完整解案例1:最优装载问题 有n个集装箱需要装上一艘重量为W的轮船。 其中...
    99+
    2023-10-26
    贪心算法 python 算法 数据结构 pycharm
  • C++实现贪心算法的示例详解
    目录区间问题区间选点最大不相交区间数量区间分组区间覆盖Huffman树合并果子排序不等式排队打水绝对值不等式货舱选址区间问题 区间选点 给定 N 个闭区间 [ai,bi],请你在数轴...
    99+
    2022-11-13
  • C++ Boost CircularBuffer算法超详细精讲
    提要 库 Boost.CircularBuffer 提供了一个循环缓冲区,它是一个具有以下两个基本属性的容器: 循环缓冲区的容量是恒定的,由您设置。当您调用成员函数(例如 push_...
    99+
    2022-11-13
    C++ Boost CircularBuffer Boost.CircularBuffer C++ CircularBuffer
  • 如何使用贪心算法
    这篇文章主要讲解了“如何使用贪心算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用贪心算法”吧!活动规则客户购买 X 瓶酒,就可以用 Y 个空酒瓶来...
    99+
    2022-10-19
  • Java算法之BFS,DFS,动态规划和贪心算法的实现
    目录前言广度优先搜索深度优先搜索动态规划贪心总结前言 广度优先搜索(BFS)和深度优先搜索(DFS)是图遍历算法中最常见的两种算法,主要用于解决搜索和遍历问题。动态规划和贪心算法则用...
    99+
    2023-05-14
    Java BFS Java DFS Java动态规划 Java贪心
  • Java数据结构与算法系列精讲之KMP算法
    概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. KMP 算法 KMP (Knuth-Morris-Pratt), 是一种改进的字符串匹配算法...
    99+
    2022-11-13
  • Java算法之BFS,DFS,动态规划和贪心算法如何实现
    本篇内容主要讲解“Java算法之BFS,DFS,动态规划和贪心算法如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java算法之BFS,DFS,动态规划和贪心算法如何实现”吧!广度优先搜索...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作