week 2 part 2

7月9日

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

示例 1:

输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
   2
  3 4
 6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
示例 2:

输入:triangle = [[-10]]
输出:-10

提示:

1 <= triangle.length <= 200
triangle[0].length == 1
triangle[i].length == triangle[i - 1].length + 1
-104 <= triangle[i][j] <= 104

思路:自顶向下的动态规划。定义了一个二维数组dp,dp[i][j]表示从顶部到(i,j)的最短路径

dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j];

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int hangshu=triangle.size();
        vector<vector<int>> dp(hangshu,vector<int>(hangshu));
        dp[0][0]=triangle[0][0];
        for(int i=1;i<hangshu;++i)
        {
            dp[i][0]=dp[i-1][0]+triangle[i][0];
            for(int j=1;j<i;++j)
            {
                dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j];
            }
            dp[i][i]=dp[i-1][i-1]+triangle[i][i];
        }    
        int minsum=dp[hangshu-1][0];
        for(int i=0;i<hangshu;++i){minsum=min(minsum,dp[hangshu-1][i]);}
        return minsum;
    }
};

给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 

示例 1:

输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]
输出:13
解释:如图所示,为和最小的两条下降路径
示例 2:

输入:matrix = [[-19,57],[-40,-5]]
输出:-59
解释:如图所示,为和最小的下降路径

提示:

n == matrix.length == matrix[i].length
1 <= n <= 100
-100 <= matrix[i][j] <= 100

思路:和上一题一模一样。

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
        int n= matrix.size();
        int dp[n][n];
        for(int i=0;i<n;i++) {dp[0][i]=matrix[0][i];}
        for(int i=1;i<n;++i)
        {
            dp[i][0]=min(dp[i-1][0],dp[i-1][1])+matrix[i][0];
            for(int j=1;j<n-1;++j)
            {
                dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i-1][j+1]))+matrix[i][j];
            }
            dp[i][n-1]=min(dp[i-1][n-1],dp[i-1][n-2])+matrix[i][n-1];
        }
        int minsum=dp[n-1][0];
        for(int i=1;i<n;i++){minsum=min(minsum,dp[n-1][i]);}
        return minsum;

    }
};

整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]

提示:

1 <= nums.length <= 100
0 <= nums[i] <= 100

思路:因为要找到调整之后变化幅度最小的序列,所以咱们得从后往前,找到一对数(i,j),使得i>j 且nums[i]>nums[j] 且i尽量靠右、j尽量靠左 。交换两数后,得到的j之后的序列为需要做处理的序列(变动幅度最小的序列),即将逆序变为正序。

第一步,从后往前遍历,找到第一个打破递增规律的数i;

第二步,同样后往前遍历,找到第一个大于i的数j;

第三步,交换i和j,得到j之后为最短的逆序的序列;

第四步,将逆序翻转为正序,即为最终结果。

证明交换后必定为逆序序列。

证:找到i,如(i,a,b,c,d,j,e)。由于i是第一个打破e到a递增规律的数,所以a到e必为逆序,即d>j>e;由于j是第一个大于i的数,也就是说j之后的都小于i,即j>i>e,同时因为d>j,所以d>j>i>e成立。即a>b>c>d>i>e成立,证毕。

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int i=nums.size()-2;
        while(i>=0&&nums[i]>=nums[i+1]){--i;}
        if(i>=0)
        {
            int j=nums.size()-1;
            while(nums[j]<=nums[i]&&j>=0){--j;}
            swap(nums[i],nums[j]);
        }
         reverse(nums.begin() + i + 1, nums.end());
    }
};

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:

输入: candidates = [2], target = 1
输出: []

提示:

1 <= candidates.length <= 30
2 <= candidates[i] <= 40
candidates 的所有元素 互不相同
1 <= target <= 40

