1. Longest Substring Without Repeating Characters
思路:需要 hashmap 辅助保存各个字符的位置,且随时更新最新位置
若第 i 个位置的字符 c 出现过,则 dp[i] = min(map.get(c)-i,dp[i+1]+1)
若没出现则 dp[i] = dp[i+1] + 1;
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
Map<Character, Integer> m = new HashMap<Character, Integer>();
int[] dp = new int[s.length()];
dp[s.length() - 1] = 1;
int max = 1; // 初始化dp 数组 与 返回值
m.put(s.charAt(s.length() - 1), s.length() - 1); // 初始化 map
for (int i = s.length() - 2; i >= 0; i--) {
if (m.containsKey(s.charAt(i)))
// 这里要取比较小的一个,避免出现 abbbba 这种情况,虽然间隔大,但是中间都是重复的
dp[i] = Math.min(m.get(s.charAt(i)) - i, dp[i+1]+1);
else
dp[i] = dp[i + 1] + 1;
max = max > dp[i] ? max : dp[i];
m.put(s.charAt(i), i); // 更新位置
}
return max;
}
2. Longest Valid Parentheses
For "(()", the longest valid parentheses substring is "()", which has length = 2.
Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.
题目大意:找到最长的合法括号序列 ,两种形式的 "()()" 与 "((()))" 都是合法的。
思路: 若 i == ')' 设置 dp[i] = 0 即可;
若 i == '(' ,不仅考虑 r = i+1 ; s[r]=')' 然后加上 dp[r+1]. 因为还有 "(())" 这种情况
应该考虑 r = i + dp[i+1] + 1; 然后在考虑 dp[r+1] ;这样会考虑到 "(())" 这种情况
public int longestValidParentheses(String s) {
if (s == null || s.length() < 2) return 0;
int max = 0; // 弄个最大值
int []dp = new int[s.length()];
dp[s.length() - 1] =0;
for(int i = s.length() - 2 ; i >= 0 ; -- i){
if(s.charAt(i) == '('){
int ri = i + dp[i+1] + 1;
if(ri < s.length() && s.charAt(ri) == ')'){
dp[i] = dp[ri] + dp[i+1] + 2;
if(ri + 1 < s.length()-1) dp[i] += dp[ri+ 1];
}
//else dp[i] ==0 可以省略,因为本来就 = 0
}
max = max > dp[i] ? max : dp[i];
}
return max;
}
3. 最长公共子串(Longest Common Substirng)
子串是串的一个连续的部分。
4. 最长公共子序列(Longest Common Sequence)
而从序列中去掉任意的元素而获得新的序列,最长子序列则可以不必连续。
//求 最长子序列的长度
public static void LongestCommonSequence(String s1 , String s2){
int m = s1.length();
int n = s2.length();
if(m == 0 || n == 0) return;
int dp[][] = new int[m+1][n+1];
//构建
for(int i = 1 ; i <= m; i ++){
for(int j = 1; j <= n; j ++){
if(s1.charAt(i-1)== s2.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]);
}
}
//查找
String LCS = ""; int i = m,j = n;
while (i >= 1 && j >= 1) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
char c = s1.charAt(i - 1);
LCS = c + LCS;
i--;
j--;
} else if (dp[i][j - 1] > dp[i - 1][j]) {
j--;
} else {
i--;
}
}
System.out.println(LCS);// 打印
}
//类似于 LCS 的动态规划 public boolean isInterleave(String s1, String s2, String s3) { int m = s1.length(),n = s2.length(); if(m + n != s3.length()) return false; //横向放 s1 ,纵向放 s2 boolean dp[][] = new boolean [m+1][n+1]; dp[0][0] = true; // 把左上角元素置 true ,因为有 S1=""、 S2="" 、S3="" 的情况 for(int i = 1 ; i < dp.length; i ++){ if(s1.charAt(i-1) == s3.charAt(i-1)) dp[i][0] = true; else break; } for(int j = 1 ; j < dp[0].length; j ++){ if(s2.charAt(j-1) == s3.charAt(j-1)) dp[0][j] = true; else break; } for(int i = 0 ; i < m ; i ++){ for(int j = 0 ; j < n ; j ++){ if(s2.charAt(j) == s3.charAt(i+j+1) && dp[i+1][j] == true){dp[i+1][j+1] = true;} if(s1.charAt(i) == s3.charAt(i+j+1) && dp[i][j+1] == true){dp[i+1][j+1] = true;} } } return dp[m][n] == true ; }
6. Maximum Subarray (leetcode)
找到和最大的连续子序列,比如对于序列 [−2,1,−3,4,−1,2,1,−5,4],和最大的连续子序列为[4,−1,2,1] ,和的最大值= 6.
public int maxSubArray(int[] nums) { if(nums == null || nums.length == 0) return 0; int dp[] = new int[nums.length];// 动态规划数组 dp[dp.length-1] = nums[nums.length - 1]; int ret = nums[nums.length - 1];// 待返回结果 for(int i = nums.length - 2; i >= 0 ; i --){ if(nums[i] + dp[i+1] <= nums[i]){ dp[i] = nums[i]; }else{ dp[i] = dp[i+1] + nums[i]; } ret = Math.max(dp[i],ret); } return ret; }