传送门 | 难度 |
---|---|
70. 爬楼梯 | 简单 |
53. 最大子数组和 | 简单 |
1594. 矩阵的最大非负积 | 中等 |
撸码时间
1、爬楼梯
题目描述:需要爬n
阶才能到达楼顶。每次可以爬1
或2
个台阶。请问有多少种不同的方法可以爬到楼顶?(1<=n<=45)
解法1
思路:假设已经到达了楼顶,现在往后退一步,由于一次只能爬1
或2
个台阶,那么退一步就是在n-1
或n-2
的位置,假设到达n-1
个台阶时有i
种走法,n-2
有j
中走法,那么最终到达n
处就是i+j
种走法。再分别从n-1
处和n-2
处各退一步,以此类推…临界点为n=1
和n=2
时走法各为1
和2
。
代码如下:
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亿多,这个次数还是非常大的。
解法晚上更~