热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

贪心策略在算法设计中的应用与优化

贪心算法在算法设计中具有广泛的应用,特别是在解决优化问题时表现出色。本文通过分析经典问题“买卖股票的最佳时机II”,探讨了贪心策略的基本原理及其在实际问题中的应用。通过实例分析,展示了贪心算法如何通过局部最优选择逐步达到全局最优解,并讨论了其在时间和空间复杂度上的优势。此外,还提出了一些优化方法,以提高算法的效率和适用性。


贪心算法


    • 什么是贪心算法
    • [122. 买卖股票的最佳时机 II](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/)
      • 代码

    • [455. 分发饼干](https://leetcode.cn/problems/assign-COOKIEs/)
      • 思路
      • 代码

    • [435. 无重叠区间](https://leetcode.cn/problems/non-overlapping-intervals/)
      • 1.动态规划
      • 2.贪心

    • [55. 跳跃游戏](https://leetcode-cn.com/problems/jump-game/) (medium)
      • 1.动态规划
      • 2.贪心

    • [881. 救生艇](https://leetcode.cn/problems/boats-to-save-people/)
      • 思路
      • 代码

    • [452. 用最少数量的箭引爆气球](https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/)
      • 代码

    • [134. 加油站](https://leetcode.cn/problems/gas-station/)
      • 思路
      • 代码

    • [860. 柠檬水找零](https://leetcode.cn/problems/lemonade-change/)
      • 代码





什么是贪心算法

贪心法,又称贪心算法,贪婪算法,在对问题求解时,总是做出在当前看来最好的选择,期望通过每个阶段的局部最优选择达到全局最优,但结果不一定最优

适用场景:简单的说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解,就能用贪心算法的到最后的最优解,这种子问题最优解称为最优子结构

贪心算法与动态规划的不同点在于它对每个子问题的解决方案都做出当前的最优选择,不能回退,而动态规划会保留之前的运算结果,并根据之前的结果进行选择,有回退的功能,贪心是动态规划的理想化的情况。


122. 买卖股票的最佳时机 II

难度中等

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示:


  • 1 <&#61; prices.length <&#61; 3 * 104
  • 0 <&#61; prices[i] <&#61; 104

ds_56


  • 思路&#xff1a;因为不限制交易次数&#xff0c;只要今天价格比昨天高&#xff0c;就交易&#xff0c;利润为正累加&#xff0c;最后的和就是最大的利润&#xff0c;注意第一天是没有利润的&#xff0c;这道题之所以可以用贪心是因为局部最优&#xff1a;收集每天的正利润&#xff0c;可以推导出&#xff0c;全局最优&#xff1a;求得最大利润
  • 复杂度分析&#xff1a;时间复杂度O(n)&#xff0c;n是数组的长度。空间复杂度是O(1)

代码

class Solution {
public int maxProfit(int[] prices) {
int n &#61; prices.length;
int res &#61; 0;
for (int i &#61; 1; i < n; &#43;&#43;i) {
//今天价格和昨天的差值是否为正&#xff0c;如果为正累加进去&#xff0c;为负则加0
res &#43;&#61; Math.max(0, prices[i] - prices[i - 1]);
}
return res;
}
}

455. 分发饼干

难度简单

假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。

对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都有一个尺寸 s[j] 。如果 s[j] >&#61; g[i]&#xff0c;我们可以将这个饼干 j 分配给孩子 i &#xff0c;这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子&#xff0c;并输出这个最大数值。

示例 1:

输入: g &#61; [1,2,3], s &#61; [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干&#xff0c;3个孩子的胃口值分别是&#xff1a;1,2,3。
虽然你有两块小饼干&#xff0c;由于他们的尺寸都是1&#xff0c;你只能让胃口值是1的孩子满足。
所以你应该输出1。

示例 2:

输入: g &#61; [1,2], s &#61; [1,2,3]
输出: 2
解释:
你有两个孩子和三块小饼干&#xff0c;2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

提示&#xff1a;


  • 1 <&#61; g.length <&#61; 3 * 104
  • 0 <&#61; s.length <&#61; 3 * 104
  • 1 <&#61; g[i], s[j] <&#61; 231 - 1

思路


  • 思路&#xff1a;大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子&#xff0c;那么就应该优先满足胃口大的。排序两个数组&#xff0c;从右到左遍历&#xff0c;用大饼干首先满足胃口大的小孩
  • 复杂度&#xff1a;时间复杂度O(mlogm &#43; nlogn)。空间复杂度O(logm &#43; logn)

代码

class Solution {
public int findContentChildren(int[] g, int[] s) {
//排序
Arrays.sort(g);
Arrays.sort(s);
int nums &#61; 0;
int index &#61; s.length -1;//饼干的下标
for (int i &#61; g.length - 1; i >&#61; 0; i--) {
//如果当前饼干能够分给要求最大的孩子
if(index >&#61; 0 && s[index] >&#61; g[i]){
nums&#43;&#43;;
index--;
}
}
return nums;
}
}

435. 无重叠区间

难度中等

给定一个区间的集合 intervals &#xff0c;其中 intervals[i] &#61; [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠

示例 1:

输入: intervals &#61; [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后&#xff0c;剩下的区间没有重叠。

示例 2:

输入: intervals &#61; [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: intervals &#61; [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间&#xff0c;因为它们已经是无重叠的了。

提示:


  • 1 <&#61; intervals.length <&#61; 105
  • intervals[i].length &#61;&#61; 2
  • -5 * 104 <&#61; starti

ds_143


1.动态规划


  • 思路&#xff1a;dp[i]表示前i个区间中最大不重合区间的个数&#xff0c;首先将区间数组按左边界排序&#xff0c;找出intervals中最多有多少个不重复的区间&#xff0c;动态规划方程dp[i] &#61; Math.max(dp[i], dp[j] &#43; 1)。intervals的长度减去最多的不重复的区间 就是最少删除区间的个数
  • 复杂度&#xff1a;时间复杂度O(n^2)&#xff0c;两层嵌套循环leetcode执行超时 复杂度过高。空间复杂度O(n)&#xff0c;dp数组的空间

超时

public int eraseOverlapIntervals(int[][] intervals) {
int n &#61; intervals.length;
int[] dp &#61; new int[n];
//按照左边界排序
Arrays.sort(intervals,(o1,o2)->{
return o1[0] - o2[0];
});
Arrays.fill(dp, 1);

for (int i &#61; 1; i < n; &#43;&#43;i) {
for (int j &#61; 0; j < i; &#43;&#43;j) {
if (intervals[j][1] <&#61; intervals[i][0]) {
dp[i] &#61; Math.max(dp[i], dp[j] &#43; 1);
}
}
}
return n - Arrays.stream(dp).max().getAsInt();
}

2.贪心

ds_142


  • 思路&#xff1a;intervals按右边界排序&#xff0c;然后从左往右遍历&#xff0c;右边界结束的越早&#xff0c;留给后面的区间的空间就越大&#xff0c;不重合的区间个数就越多&#xff0c;intervals的长度减去最多的不重复的区间 就是最少删除区间的个数
  • 复杂度&#xff1a;时间复杂度O(nlogn)&#xff0c;数组排序O(nlogn)&#xff0c;循环一次数组O(n)。空间复杂度O(logn)&#xff0c;排序需要的栈空间

https://leetcode.cn/problems/non-overlapping-intervals/solution/435-wu-zhong-die-qu-jian-tan-xin-jing-di-qze0/

class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
//按照右边界排序
//按右边界排序&#xff0c;然后从左往右遍历&#xff0c;右边界结束的越早&#xff0c;
//留给后面的区间的空间就越大&#xff0c;不重合的区间个数就越多
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals,(o1,o2)->{
return Integer.compare(o1[1],o2[1]);
});
int n &#61; intervals.length;
int nums &#61; 0;
int right &#61; intervals[0][1];
for (int i &#61; 1; i < n; i&#43;&#43;) {
if(intervals[i][0] < right){
//如果重叠就丢掉
nums&#43;&#43;;
}else{
//不重叠就更新
right &#61; intervals[i][1];
}
}
return nums;

}
}

能不能用贪心算法需要满足贪心选择性&#xff0c;贪心算法正确的的证明可以用反证法

以这一题为例&#xff1a;


  • 我们的思路是保留最多的不重合的区间&#xff0c;所以按照区间结尾排序&#xff0c;区间结尾结束的越早且和前一个区间不重叠的&#xff0c;就加入最多不重复的区间中&#xff0c;我们称为算法a&#xff0c;假如算法a中的某一个步骤是选择区间[a, b]&#xff0c;我们称为区间A。
  • 假设这个选择不正确&#xff0c;也就是说算法a得到的不是最优解。
  • 我们假设存在另一个算法c能得到最优解&#xff0c;算法c中的一个步骤是选择区间[c, d]&#xff0c;我们称为区间C&#xff0c;使得它是最优解中的一个区间&#xff0c;其中d>b,因为算法a选择的是结尾最先结束且不重合的区间&#xff0c;如果算法a不正确&#xff0c;又因为区间数组中的区间是固定的&#xff0c;则其他算法c肯定存在d>b的情况。
  • 我们用区间A替换区间C完全不影响算法c的结果&#xff0c;因为b,所以不影响区间C后面区间的结果。所以我们选择了区间A也构成了一个最优解。而我们假设的是选择区间A不是最优解&#xff0c;所以和之前的假设矛盾&#xff0c;所以算法a是正确的贪心算法

55. 跳跃游戏 &#xff08;medium&#xff09;

难度中等

给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1&#xff1a;

输入&#xff1a;nums &#61; [2,3,1,1,4]
输出&#xff1a;true
解释&#xff1a;可以先跳 1 步&#xff0c;从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2&#xff1a;

输入&#xff1a;nums &#61; [3,2,1,0,4]
输出&#xff1a;false
解释&#xff1a;无论怎样&#xff0c;总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 &#xff0c; 所以永远不可能到达最后一个下标。

1.动态规划


  • 思路&#xff1a;dp[i]表示能否到达位置i&#xff0c;对每个位置i判断能否通过前面的位置跳跃过来&#xff0c;当前位置j能达到&#xff0c;并且当前位置j加上能到达的位置如果超过了i&#xff0c;那dp[i]更新为ture&#xff0c;便是i位置也可以到达。
  • 复杂度&#xff1a;时间复杂度O(n^2)&#xff0c;空间复杂度O(n)

class Solution {
public boolean canJump(int[] nums) {
int n &#61; nums.length;
boolean[] dp &#61; new boolean[n];
dp[0] &#61; true;
for (int i &#61; 1; i < n; i&#43;&#43;) {
for (int j &#61; 0; j < i; j&#43;&#43;) {
//当前位置j能达到&#xff0c;并且当前位置j加上能到达的位置如果超过了i&#xff0c;那dp[i]更新为ture&#xff0c;便是i位置也可以到达
if(dp[j] &#61;&#61; true && nums[j] &#43; j >&#61; i){
dp[i] &#61; true;
break;
}
}
}
return dp[n - 1];
}
}

2.贪心


  • 思路&#xff1a;不用考虑每一步跳跃到那个位置&#xff0c;而是尽可能的跳跃到最远的位置&#xff0c;看最多能覆盖的位置&#xff0c;不断更新能覆盖的距离。
  • 复杂度&#xff1a;时间复杂度O(n)&#xff0c;遍历一边。空间复杂度O(1)

ds_147

public boolean canJump(int[] nums) {
if (nums.length &#61;&#61; 1) {
return true;
}
int cover &#61; nums[0];//能覆盖的最远距离
for (int i &#61; 0; i <&#61; cover; i&#43;&#43;) {
cover &#61; Math.max(cover, i &#43; nums[i]);//当前覆盖距离cover和当前位置加能跳跃的距离中取一个较大者
// 覆盖距离超过或等于nums.length - 1 说明能到达终点
if (cover >&#61; nums.length - 1) {
return true;
}
}
return false;//循环完成之后 还没返回true 就是不能达到终点
}

881. 救生艇

难度中等

给定数组 peoplepeople[i]表示第 i 个人的体重 &#xff0c;船的数量不限&#xff0c;每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人&#xff0c;但条件是这些人的重量之和最多为 limit

返回 承载所有人所需的最小船数

示例 1&#xff1a;

输入&#xff1a;people &#61; [1,2], limit &#61; 3
输出&#xff1a;1
解释&#xff1a;1 艘船载 (1, 2)

示例 2&#xff1a;

输入&#xff1a;people &#61; [3,2,2,1], limit &#61; 3
输出&#xff1a;3
解释&#xff1a;3 艘船分别载 (1, 2), (2) 和 (3)

示例 3&#xff1a;

输入&#xff1a;people &#61; [3,5,3,4], limit &#61; 5
输出&#xff1a;4
解释&#xff1a;4 艘船分别载 (3), (3), (4), (5)

提示&#xff1a;


  • 1 <&#61; people.length <&#61; 5 * 104
  • 1 <&#61; people[i] <&#61; limit <&#61; 3 * 104

思路

ds_155


  • 思路&#xff1a;题意是一条船只能坐2人&#xff0c;要求尽可能的用少的船装下这些人。所以可以用贪心策略。让更多的人组成2人组&#xff0c;而且这些2人组的两人重量加起来不超过船的载重。所以可以先排序people&#xff0c;用双指针从两边向中间遍历&#xff0c;让重的人和轻的人组成2人组&#xff0c;如果当前最重的人和最轻的人的重量和超过了载重&#xff0c;那只能让重的人先乘一条船。
  • 复杂度&#xff1a;时间复杂度O(nlogn)&#xff0c;排序的复杂度。空间复杂度O(logn)&#xff0c;排序的栈空间

代码

public int numRescueBoats(int[] people, int limit) {
int n &#61; people.length;
Arrays.sort(people);
int left &#61; 0;
int right &#61; n-1;
int nums &#61; 0;
//让最重的最轻的先走
while (left <&#61; right){
if(people[right] &#43; people[left] <&#61; limit){
right--;
left&#43;&#43;;
nums&#43;&#43;;
}else{
//让最重的一个人走
right--;
nums&#43;&#43;;
}
}
return nums;
}

452. 用最少数量的箭引爆气球

难度中等719收藏分享切换为英文接收动态反馈

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] &#61; [xstart, xend] 表示水平直径在 xstartxend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭&#xff0c;若有一个气球的直径的开始和结束坐标为 x&#96;&#96;start&#xff0c;x&#96;&#96;end&#xff0c; 且满足 xstart ≤ x ≤ x&#96;&#96;end&#xff0c;则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后&#xff0c;可以无限地前进。

给你一个数组 points &#xff0c;返回引爆所有气球所必须射出的 最小 弓箭数

示例 1&#xff1a;

输入&#xff1a;points &#61; [[10,16],[2,8],[1,6],[7,12]]
输出&#xff1a;2
解释&#xff1a;气球可以用2支箭来爆破:
-在x &#61; 6处射出箭&#xff0c;击破气球[2,8]和[1,6]。
-在x &#61; 11处发射箭&#xff0c;击破气球[10,16]和[7,12]。

示例 2&#xff1a;

输入&#xff1a;points &#61; [[1,2],[3,4],[5,6],[7,8]]
输出&#xff1a;4
解释&#xff1a;每个气球需要射出一支箭&#xff0c;总共需要4支箭。

示例 3&#xff1a;

输入&#xff1a;points &#61; [[1,2],[2,3],[3,4],[4,5]]
输出&#xff1a;2
解释&#xff1a;气球可以用2支箭来爆破:
- 在x &#61; 2处发射箭&#xff0c;击破气球[1,2]和[2,3]。
- 在x &#61; 4处射出箭&#xff0c;击破气球[3,4]和[4,5]。


有点类似前面的最小区间,注意不能直接o1[1] - o2[1] 有个案例会溢出


ds_163


  • 思路&#xff1a;区间按照结尾从小到大排序&#xff0c;循环数组&#xff0c;如果后面一个区间的开始大于前一个区间的结尾 就需要新增一支箭。
  • 复杂度&#xff1a;时间复杂度O(nlogn)&#xff0c;排序的复杂度O(nlogn)&#xff0c;循环数组的复杂度O(n)。空间复杂度O(logn)&#xff0c;排序栈空间

代码

class Solution {
public int findMinArrowShots(int[][] points) {

//按照右边界升序排序
Arrays.sort(points, (o1, o2) -> {
return Integer.compare(o1[1], o2[1]);
});
int n &#61; points.length;
// for (int[] point : points) {
// for (int i : point) {
// System.out.print(i &#43; " ");
// }
// System.out.println();
// }
int nums &#61; 1;
int right &#61; points[0][1];

//如果下一个的左边比之前的右边大 nums&#43;1
for (int i &#61; 1; i < n; i&#43;&#43;) {
if (points[i][0] > right) {
right &#61; points[i][1];
nums&#43;&#43;;
}
}
return nums;
}
}

134. 加油站

难度中等

在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i&#43;1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。

给定两个整数数组 gascost &#xff0c;如果你可以绕环路行驶一周&#xff0c;则返回出发时加油站的编号&#xff0c;否则返回 -1 。如果存在解&#xff0c;则 保证 它是 唯一 的。

示例 1:

输入: gas &#61; [1,2,3,4,5], cost &#61; [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发&#xff0c;可获得 4 升汽油。此时油箱有 &#61; 0 &#43; 4 &#61; 4 升汽油
开往 4 号加油站&#xff0c;此时油箱有 4 - 1 &#43; 5 &#61; 8 升汽油
开往 0 号加油站&#xff0c;此时油箱有 8 - 2 &#43; 1 &#61; 7 升汽油
开往 1 号加油站&#xff0c;此时油箱有 7 - 3 &#43; 2 &#61; 6 升汽油
开往 2 号加油站&#xff0c;此时油箱有 6 - 4 &#43; 3 &#61; 5 升汽油
开往 3 号加油站&#xff0c;你需要消耗 5 升汽油&#xff0c;正好足够你返回到 3 号加油站。
因此&#xff0c;3 可为起始索引。

示例 2:

输入: gas &#61; [2,3,4], cost &#61; [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发&#xff0c;因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发&#xff0c;可以获得 4 升汽油。 此时油箱有 &#61; 0 &#43; 4 &#61; 4 升汽油
开往 0 号加油站&#xff0c;此时油箱有 4 - 3 &#43; 2 &#61; 3 升汽油
开往 1 号加油站&#xff0c;此时油箱有 3 - 3 &#43; 3 &#61; 3 升汽油
你无法返回 2 号加油站&#xff0c;因为返程需要消耗 4 升汽油&#xff0c;但是你的油箱只有 3 升汽油。
因此&#xff0c;无论怎样&#xff0c;你都不可能绕环路行驶一周。

提示:


  • gas.length &#61;&#61; n
  • cost.length &#61;&#61; n
  • 1 <&#61; n <&#61; 105
  • 0 <&#61; gas[i], cost[i] <&#61; 104

思路


ds_173
  • 思路&#xff1a;首先判断总油量是否小于总油耗&#xff0c;如果是则肯定不能走一圈。如果否&#xff0c;那肯定能跑一圈。接下来就是循环数组&#xff0c;从第一个站开始&#xff0c;计算每一站剩余的油量&#xff0c;如果油量为负了&#xff0c;就以这个站为起点从新计算。如果到达某一个点为负&#xff0c;说明起点到这个点中间的所有站点都不能到达该点。
  • 复杂度&#xff1a;时间复杂度O(n)&#xff0c;空间复杂度O(1)

代码

class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n &#61; gas.length;
int sumGas &#61; 0;
int sumCost &#61; 0;
for (int i &#61; 0; i < n; i&#43;&#43;) {
sumGas &#43;&#61; gas[i];
sumCost &#43;&#61; cost[i];
}
//如果总油量小于总距离,失败
if (sumGas < sumCost) {
return -1;
}
int currentGas &#61; 0;
int start &#61; 0;
for (int i &#61; 0; i < n; i&#43;&#43;) {
currentGas &#43;&#61; gas[i] - cost[i];
//如果到达下一站的时候油量为负数 就以这个站为起点 从新计算
if (currentGas < 0) {
currentGas &#61; 0;
start &#61; i &#43; 1;
}
}
return start;
}
}

