LeetCode 135:分糖果

LeetCode 135:分糖果

问题本质与核心挑战

给定孩子的评分数组,需满足 "每个孩子至少1颗糖果,相邻评分高的孩子糖果更多",求最少糖果总数。核心挑战:

  • 相邻约束是双向的(左→右和右→左都需满足),直接枚举无法高效解决;
  • 需通过 两次贪心遍历(左→右、右→左)分别处理单向约束,再合并结果。

核心思路:双向贪心 + 合并约束

1. 单向约束处理(左→右遍历)
  • 定义数组 leftleft[i] 表示 从左到右遍历 时,第 i 个孩子应得的最少糖果(仅满足"左边约束":若 ratings[i] > ratings[i-1],则 left[i] = left[i-1]+1;否则为 1)。
2. 单向约束处理(右→左遍历)
  • 定义数组 rightright[i] 表示 从右到左遍历 时,第 i 个孩子应得的最少糖果(仅满足"右边约束":若 ratings[i] > ratings[i+1],则 right[i] = right[i+1]+1;否则为 1)。
3. 合并双向约束
  • 每个孩子最终的糖果数为 max(left[i], right[i])(同时满足左右约束),求和即为答案。

算法步骤详解(以示例 ratings = [1,0,2] 为例)

步骤 1:左→右遍历,处理左边约束
孩子索引 i 评分 ratings[i] 与左边比较(ratings[i] > ratings[i-1] left[i] 计算 left 数组
0 1 -(无左边孩子) 初始为 1 [1]
1 0 0 > 1?否 设为 1 [1,1]
2 2 2 > 0?是 left[1]+1 = 2 [1,1,2]
步骤 2:右→左遍历,处理右边约束
孩子索引 i 评分 ratings[i] 与右边比较(ratings[i] > ratings[i+1] right[i] 计算 right 数组
2 2 -(无右边孩子) 初始为 1 [1]
1 0 0 > 2?否 设为 1 [1,1]
0 1 1 > 0?是 right[1]+1 = 2 [2,1,1]
步骤 3:合并约束,计算总和
孩子索引 i left[i] right[i] max(left[i], right[i]) 贡献糖果数
0 1 2 2 2
1 1 1 1 1
2 2 1 2 2
总和 - - - 2+1+2=5

完整代码(Java)

java 复制代码
class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        if (n == 0) return 0; // 边界处理(题目保证n≥1,可省略)
        
        // 1. 左→右遍历,处理左边约束
        int[] left = new int[n];
        left[0] = 1; // 第一个孩子至少1颗
        for (int i = 1; i < n; i++) {
            if (ratings[i] > ratings[i-1]) {
                left[i] = left[i-1] + 1;
            } else {
                left[i] = 1;
            }
        }
        
        // 2. 右→左遍历,处理右边约束
        int[] right = new int[n];
        right[n-1] = 1; // 最后一个孩子至少1颗
        for (int i = n-2; i >= 0; i--) {
            if (ratings[i] > ratings[i+1]) {
                right[i] = right[i+1] + 1;
            } else {
                right[i] = 1;
            }
        }
        
        // 3. 合并双向约束,计算总和
        int total = 0;
        for (int i = 0; i < n; i++) {
            total += Math.max(left[i], right[i]);
        }
        return total;
    }
}

关键逻辑解析

  1. 左→右遍历 :确保 "右边孩子评分更高时,糖果数比左边多" ,但无法处理"左边孩子评分更高,右边需更多"的情况(如 [5,4,3,2,1],左遍历后所有 left[i]=1,需右遍历修正)。
  2. 右→左遍历 :确保 "左边孩子评分更高时,糖果数比右边多",与左遍历互补。
  3. 合并约束:取两者最大值,保证同时满足左右双向约束,且糖果数最少(贪心思想:仅在必要时增加糖果)。

复杂度分析

  • 时间复杂度O(n)(两次遍历数组,每次 O(n),合并遍历 O(n))。
  • 空间复杂度O(n)(存储 leftright 数组,可优化为 O(1),但代码可读性降低)。

该方法通过 两次贪心遍历拆分双向约束,将复杂的双向问题转化为两个单向问题,再合并求解,确保了效率和可读性的平衡,是处理此类"双向约束"问题的经典思路。

相关推荐
wfbcg13 小时前
每日算法练习:LeetCode 167. 两数之和 II - 输入有序数组 ✅
算法·leetcode·职场和发展
A~MasterYi13 小时前
深入理解 Microscaling (MX) 格式:从浮点基础到共享指数矩阵乘法
算法·矩阵
环黄金线HHJX.14 小时前
《Tuan(拼音字母)⇆团(Group)/&湍(Turbulence)/&双结构链路道/&文字、符号、语言/&源点设计、连接起:人类与自然+AICosmOS》
开发语言·人工智能·算法·编辑器
有时间要学习14 小时前
面试150——第七周
算法·面试·深度优先
AI科技星14 小时前
万能学习方法论的理论建构与多领域适配性研究(乖乖数学)
人工智能·学习·算法·机器学习·平面·数据挖掘
Ashore11_14 小时前
蓝桥杯16届Java研究生组
java·算法·蓝桥杯
6Hzlia14 小时前
【Hot 100 刷题计划】 LeetCode 76. 最小覆盖子串 | C++ 滑动窗口题解
c++·算法·leetcode
像素猎人14 小时前
蓝桥杯OJ2049蓝桥勇士【动态规划】【dp[n]不是符合题意的答案,只是以an结尾的子问题的答案】
c++·算法·蓝桥杯·动态规划·区间dp
羊小猪~~14 小时前
LLM--SFT简介
python·考研·算法·ai·大模型·llm·微调
广州灵眸科技有限公司14 小时前
瑞芯微(EASY EAI)RV1126B 人脸98关键点算法识别
开发语言·科技·嵌入式硬件·物联网·算法·php