392 是一个easy题, 就是问 s 是否能由t 构成。 当然不能把 t 的 所有2^n个子串都拿出来,一一和s比较。 只需要two points就行了。
Example 1:
s = "abc"
, t = "ahbgdc"
这道题很简单,但写出的code 可能差别很大,看看我第一次提交的code 和最新的code 差别就知道。
这个题还有 follow up 的解法: 思路就是把T的每个字母当作key,字母所在的index加入list作为value,然后就利用二分搜索来找s中某个字母的下一个位置。
521 是目前遇到的leetcode 上最扯淡的题,但很有启发性,不要小看这个问题,让你思考两个string 最长的 Uncommon Subsequence
算法: 如果字符串一样,不存在,如果字符串不同,则长的那一个。
522 把两个字符串扩展成 N 个字符串
这是一个非常优秀的题目,真的非常喜欢,因为几个解法都很有启发性。
算法一: 纯粹暴力解 (暴力解),会TLE, 我竟然花了一个多小时去写了code , code 写的特别丑。
把每个字符串的subsequence 全部求出来, 复杂度是 2^n。 参考 78 subsets写一个backtracking 的算法。
得到 N 个 2^n 字符串, 然后两两进行比较,找出没有dupilicate 的最长的子串。复杂度竟然达到了 2^N * 2^N ,不超时才怪。
算法二: 优化暴力 算法 backTracking + hashMap(优化):
把得到的字符串全部存入 hashMap, hashMap 的value 存 Frequence, 如果 Frequence >1, 说明字符串重复, 所以在 Frequence ==1 的key 中找到 最长的那一个就行了.
code如下, 涉及遍历 hashmap ,给出了两个方法,希望记牢。
public int findLUSlength(String[] strs) { Map<String, Integer> map = new HashMap<>(); for(String str: strs){ getSubString(0, str,map, new StringBuilder()); } int ans = -1; /* for(String s: map.keySet()){ if(map.get(s) == 1){ ans = Math.max(ans, s.length()); } }*/ for(Map.Entry<String,Integer> entry: map.entrySet()){ if(entry.getValue() ==1) { ans = Math.max(ans,entry.getKey().length()); } } return ans; } void getSubString(int start, String str, Map<String,Integer> result, StringBuilder sb) { result.put(sb.toString(), result.getOrDefault(sb.toString(),0)+1); for(int i= start; i< str.length(); i++){ sb.append(str.charAt(i)); getSubString(i+1,str,result,sb); sb.setLength(sb.length()-1); } }
算法三:
通过观察分两种情况
1) 如果字符串全部不一样,那取最长的那一个。
2)如果 很多相同的, 例如 aabb, aabb, aa, ab, 那结果只能返回 -1了。
算法: 从上面观察出结论:answer 是 N个字符串某个字符串,这个字符串不是别人的subsequence, 这就用到391的算法了。
391 算法的复杂度是 len, len 是字符串的长度, 需要两两比较, 因此总的复杂度是 len*N^2. N是字符串的个数。
写code 时遇到一个坑: WA 了这组数据 ["a","b","c","d","e","f","a","b","c","d","e","f"]
把 "a " 和整个数组比较,一定要设置flag.发现 "a" 不是别人的 subSequence 时 才和max_len 进行比较。
算法的复杂度为 len *N2
算法四: 算法三的改进版:
先排序,按照长度从长到短排列, 从最长的开始找,当找到某个长度问L, 并且 只需要在同样长度L 字符串中比较 是否是某个的subsequence, 因为当 L1> L2 时, L1 一定不是L2的subsequence.
PS: 有时为了把循环里逻辑不要搞那么复杂,多循环几次没啥不好的。
比如最优化的循环写法:
for(int i=0; i<strs.length; i++){ String s = strs[i]; boolean flag = true; for(int j=0; j<strs.length; j++){ if(i!=j ){ if(s.length()> strs[j].length()) return s.length(); else if(isSubsequence(s, strs[j])) {flag = false; break;} } } if(flag) return s.length(); }
但其实没必要,判断那么充分,完整的code 清晰的写法:
//Arrays.sort(strs, (o1,o2)->(o2.length()-o1.length())); Arrays.sort(strs, new Comparator < String > () { public int compare(String s1, String s2) { return s2.length() - s1.length(); } }); for(int i=0; i<strs.length; i++){ String s = strs[i]; boolean flag = true; for(int j=0; j<strs.length; j++){ if(i==j) continue; if(isSubsequence(s, strs[j])) {flag = false; break;} } if(flag) return s.length(); } return -1; } boolean isSubsequence(String s, String t){ int index_s=0, index_t=0; while(index_s < s.length() && index_t < t.length()){ if(s.charAt(index_s) == t.charAt(index_t)) { index_s ++; } index_t++; } if(index_s == s.length()) return true; return false; }
还有一个问题百思不得其解:为何排序的简略写法 效率会很低呢? 第一个一行排序竟然需要32ms, 而第二个才1ms, 差别在哪?
//Arrays.sort(strs, (o1,o2)->(o2.length()-o1.length())); Arrays.sort(strs, new Comparator < String > () { public int compare(String s1, String s2) { return s2.length() - s1.length(); } });
524 就是从字典里找出 是 给出字符串s 的subsequence , 完全用到392写法,只是需要排序。
排序要求: 按照字符串长度从长到短,相同长度下 按照 字典序排列。
public String findLongestWord(String s, List<String> d) { if(d == null || s ==null ) return ""; Collections.sort(d,(o1,o2)->o2.length()==o1.length()? o1.compareTo(o2) : o2.length()-o1.length()); // for(String str: d) System.out.println(str); for(String t: d){ if(isSubsequence(s,t)) return t; } return ""; } boolean isSubsequence(String s, String t) { int index_t=0; int index_s=0; while(index_s <s.length() && index_t <t.length() ){ if(s.charAt(index_s) == t.charAt(index_t) ) index_t ++; index_s++; } if(index_t == t.length()) return true; return false; }