【LeetCode】动态规划篇

传送门难度
70. 爬楼梯简单
53. 最大子数组和简单
1594. 矩阵的最大非负积中等

撸码时间

1、爬楼梯

题目描述:需要爬n阶才能到达楼顶。每次可以爬12个台阶。请问有多少种不同的方法可以爬到楼顶?(1<=n<=45)
解法1
思路:假设已经到达了楼顶,现在往后退一步,由于一次只能爬12个台阶,那么退一步就是在n-1n-2的位置,假设到达n-1个台阶时有i种走法,n-2j中走法,那么最终到达n处就是i+j种走法。再分别从n-1处和n-2处各退一步,以此类推…临界点为n=1n=2时走法各为12
代码如下:

public int climbStairs(int n) {
   if (n == 1){
     return 1;
   }
   if (n == 2){
     return 2;
   }
   return climbStairs(n-1)+climbStairs(n-2);
}

代码运行结果是正确的。但是在LeetCode上提交时,n=45的时候超时…
于是就使用了解法2
解法2:菲波那切数列
思路:n=1时sum=1,n=2时sum=2;n=3时sum=3;n=4时sum=5;n=5时sum=8…由此可以发现这是一个菲波那切数列,即,后面一项等于前两项之和。
代码:

public int climbStairs(int n) {
	 int pre = 1;
	 int next = 1;
	 int num = 1;
	 for (int i = 2; i <= n; i++) {
	     num = pre + next;
	     pre = next;
	     next = num;
	 }
	 return num;
}

过辣~

2、最大子数组和

题目描述:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
(子数组 是数组中的一个连续部分。)

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
输入:nums = [-1]
输出:-1
输入:nums = [5,4,-1,7,8]
输出:23

解法1:一力降十会
思路:其实第一眼看到这道题,脑子有点乱…先暴力解试试看。首先依次从数组的每个数开始遍历,每个数遍历时依次往后加。

public int maxSubArray(int[] nums) {
    int max = nums[0];
    for (int i = 0; i < nums.length; i++) {
        int temp = nums[i];
        if (temp > max){
            max = temp;
        }
        for (int j = i+1; j < nums.length; j++) {
            temp += nums[j];
            if (temp > max){
                max = temp;
            }
        }
    }
    return max;
}

很明显,时间复杂度为O(n2),所以…超时了呜呜呜呜!
不过这段代码应该没毛病~

解法2
看的一位大佬的解法。
思路:sum为子数组的和。假设现在sum是前n-1项的和,如果sum<=0,那么对第n项是没有帮助的,此时最大子数组和只能从第n项开始算起。只有sum>0时才会对第n项有帮助。所以当sum>0时,子数组和算上第n项。
每次保存一下sum的最大值即可。

public int maxSubArray(int[] nums) {
    int max = nums[0];
    int sum = 0;
    for (int num : nums) {
        if (sum>0){
            sum += num;
        }else{
            sum = num;
        }
        max = Math.max(sum,max);
    }
    return max;
}

过辣~

3、1594. 矩阵的最大非负积

题目描述:

给你一个大小为 rows x cols 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右 或 向下 移动。

在从左上角 (0, 0) 开始到右下角 (rows - 1, cols - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。

返回 最大非负积 对 109 + 7 取余 的结果。如果最大积为负数,则返回 -1 。
注意,取余是在得到最大积之后执行的。

思路:
模拟向右或者向下移动,一直移动到右下角找到最大非负积。

代码如下:

public class Solution {
    long max = -1;

    public int maxProductPath(int[][] grid) {
        search(grid, 0, 0, 1);
        return (int)(max<0?-1:max%1000000007);
    }

    public void search(int[][] grid, int x, int y, long sum) {
        sum *= grid[x][y];
        if (x < grid.length - 1) {
            search(grid, x + 1, y, sum);
        }
        if (y < grid[0].length - 1) {
            search(grid, x, y + 1, sum);
        }
        if (y == grid[0].length - 1 && x == grid.length - 1) {
                max = Math.max(sum, max);
        }
    }
}

理论上来说,逻辑是正确的,但是遗憾的是,超时了…
假设该矩阵为m * n,那么从左上角移动到右下角,一共需要移动m+n次,其中需要向右移动m次,向下移动n次。所以时间复杂度是Cm+nm 或者Cnm+n
当m和n都取15时,计算次数为23亿多,这个次数还是非常大的。

解法晚上更~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值