JAVA进步一点点--数据结构与算法(贪心)

贪心

贪心原理
在这里插入图片描述
在这里插入图片描述

贪心原理的第3点和第4点事难以直接描述的,我们以最常见的问题来说明

活动规划问题

【leetcode】253. 会议室 II
https://leetcode-cn.com/problems/meeting-rooms-ii/
本人非会员,只能找其他人截的图了,
在这里插入图片描述
(1)确定最优子结构
假定ak已经是ai到aj活动中最大相互相容的多活动中的一个,那么Aij(从ai活动到aj活动)可以拆解为下图红框中的部分,此处的最优解就证明和dijkstra的证明十分相似,全路径的最短必然是中间路径的最短。
在这里插入图片描述
因此得到了子结构问题,即递推关系。
f(i,j)=f(i,k)+f(k,j)+1
因为k的位置不确定,形成了最优比较,这个和动态规划的思路一致。
在这里插入图片描述
(2)确定问题的所有子问题是否可以贪心选择
贪心选择其实可以有多种,本问题有两个参数,开始时间和结束时间,那么选择结束时间最早看起来是一种选择
a.结束时间最早
b.开始时间最晚
这个定理就是说,如果最大兼容不包含结束时间最早的,那么用结束时间最早的替换掉现有集合中结束时间最早的那一个,也同样是兼容的集合,因此结束时间最早的必然在里面
在这里插入图片描述
因此ak已经确定,关系式将去掉比较的过程,仅剩一个分支。
(3)使用递归逻辑实现
在这里插入图片描述
无重叠区间
https://leetcode-cn.com/problems/non-overlapping-intervals/
在这里插入图片描述
和活动排序问题十分相似,问题可以转换为最多多少个活动不重叠,即删除的活动数目为length-Max;
部分参考大神代码

	public int eraseOverlapIntervals(int[][] intervals) {
		if(intervals.length==0){
			return 0;
		}
		//以结束时间排序
		Arrays.sort(intervals,((o1, o2) -> o1[1]-o2[1] ));

		int n = intervals.length;
		int right = intervals[0][1];
		//将1加入进去,下一个的活动必须在1的结束时间right之后
		int ans = 1;
		for (int i = 1; i < n; ++i) {
			//如果下一个活动的开始时间比上一个的结束时间right晚,则加入进去
			if (intervals[i][0] >= right) {
				ans++;
				right = intervals[i][1];
			}
		}
		return n - ans;
	}

https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/
在这里插入图片描述
这个题其实和上面的还是一致的,弓箭的位置是任意的,只要重复就可以打爆多个,那么,不重复的就没有办法一起打爆了,所以还是找到所有不重复的数量。

1578. 避免重复字母的最小删除成本
https://leetcode-cn.com/problems/minimum-deletion-cost-to-avoid-repeating-letters/
在这里插入图片描述
题目分析
(1)如果我在一个不重复的位置将字符串S拆分为两个子串,总的最小成本是两个子串的最小成本之和,这个是很容易发现的,因为不重复的字符串 前面和后面是不相关的
f(s)=f(S1)+f(S2)
那么,整体字符串的最小成本为字符串中所有连续重复子串的删除成本之和
比如 f(aabcc) = f(aa)+ f(cc)
(2)尝试贪心策略
f(aa)重复字符串的最小成本其实很简单,留下需要花费最大的那一个就可以了,其余的都干掉
(3)递归实现
问题转换为找到重复区间,花费为重复区间的sum-max

分支处理不太好,思维有点混乱

	public int minCost(String s, int[] cost) {
		if (s == null || s.length() <= 2) {
			return 0;
		}
		//用left和right记录重复字符的位置
		int left = 0;
		int right = 0;
		int result = 0;
		while (right +1 < s.length()) {
			while (left < s.length() && right + 1 < s.length() && s.charAt(left) != s.charAt(right + 1)) {
				left++;
				right++;
			}
			int sum = 0;
			int max = 0;
			while (right + 1 < s.length() && s.charAt(left) == s.charAt(right + 1)) {
				right++;
			}
			if (left != right) {
				for (int i = left; i <= right; i++) {
					sum = sum + cost[i];
					max = Math.max(cost[i], max);
				}
				result = result + sum - max;
				left = ++right;
			}
		}
		return result;
	}

https://leetcode-cn.com/problems/smallest-string-with-a-given-numeric-value/
在这里插入图片描述
题目分析:
(1)最优子结构
即第一个字符确定时的值,而第一个字符越小越好。形成了一个子结构
f(n)=Min{char + f(n-1)}
其中f(n)的目标是小于k
f(n-1)的目标是小于k-char
(2)选择贪心策略
char选择越小时,字典序越小,而char的值和f(n-1)的最大有关,f(n-1)的最大为(n-1)*z
因此分支如下:
char=a (n-1)*z<=k
char = k-(n-1)*z (n-1)*z < k

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值