春招Leetcode刷题日记-D2-贪心算法-训练专题


贪心算法使用总结

当我们意识到,满足贪心算法三要素时候,解决贪心算法问题的时候,一定要遵循的步骤:

1、读懂题目限制条件
2、明确贪心算法使用的三大原则
3、切记,对原始数组中的数据,可以先进行预处理(统计一遍信息-如频率、个数、第一次出现位置、最后一次出现位置等,或者进行相关运算-如计算前缀和等)之后,再进行操作
4、制定贪心策略

力扣605. 种花问题

题目链接:605. 种花问题
在这里插入图片描述

思路

题目要求我们,在不打破规则的前提下,看能否种下n个东西:所以我们只需要看这个地方,最多能种多少即可,明显贪心思想。
1、一定要搞明白规则!想种东西,位置i必须满足:

1、必须是’0’
2、前后必须都得是’0’(边界也可以)

2、所以在这个规则之下,遍历一遍数组即可,发现可以种下,就把数组第i处改为1即可,统计最多可以种多少。

代码

class Solution {
public:
	bool canPlaceFlowers(vector<int>& flowerbed, int n) {
		int size = flowerbed.size();
		int i = 0;
		int cnt = 0;
		while (i < size) {
			if (flowerbed[i] == 1) {
				i++;
			}
			else {
				if ((i - 1 < 0 || flowerbed[i - 1] != 1) && (i + 1 >= size || flowerbed[i + 1] != 1)) {//先考虑边界,在考虑是不是0
					cnt++;
					flowerbed[i] = 1;
					i++;
				}
				else {
					i++;
				}
			}
		}
		return cnt >= n;
	}
};

力扣763. 划分字母区间

题目链接:763. 划分字母区间
在这里插入图片描述
在这里插入图片描述

思路

根据题意,我们需要按照一定的规则进行分划数组
1、但是,我们什么额外的信息都没有,不方便操作,所以,一定要记住!!!!!!对于给出的一大串数据无头绪,先进行"预处理"工作,预处理方向有限,可以帮助我们找到数据规律,确定解题方案。

1、统计形式的预处理,包括:频率、个数、第一次出现位置、最后一次出现位置等
2、运算形式的预处理,包括:前缀和等

2、根据规则,划分好的一个片段中出现的字母,不能在其他片段中出现,所以对于任何一个字母而言,他最后一次出现的地方才可能是作为划分终点的,要不就一定违背了规则。
3、所以,预处理时候,我们存一下所有字母最后出现位置。
4、初始化划分起点终点,初始都为0。
5、用指针i遍历s,每走到一个地方,那个字母一定包括在这个片段之中,那么最终分划的位置和这个字母最后出现的位置二者取最大的,保证这个字母能完全出现在这个片段之中,当足迹i==分划终点,则这个片段分完了,这就是贪心策略

代码

class Solution {
public:
	vector<int> partitionLabels(string s) {//另一种贪心思想,效率更优秀
		int ends[30];
		int n = s.size();
		vector<int> ans;
		for (int i = 0; i < n; i++) {//记录每个字母最后出现位置
			ends[s[i] - 'a'] = i;
		}
		int b = 0, e = 0;
		for (int i = 0; i < n; i++) {
			e = max(e, ends[s[i] - 'a']);
			if (i == e) {
				ans.push_back(e - b + 1);
				b = e + 1;//重新初始化下一个片段起点
			}
		}
		return ans;
	}
};

另一种思路

1、预处理中,我们可以同时收集,“刚出现位置"和"最后出现位置”,这样,任意一个字母,就都可以看成出现在一个区间上,统计出所有这些区间。
2、比如说,题目中,第一个样例,前九个元素,分成第一个片段,a出现在[0,8],b出现在[1,5],c出现在[4,7],同理再找到第二个片段中,字母出现的区间
3、不难发现:
<1>当我们列出所有的出现了的字母的区间之后,每一个片段里的字母对应的区间都是可以合并的,a、b、c有交集,可以合并成一个大的区间,恰好是[0,8]长度为9
<2>不同片段对应的字母区间,无交集,不能合并重叠区间
4、综上,这道题统计完字母出现区间之后,就转化成了合并重叠区间问题,这个详见D2-贪心算法-区间问题中的第三题

class Solution {
public:
	vector<int> partitionLabels(string s) {
		vector<vector<int>> section;//统计出现的字母的起始位置和终止位置
		int start[30] = {};
		int ends[30] = {};
		vector<int> ans;
		vector<bool> v(30, false);

		int n = s.size();
		for (int i = 0; i < n; i++) {
			if (!v[s[i] - 'a']) {
				start[s[i] - 'a'] = i;
				v[s[i] - 'a'] = true;
			}
		}
		for (int i = 0; i < n; i++) {
			ends[s[i] - 'a'] = i;
		}

		for (int i = 0; i < 30; i++) {
			if (v[i]) {
				section.push_back({ start[i],ends[i] });
			}
		}
		int size = section.size();

		sort(section.begin(), section.end(), [](const auto& a, const auto& b) {//合并重叠区间
			return a[0] < b[0];
		});
		int b = section[0][0], e = section[0][1];
		for (int i = 1; i < size; i++) {
			if (section[i][0] > e) {//不可以合并
				ans.push_back(e - b + 1);//写入答案
				b = section[i][0];//初始化端点位置
				e = section[i][1];
			}
			else {//可以合并,更新端点位置
				b = min(b, section[i][0]);
				e = max(e, section[i][1]);
			}
		}
		ans.push_back(e - b + 1);
		return ans;
	}
};


力扣122. 买卖股票的最佳时机 II(不限交易次数的简单股票问题)

题目链接:122. 买卖股票的最佳时机 II
在这里插入图片描述
在这里插入图片描述

思路

1、首先明确题目要求,通过若干次的股票买卖,来让收益最大化,并且不限制交易次数
2、在i天买入,在第j天卖出,收益prices[j]-prices[i],正数为收益,反之为亏损
3、因为总收益是在每次交易中的收益累计而来,所以,我们单独看,每次交易:

1、i+1天相较于i天,价格只要上涨,根据我们计算收益公式可知,我们必会带来收益
2、反之,会亏损
3、那么,我每一次交易,都不会亏损,都只会带来收益,那么,到最后我一定是收益最大化
4、这样,满足贪心算法三个条件,贪心策略也就制定完毕

4、怎么实现上述策略?

只需要看i+1天价格和I天价格比较,若更高,就i天买入,i+1天卖出即可
(一直连续上涨的话,比如示例2,其实也可以拆分成上述方法)

代码

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JLU_LYM

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

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

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

打赏作者

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

抵扣说明:

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

余额充值