贪心算法-LeetCode 热题 100
本质:局部最优(每次)→全局最优(最终)。
2789. 合并后数组中的最大元素
class Solution {
public long maxArrayValue(int[] nums) {
// 题意:左边的元素要小于它右边的元素,将右边的元素替换为二者之和,删去左边的元素
// 只用sum记录当前数组中的最大值,但是不改变原数组
long sum = nums[nums.length - 1];
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] <= sum)// 当前元素是否小于sum(合并后的数)
sum = nums[i] + sum;// 是,则合并
else
sum = nums[i];// 否,将sum更新为当前元素
}
return sum;
}
}
455. 分发饼干
class Solution {
// g是每个孩子的胃口,s是饼干大小
// "每个孩子最多只能给一块饼干"
public int findContentChildren(int[] g, int[] s) {
// 思路:按孩子胃口从小到大的顺序依次满足每个孩子,且对于每个孩子,选择可以满足这个孩子的胃口且尺寸最小的饼干。
Arrays.sort(g);
Arrays.sort(s);
int child = 0;// 能吃饱的孩子的数量,g数组的指针
int cookie = 0;// 饼干数组的指针,s数组的指针
while (child < g.length && cookie < s.length) {
if (g[child] <= s[cookie])
child++;// 只有当前的饼干能够满足孩子的胃口,孩子指针才向后移
cookie++;// 无论这块饼干有没有分配给孩子,都要向后移
}
return child;
}
}
121. 买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
// 思路:低买高卖就能赚钱
// 历史最低价格 minprice,假设自己的股票是在那天买的。
// 那么我们在第 i 天卖出股票能得到的利润就是 prices[i] - minprice
int minprice = Integer.MAX_VALUE;//历史最低价
int maxprofit = 0;//最大利润值
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice)//如果当前价格比历史最低价还低
minprice = prices[i];// 更新历史最低价
else if (prices[i] - minprice > maxprofit)//如果我在这天卖出,获得的利润大于我之前能获得的最大利润
maxprofit = prices[i] - minprice;// 更新最大利润值
}
return maxprofit;
}
}
55. 跳跃游戏
class Solution {
// 任意一个位置 y,要存在一个位置 x,它本身可以到达&&x+numx[x]>=y,y则可以到达
public boolean canJump(int[] nums) {
int rightmost = 0;// 最远可到达的位置
int n = nums.length;
//如果第一个元素为0,可根据数组长度直接进行判断
if (nums[0] == 0) {
if (nums.length == 1)
return true;
else
return false;
}
for (int i = 0; i < n; ++i) {
if (i <= rightmost) {// 如果当前位置可达
rightmost = Math.max(rightmost, i + nums[i]);// 最远可到达的位置
if (rightmost >= n - 1)// 如果最远可到达的位置到达了数组末尾
return true;
}
}
return false;
}
}
45. 跳跃游戏 II
class Solution {
public int jump(int[] nums) {
int n = nums.length;// 数组长度
int rightmost = 0;// 目前能跳到的最远位置
int steps = 0;// 跳跃步数
int end = 0;// 上次跳跃可达范围右边界(下次的最右起跳点)
for (int i = 0; i < n - 1; ++i) {
if (i <= rightmost) {// 如果当前位置可达
rightmost = Math.max(rightmost, i + nums[i]);// 更新 最远可到达的位置
// 到达上次跳跃能到达的右边界了
if (i == end) {
end = rightmost;// 目前能跳到的最远位置变成了下次起跳位置的右边界
steps++; // 进入下一次跳跃
}
}
}
return steps;
}
}
763. 划分字母区间
class Solution {
public List<Integer> partitionLabels(String s) {
int[] maxPosition = new int[26];// 记录每个字母出现的最远位置
List<Integer> result = new ArrayList<>();// 记录切分后的结果[9,7,8]
for (int i = 0; i < s.length(); i++) {
maxPosition[s.charAt(i) - 'a'] = i;
}
// for (int i = 0; i < maxPosition.length; i++) {
// System.out.println((char) (i + 'a') + "=" + maxPosition[i]);
// }
int start = 0;// 待切割的起始位置
int scannedCharMaxPos = 0;// 已扫描的字符中最远的位置
// 开始切割
for (int i = 0; i < s.length(); i++) {
int curCharMaxPos = maxPosition[s.charAt(i) - 'a']; // 当前扫描的字符的最远位置
scannedCharMaxPos = Math.max(scannedCharMaxPos, curCharMaxPos); // 更新「已扫描的字符中最远的位置」
if (i == scannedCharMaxPos) { // 正好扫描到「已扫描的字符的最远位置」,到达切割点
result.add(i - start + 1);// 此次切割长度
start = i + 1;// 更新,下一个待切割的字符串的起始位置
}
}
return result;
}
}