860. 柠檬水找零

难度简单

在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。

每位顾客只买一杯柠檬水&#xff0c;然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零&#xff0c;也就是说净交易是每位顾客向你支付 5 美元。

注意&#xff0c;一开始你手头没有任何零钱。

给你一个整数数组 bills &#xff0c;其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零&#xff0c;返回 true &#xff0c;否则返回 false

示例 1&#xff1a;

输入&#xff1a;bills &#61; [5,5,5,10,20]
输出&#xff1a;true
解释&#xff1a;
前 3 位顾客那里&#xff0c;我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里&#xff0c;我们收取一张 10 美元的钞票&#xff0c;并返还 5 美元。
第 5 位顾客那里&#xff0c;我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零&#xff0c;所以我们输出 true。

示例 2&#xff1a;

输入&#xff1a;bills &#61; [5,5,10,10,20]
输出&#xff1a;false
解释&#xff1a;
前 2 位顾客那里&#xff0c;我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客&#xff0c;我们收取一张 10 美元的钞票&#xff0c;然后返还 5 美元。
对于最后一位顾客&#xff0c;我们无法退回 15 美元&#xff0c;因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零&#xff0c;所以答案是 false。

代码

class Solution {
public boolean lemonadeChange(int[] bills) {
int five &#61; 0, ten &#61; 0;
for (int bill : bills) {
if (bill &#61;&#61; 5) {
five&#43;&#43;;
} else if (bill &#61;&#61; 10) {
if (five &#61;&#61; 0) {
return false;
}
five--;
ten&#43;&#43;;
} else {
if (five > 0 && ten > 0) {
five--;
ten--;
} else if (five >&#61; 3) {
five -&#61; 3;
} else {
return false;
}
}
}
return true;

}
}






