Day16(贪心算法)——LeetCode45.跳跃游戏II&763.划分字母区间

1 LeetCode45.跳跃游戏II

1.1 题目描述

与跳跃游戏类似,跳跃游戏II给定长为n的从0开始索引的整数数组numsnums[i]是你在i处能向右跳跃的最大步数,求到达数组最后一个索引处需要跳跃的最少次数。

一个示例:nums[2,3,1,1,4],则到达下标4的位置需要跳至少两次,即从下标0跳到下标1,再从下标1跳到下标4

1.2 问题分析及解决

贪心的思想,即在当前位置所能跳跃的范围内,选择跳跃到有最大跳跃长度的位置。例如nums=[2,3,1,1,4],从下标0可以跳跃到下标1、下标2,但下标1最大跳跃长度为3,比下标2的最大跳跃长度大,因此我们选择跳跃到下标1。

像上面的思路我们貌似需要每一次遍历数组的一小部分决定下一步要走到哪,这样的话时间复杂度为 O ( n 2 ) O(n^2) O(n2)。可以换个角度,但本质上与上述思路相同。

我们从一个位置跳跃到其能跳远的最远长度所在的下标now_right的过程中,记录下这之间的所有位置能达到的最远位置的下标max_right,若我们到达了now_right,但仍没到最后一个下标,此时步数就得+1。因为相当于我们回头从具有最大跳跃长度的位置开始跳(步数+1),而回头不需要步数。

仍以上述为例,nums=[2,3,1,1,4],我们从nums[0]开始跳,其最远可以到达nums[0]+0=2(now_right=2),并记录下在其跳跃范围内的位置能到达的最远下标nums[1]+1=4(max_right=4)。当我们跳到下标2时,我们无法从nums[0]开始再往右跳,因此需要步数+1,从nums[1]起跳,由于我们记录了从nums[1]起跳最远能到达下标4,因此我们只需更新now_right=max_right即可,然后继续上述操作。注意我们只需要判断最远距离能否到达倒数第2个下标,因为若能从某个位置直接到最后一个下标,这不算步数,因此只需判断能否到达倒数第二个下标,若能则肯定也能到最后一个下标;若不能则步数+1就能到达最后一个下标了。

具体实现如下:

cpp 复制代码
class Solution {
public:
    int jump(vector<int>& nums) {
        int ans=0;
        //记录跳跃过程中能到达的最大下标
        int maxright=0;
        //记录从当前位置跳跃能到达的最大下标
        int nowright=0;
        for(int i=0;i<nums.size()-1;i++){
            maxright=max(maxright,nums[i]+i);
            //如果此时还没到最后一个下标
            if(i==nowright){
                //步数+1,从而才能继续向前
                nowright=maxright;
                ans++;
            }
        }
        return ans;
    }
};

2 LeetCode763.划分字母区间

2.1 题目描述

给定一个字符串s,将字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。如s="ababcc",则最终的划分结果为["abab","cc"]。返回表示每个字符串片段的长度的列表。

一个示例如下:

2.2 问题分析及解决

贪心的思想,从第一个字母开始遍历,定义指针left指向划分的最左边,right指向划分的最右边,因此right要更新为遍历字母中最后出现的位置的最大值,直到遍历位置与right相等,说明leftright之间就是一个划分。更新left=right+1,继续上述操作即可。

具体实现如下:

cpp 复制代码
class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> ans;
        int end_char[26];
        //记录每个字母最后出现的位置
        for(int i=0;i<s.length();i++){
            end_char[s[i]-'a']=i;
        }
        //记录遍历过程中每个字母最后一次出现的位置
        int right=0;
        //划分的左边
        int left=0;
        //划分的右边
        int partition=-1;
        for(int i=0;i<s.length();i++){
            right=end_char[s[i]-'a'];
            //划分右边为遍历字母最后一次出现位置的最大值
            partition=max(partition,right);
            //如果遍历到划分位置,则说明是一个划分
            if(i==partition){
                ans.push_back(partition-left+1);
                left=right+1;
            }
        }
        return ans;
    }
};
相关推荐
铭哥的编程日记1 天前
C++优选算法精选100道编程题(附有图解和源码)
开发语言·c++·算法
深思慎考1 天前
LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(2——Parser解析html模块)
linux·c++·搜索引擎
不枯石1 天前
Matlab通过GUI实现点云的最远点下采样(Farthest point sampling)
开发语言·图像处理·算法·计算机视觉·matlab
wanhengidc1 天前
BGP高防服务器具体是指什么
运维·服务器·网络·安全·游戏·智能手机
-Aerolite-1 天前
【C/C++】C/C++状态机实现方法
c语言·c++
轩情吖1 天前
Qt常用控件之QLabel(一)
开发语言·数据库·c++·qt·小程序·qlabel·桌面开发
m0_552200821 天前
《UE5_C++多人TPS完整教程》学习笔记58 ——《P58 旋转奔跑动画(Rotate Running Animations)》
c++·游戏·ue5
wanhengidc1 天前
云手机性能会受到哪些因素的影响?
运维·服务器·网络·游戏·智能手机
Nix Lockhart1 天前
《算法与数据结构》第六章[第4节]:哈夫曼树
数据结构·算法
般若Neo1 天前
人工智能与数字艺术 - AI技术创意应用(多模态、数字展演、游戏、元宇宙)
游戏·元宇宙·多模态