思路:用递归枚举,遇到大于target的,不可达跳过;小于target的,将当前元素加入临时数组temp中,继续向下递归,寻找满足条件的元素;等于target的,输出此时满足条件的临时数组temp。

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> result;//最终组合
        vector<int> temp;//临时组合
        int sum=0;
        int m=candidates.size();//元素个数
        function<void(int)> dfs = [&] (int n) {
        if(sum==target) {result.push_back(temp);}
        else if(sum>target) {return ;}
        else{
            for(int i=n;i<m;i++)
            {
                temp.push_back(candidates[i]);
                sum+=candidates[i];
                dfs(i);
                sum-=candidates[i];
                temp.pop_back();
            }
        }
        };
        dfs(0);
        return result;
    }
};

7月10日

给定一个正整数 n ,输出外观数列的第 n 项。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

你可以将其视作是由递归公式定义的数字字符串序列:

countAndSay(1) = "1"
countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。
前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221
第一项是数字 1 
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

例如,数字字符串 "3322251" 的描述如下图:

示例 1:

输入:n = 1
输出:"1"
解释:这是一个基本样例。
示例 2:

输入:n = 4
输出:"1211"
解释:
countAndSay(1) = "1"
countAndSay(2) = 读 "1" = 一 个 1 = "11"
countAndSay(3) = 读 "11" = 二 个 1 = "21"
countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"

提示:

1 <= n <= 30

思路:定义一个字符串,用来存储上一行生成的结果。

class Solution {
public:
    string countAndSay(int n) {
        string pre="1";
        for(int i=2;i<=n;i++)
        {
            string now="";
            int start=0;//下标 
            int pos=0;//变化的下标

            while(pos<pre.size())
            {
                while(pre[pos]&&pre[start]==pre[pos]) {pos++;}
                now=now+to_string(pos-start)+pre[start];
                start=pos;
            }
            pre=now;
        }
        return pre;
    }
};

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

提示:

1 <= num1.length, num2.length <= 200
num1 和 num2 只能由数字组成。
num1 和 num2 都不包含任何前导零,除了数字0本身。

class Solution {
public:
    string multiply(string num1, string num2) {
        if(num1=="0"||num2=="0") return "0";
        int m = num1.size();
        int n = num2.size();
        vector<int> count(m+n);
        for(int i=m-1;i>=0;i--)
        {
            int x=num1[i]-'0';
            for(int j=n-1;j>=0;j--)
            {
                int y=num2[j]-'0';
                count[i+j+1] += x*y;
            }
        }
        for(int i=m+n-1;i>0;i--)
        {
            count[i-1]+=count[i]/10;
            count[i]=count[i]%10;
        }
        int flag;
        if(count[0]==0) flag=1;
        else{flag=0;}
        string result;
        while(flag<m+n)//把数组放入字符串
        {
            result.push_back(count[flag]);
            flag++;
        }
        for(char &a:result){//把数字转化为字符
            a+='0';
        }
        return result;
    }
};

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:

输入:nums = [1]
输出:[[1]]

提示:

1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同

class Solution {
public:
    vector<vector<int>> result;//最终数组
    vector<int> now;//临时数组
    bool visited[8];
    vector<vector<int>> permute(vector<int>& nums) {
        dfs(nums,0,result,now);
        return result;
    }
    void dfs(const vector<int>&nums,int k,vector<vector<int>>&result,vector<int>& now)
    {
        if(k==nums.size())
        {result.push_back(now);return ;}//如果到最后一个,将排列好的数组输入最终数组中
        //如果没有到,那就继续打乱递归排列
        for(int i=0;i<nums.size();i++)
        {
            if(visited[i]){continue;};//如果该数已经遍历到则跳过
            visited[i]=true;//现在遍历到了
            now.push_back(nums[i]);
            dfs(nums,k+1,result,now);//层数+1的遍历
            now.pop_back();
            visited[i]=false;//用于下一分支可以继续遍历
        }
    }
};

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:

输入:nums = [0,0,0], target = 1
输出:0

提示:

