# LeetCode题解——动态规划（三）

### 300. 最长上升子序列

#### 动态规划

class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if (nums == null || n == 0) {
return 0;
}
int[] dp = new int[n];
for (int i = 0; i < n; ++i) {
int count = 1;
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
count = Math.max(count, dp[j] + 1);
}
}
dp[i] = count;
}
int maxLength = 0;
for (int i = 0; i < n; ++i) {
maxLength = Math.max(maxLength, dp[i]);
}
return maxLength;
}
}


#### 二分查找

tails      len      num
[]         0        4
[4]        1        3
[3]        1        6
[3,6]      2        5
[3,5]      2        null


class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if (nums == null || n == 0) {
return 0;
}
int[] tails = new int[n];
int maxLength = 0;
for (int num : nums) {
int index = binarySearch(tails, maxLength, num);
tails[index] = num;
if (index == maxLength) {
maxLength++;
}
}
return maxLength;
}
private int binarySearch(int[] tails, int len, int key) {
int left = 0, right = len;
while (left < right) {
int mid = left + (right - left) / 2;
if (tails[mid] == key) {
return mid;
} else if (tails[mid] > key) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}


### 646. 最长数对链

#### 动态规划

class Solution {
public int findLongestChain(int[][] pairs) {
if (pairs == null || pairs.length == 0) {
return 0;
}
Arrays.sort(pairs, (a, b) -> (a[0] - b[0]));
int n = pairs.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (pairs[j][1] < pairs[i][0]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int result = 0;
for (int d : dp) {
result = Math.max(d, result);
}
return result;
}
}


### 376. 摆动序列

#### 动态规划

class Solution {
public int wiggleMaxLength(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int up = 1, down = 1;
for (int i = 1; i < n; ++i) {
if (nums[i] > nums[i - 1]) {
up = down + 1;
} else if (nums[i] < nums[i - 1]) {
down = up + 1;
}
}
return Math.max(up, down);
}
}


### 1143. 最长公共子序列

示例 1:

1 <= text1.length <= 1000
1 <= text2.length <= 1000



#### 动态规划

class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length(), n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; ++j) {
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
}


### 416. 分割等和子集

#### 动态规划

class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
int n = nums.length;
for (int num : nums) {
sum += num;
}
if (sum % 2 == 1) {
return false;
}
int target = sum / 2;
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for (int num : nums) {
for (int i = target; i >= num; i--) {
if (dp[target] == true) {
return true;
}
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
}
}


### 494. 目标和

示例 1:

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3


#### 动态规划

class Solution {
public int findTargetSumWays(int[] nums, int S) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum < S || (sum + S) % 2 == 1) {
return 0;
}
int target = (sum + S) / 2;
int[] dp = new int[target + 1];
dp[0] = 1;
for (int num : nums) {
for (int i = target; i >= num; i --) {
dp[i] = dp[i] + dp[i - num];
}
}
return dp[target];
}
}


03-25 128
02-06 82
04-03 161
03-04 257
02-18 109
07-13 910
01-14 112
09-15 412
05-25 376
10-18 94
06-12 48