推荐阅读
  • BZOJ4240 Gym 102082G:贪心算法与树状数组的综合应用
    BZOJ4240 Gym 102082G 题目 "有趣的家庭菜园" 结合了贪心算法和树状数组的应用,旨在解决在有限时间和内存限制下高效处理复杂数据结构的问题。通过巧妙地运用贪心策略和树状数组,该题目能够在 10 秒的时间限制和 256MB 的内存限制内,有效处理大量输入数据,实现高性能的解决方案。提交次数为 756 次,成功解决次数为 349 次,体现了该题目的挑战性和实际应用价值。 ... [详细]
  • 今天我开始学习Flutter,并在Android Studio 3.5.3中创建了一个新的Flutter项目。然而,在首次尝试运行时遇到了问题,Gradle任务 `assembleDebug` 执行失败,退出状态码为1。经过初步排查,发现可能是由于依赖项配置不当或Gradle版本不兼容导致的。为了解决这个问题,我计划检查项目的 `build.gradle` 文件,确保所有依赖项和插件版本都符合要求,并尝试更新Gradle版本。此外,还将验证环境变量配置是否正确,以确保开发环境的稳定性。 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 本文探讨了 Java 中 Pair 类的历史与现状。虽然 Java 标准库中没有内置的 Pair 类,但社区和第三方库提供了多种实现方式,如 Apache Commons 的 Pair 类和 JavaFX 的 javafx.util.Pair 类。这些实现为需要处理成对数据的开发者提供了便利。此外,文章还讨论了为何标准库未包含 Pair 类的原因,以及在现代 Java 开发中使用 Pair 类的最佳实践。 ... [详细]
  • HTML 页面中调用 JavaScript 函数生成随机数值并自动展示
    在HTML页面中,通过调用JavaScript函数生成随机数值,并将其自动展示在页面上。具体实现包括构建HTML页面结构,定义JavaScript函数以生成随机数,以及在页面加载时自动调用该函数并将结果呈现给用户。 ... [详细]
  • 在IIS上运行的WebApi应用程序在开发环境中能够正常进行文件的读写操作。然而,在尝试通过FTP访问实时服务器上的文件列表时,遇到了无法显示的问题,尽管服务器配置与开发环境相同。这可能涉及权限设置、FTP服务配置或网络连接等方面的问题。 ... [详细]
  • 本文探讨了如何利用Java 8 Stream API 对数组进行高效排序和筛选处理。具体而言,通过 `stream()` 方法将 `listResult` 转换为流,然后使用 `sorted(Comparator.comparing())` 方法按伴随度进行降序排序,并最终收集结果。此外,还介绍了如何结合过滤条件进一步优化数据处理流程,提升代码的可读性和执行效率。 ... [详细]
  • HBase Java API 进阶:过滤器详解与应用实例
    本文详细探讨了HBase 1.2.6版本中Java API的高级应用,重点介绍了过滤器的使用方法和实际案例。首先,文章对几种常见的HBase过滤器进行了概述,包括列前缀过滤器(ColumnPrefixFilter)和时间戳过滤器(TimestampsFilter)。此外,还详细讲解了分页过滤器(PageFilter)的实现原理及其在大数据查询中的应用场景。通过具体的代码示例,读者可以更好地理解和掌握这些过滤器的使用技巧,从而提高数据处理的效率和灵活性。 ... [详细]
  • 本文介绍了如何利用Apache POI库高效读取Excel文件中的数据。通过实际测试,除了分数被转换为小数存储外,其他数据均能正确读取。若在使用过程中发现任何问题,请及时留言反馈,以便我们进行更新和改进。 ... [详细]
  • 每日精选Codeforces训练题:1119E(贪心算法)、821C(栈模拟)和645D(拓扑排序)
    题目涉及三种不同类型的算法问题:1119E(贪心算法)、821C(栈模拟)和645D(拓扑排序)。其中,1119E的问题背景是有n种不同长度的棍子,长度分别为2^0, 2^1, …, 2^(n-1),每种棍子的数量为a[i]。任务是计算可以组成的三角形数量。根据三角形的性质,任意两边之和必须大于第三边。该问题可以通过贪心算法高效解决,通过合理选择棍子组合来最大化三角形的数量。 ... [详细]
  • 如何撰写PHP电商项目的实战经验? ... [详细]
  • Node.js 教程第五讲:深入解析 EventEmitter(事件监听与发射机制)
    本文将深入探讨 Node.js 中的 EventEmitter 模块,详细介绍其在事件监听与发射机制中的应用。内容涵盖事件驱动的基本概念、如何在 Node.js 中注册和触发自定义事件,以及 EventEmitter 的核心 API 和使用方法。通过本教程,读者将能够全面理解并熟练运用 EventEmitter 进行高效的事件处理。 ... [详细]
  • 蓝桥杯算法实战:节点选取策略优化分析
    本文针对蓝桥杯算法竞赛中的节点选取策略进行了深入分析与优化。通过对比不同节点选择方法的效果,提出了基于贪心算法和动态规划的综合优化方案,旨在提高算法效率和准确性。实验结果表明,该优化策略在处理大规模数据集时表现出色,显著提升了算法性能。 ... [详细]
  • 在腾讯云服务器上部署Nginx的详细指南中,首先需要确保安装必要的依赖包。如果这些依赖包已安装,可直接跳过此步骤。具体命令包括 `yum -y install gcc gcc-c++ wget net-tools pcre-devel zlib-devel`。接下来,本文将详细介绍如何下载、编译和配置Nginx,以确保其在腾讯云服务器上顺利运行。此外,还将提供一些优化建议,帮助用户提升Nginx的性能和安全性。 ... [详细]
  • 机器学习中的标准化缩放、最小-最大缩放及鲁棒缩放技术解析 ... [详细]
author-avatar
手机用户2502863361
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有