3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104

思路:本来用三层for循环,直接超时。现在是有一层for循环+首尾双指针,减少重复组合。通过定义一个变量zuizhong和update函数,来更新最小差距的和。

优化:先进行排序,这样遇到相邻的重复元素时,可直接跳过,减少运行时间。

在遇到和target相同的和时,直接返回,因为此时是最好答案。在遇到sum>target情况时,右边界指针向左移动,看看能不能更新zuizhong。在遇到sun<target时,左边界指针向右移动。因为数组已经排序,右边界左移之后的三数之和一定是小于当前数的。

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int zuizhong=nums[0]+nums[1]+nums[2];
        auto update = [&](int cur) {
            if (abs(cur - target) < abs(zuizhong - target)) {
                zuizhong = cur;
            }
        };
        for(int i=0;i<nums.size();i++)
        {
            if(i>0&&nums[i]==nums[i-1]){continue;}
            int j=i+1;//左边界
            int k=nums.size()-1;//右边界
            while(j<k)
            {
                int sum=nums[i]+nums[j]+nums[k];
                if(sum==target) return target;
                update(sum);
                if(sum>target)
                {
                    int k0=k-1;
                    while(j<k0&&nums[k0]==nums[k]){k0--;}
                    k=k0;
                }
                if(sum<target)
                {
                    int j0=j+1;
                    while(j0<k&&nums[j]==nums[j0]){j0++;}
                    j=j0;
                }
            }
            
        }
        return zuizhong;
    }
};

7月11日

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。 

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

提示:

1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30

思路:这题和组合排列以及全排列的一样。都是遍历数组candidates。

 为什么if(i>n&&candidates[i]==candidates[i-1]){continue;}可以避免重复解,而不是重复元素呢。

在例子[1,1,2,5,6,7,10],target=8的例子(假设已经sort过了)中, 
当idx = 0时,已经配对了[1,2,5]的结果,当最后回溯到该调用(即第一个调用)后,
迭代到idx = 1时,该位置上的值还是1,且因为升序排序,此时若不讲idx=1排除,
则它仍可以与后续的元素再匹配出一个[1,2,5]的结果。
class Solution {
public:
    vector<vector<int>> result;
    vector<int> temp;
    
    void dfs(const vector<int>& candidates, int target, int n)
    {
        if(target==0) {result.push_back(temp); return ;}
        for(int i=n; i<candidates.size() && target-candidates[i]>=0;i++)
        {
            if(i>n&&candidates[i]==candidates[i-1]){continue;}//避免重复解
            temp.push_back(candidates[i]);
            dfs(candidates,target-candidates[i],i+1);
            temp.pop_back();

        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
       dfs(candidates,target,0);
       return result;

    }
};

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

1 <= nums.length <= 8
-10 <= nums[i] <= 10

思路:该题和全排列I的区别就是:该题的数组中会有重复元素,光按照I的方法写,会有重复的数组。但是,大体上的思路是一样的,都是递归回溯。只加了一个判断条件来剪枝

if(visited[i]||(i>0&&nums[i]==nums[i-1]&&!visited[i-1])) {continue ;}

这个条件的意思很好理解,都在下图。我刚开始想不明白,visited[i]||(i>0&&nums[i]==nums[i-1]),这样就可以了吧,为什么会有!visited[i-1]这个条件。遍历到i时,i-1必定会因为visited[i]=false;而为0,既然必定为零,为什么一定要加这个条件。想了很久,终于发现,我就是个呆子。理由在下图。

class Solution {
public:
    vector<bool> visited;
    void dfs(const vector<int>& nums,vector<vector<int>>& result,vector<int>& temp,int n)
    {
        if(n==nums.size()) 
        {result.push_back(temp); return;}
        for(int i=0;i<nums.size();i++)
        {
            if(visited[i]||(i>0&&nums[i]==nums[i-1]&&!visited[i-1])) {continue ;}
            temp.push_back(nums[i]);
            visited[i]=true;
            dfs(nums,result,temp,n+1);
            visited[i]=false;
            temp.pop_back();
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> temp;
        visited.resize(nums.size());
        sort(nums.begin(),nums.end());
        dfs(nums,result,temp,0);
        return result;
    }
};

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
空白格用 '.' 表示。

示例 1:
输入:board = 
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:true
示例 2:

输入:board = 
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

提示:

board.length == 9
board[i].length == 9
board[i][j] 是一位数字(1-9)或者 '.'

思路:刚开始打算判断整个数独满不满足条件1(每行中数字不重复)、再条件2、最后条件3。

实际上,这种方法会遍历3次数独。

而利用哈希表则只需要遍历1次。维护三张哈希表,分别是hang、lie、gongge。其中,hang[i][j]表示第i行中,数字j出现的次数。hang[i][j]大于1时,表示第i行出现多个数字j,不满足条件1。同理,lie和gongge一样。

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int hang[9][9];
        int lie[9][9];
        int gongge[3][3][9];
        memset(hang,0,sizeof(hang));
        memset(lie,0,sizeof(lie));
        memset(gongge,0,sizeof(gongge));
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
            {
                    if(board[i][j]!='.')
                    {
                    int num=board[i][j]-'0'-1;
                    hang[i][num]++;
                    lie[j][num]++;
                    gongge[i/3][j/3][num]++; 
                    if(hang[i][num]>1||lie[j][num]>1||gongge[i/3][j/3][num]>1)
                    {return false;}
                    }                      
            }
        }
        return true;
    }
};

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:

