热门标签 | 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;

}
}






推荐阅读
  • 本文深入探讨了HTTP请求和响应对象的使用,详细介绍了如何通过响应对象向客户端发送数据、处理中文乱码问题以及常见的HTTP状态码。此外,还涵盖了文件下载、请求重定向、请求转发等高级功能。 ... [详细]
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 本题探讨了在一个有向图中,如何根据特定规则将城市划分为若干个区域,使得每个区域内的城市之间能够相互到达,并且划分的区域数量最少。题目提供了时间限制和内存限制,要求在给定的城市和道路信息下,计算出最少需要划分的区域数量。 ... [详细]
  • 在现代Web应用中,当用户滚动到页面底部时,自动加载更多内容的功能变得越来越普遍。这种无刷新加载技术不仅提升了用户体验,还优化了页面性能。本文将探讨如何实现这一功能,并介绍一些实际应用案例。 ... [详细]
  • 给定行数 numRows,生成帕斯卡三角形的前 numRows 行。例如,当 numRows 为 5 时,返回的结果应为:[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文探讨了如何在iOS开发环境中,特别是在Xcode 6.1中,设置和应用自定义文本样式。我们将详细介绍实现方法,并提供一些实用的技巧。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 本文详细介绍了 org.apache.commons.io.IOCase 类中的 checkCompareTo() 方法,通过多个代码示例展示其在不同场景下的使用方法。 ... [详细]
  • 在网站制作中随时可用的10个 HTML5 代码片段
    HTML很容易写,但创建网页时,您经常需要重复做同样的任务,如创建表单。在这篇文章中,我收集了10个超有用的HTML代码片段,有HTML5启动模板、空白图片、打电话和发短信、自动完 ... [详细]
  • 本文详细介绍了C语言的起源、发展及其标准化过程,涵盖了从早期的BCPL和B语言到现代C语言的演变,并探讨了其在操作系统和跨平台编程中的重要地位。 ... [详细]
  • Python第三方库安装的多种途径及注意事项
    本文详细介绍了Python第三方库的几种常见安装方法,包括使用pip命令、集成开发环境(如Anaconda)以及手动文件安装,并提供了每种方法的具体操作步骤和适用场景。 ... [详细]
  • 本文介绍如何在SQL Server中创建动态SQL存储过程,并提供详细的代码实例和解释。通过这种方式,可以更灵活地处理查询条件和参数。 ... [详细]
  • 反向投影技术主要用于在大型输入图像中定位特定的小型模板图像。通过直方图对比,它能够识别出最匹配的区域或点,从而确定模板图像在输入图像中的位置。 ... [详细]
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社区 版权所有