贪心算法

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

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

贪心策略适用的前提是**:局部最优策略能导致产生全局最优解**。

相关笔记:贪心算法及LeetCode中相关问题

一、分配问题
  1. 分配饼干

有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃 最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩 子可以吃饱。

输入两个数组,分别代表孩子的饥饿度和饼干的大小。输出最多有多少孩子可以吃饱的数 量。

Input: [1,2], [1,2,3]

Output: 2

  • 贪心策略:给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干

  • 两个数组分别排序,然后遍历

  • while (child < children.size() && cookie < cookies.size()) {
    	if (children[child] <= cookies[cookie]) ++child;
    	++cookie;
    }
    return child;
    
  1. 发糖果

一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一 个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果;所 有孩子至少要有一个糖果。求解最少需要多少个糖果。

输入是一个数组,表示孩子的评分。输出是最少糖果的数量。

Input: [1,0,2]

Output: 5

  • 首先要准确理解题意:2,4,4的情况最少发的糖果是1,2,1
  • 不需要排序
  • 贪心策略:每次只检查一侧的大小情况(在每次遍历中只考虑并更新相邻一侧的大小关系。 )
    • 不一定所有的贪心策略都是**”优先选择“,也可以是”只处理/先处理“**
    • –> <–两次遍历
二、区间问题/间隔调度

435.不重叠区间

给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。

输入是一个数组,数组由多个长度固定为 2 的数组组成,表示区间的开始和结尾。输出一个 整数,表示需要移除的区间数量。

Input: [[1,2], [2,4], [1,3]]

Output: 1

  • 重叠产生的原因:end值大的区间的start值 < end值小的区间的end值

  • 排序:按end值排序(降低对后面的区间的start值的“要求”)

    • 多维数组自定义排序

    • class myComparator implements Comparator<int []>{
      	public int compare(int[] a,int[] b){
      		return a[1]-b[1];
      	}
      }
      //int[][]的元素类型为int[]
      
  • 贪心策略:优先选择不重叠的,end值小的区间

  1. 用最少数量的箭引爆气球 TO DO

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。

一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。

Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球

三、其他
  1. 划分字母区间

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

Input: S = “ababcbacadefegdehijhklij”
Output:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少

  • 使用贪心策略之前,可能需要进行一些预处理
    • 在处理数组前,统计一遍信息(如频率、个数、第一次出现位置、最后一次出现位置等)可以使题目难度大幅降低 -----lastIndex[]存储每个字母最后出现的位置
  • 贪心策略:不断选择更大的last index
  1. 非递减数组

给你一个长度为 n 的整数数组,请你判断在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列。

我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。

Input: nums = [4,2,3]
Output: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。

  • 题意理解(结合例子)
    • 重点在于:“改变一个元素”:改大or改小?改谁?
      • 4 2 3: 2<4 不满足,要把4改小(改nums[i-1])
      • 3 1 5: 1<3 不满足,要把1改大i(改nums[i])
    • 贪心策略:进行更改时,选择可以使当前三个元素(i-2,i-1,i)满足非递减关系的更改方案
  1. 根据身高重建队列 TO DO

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj]是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

Input: people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
Output:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值