代码随想录算法训练营第二十九天

LeetCode.134 加油站

题目链接 加油站

题解

java 复制代码
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int curSum = 0;
        int targetSum = 0;
        int startIndex = 0;
        for(int i = 0;i<gas.length;i++){
            curSum += gas[i] - cost[i];
            targetSum += gas[i] - cost[i];
            if(curSum < 0) {
                curSum = 0;
                startIndex = i + 1;
            }
        }
        if(targetSum < 0) return -1;
        return startIndex;
        
    }
}

解题思路

问题描述:假设有一个环形路线上有 n 个加油站,每个加油站有汽油 gas [i],从第 i 个加油站开到下一个加油站需要消耗汽油 cost [i]。你需要判断是否存在一个起点,使得从该起点出发可以绕环形路线一周。如果存在,返回该起点的索引;否则返回 - 1。

算法思路:

  1. 定义两个变量:curSum用于累计当前路段的剩余油量,targetSum用于累计全程的总剩余油量
  2. startIndex记录可能的起点位置
  3. 遍历每个加油站:
    • 计算当前加油站的剩余油量(gas [i] - cost [i]),并累加到curSumtargetSum
    • 如果curSum小于 0,说明从当前起点到这里无法通过,需要重新设置起点为下一个加油站,并重置curSum
  4. 遍历结束后,如果targetSum小于 0,说明全程总油量不足以支撑一圈,返回 - 1
  5. 否则,返回记录的起点startIndex

这个算法的时间复杂度是 O (n),空间复杂度是 O (1),非常高效。其核心思想是:如果从起点 A 到 B 无法到达,那么 A 到 B 之间的任何一点都不能作为起点;如果全程总油量充足,那么必然存在一个可以完成环路的起点。

LeetCode.135 分发糖果

题目链接 分发糖果

题解

java 复制代码
class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int[] res = new int[n];
        res[0]=1;
        for(int i = 1;i<n;i++){
            if(ratings[i] > ratings[i-1]) {
                res[i] = res[i-1] + 1;
            } else res[i] = 1;
        }  
        for(int i = n - 2;i>=0;i--){
            if(ratings[i] > ratings[i+1]) res[i] = Math.max(res[i],res[i+1] + 1);
        }
        int result = 0;
        for(int i =  0;i<n;i++) result += res[i];
        return result;
    }
}

解题思路

这段代码实现了一个解决 "分发糖果" 问题的算法。让我来解释一下它的工作原理:

问题描述:有 n 个孩子站成一排,每个孩子有一个评分。需要给这些孩子分发糖果,规则是:

  1. 每个孩子至少得 1 颗糖果
  2. 评分更高的孩子必须比他相邻的孩子得到更多的糖果

算法思路:

  1. 创建一个结果数组res,用于存储每个孩子应得的糖果数
  2. 首先从左到右遍历:
    • 第一个孩子至少得 1 颗糖果
    • 对于每个后续孩子,如果他的评分高于左边孩子,则他的糖果数比左边多 1
    • 否则,他至少得 1 颗糖果
  3. 然后从右到左遍历:
    • 对于每个孩子,如果他的评分高于右边孩子,则取他当前糖果数和右边孩子糖果数 + 1 中的较大值
  4. 最后将所有孩子的糖果数相加,得到总糖果数

这个算法的时间复杂度是 O (n),空间复杂度是 O (n)。其核心思想是通过两次遍历确保同时满足左右两边的条件:

  • 左到右遍历确保每个孩子比左边评分低的孩子得到更多糖果
  • 右到左遍历确保每个孩子比右边评分低的孩子得到更多糖果

代码逻辑清晰,通过两次单向遍历就解决了需要同时考虑左右邻居的问题,是这个问题的高效解法。

LeetCode.860 柠檬水找零

题目链接 柠檬水找零

题解

java 复制代码
class Solution {
    public boolean lemonadeChange(int[] bills) {
        int five = 0;
        int ten = 0;
        for(int i = 0;i<bills.length;i++){
            if(bills[i] == 5){
                five ++;
            }
            if(bills[i] == 10){
                ten ++;
                five --;
            }
            if(bills[i] == 20){
                if(ten > 0){
                    ten --;
                    five --;
                }else {
                    five -=3;
                }
            }
            if(ten < 0 || five < 0) return false;
        }
        return true;
    }
}

解题思路

这段代码实现了一个解决 "柠檬水找零" 问题的算法。让我来解释一下它的工作原理:

问题描述:假设你正在经营一家柠檬水摊,每杯柠檬水售价 5 美元。顾客排队购买,每人只会付 5 美元、10 美元或 20 美元。你需要判断能否给每个顾客都正确找零(假设开始时你没有任何零钱)。

  1. 定义两个变量fiveten,分别记录手中 5 美元和 10 美元钞票的数量
  2. 遍历每位顾客支付的钞票:
    • 如果收到 5 美元,直接增加 5 美元钞票的数量
    • 如果收到 10 美元,需要找零 5 美元,因此减少 1 张 5 美元钞票,增加 1 张 10 美元钞票
    • 如果收到 20 美元,优先用 1 张 10 美元 + 1 张 5 美元找零(因为 5 美元更灵活),如果没有 10 美元则用 3 张 5 美元找零
    • 每次交易后检查钞票数量是否为负数,如果是则说明无法正确找零,返回 false
  3. 遍历结束后如果都能正确找零,返回 true

这个算法的时间复杂度是 O (n),空间复杂度是 O (1)。其核心思想是:

  • 尽量保留更多的 5 美元钞票,因为它可以用于各种面额的找零
  • 20 美元钞票无法用于找零,所以不需要记录其数量

LeetCode.406 根据身高重建队列

题目链接 根据身高重建队列

题解

java 复制代码
class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,(a,b) -> {
            if(a[0] == b[0]) return a[1] - b[1];
            return b[0] - a[0];
        });
        LinkedList<int[]> que = new LinkedList<>();
        for(int[] p : people){
            que.add(p[1],p);
        }
        return que.toArray(new int[people.length][]);
    }
}

解题思路

这段代码实现了一个解决 "根据身高重建队列" 问题的算法。让我来解释一下它的工作原理:

问题描述:假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中的一些人的属性(每个 people [i] = [h, k] 表示第 i 个人的身高为 h,前面正好有 k 个身高大于或等于 h 的人)。请你重新构造并返回输入数组 people 所表示的队列。

  1. 首先对人群进行排序:
    • 按照身高 h 从高到低排序(降序)
    • 当身高相同时,按照前面应有的人数 k 从小到大排序(升序)
  2. 创建一个链表作为队列容器
  3. 遍历排序后的人群,按照每个人的 k 值将其插入到链表的对应位置
  4. 最后将链表转换为数组返回

这个算法的时间复杂度是 O (n²)(排序 O (nlogn) + 插入操作 O (n²)),空间复杂度是 O (n)。

相关推荐
We་ct12 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
王老师青少年编程16 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮17 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说17 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove17 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung18 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了18 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL18 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰18 小时前
C++ 排列组合完整指南
开发语言·c++·算法
代码中介商19 小时前
银行管理系统的业务血肉 —— 流程、状态机、输入校验与持久化(下篇)
c语言·算法