LeetCode寒假刷题 Day08


前言

今天是寒假LeetCode刷题打卡的第八天,继续坚持、继续加油!也希望我的博文能够帮助到大家,若有疑问,可以随时私信Call我!

今天的三道题中,有两道采用动态规划的方法做,有一道用的回溯算法完成。下面便是每道题的具体题目、思考过程以及代码实现。

一、062 不同路径

1. 题目描述

题号:62
难度:中等
062 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

问题

例如,上图是一个7 x 3 的网格。有多少可能的路径?

说明:m 和 n 的值均不超过 100。

示例 1:

输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向右 -> 向下
  2. 向右 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向右
    示例 2:

输入: m = 7, n = 3
输出: 28
示例 3:

输入: m = 23, n = 12
输出: 193536720

2. 解题思路

由于最近一直在练习递归,这道题也很明显可以用递归的方法来实现,因此最初我是采用的递归来实现。但是由于递归会有重叠子问题,导致计算速度变慢,在上传LeetCode后AC不通过,显示时间超时。所以我又重新用动态规划的思想来实现这道题,并最后提交通过。

在动态规划的方法中,我们首先建立一个与原来格子一样大小的dp二维数组,然后将循环从后往前开始。显然,最右边的一列和最下面的一行,由于只能往一个方向移动,显然都为1。

然后对于不是上述情况的其他格子,显然他的值等于其下面一个的格子的值加上右边一个格子的值,即 dp[i][j] = dp[i+1][j] + dp[i][j+1]。

3. 代码实现

方法一:递归

class Solution {
    public int uniquePaths(int m, int n) {
        return dfs(m-1,n-1,0,0);
    }
    private int dfs(int m,int n,int row,int col)
    {
        if(row==m&&col==n)
            return 1;
        int count=0;
        if(row<m)
            count+=dfs(m,n,row+1,col);
        if(col<n)
            count+=dfs(m,n,row,col+1);
        return count;
    }
}

方法二:动态规划

class Solution {
    public int uniquePaths(int m, int n) {
        int dp[][]=new int[m][n];
        dp[m-1][n-1]=1;
        int i=m-1,j;
        for(j=0;j<n-1;++j)
        {
            dp[i][j]=1;
        }
        j=n-1;
        for(i=0;i<m-1;++i)
        {
            dp[i][j]=1;
        }
        for(i=m-2;i>=0;--i)
        {
            for(j=n-2;j>=0;--j)
            {
                dp[i][j]=dp[i+1][j]+dp[i][j+1];
            }
        }
        return dp[0][0];
    }
}

二、070 爬楼梯

1. 题目描述

题号:70
难度:简单
070 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶
    示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。

  1. 1 阶 + 1 阶 + 1 阶
  2. 1 阶 + 2 阶
  3. 2 阶 + 1 阶
    示例 3:

输入: 44
输出: 1134903170

2. 解题思路

本题采用动态规划的方法来实现。状态转移方程为dp[i]=dp[i-1]+dp[i-2]。
由于实际使用中并未用到整个dp数组,不必创建与原来数组等长的dp数组来实现,可以只用三个变量pre1、pre2和res就能实现。

3. 代码实现

具体代码如下:

class Solution {
    public int climbStairs(int n) {
        if(n==1||n==2)
            return n;
        int pre1=1;
        int pre2=2;
        int res=0;
        for(int i=3;i<=n;i++)
        {
            res=pre1+pre2;
            pre1=pre2;
            pre2=res;
        }
        return res;
    }
}

三、078 子集

1. 题目描述

题号:78
难度:中等
078 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

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

2. 解题思路

本题采用回溯法实现。

对于采用回溯法解决的问题,具体操作如下:

  • 确定递归回溯函数的参数。start:记录下次选取的开始位置
  • 确定递归终止条件。当递归树到达叶子节点时,start >= nums.size(),此时就是候选元素用尽,可以return了。但是因为start >= nums.size()时,本层for循环本来也结束了,所以无需再加终止条件判断了;
  • 确定单层遍历逻辑。求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树;

1、选取一个元素;
2、在剩余元素中递归搜索;
3、回溯;

3. 代码实现

class Solution {

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list=new ArrayList<List<Integer>>();
        dfs(nums,0,list,new ArrayList<Integer>());
        return list;
    }
    private void dfs(int[] nums,int start,List<List<Integer>> list,List<Integer> sub)
    {
        list.add(new ArrayList<Integer>(sub));
        for(int i=start;i<nums.length;++i)
        {
            sub.add(nums[i]);
            dfs(nums,i+1,list,sub);
            sub.remove(sub.size()-1);
        }
    }   
}

总结

以上就是今天 LeetCode寒假刷题 Day08 所做的三道题。若有任何疑问,欢迎私信或评论区留言鸭!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值