子序列
392. 判断子序列 - 力扣(LeetCode)
方法一:自己想的用的非常辣鸡的栈的方法(shi)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public boolean isSubsequence(String s, String t) { Stack<Character> stack1 = new Stack<>(); Stack<Character> stack2 = new Stack<>(); for (char c1 : s.toCharArray()) stack1.push(c1); for (char c2 : t.toCharArray()) stack2.push(c2); while (!stack2.isEmpty() && !stack1.isEmpty()) { if (stack2.peek() == stack1.peek()) { stack1.pop(); } stack2.pop(); } return stack1.isEmpty(); } }
|
方法二:双指针
给人的感觉就是这个方法跟上面我想的差不了多少,但是呢,我没有想到i == n这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public boolean isSubsequence(String s, String t) { int n = s.length(), m = t.length(); int i = 0, j = 0; while(i < n && j < m){ if(s.charAt(i) == t.charAt(j)){ i++; } j++; } return i == n; } }
|
方法三:动态规划
这个方法真是顶级
最后,是将26列均置为m而不是简单地把m列均置为m,因为这个今天已经错了好多次了
f[i][j]表示从字符i位置开始向后f[i][j]个位置字符j第一次出现的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import java.util.Arrays;
class Solution { public boolean isSubsequence(String s, String dictiobary) { int n = s.length(), m = dictiobary.length(); int[][] f = new int[m + 1][26]; Arrays.fill(f[m], m); for (int i = m - 1; i >= 0; i--) { for (int j = 0; j < 26; j++) { if (dictiobary.charAt(i) - 'a' == j) f[i][j] = i; else f[i][j] = f[i + 1][j]; } } int add = 0; for (int i = 0; i < n; i++) { if (f[add][s.charAt(i) - 'a'] == m) return false; add = f[add][s.charAt(i) - 'a'] + 1; } return true; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public boolean isSubsequence(String s, String dictionary) { int m = s.length(), n = dictionary.length(); if (m == 0)return true; if (m > n) return false; int[][] f = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (s.charAt(i - 1) == dictionary.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[i][j] == m) return true; } } return false; } }
|
524. 通过删除字母匹配到字典里最长单词 - 力扣(LeetCode)
方法一:双指针
刚开始看到答案的时候理解不了t.compareTo(res) < 0这一句到底是干什么的
- 经过一节课的沉淀之后理解了
(t.length() == res.length() && t.compareTo(res) < 0当字典中的两个单词长度一致时候,t.compareTo(res)可以比较二者的字典序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public String findLongestWord(String s, List<String> dictionary) { String res = ""; for (String t : dictionary) { int i = 0, j = 0; while (i < t.length() && j < s.length()) { if (t.charAt(i) == s.charAt(j)) ++i; ++j; } if (i == t.length()) { if (t.length() > res.length() || (t.length() == res.length() && t.compareTo(res) < 0)) { res = t; } } } return res; } }
|
方法二:排序(方法一的基础)
有一说一,这Lambda表达式真难写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public String findLongestWord(String s, List<String> dictionary) { Collections.sort(dictionary,(a, b) ->{ if (a.length() != b.length()) return b.length() - a.length(); return a.compareTo(b); }); int n = s.length(); for (String ss : dictionary){ int m = ss.length(); int i = 0, j = 0; while (i < n && j < m){ if (s.charAt(i) == ss.charAt(j)) j++; i++; } if (j == m) return ss; } return ""; } }
|
展开来写就是这样
1 2 3 4 5 6
| Collections.sort(dictionary, new Comparator<String>() { public int compare(String o1, String o2) { if (o1.length() != o2.length()) return o2.length() - o1.length(); else return o1.compareTo(o2); } });
|
方法三:动态规划写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { public String findLongestWord(String s, List<String> dictionary) { int m = s.length(); int[][] f = new int[m + 1][26]; for (int i = 0; i < 26; i++) f[m][i] = m; for (int i = m - 1; i >= 0; i--) { for (int j = 0; j < 26; j++) { if (s.charAt(i) - 'a' == j) f[i][j] = i; else f[i][j] = f[i + 1][j]; } } String ret = ""; for (String ss : dictionary) { boolean flag = true; int len = ss.length(); int add = 0; for (int i = 0; i < len; i++) { if (f[add][ss.charAt(i) - 'a'] == m) { flag = false; break; } add = f[add][ss.charAt(i) - 'a'] + 1; } if (flag) { if (ret.length() < ss.length() || (ret.length() == ss.length() && ss.compareTo(ret) < 0)) { ret = ss; } } } return ret; } }
|
522. 最长特殊序列 II - 力扣(LeetCode)
方法一:枚举法
我陷入了一个误区,就是这个is_Match函数的这两个参数,它的次序很重要,在findLUSlength的第二个for循环中,如果两个不同的字符串后面有一个字符串完全可以匹配当前(strs[i]字符串)字符串,就可以完全跳过当前(strs[i]字符串)去寻找下一个目标了,因为我你strs[i]字符串所拥有的字符我strs[j]全部都具有,strs[j]位置靠后,具有一定的绝对主动权(感觉这个应该也算是一种贪心吧)。(理解到位)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public int findLUSlength(String[] strs) { int n = strs.length; int ret = -1; for (int i = 0; i < n; i++) { boolean flag = true; for (int j = 0; j < n; j++) { if (i != j && is_Match(strs[i], strs[j])){ flag = false; break; } } if (flag){ ret = Math.max(ret, strs[i].length()); } } return ret; }
public boolean is_Match(String s, String dictionary){ int m = s.length(), n = dictionary.length(); int i = 0, j = 0; while (i < m && j < n){ if (s.charAt(i) == dictionary.charAt(j)) i++; j++; } return i == s.length(); }
}
|
方法二:DP
这里需要最长公共子序列的DP基础,没学过,呜呜呜~~~,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public int findLUSlength(String[] strs) { int n = strs.length, ans = -1; for (int i = 0; i < n; i++) { boolean flag = true; for (int j = 0; j < n; j++) { if (i != j && check(strs[i], strs[j])){ flag = false; break; } } if (flag) ans = Math.max(ans, strs[i].length()); } return ans; } boolean check(String s, String d){ int len1 = s.length(), len2 = d.length(); if (len1 > len2) return false; int[][] f = new int[len1 + 1][len2 + 1]; for (int i = 1; i <= len1; i++) { for (int j = 1; j <= len2; j++) { if (s.charAt(i - 1) == d.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[i][j] == len1) return true; } } return false; } }
|
1143. 最长公共子序列 - 力扣(LeetCode)
定义f[i][j]表示:s1[0 : i] 和s2[0 : j]的最长公共子序列的长度
- 上述表示种,
s1[0 : i]表示s1长度为i的前缀,s2[0 : j]表示s2长度为j的前缀,
考虑动态规划的边界情况:
- 当 i = 0时候,
s1[0 : i]为空,空字符串和任何字符串的最长公共子序列长度均为0,因此对于任意0 <= j <= m ,都有f[0][j] = 0
- 当 j = 0时候,
s2[0 : j]为空,空字符串和任何字符串的最长公共子序列长度均为0,因此对于任意0 <= i <= m ,都有f[i][0] = 0
因此动态规划的边界情况是:当i或者j等于0的时候f[i][j] = 0。
当 i > 0 且 j > 0 的时候,,考虑f[i][j]的计算:
- 当
s1[i - 1] = s2[j - 1]时,将这两个相同的字符串称为公共字符,考虑 s1[0 : i - 1] 和 s2[0 : j - 1] 的最长公共子序列,再增加一个字符(公共字符)即可得到s1[0 : i] 和s2[0 : j]的最长公共子序列因此 f[i][j] = f[i - 1][j - 1] + 1
- 当
s1[i - 1] != s2[j - 1]时,考虑s1[0 : i] 和 s2[0 : j - 1] 的最长公共子序列和s1[0 : i - 1] 和 s2[0 : j] 的最长公共子序列。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public int longestCommonSubsequence(String s1, String s2) { int m = s1.length(), n = s2.length(); int[][] f = 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)) f[i][j] = f[i - 1][j - 1] + 1; else f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]); } } return f[m][n]; } }
|