贪心算法10道经典例题(Java实现,含题意、贪心思路、完整代码)
覆盖区间调度、跳跃游戏、零钱、分发糖果、最优买卖股票、区间合并等面试高频题型,难度由入门到中等,每道题明确贪心选择策略(贪心核心:局部最优→全局最优)。
贪心算法核心思想
每一步做出当前看起来最优的选择,无需回溯、无需考虑后续子问题,多数场景需要排序预处理。
例题1:分发饼干(入门基础)
题目
孩子胃口数组g,饼干尺寸数组s。每块饼干最多给1个孩子,尺寸≥胃口才能满足。求最多能满足几个孩子。
贪心策略
两个数组升序排序,小饼干优先喂胃口小的孩子。
import java.util.Arrays;
public class Solution {
public int findContentChildren(int\[\] g, int\[\] s) {
Arrays.sort(g);
Arrays.sort(s);
int child = 0, cookie = 0;
while(child < g.length && cookie < s.length) {
if(scookie >= gchild) {
child++;
}
cookie++;
}
return child;
}
}
例题2:跳跃游戏Ⅰ
题目
数组每个元素代表当前位置最远跳跃长度,判断能否跳到数组最后一位。
贪心策略
遍历每一格,实时更新能到达的最远下标;最远下标覆盖终点则可行。
public boolean canJump(int\[\] nums) {
int far = 0;
for(int i = 0; i < nums.length; i++) {
if(i > far) return false; // 当前位置无法抵达
far = Math.max(far, i + numsi);
if(far >= nums.length - 1) return true;
}
return true;
}
例题3:跳跃游戏Ⅱ(最少跳跃次数)
题目
数组元素代表最远跳跃距离,保证一定能跳到末尾,求最少跳跃次数。
贪心策略
遍历区间,到达上一轮最远边界时触发一次跳跃,更新新的最远可达位置。
public int jump(int\[\] nums) {
int steps = 0;
int curEnd = 0;
int far = 0;
for(int i = 0; i < nums.length - 1; i++) {
far = Math.max(far, i + numsi);
if(i == curEnd) {
steps++;
curEnd = far;
}
}
return steps;
}
例题4:无重叠区间(区间调度经典)
题目
二维数组intervals,每个区间start, end,求最少移除多少区间,剩余区间互不重叠。
贪心策略
按区间右端点升序排序,优先选结束最早的区间,留给后续更多空间。
import java.util.Arrays;
public int eraseOverlapIntervals(int\[\]\[\] intervals) {
if(intervals.length == 0) return 0;
Arrays.sort(intervals, (a,b) -> a1 - b1);
int count = 1;
int lastEnd = intervals01;
for(int i = 1; i < intervals.length; i++) {
if(intervalsi0 >= lastEnd) {
count++;
lastEnd = intervalsi1;
}
}
return intervals.length - count;
}
例题5:区间合并
题目
若干重叠区间,合并所有重叠区间,返回不重叠区间列表。
贪心策略
按区间起点排序,逐个遍历,能合并就更新右端点,不能合并直接存入结果。
import java.util.*;
public int\[\]\[\] merge(int\[\]\[\] intervals) {
if(intervals.length <= 1) return intervals;
Arrays.sort(intervals, (a,b) -> a0 - b0);
List<int\[\]> res = new ArrayList<>();
res.add(intervals0);
for(int i = 1; i < intervals.length; i++) {
int\[\] last = res.get(res.size()-1);
int\[\] curr = intervalsi;
if(curr0 <= last1) {
last1 = Math.max(last1, curr1);
} else {
res.add(curr);
}
}
return res.toArray(new intres.size()\[\]);
}
例题6:买卖股票的最佳时机(只能一次交易)
题目
数组为每日股价,只能买入一次、卖出一次,求最大利润。
贪心策略
遍历同时记录历史最低价格,每天尝试以当前价卖出,更新最大收益。
public int maxProfit(int\[\] prices) {
int minPrice = Integer.MAX_VALUE;
int maxProfit = 0;
for(int p : prices) {
minPrice = Math.min(minPrice, p);
maxProfit = Math.max(maxProfit, p - minPrice);
}
return maxProfit;
}
例题7:买卖股票的最佳时机Ⅱ(无限次交易)
题目
可无限次买卖股票,不能同时持有多股,求最大利润。
贪心策略
只要后一天股价高于前一天,就当天买入次日卖出,累加所有正差值。
public int maxProfit2(int\[\] prices) {
int profit = 0;
for(int i = 1; i < prices.length; i++) {
if(pricesi > pricesi-1) {
profit += pricesi - pricesi-1;
}
}
return profit;
}
例题8:分发糖果
题目
ratings评分数组,规则:每个孩子至少1颗糖果;评分更高的相邻孩子糖果更多。求最少糖果总数。
贪心策略
两次遍历:左→右保证高分右侧更多;右→左保证高分左侧更多,取两者最大值。
public int candy(int\[\] ratings) {
int n = ratings.length;
int\[\] left = new intn;
int\[\] right = new intn;
Arrays.fill(left, 1);
Arrays.fill(right, 1);
// 左到右
for(int i = 1; i < n; i++) {
if(ratingsi > ratingsi-1) lefti = lefti-1+1;
}
// 右到左
for(int i = n-2; i >= 0; i--) {
if(ratingsi > ratingsi+1) righti = righti+1+1;
}
int sum = 0;
for(int i = 0; i < n; i++) sum += Math.max(lefti, righti);
return sum;
}
例题9:跳跃最少加油次数(加油站贪心)
简化版:到达终点最少加油次数
题意
沿路加油站数组,每个站油量,油箱无限容量,初始油量足够开到第一站,求最少加油次数。
贪心策略:路过站点先不加油,油量不足时,回头选途经油量最大的站点补油。
import java.util.PriorityQueue;
public int minRefuelStops(int target, int startFuel, int\[\]\[\] stations) {
PriorityQueue heap = new PriorityQueue<>((a,b)->b-a);
int fuel = startFuel;
int res = 0;
int prev = 0;
for(int\[\] st : stations) {
int pos = st0, gas = st1;
fuel -= pos - prev;
// 油不够,选之前最大油站加油
while(fuel < 0 && !heap.isEmpty()) {
fuel += heap.poll();
res++;
}
if(fuel < 0) return -1;
heap.add(gas);
prev = pos;
}
fuel -= target - prev;
while(fuel < 0 && !heap.isEmpty()) {
fuel += heap.poll();
res++;
}
return fuel >= 0 ? res : -1;
}
例题10:柠檬水找零
题目
顾客依次付5、10、20元,柠檬水单价5元。手里初始无零钱,能否依次完成所有找零。
贪心策略
收到10元优先用5元找零;收到20元优先组合「10+5」,无10元再用3张5元。
public boolean lemonadeChange(int\[\] bills) {
int five = 0, ten = 0;
for(int b : bills) {
if(b == 5) {
five++;
} else if(b == 10) {
if(five == 0) return false;
five--;
ten++;
} else {
// 20元
if(ten > 0 && five > 0) {
ten--;
five--;
} else if(five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
}
题型分类梳理
-
贪心分配类:例题1、例题8、例题10
-
跳跃可达类:例题2、例题3
-
区间贪心(排序):例题4、例题5
-
股票交易贪心:例题6、例题7
-
堆优化进阶贪心:例题9