leetcode 50-100题-java版
(53)最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
思路:一般情况下,两个数组或两个字符串,都需要双指针,二维dp;但是一维数组和一个字符串情况下,要先考虑一维dp函数可行否。本题:dp[i] 表示以下标i结尾的子数组的最大和。i为状态,就是下标的一次遍历;dp[i]就是想要的结果;选择就是 nums[i] 和 nums[i] + dp[i-1]谁更大;basecase也简单。
class Solution {
public int maxSubArray(int[] nums) {
// 可以用一维dp,也可以用二维dp和双指针;但能一维就不二维
// 以后遇到题先考虑一维行不行,再考虑二维
// dp[i] 表示以下标i结尾的子数组的最大和。i为状态,就是下标的一次遍历;dp[i]就是想要的结果;
// 选择就是 nums[i] 和 nums[i] + dp[i-1]谁更大;basecase也简单
// int n = nums.length;
// if(n==1)
// return nums[0];
// int [] dp = new int[n];
// dp[0] = nums[0];
// int ans=dp[0];
// for(int i=1; i<n; i++){
// dp[i] = Math.max(nums[i], nums[i]+dp[i-1]);
// ans = ans>dp[i]?ans:dp[i];
// }
// return ans;
// 因为dp[i]只和上一个状态dp[i-1]有关,所以可以不用dp数组,只用一个变量
int n = nums.length;
if(n==1)
return nums[0];
int ans = nums[0];
int dp_i = nums[0];
for(int i=1; i<n; i++){
dp_i = Math.max(nums[i], nums[i]+dp_i);
ans = ans>dp_i?ans:dp_i;
}
return ans;
}
}
(58)最后一个单词的长度
给你一个字符串 s,由若干单词组成,单词之间用空格隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 1:
输入:s = “Hello World”
输出:5
示例 2:
输入:s = " "
输出:0
提示:
1 <= s.length <= 104
s 仅有英文字母和空格 ’ ’ 组成
思路:从后向前遍历就可
class Solution {
public int lengthOfLastWord(String s) {
if(s.length()==1 && " ".equals(s))
return 0;
int n = s.length();
int cnt=0;
for(int i=n-1; i>=0; i--){
// s.charAt(i)如果是空格,有可能是最后一个单词后边的,也可能前边的空格
if(s.charAt(i)==' '){
if(cnt>0){
// cnt>0说明是最后一个单词左边的空格,此时cnt的值就是最后一个单词的长度
return cnt;
} else {
// cnt=0说明还没遍历到最后一个单词,继续遍历
continue;
}
} else {
cnt++; // 不是空格,说明正在遍历最后一个单词,长度加1
}
}
return cnt;
}
}
(62)不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?
示例:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
- 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右
- 向下 -> 向右 -> 向下
提示:
1 <= m, n <= 100
题目数据保证答案小于等于 2 * 10^9,小于20亿,也就是说int类型数据就可以
思路:最简单的状态转移,因为是二维地图,所以得用二维dp。因为这个dp的base case都是1,并且每个位置的数据只和自己左边和上边有关系,所以完全可以把dp[m[[n] 改成dp[2][n] 稍微减少点空间消耗。
class Solution {
public int uniquePaths(int m, int n) {
int [][] dp = new int[m][n];
dp[0][0] = 1; //m=n=1时,代表什么都不做就到达终点,只有一种情况
for(int i=1; i<n; i++){
dp[0][i] = 1;
}
for(int i=1; i<m; i++){
dp[i][0] = 1;
}
for(int i=1; i<m; i++){
for(int j=1; j<n; j++){
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
}
(63)不同路径2
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。
提示:
m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j] 为 0 或 1
思路:和上题一样
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int [][] dp = new int[m][n];
for(int i=0; i<n; i++){
if(obstacleGrid[0][i]==0)
dp[0][i] = 1;
else
break;
}
for(int i=0; i<m; i++){
if(obstacleGrid[i][0]==0)
dp[i][0] = 1;
else
break;
}
for(int i=1; i<m; i++){
for(int j=1; j<n; j++){
if(obstacleGrid[i][j]==1){
dp[i][j] = 0;
} else{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
}
(64)最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。
示例1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:
输入:grid = [[1,2,3],[4,5,6]]
输出:12
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 200
0 <= grid[i][j] <= 100
思路:和前两题一样。Math.min(), Math.max(), Math.abs(), Math.pow(a,b)是java.lang包下的,不用自己导包
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int [][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for(int i=1; i<n; i++){
dp[0][i] = grid[0][i]+dp[0][i-1];
}
for(int i=1; i<m; i++){
dp[i][0] = grid[i][0]+dp[i-1][0]<