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

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)。

相关推荐
科大饭桶2 小时前
数据结构自学Day13 -- 快速排序--“分而治之”
数据结构·算法·排序算法
某个默默无闻奋斗的人3 小时前
【矩阵专题】Leetcode54.螺旋矩阵(Hot100)
java·算法·leetcode
JXL18604 小时前
Leetcode-.42接雨水
算法·leetcode·职场和发展
啊我不会诶5 小时前
CF每日5题(1500-1600)
c++·学习·算法
巴伦是只猫6 小时前
Java 高频算法
java·开发语言·算法
点云SLAM6 小时前
C++中std::string和std::string_view使用详解和示例
开发语言·c++·算法·字符串·string·c++标准库算法·string_view
88号技师6 小时前
2025年7月Renewable Energy-冬虫夏草优化算法Caterpillar Fungus Optimizer-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
dragoooon347 小时前
优选算法:移动零
c++·学习·算法·学习方法
运维小文7 小时前
初探贪心算法 -- 使用最少纸币组成指定金额
c++·python·算法·贪心算法
智者知已应修善业8 小时前
【C# 找最大值、最小值和平均值及大于个数和值】2022-9-23
经验分享·笔记·算法·c#