目录
题目1:最长递增子序列
题目2:最长公共子序列
思路:
如果是用动态规划的话,我们就要先清楚dp[i]表示啥,里面的i表示啥。首先这道题的 i 表示给的数组nums的各个元素的下标。dp[i]表示从数组头到nums[i]这段序列的最长递增子序列的元素个数。
得到所有nums[i]的dp[i]后,最后取这些dp[i]的最大值就是我们的最长递增子序列的元素个数。
所以我们的目标就是去求每个nums[i]的dp[i]值。
怎么去求dp[i]?就要我们用到动态规划的思路。
dp[i]怎么用更小的子问题去表示呢?我们用j去遍历比i小的所有元素,如果这个元素即nums[ j1 ]小于nums[i]这个元素,说明nums[i]可以加入到dp[ j1 ]这个序列,加入后,①dp[i]=dp[ j1 ]+1;在遍历的时候,肯定会不止一个元素小于nums[i],记作nums[ j2 ],计算②dp[i]=dp[ j2 ]+1;我们看①②哪个得到的dp[i]大,即我们最后保留的dp[i]值。
代码:
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp=new int[nums.length];
Arrays.fill(dp,1);
for(int i=0;inums[j]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
}
int res=0;
for(int i=0;ires){
res=dp[i];
}
}
return res;
}
}
思路: dp[i]表示 数组头到下标为i的数组元素这一段数组序列的最大连续子数组的值,dp的思想就是用更小规模的问题去表示原问题。
所以我们就会想到dp[i]=dp[i-1]+nums[i]。因为要考虑到是要最大的,所以我们计算dp[i]时,如果加后的值比加的这个元素本身还小,那还不如不加。所以 dp[i]=max(dp[i-1]+nums[i],nums[i])。
最后取这些元素对应的dp[i]最大值即可。
代码:
class Solution {
public int maxSubArray(int[] nums) {
int[] dp=new int[nums.length];
dp[0]=nums[0];
for(int i=1;ires){
res=dp[i];
}
}
return res;
}
}
题目1.2:674. 最长连续递增序列
这道题简单,直接上代码:
class Solution {
public int findLengthOfLCIS(int[] nums) {
int[] dp=new int[nums.length+1];
dp[0]=1;
for(int i=1;inums[i-1]){
dp[i]=dp[i-1]+1;
}
else{
dp[i]=1;
}
}
int res=0;
for(int i=0;ires){
res=dp[i];
}
}
return res;
}
}
思路:
我们拿
text1 = "abcde", text2 = "ace"举例:
我们定义dp[i][j],i表示指向text1字符串的字符下标。j表示指向text2字符串的字符下标。
dp[i][j]表示字符串①和②最长公共子序列的元素个数。
那我们现在要怎么表示这个dp[i][j]的值呢?我们肯定是要用更小的规模去表示,即dp[i-1][j-1],dp[i-1][j],dp[i][j-1](就是更小规模的两个字符串序列)等来表示。
但是i,j 所指的这个字符会有两种情况,一种是这两个字符相同:
这个时候dp[i][j]就等于dp[i-1][j-1]+1。(按照情境来解释就是①②两个更小规模的字符串的最长公共子序列的元素个数+我们现在扫描到的相同元素,就是我们要求的原问题。)
一种是这两个字符不相同:
这个时候dp[i][j]=max(dp[i-1][j],dp[i][j-1])。 (按照情境来解释就是dp[i][j]可以用紫色框的两个更小规模的字符串的最大公共子序列来表示or可以用红色框的两个更小规模的字符串的最大公共子序列来表示)
按上面的方法分析,就可以依次画出每个dp[i][j]的值:
代码:
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp=new int[text1.length()+1][text2.length()+1];
for(int i=1;i<=text1.length();i++){
char char1=text1.charAt(i-1);
for(int j=1;j<=text2.length();j++){
char char2=text2.charAt(j-1);
if(char1==char2){
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[text1.length()][text2.length()];
}
}
思路:因为要满足每条线不相交,可以理解为每个相等的数的相对位置不变,所以相当于就是问最长公共不连续序列的元素个数。
代码(与上一道题目一样):
class Solution {
public int maxUncrossedLines(int[] nums1, int[] nums2) {
int[][] dp=new int[nums1.length+1][nums2.length+1];
for(int i=1;i<=nums1.length;i++){
for(int j=1;j<=nums2.length;j++){
if(nums1[i-1]==nums2[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[nums1.length][nums2.length];
}
}
思路:也是一样按照上面的题去想,首先先确定dp[i][j]是指在前i个nums1元素和前j个nums2元素里最长公共子数组的元素个数。
所以当i所指的元素与j所指的元素相同时,dp[i][j]=dp[i-1][j-1]+1.
而如果当i所指的元素与j所指的元素不相同,则不作操作。
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int[][] dp=new int[nums1.length+1][nums2.length+1];
int res=0;
for(int i=1;i<=nums1.length;i++){
for(int j=1;j<=nums2.length;j++){
if(nums1[i-1]==nums2[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
res=Math.max(dp[i][j],res);//每次都保留最大的
}
}
}
return res;
}
}