算法题(贪心算法)

一、题目

1、跳跃游戏(LC 55)

2、跳跃游戏2 (LC 45)

3、划分字母区间(LC 763)

二、题解

1、跳跃游戏(LC 55)

(1)分析

这道题判断能否从数组的第一个位置跳到最后一个位置,就是看每一步能覆盖到的最远范围。

可以维护一个变量表示当前能到达的最远下标,从头开始遍历每一个位置。在遍历过程中,如果当前位置已经超出了能到达的最远下标,那就说明根本跳不到这里,直接返回 false 就可以。如果能到达当前位置,就用当前位置加上能跳的长度,更新能到达的最远下标。只要一直遍历到数组结束,都没有出现无法到达的情况,就说明一定能跳到最后一位,返回 true 即可。过程中不纠结具体怎么跳,只关注最远覆盖范围。

时间复杂度是 O (n),只需要一次遍历数组。空间复杂度是 O (1),只用了几个变量记录状态,没有额外空间开销。

(2)题解
java 复制代码
class Solution {
    public boolean canJump(int[] nums) {
        int maxIndex = 0;         //可以到达的最大下标
        for(int i = 0; i < nums.length; i++){
            if(maxIndex < i){
                return false;   //到达不了当前位置,返回false
            }
            maxIndex = Math.max(maxIndex, i+nums[i]);  //更新最大下标
        }
        return true;  //循环结束,说明可以到达最大下标
    } 
}

2、跳跃游戏2 (LC 45)

(1)分析

这道题在跳跃游戏的基础上,要求算出跳到终点的最少步数,同样适用贪心算法,在当前能到达的范围内,尽可能跳到最远的地方,以此减少跳跃次数。

使用三个变量来完成整个逻辑,分别记录跳跃次数、当前这一步能到达的最远位置、下一步能到达的最远位置。遍历数组的时候,不断更新下一步能到达的最远位置,当遍历到当前这一步的边界时,就必须再跳一次,这时候把跳跃次数加一,并且把当前边界更新为下一步的最远位置。因为题目保证一定可以到达终点,所以只需要遍历到倒数第二个位置就够了。

时间复杂度是 O (n),一次遍历完成计算。空间复杂度是 O (1),仅使用常数变量。

(2)题解
java 复制代码
class Solution {
    public int jump(int[] nums) {
        int ans = 0;        //步数
        int curEnd = 0;     //当前的位置
        int nextEnd = 0;    //当前可以到达的最大位置
        for(int i = 0; i < nums.length - 1; i++){
            nextEnd = Math.max(nextEnd, i + nums[i]);
            if(i == curEnd){   //此时需要再走一步,到达nextEnd
                curEnd = nextEnd;
                ans++;
            }
        }
        return ans;
    }
}

3、划分字母区间(LC 763)

(1)分析

这道题要把字符串划分成最多的片段,保证同一个字母只出现在一个片段里,最关键的思路就是先确定每个字母最后出现的位置,再用贪心的方式确定分割点。

先遍历一遍字符串,用数组记录下每一个字母最后一次出现的下标。然后再次遍历字符串,不断更新当前片段的结束位置,这个结束位置取当前字母最后出现位置的最大值。当遍历到当前片段的结束位置时,就说明这个片段里所有字母都不会再出现在后面了,此时可以完成一次分割,记录片段长度,再把起点设为下一个位置继续遍历。遍历结束后返回 ans 结果。

时间复杂度是 O (n),只需要两次线性遍历字符串。空间复杂度是 O (1),记录最后位置的数组大小固定,属于常数级空间。

(2)题解
java 复制代码
class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> ans = new ArrayList<>(); //结果集合
        char[] chs = s.toCharArray();      
        int n = chs.length;
        int[] last = new int[26];  //每个字符最后出现的位置
        for(int i = 0; i < n; i++){
            last[chs[i] - 'a'] = i;  //记录每个字符的最后下标
        }

        int start = 0;      //闭区间
        int end = 0;
        for(int i =0; i <n; i++){
            end = Math.max(last[chs[i] -'a'], end); //更新最大下标
            if(i == end){              //此时可以分割
                ans.add(end - start + 1);
                start = end + 1;
            }
        }
        return ans;
    }
}
相关推荐
aramae2 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
荆棘鸟智能2 小时前
城市感知设备怎么统一接入?从多协议网关到设备模型的中间件架构设计
人工智能·算法·边缘计算
INGNIGHT6 小时前
270 · 电话号码的字母组合II(Trie)
linux·算法
2401_839080546 小时前
C++常见八股
数据结构·c++·算法
青山是哪个青山7 小时前
LeetCode 188:买卖股票的最佳时机 IV
算法
mikuyyds7 小时前
geo-toolbox 插件算法解析:RUSLE 与 MUSLE 的工程化落地
算法·rust·gis
a187927218317 小时前
【算法】树(二):队列与祖先——BFS 骨架三配件、短路透传与合流
算法·leetcode·二叉树··bfs·算法讲解·树遍历
syagain_zsx8 小时前
算法基础篇 · 03 枚举(C++ 题解)
c++·算法·二进制·枚举
weixin_307779138 小时前
C++代码实现MATLAB中的ode23tb函数功能
开发语言·c++·算法·matlab
我是章汕呐9 小时前
地级市能源消耗量及消耗强度数据【2006-2023年】平衡面板
人工智能·经验分享·算法·回归