动态规划dp
连续子数组的最大和
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return -1;
}
int ret = nums[0];
for(int i = 1; i < nums.length; i++) {
nums[i] += Math.max(nums[i - 1], 0);
ret = Math.max(ret, nums[i]);
}
return ret;
}
}
连续子数组的最大乘积
import java.util.*;
public class Solution {
public int maxProduct (int[] nums) {
//max是以i结尾的最大乘积 min是以i结尾的最小乘积
int max = nums[0];
int min = nums[0];
int ret = nums[0];
for (int i = 1; i < nums.length; i++) {
int tmp = max;
max = Math.max(nums[i], Math.max(max * nums[i], min * nums[i]));
min = Math.min(nums[i], Math.min(tmp * nums[i], min * nums[i]));
ret = Math.max(ret,max);
}
return ret;
}
}
礼物的最大价值
class Solution {
public int maxValue(int[][] arr) {
int n = arr.length, m = arr[0].length;
int[][] f = new int[n + 1][m + 1];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]) + arr[i - 1][j - 1];
}
}
return f[n][m];
}
}
矩阵的最小路径(最小路径之和)
三角形最小路径和
题目链接:https://leetcode-cn.com/problems/triangle/
//自底向上
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
if (triangle == null || n == 0){
return 0;
}
// 加1可以不用初始化最后一层
int[][] f = new int[n + 1][n + 1];
for (int i = n-1; i>=0; i--){
List<Integer> cur = triangle.get(i);
for(int j = 0 ; j < cur.size(); j++){
f[i][j] = Math.min(f[i+1][j], f[i+1][j+1]) + cur.get(j);
}
}
return f[0][0];
}
}
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
// dp[i][j] 表示从点 (i, j) 到底边的最小路径和。
int[][] f = new int[n + 1][n + 1];
// 从三角形的最后一行开始递推。
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
f[i][j] = Math.min(f[i + 1][j], f[i + 1][j + 1]) + triangle.get(i).get(j);
}
}
return f[0][0];
}
}
岛屿的数量
import java.util.*;
public class Solution {
public int solve (char[][] grid) {
// write code here
int count = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1'){
dfs(grid, i, j);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
grid[i][j] = '0';
dfs(grid, i + 1, j);
dfs(grid, i, j + 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
}
不同路径I
https://leetcode-cn.com/problems/unique-paths/
class Solution {
public int uniquePaths(int m, int n) {
int[][] f = new int[m ][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 || j == 0)
f[i][j] = 1;
else {
f[i][j] = f[i - 1][j] + f[i][j - 1];
}
}
}
return f[m - 1][n - 1];
}
}
不同路径II(有障碍版)
https://leetcode-cn.com/problems/unique-paths-ii/
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid == null || obstacleGrid.length == 0) {
return 0;
}
// 定义 dp 数组并初始化第 1 行和第 1 列。
int m = obstacleGrid.length, n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) {
dp[i][0] = 1;
}
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) {
dp[0][j] = 1;
}
// 根据状态转移方程 dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 进行递推。
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 0) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
最长公共前缀
https://leetcode-cn.com/problems/longest-common-prefix/
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs == null || strs.length == 0) {
return "";
}
String ret = strs[0];
for(int i = 0; i < strs[0].length(); i++) {
for(int j = 1; j < strs.length; j++) {
if(i == strs[j].length() || strs[0].charAt(i) != strs[j].charAt(i)) {
return ret.substring(0, i);
}
}
}
return ret;
}
}
最长无重复子数组
public class Solution {
public int maxLength (int[] nums) {
// write code here
if(nums == null) {
return -1;
}
int max = 0;
int left = 0;
HashMap<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++) {
if(map.containsKey(nums[i])) {
left = Math.max(left, map.get(nums[i]) + 1);
}
map.put(nums[i], i);
max = Math.max(max, i - left + 1);
}
return max;
}
}
最长不重复子串
import java.util.*;
public class Solution {
public int maxLength (int[] nums) {
// write code here
if(nums == null || nums.length == 0) {
return 0;
}
HashMap<Integer, Integer> map = new HashMap<>();
int max = 0, left = 0;
for(int i = 0; i < nums.length; i++) {
if(map.containsKey(nums[i])) {
left = Math.max(left, map.get(nums[i]) + 1);
}
map.put(nums[i], i);
max = Math.max(max, i - left + 1);
}
return max;
}
}
class Solution {
public int lengthOfLongestSubstring(String s) {
// 记录字符上一次出现的位置
int[] last = new int[128];
for(int i = 0; i < 128; i++) {
last[i] = -1;
}
int n = s.length();
int res = 0;
int start = 0; // 窗口开始位置
for(int i = 0; i < n; i++) {
int index = s.charAt(i);
start = Math.max(start, last[index] + 1);
res = Math.max(res, i - start + 1);
last[index] = i;
}
return res;
}
}
最长上升子序列(一)
https://www.nowcoder.com/questionTerminal/5164f38b67f846fb8699e9352695cd2f
import java.util.*;
public class Solution {
public int LIS (int[] arr) {
// write code here
int n = arr.length;
if(n == 0) return 0;
int[] f = new int[n]; // dp[i]表示以arr[i]结尾时的最长递增子序列长度
Arrays.fill(f, 1);
int max = 1;
for(int i = 1; i < n; i++){
for(int j = i - 1; j >= 0; j--){
if(arr[j] < arr[i]){
// arr[j] < arr[i],可以把arr[i]接在arr[j]后面,构成长度为dp[j]+1的递增子序列
f[i] = Math.max(f[i], f[j] + 1); // 选择能构成更长递增子序列的arr[j]
}
}
max = Math.max(max, f[i]);
}
return max;
}
}
最长上升子序列(三)
import java.util.*;
public class Solution {
/**
* retrun the longest increasing subsequence
* @param arr int整型一维数组 the array
* @return int整型一维数组
*/
public int[] LIS (int[] arr) {
// write code here
int n = arr.length;
int[] tail = new int[n+1];
tail[0] = Integer.MIN_VALUE;
int[] dp = new int[n];
int end = 0;
for(int i = 0;i < arr.length; i++){
int num = arr[i];
if(num > tail[end]){
end++;
dp[i] = end;
tail[end] = num;
}else{
int left = 1;
int right = end;
while(left < right){
int mid = (left + right) / 2;
if(tail[mid] >= num){
right = mid;
}else if(tail[mid] < num){
left = mid + 1;
}
}
tail[left] = num;
dp[i] = left;
}
}
int[] res = new int[end];
int length = end;
for(int i = n - 1;i >= 0; i--){
if(dp[i] == length){
res[length - 1] = arr[i];
length--;
}
}
return res;
}
}
连续子数组的最大和
https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return -1;
}
int ret = nums[0];
for(int i = 1; i < nums.length; i++) {
nums[i] += Math.max(nums[i - 1], 0);
ret = Math.max(ret, nums[i]);
}
return ret;
}
}
最长连续增长序列
https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/
class Solution {
public int findLengthOfLCIS(int[] nums) {
if(nums.length <= 1)
return nums.length;
int ret = 1;
int count = 1;
for(int i = 0; i < nums.length - 1; i++) {
if(nums[i+1] > nums[i]) {
count++;
} else {
count = 1;
}
ret = Math.max(ret, count);
}
return ret;
}
}
最长连续序列
https://leetcode-cn.com/problems/longest-consecutive-sequence/
- set
class Solution {
public int longestConsecutive(int[] nums) {
HashSet<Integer> set = new HashSet<Integer>();
for(int x : nums) {
set.add(x);
} //放入hash表中
int ret = 0;
for(int x : set)
{
if(!set.contains(x-1))
{
int y = x; //以当前数x向后枚举
while(set.contains(y + 1)) {
y++;
}
ret = Math.max(ret, y - x + 1); //更新答案
}
}
return ret;
}
}
- hashset
class Solution {
public int longestConsecutive(int[] nums) {
// key表示num,value表示num最远到达的连续右边界
Map<Integer, Integer> map = new HashMap<>();
// 初始化每个num的右边界为自己
for (int num : nums) {
map.put(num, num);
}
int ret = 0;
for (int num : nums) {
if (!map.containsKey(num - 1)) {
int right = map.get(num);
// 遍历得到最远的右边界
while (map.containsKey(right + 1)) {
right = map.get(right + 1);
}
// 更新右边界
map.put(num, right);
// 更新答案
ret = Math.max(ret, right - num + 1);
}
}
return ret;
}
}
最长递增子序列
https://leetcode-cn.com/problems/longest-increasing-subsequence/
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums == null || nums.length == 0) {
return -1;
}
int n = nums.length;
int[] f = new int[n + 1];
int ret = 0;
for(int i = 0; i < n; i++) {
f[i] = 1;
for(int j = 0; j < i; j++) {
if(nums[j] < nums[i]) {
f[i] = Math.max(f[i], f[j] + 1);
}
}
}
for(int i = 0; i < n; i++) {
ret = Math.max(ret, f[i]);
}
return ret;
}
}
最长公共子串
- 求长度
//最大值
public static int func(String s1, String s2) {
int n = s1.length(), m = s2.length();
int[][] f = new int[n + 1][m + 1];
int max = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(s1.charAt(i - 1) == s2.charAt(j - 1)) {
f[i][j] = Math.max(f[i - 1][j - 1] + 1, f[i][j]);
if(f[i][j] > max) {
max = f[i][j];
}
}
}
}
return max;
}
- 求字符串
//求结果
public static String func2(String s1, String s2) {
int n = s1.length(), m = s2.length();
int[][] f = new int[n + 1][m + 1];
int max = 0, end = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(s1.charAt(i - 1) == s2.charAt(j - 1)) {
f[i][j] = Math.max(f[i - 1][j - 1] + 1, f[i][j]);
if(f[i][j] > max) {
max = f[i][j];
end = i;
}
}
}
}
return s1.substring(end - max, end);
}
最长公共子序列(一) 求长度
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int n = text1.length(), m = text2.length();
int[][] f = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (text1.charAt(i - 1) != text2.charAt(j - 1)) {
f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]);
}else {
f[i][j] = Math.max(f[i][j], f[i - 1][j - 1] + 1);
}
}
}
return f[n][m];
}
}
最长公共子序列(二) 求字符串
import java.util.*;
public class Solution {
public String LCS (String s1, String s2) {
// write code here
int n = s1.length();
int m = s2.length();
int [][] f = new int[n + 1][m + 1];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(s1.charAt(i - 1) == s2.charAt(j - 1)){
f[i][j] = f[i - 1][j - 1] + 1;
}else{
f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]);
}
}
}
if(f[n][m] == 0)return "-1";
StringBuilder ret = new StringBuilder();
while(n > 0 && m > 0){
if(s1.charAt(n - 1) == s2.charAt(m - 1)){
ret.append(s1.charAt(n - 1));
n--;
m--;
}else{
if(f[n - 1][m] > f[n][m - 1]){
n--;
}else{
m--;
}
}
}
return ret.reverse().toString();
}
}
最长回文串(给字母,自己构造最长的回文串)
https://leetcode-cn.com/problems/longest-palindrome/
- 题解:
class Solution {
public int longestPalindrome(String s) {
int[] letters = new int[128];
char[] arr = s.toCharArray();
for(char c : arr) letters[c]++;
int res = 0;
for(int i : letters) res += i - (i % 2);
return res == arr.length ? res : res + 1;
}
}
最长回文子串I(求长度)
- 普通版
public static boolean isHuiWen(String s) {
if(s == null ||s.length() == 0) {
return false;
}
int i = 0, j = s.length() - 1;
while(i < j) {
if(s.charAt(i) != s.charAt(j)) {
return false;
}
i++;
j--;
}
return true;
}
//最长回文长度(普通版)
public static int func(String s) {
// write code here
int n = s.length();
int ret = 0;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
if(isHuiWen(s.substring(i, j))) {
if(ret < j - i) {
ret = j - i;
}
}
}
}
return ret;
}
- dp版
//最长回文长度(dp版)
import java.util.*;
public class Solution {
public int getLongestPalindrome (String s) {
//定义一个表示字符长度
int len = s.length();
//如果字符小于2,直接返回
if(len < 2){
return 1;
}
//定义一个表示回文字符数量的变量
int maxlen = 1;
//定义一个存储所有可能的结果,一个二维数组
boolean[][] dp = new boolean[len][len];
//单个字符本身就是回文串
for(int i = 0; i < len; i++){
dp[i][i] = true;
}
//递归遍历,二维数组的对角线上方的所有元素
for(int j = 1; j < len; j++){
for(int i = 0; i < len - 1 && i < j; i++){
//如果两个字符相等,就说明不是回文串
if(s.charAt(i) != s.charAt(j)){
dp[i][j] = false;
}else{
//当是回文串时,字符个数小于等于3个,就是回文串
if(j - i < 3){
dp[i][j] = true;
}else{
//递归判断当边界两边的字符相等时,继续判断内层的字符是否相等
dp[i][j] = dp[i + 1][j - 1];
}
}
//对比所有的回文串,取出长度最大的,回文串的起始位置
if(dp[i][j] && j - i + 1 > maxlen){
maxlen = j - i + 1;
}
}
}
//字符串的切割
return maxlen;
}
}
最长回文子串II(求字符串)
- 普通版
//最长回文的字符串
public static boolean isHuiWen(String s) {
if(s == null ||s.length() == 0) {
return false;
}
int i = 0, j = s.length() - 1;
while(i < j) {
if(s.charAt(i) != s.charAt(j)) {
return false;
}
i++;
j--;
}
return true;
}
public static String func2(String s) {
// write code here
int n = s.length();
int max = 0, end = 0;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
if(isHuiWen(s.substring(i, j))) {
if(max < j - i) {
max = j - i;
end = j;
}
}
}
}
return s.substring(end - max, end);
}
- dp版
//dp版
class Solution {
public String longestPalindrome(String s) {
//定义一个表示字符长度
int len = s.length();
//如果字符小于2,直接返回
if(len < 2){
return s;
}
//定义一个表示回文字符数量的变量
int maxlen = 1;
//回文字串的开始索引
int begin = 0;
//定义一个存储所有可能的结果,一个二维数组
boolean[][] dp = new boolean[len][len];
//单个字符本身就是回文串
for(int i = 0; i < len; i++){
dp[i][i] = true;
}
//递归遍历,二维数组的对角线上方的所有元素
for(int j = 1; j < len; j++){
for(int i = 0; i < len - 1 && i < j; i++){
//如果两个字符相等,就说明不是回文串
if(s.charAt(i) != s.charAt(j)){
dp[i][j] = false;
}else{
//当是回文串时,字符个数小于等于3个,就是回文串
if(j - i < 3){
dp[i][j] = true;
}else{
//递归判断当边界两边的字符相等时,继续判断内层的字符是否相等
dp[i][j] = dp[i + 1][j - 1];
}
}
//对比所有的回文串,取出长度最大的,回文串的起始位置
if(dp[i][j] && j - i + 1 > maxlen){
maxlen = j - i + 1;
begin = i;
}
}
}
//字符串的切割
return s.substring(begin, begin + maxlen);
}
}
最长回文序列
public static int func3(String s) {
if(s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int[][] f = new int[n + 1][n + 1];
for(int i = 1; i <= n; i++) {
for(int j =1; j <= n; j++) {
if(s.charAt(i - 1) != s.charAt(n - j)) {
f[i][j] = Math.max(f[i - 1][j], f[i][j -1]);
}else {
f[i][j] = Math.max(f[i - 1][j - 1] + 1, f[i][j]);
}
}
}
return f[n][n];
}
最长括号子串
import java.util.*;
public class Solution {
public int longestValidParentheses (String s) {
// write code here
if (s == null || s.length() < 2) {
return 0;
}
int[] f = new int[s.length()];
if (s.charAt(0) == '(' && s.charAt(1) == ')') {
f[1] = 2;
}
int ret = Math.max(f[1], 0);
for (int i = 2; i < s.length(); i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
f[i] = 2 + f[i - 2];
} else {
int index = i - f[i - 1] - 1;
if (index >= 0 && s.charAt(index) == '(') {
f[i] = 2 + f[i - 1];
if (index - 1 >= 0) {
f[i] += f[index - 1];
}
}
}
}
ret = Math.max(ret, f[i]);
}
return ret;
}
}
编辑距离
题目连接:https://leetcode-cn.com/problems/edit-distance/
核心思路:
class Solution {
public int minDistance(String s1, String s2) {
int n = s1.length();
int m = s2.length();
int[][] f = new int[n + 1][m + 1];
for (int i = 0; i <= n; i++) f[i][0] = i;
for (int j = 0; j <= m; j++) f[0][j] = j;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
f[i][j] = Math.min(f[i - 1][j] + 1, f[i][j - 1] + 1);
if (s1.charAt(i - 1) == s2.charAt(j - 1)) f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
else f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
}
}
return f[n][m];
}
}
变态跳台阶
public class Solution {
public int jumpFloorII(int target) {
if(target < 2) {
return 1;
}
int[] arr = new int[target + 1];
arr[1] = 1;
for(int i = 2; i <= target; i++) {
arr[i] = 2 * arr[i - 1];
}
return arr[target];
}
}
矩阵覆盖
核心思路
递归实现
public class Solution {
public int rectCover(int target) {
if(target < 1) {
return 0;
}else if(target <= 2) {
return target;
}else {
return rectCover(target - 1) + rectCover(target - 2);
}
}
}
迭代实现
public class Solution {
public int rectCover(int target) {
if(target < 1) {
return 0;
}else if(target <= 2) {
return target;
}
int f1 = 1;
int f2 = 2;
int f3 = 0;
for(int i = 3; i <= target; i++){
//f3先更新
f3 = f1 + f2;
f1 = f2;
f2 = f3;
}
return f3;
}
}
动态规划实现
public class Solution {
public int rectCover(int target) {
if(target < 1) {
return 0;
}else if(target <= 2) {
return target;
}
int[] arr = new int[target + 1];
arr[0] = 1;
arr[1] = 1;
// int ret = 0;
for(int i = 2; i <= target; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr[target];
}
}
买卖股票的最佳时机I
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/submissions/
class Solution {
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0) {
return 0;
}
int ret = 0, min = prices[0];
for(int i = 1; i < prices.length; i++) {
if(min > prices[i]) {
min = prices[i];
}
ret = Math.max(ret, prices[i] - min);
}
return ret;
}
}
买卖股票的最佳时机II
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
class Solution {
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0) {
return 0;
}
int ret = 0;
for(int i = 1; i < prices.length; i++) {
if(prices[i] > prices[i - 1]) {
ret += prices[i] - prices[i - 1];
}
}
return ret;
}
}
兑换零钱(一)
import java.util.*;
public class Solution {
public int minMoney (int[] arr, int aim) {
// write code here
//dp[i] 换得金额i能用的最少硬币数
int[] dp = new int[aim + 1];
//后面要比较最小值 所以每个dp的初始值都是aim+1 , 考虑硬币额度全为1用aim枚能换aim额度 aim+1必然是越界值了
Arrays.fill(dp, aim + 1);
dp[0] = 0; //因为要给dp[1-1]做铺垫 所以dp[0]必须是0
for (int i = 1; i < aim + 1; i++) {
for (int j = 0; j < arr.length; j++) {
//别越界 && 至少能换出来才换 && 能换的话 看看我用这枚硬币好 还是不用好
// && 如果能用硬币你不用的话(或者压根换不出来) 那代价可是MAX值 逼着你尽可能换
if (i - arr[j] >= 0) {
dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
}
}
}
//要是流程走下来 dp值是非法值 说明换不出来
return dp[aim]==aim+1?-1:dp[aim];
}
}
打家劫舍I
https://leetcode-cn.com/problems/house-robber/
class Solution {
public int rob(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] f = new int[n + 1];
f[0] = 0;
f[1] = nums[0];
for(int i = 2; i <= n; i++) {
f[i] = Math.max(f[i - 1], f[i - 2] + nums[i - 1]);
}
return f[n];
}
}
打家劫舍II
https://leetcode-cn.com/problems/house-robber-ii/
class Solution {
public int rob(int[] nums) {
if(nums == null || nums.length == 0) {
return -1;
}
if(nums.length == 1){
return nums[0];
}
int[] dp1 = new int[nums.length];
int[] dp2 = new int[nums.length];
dp1[0] = 0;//不抢第一个
dp1[1] = nums[1];
dp2[dp1.length - 1] = 0;//不抢最后一个
dp2[dp1.length - 2] = nums[nums.length - 2];
for(int i = 2; i < nums.length; i++){
dp1[i] = Math.max(dp1[i - 2] + nums[i], dp1[i - 1]);
}
for(int i = dp2.length-3; i >= 0; i--){
dp2[i] = Math.max(dp2[i + 2] + nums[i], dp2[i + 1]);
}
return Math.max(dp2[0], dp1[dp1.length - 1]);
}
}
持续更新中。。。。。。。。