点击跳转到题目位置
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
提示:
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[] dp = new int[n];
for(int i = n - 1; i >= 0; --i){
for(int j = 0; j < triangle.get(i).size(); ++j){
if(i == n - 1){
dp[j] = triangle.get(i).get(j);
} else{
dp[j] = triangle.get(i).get(j) + Math.min(dp[j], dp[j + 1]);
}
}
}
return dp[0];
}
}
点击跳转到题目位置
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
提示:
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(i == 0 && j == 0){
continue;
} else if(i == 0){
grid[i][j] += grid[i][j - 1];
} else if(j == 0){
grid[i][j] += grid[i - 1][j];
} else{
grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]);
}
}
}
return grid[m - 1][n - 1];
}
}
点击跳转到题目位置
给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0])。机器人尝试移动到 右下角(即 grid[m - 1][n - 1])。机器人每次只能向下或者向右移动一步。
网格中的障碍物和空位置分别用 1 和 0 来表示。机器人的移动路径中不能包含 任何 有障碍物的方格。
返回机器人能够到达右下角的不同路径数量。
测试用例保证答案小于等于 2 * 109。
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 < m; ++i){
for(int j = 0; j < n; ++j){
if(obstacleGrid[i][j] == 0){
if(i == 0 && j == 0){
dp[i][j] = 1;
} else if(j == 0){
dp[i][j] = dp[i - 1][j];
} else if(i == 0){
dp[i][j] = dp[i][j - 1];
} else{
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
}
return dp[m - 1][n - 1];
}
}
点击跳转到题目位置
给你一个字符串 s,找到 s 中最长的 回文子串。
提示:
class Solution {
public String longestPalindrome(String s) {
int m = s.length();
int max_len = 0;
int end = 0;
boolean[][] dp = new boolean[m][m];
for(int i = 0; i < m; ++i){
for(int j = m - 1; j >= i; --j){
if(i == 0){
dp[j - i][j] = true;
} else{
if(i == 1){
dp[j - i][j] = (s.charAt(j - i) == s.charAt(j));
} else{
dp[j - i][j] = (s.charAt(j - i) == s.charAt(j) && dp[j - i + 1][j - 1]);
}
}
if(dp[j - i][j] == true){
max_len = i;
end = j;
}
}
}
return s.substring(end - max_len, end + 1);
}
}
点击跳转到题目位置
给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。
两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:
**注意:**a + b 意味着字符串 a 和 b 连接。
提示:
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
int m = s1.length();
int n = s2.length();
int t = s3.length();
if(m + n != t){
return false;
}
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for(int i = 0; i <= m; ++i){
for(int j = 0; j <= n; ++j){
int idx = i + j - 1;
if(i > 0){
dp[i][j] |= (dp[i - 1][j] && (s3.charAt(idx) == s1.charAt(i - 1)));
}
if(j > 0){
dp[i][j] |= (dp[i][j - 1] && (s3.charAt(idx) == s2.charAt(j - 1)));
}
}
}
return dp[m][n];
}
}
点击跳转到题目位置
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
提示:
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
for(int i = 0; i <= m; ++i){
dp[i][0] = i;
}
for(int j = 0; j <= n; ++j){
dp[0][j] = j;
}
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= n; ++j){
int num1 = dp[i - 1][j] + 1;
int num2 = dp[i][j - 1] + 1;
int num3 = word1.charAt(i - 1) == word2.charAt(j - 1) ? dp[i - 1][j - 1] : dp[i - 1][j - 1] + 1;
dp[i][j] = Math.min(Math.min(num1, num2), num3);
}
}
return dp[m][n];
}
}
点击跳转到题目位置
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
提示:
class Solution {
public int maxProfit(int[] prices) {
return maxProfit(2, prices);
}
public int maxProfit(int k, int[] prices) {
int m = prices.length;
k = Math.min(k, m / 2);
// buy[i][j]表示在(0~i)中至少持有一只股票的情况下最大利润
int[][] buy = new int[m][k + 1];
// sell[i][j]表示在(0~i)中一只股票且卖出j只股票的最大利润
int[][] sell = new int[m][k + 1];
buy[0][0] = -prices[0];
for(int i = 1; i <= k; ++i){
buy[0][i] = Integer.MIN_VALUE / 2;
sell[0][i] = Integer.MIN_VALUE / 2;
}
for (int i = 1; i < m; ++i) {
buy[i][0] = Math.max(-prices[i], buy[i - 1][0]);
for (int j = 1; j <= k; ++j) {
buy[i][j] = Math.max(sell[i - 1][j] - prices[i], buy[i - 1][j]);
sell[i][j] = Math.max(buy[i - 1][j - 1] + prices[i], sell[i - 1][j]);
}
}
int max0 = 0;
for(int i = 0; i <= k; ++i){
max0 = Math.max(max0, sell[m - 1][i]);
}
return max0;
}
}
点击跳转到题目位置
给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
提示:
class Solution {
public int maxProfit(int k, int[] prices) {
int m = prices.length;
k = Math.min(k, m / 2);
// buy[i][j]表示在(0~i)中至少持有一只股票且卖出j次的情况下最大利润
int[][] buy = new int[m][k + 1];
// sell[i][j]表示在(0~i)中一只股票且卖出j只股票的最大利润
int[][] sell = new int[m][k + 1];
buy[0][0] = -prices[0];
for(int i = 1; i <= k; ++i){
buy[0][i] = Integer.MIN_VALUE / 2;
sell[0][i] = Integer.MIN_VALUE / 2;
}
for (int i = 1; i < m; ++i) {
buy[i][0] = Math.max(-prices[i], buy[i - 1][0]);
for (int j = 1; j <= k; ++j) {
buy[i][j] = Math.max(sell[i - 1][j] - prices[i], buy[i - 1][j]);
sell[i][j] = Math.max(buy[i - 1][j - 1] + prices[i], sell[i - 1][j]);
}
}
int max0 = 0;
for(int i = 0; i <= k; ++i){
max0 = Math.max(max0, sell[m - 1][i]);
}
return max0;
}
}
点击跳转到题目位置
在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。
提示:
class Solution {
public int maximalSquare(char[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int[][] dp = new int[m][n]; // 以i, j为右下角的最大正方形的边长
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(i == 0 || j == 0){
dp[i][j] = matrix[i][j] - '0';
} else{
if(matrix[i][j] == '1'){
if(dp[i - 1][j] == dp[i][j - 1]){
int len = dp[i - 1][j];
dp[i][j] = matrix[i - len][j - len] == '1' ? len + 1 : len;
} else{
dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
}
}
}
}
}
int ans = 0;
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
ans = Math.max(ans, dp[i][j]);
}
}
return ans * ans;
}
}