力扣top100(day04-06)--贪心算法

本文为力扣TOP100刷题笔记

笔者根据数据结构理论加上最近刷题整理了一套 数据结构理论加常用方法以下为该文章:

力扣外传之数据结构(一篇文章搞定数据结构)

121. 买卖股票的最佳时机

public class Solution {
    public int maxProfit(int prices[]) {
        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;
    }
}

算法思路

  1. 初始化:设置两个变量:

    • minprice:记录遍历过程中遇到的最低价格(初始为最大整数值)

    • maxprofit:记录当前能获得的最大利润(初始为0)

  2. 遍历价格序列

    • 如果当前价格比minprice低,更新最低价格

    • 否则,计算当前价格与最低价格的差值,如果大于maxprofit则更新最大利润

  3. 返回结果:最终返回maxprofit

关键点说明

  1. 一次遍历:算法只需要一次遍历即可完成,时间复杂度O(n)

  2. 空间效率:只使用了常数空间,空间复杂度O(1)

  3. 边界情况

    • 空数组或单元素数组直接返回0

    • 价格持续下跌时利润保持为0

示例演示

假设输入prices = [7,1,5,3,6,4]

  1. i=0: price=7

    • 7 < MAX → minprice=7

  2. i=1: price=1

    • 1 < 7 → minprice=1

  3. i=2: price=5

    • 5-1=4 > 0 → maxprofit=4

  4. i=3: price=3

    • 3-1=2 < 4 → 无变化

  5. i=4: price=6

    • 6-1=5 > 4 → maxprofit=5

  6. i=5: price=4

    • 4-1=3 < 5 → 无变化

最终结果:5

复杂度分析

  • 时间复杂度:O(n),只需一次遍历

  • 空间复杂度:O(1),只使用了两个额外变量

优化说明

这个实现已经是该问题的最优解,因为:

  1. 必须检查每个价格才能确定最大利润

  2. 无法在比O(n)更好的时间复杂度内解决

  3. 空间使用已经是最小化

边界情况测试

  1. 空数组[] → 返回0

  2. 单元素数组[1] → 返回0

  3. 持续下跌[7,6,4,3,1] → 返回0

  4. 持续上涨[1,2,3,4,5] → 返回4

  5. 波动价格[2,4,1,7] → 返回6

这个算法简洁高效地解决了股票买卖的最佳时机问题,是这类问题的经典解决方案。

55. 跳跃游戏

public class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length;
        int rightmost = 0; // 当前能到达的最远位置
        
        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;
    }
}

关键点说明

  1. rightmost变量:动态记录当前能跳到的最远位置

  2. i <= rightmost判断:确保只处理可达位置

  3. 提前终止:一旦发现能到达终点立即返回

示例演示

假设输入nums = [2,3,1,1,4]

  1. i=0:

    • 0 <= 0 (true)

    • rightmost = max(0, 0+2) = 2

  2. i=1:

    • 1 <= 2 (true)

    • rightmost = max(2, 1+3) = 4

    • 4 >= 4 → return true

复杂度分析

  • 时间复杂度:O(n),只需一次遍历

  • 空间复杂度:O(1),仅使用常数空间

边界情况测试

  1. [0] → true(起点即终点)

  2. [0,2,3] → false(卡在起点)

  3. [1,0,1,0] → false(无法跨越0)

  4. [3,0,0,0] → true(第一步就能跳到终点)

算法正确性证明

通过维护可达的最远位置,可以确保:

  1. 不会遗漏任何可能的跳跃路径

  2. 贪心选择总是保持最优可达性

  3. 提前终止保证效率

这个实现是跳跃游戏问题的最优解,既高效又易于理解。

### 关于贪心算法LeetCode 平台上的题目解析 #### 1. **最长回文串** 此题的目标是从给定字符串中找到可以构成的最大长度的回文子序列。通过贪心策略,我们可以尝试尽可能多地匹配字符来构建回文结构。 实现方式如下: - 使用 `Counter` 来统计每个字符出现的次数。 - 对于偶数次出现的字符可以直接计入回文中;对于奇数次出现的字符,最多只能取其最大偶数值加入到回文中[^1]。 ```python from collections import Counter def longestPalindrome(s: str) -> int: counts = Counter(s) length = 0 odd_found = False for count in counts.values(): if count % 2 == 0: length += count else: length += count - 1 odd_found = True if odd_found: length += 1 return length ``` --- #### 2. **柠檬水找零** 该问题描述了一个场景:顾客购买价值 $5 的商品并支付不同面额的钱币 ($5, $10, 和 $20),我们需要判断能否成功完成所有交易而不缺少找零。 解决方法基于贪心原则——优先处理大金额钱币以便保留更多小额硬币用于后续操作[^3]: ```java class Solution { public boolean lemonadeChange(int[] bills) { int five = 0; int ten = 0; for (int bill : bills) { if (bill == 5) { five++; } else if (bill == 10) { if (five == 0) return false; five--; ten++; } else { // bill == 20 if (ten > 0 && five > 0) { ten--; five--; } else if (five >= 3) { five -= 3; } else { return false; } } } return true; } } ``` --- #### 3. **分发饼干** 目标是将若干大小不同的饼干分配给孩子,使得尽可能多的孩子感到满意(即孩子的胃口需求小于等于饼干尺寸)。采用排序加双指针的方法能够高效解决问题[^4]。 代码示例如下: ```python from typing import List class Solution: def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() child, cookie = 0, 0 while child < len(g) and cookie < len(s): if g[child] <= s[cookie]: child += 1 cookie += 1 return child ``` --- #### 4. **根据身高重建队列** 这道题要求按照特定规则重新排列一组人员的位置。先按高度降序排列再插入对应索引位置即可达成目的。 以下是 Python 版本解决方案: ```python class Solution: def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: people.sort(key=lambda x: (-x[0], x[1])) result = [] for p in people: result.insert(p[1], p) return result ``` --- #### 5. **摆动序列** 定义一个数组中的“峰值”和“谷值”,并通过遍历一次数组计算出可能存在的波峰数量作为最终答案的一部分[^5]。 具体做法如下所示: ```python class Solution: def wiggleMaxLength(self, nums: List[int]) -> int: if not nums: return 0 up, down = 1, 1 for i in range(1, len(nums)): if nums[i] > nums[i - 1]: up = down + 1 elif nums[i] < nums[i - 1]: down = up + 1 return max(up, down) ``` --- ### 总结 上述各例展示了如何利用贪心算法有效求解实际编程竞赛中的经典难题。每种情况都遵循局部最优决策从而达到全局较佳效果的原则[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JBM.下北泽の大天使

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值