输入:x = 2.10000, n = 3
输出:9.26100
示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

-100.0 < x < 100.0
-231 <= n <= 231-1
n 是一个整数
要么 x 不为零,要么 n > 0 。
-104 <= xn <= 104

思路:由于一位一位的x相乘,会导致运行时间超时,所以用快速幂算法。

 x的两次方乘以x的二次方的运行速度会比直接算x的四次方来的快。

class Solution {
public:
    double myPow(double x, int n) {
        double result=1;
        double base=x;
        long long m=n;//避免-n过小时,将n正负转化,导致溢出
        bool flag=1;//1为指数正,0为指数负
        if(m<0) {flag=0;m=-m;}
        while(m>0)
        {
            if(!(m&1))//m&1是m与1做与运算,即,判断奇偶性
            {m>>=1;base=base*base;}
            else{
                m=m-1;
                result=result*base;
                m>>=1;//右移一位,即,除以2
                base=base*base;
            }
        } 
        if(flag==0){result=1.0/result;}
        return result;
    }
};

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:

输入: strs = [""]
输出: [[""]]
示例 3:

输入: strs = ["a"]
输出: [["a"]]

提示:

1 <= strs.length <= 104
0 <= strs[i].length <= 100
strs[i] 仅包含小写字母

思路:把各个字符串排序,所有字母异位词都变得一样。即,排序后的词作为哈希表的关键值,将排序前的词计入到哈希表中。

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> hash;
        for(string& str:strs)
        {
            string temp=str;
            sort(temp.begin(),temp.end());
            hash[temp].push_back(str);
        }
        vector<vector<string>> result;
        for(auto it=hash.begin();it!= hash.end();++it) //遍历一遍hash表,将表中的内容输出
        {
            result.push_back(it->second);
        }
        return result;
    }
};

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

思路:贪心算法,维护一个最远可到达位置mostyuan。假设从某一位置i起跳,该位置最远可到达距离为i+nums[i],更新两者最大值mostyuan。但是,在之前遍历时,就发现最远可达到距离根本就到不了i位置,那么就是不可达的。即,i>mostyuan。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int mostyuan=0;
        for(int i=0;i<nums.size();i++)
        {
            if(i>mostyuan) return false;
            mostyuan=max(mostyuan,i+nums[i]);
        }
        return true;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值