Tags: Hash Table
3. Longest Substring Without Repeating Characters:https://leetcode.com/problems/longest-substring-without-repeating-characters/
没有重复字符的最长子字符串:<Hash Table><Two Pointers>
解法: (使用HashMap保存字符key为字符, value为位置, 并且保持更新; 因为遇到重复字符后, 前面的最大长度就已经保存到max中了, 所以可以更换字符的的位置了; 利用两个指针i和j, i用于遍历, j指向不含重复字符的subString的首位, 当i遍历到重复字符containsKey时, 就比较map里的重复字符的后一位与当前j位置, 取最大值作为j的位置; max记录最大长度, 比较max和(i-j+1); )
(示例:adbccba 首先i和j都指向a, 然后i遍历到c时,此时max=4, map里有四个键值对(i=3,j=0); 然后i指向第2个c, 已经contain了, 所以j的位置指向重复元素的后一位, 即相当于新subString的第一位(i=4,j=4); i=5,比较j的位置和b后的位置,保留j;比较max与i-j+1; put覆盖重复字符;)
(1.map,max; 2.for(i,j,s.length()); 3.if(csKey(s.charAt(i))) j=max(j,get(s.cAt())+1); 4.put(At,i),max=(max,i-j+1); 5.return max;)
1 public class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 HashMap<Character, Integer> map = new HashMap<>(); 4 int max = 0; 5 for (int i = 0, j = 0; i < s.length(); i++) { 6 if (map.containsKey(s.charAt(i))) 7 j = Math.max(j, map.get(s.charAt(i)) + 1); 8 map.put(s.charAt(i),i); 9 max = Math.max(max, i - j + 1); 10 } 11 return max; 12 } 13 }
49. Group Anagrams: https://leetcode.com/problems/anagrams/
含有相同字母的字符串分为一组:<HashMap>
解法:(HashMap<String,List<String>>, 遍历数组str, 将字符串转为字符数组, 排序字符数组, 获取字符数组的值keyStr; 如果不含keyStr, 那么put; add对应字符串str)
(用到的method: 1.containsKey(); 2.str.toCharArray()--将字符串转为字符数组; 3.String.valueOf(ch)--将字符数组转为字符串; 4.map.values()--获取所有map值)
(1.if; 2.<Str, List<Str>>map; 3.for(str)char[] ch, sort, keyStr, if(!csKey)put, get.add; 4.return new A<<>>(values());)
1 public class Solution { 2 public List<List<String>> groupAnagrams(String[] strs) { 3 if (strs == null || strs.length == 0) return new ArrayList<List<String>>(); 4 Map<String, List<String>> map = new HashMap<>(); 5 for (String str : strs) { 6 char[] ch = str.toCharArray(); 7 Arrays.sort(ch); 8 String keyStr = String.valueOf(ch); 9 if (!map.containsKey(keyStr)) map.put(keyStr, new ArrayList<String>()); 10 map.get(keyStr).add(str); 11 } 12 return new ArrayList<List<String>>(map.values()); 13 } 14 }
94. Binary Tree Inorder Traversal: https://leetcode.com/problems/binary-tree-inorder-traversal/
二叉树的中序遍历: (todo)
136. Single Number: https://leetcode.com/problems/single-number/
数组中只有一个数出现一次, 其他都出现两次, 获取Single Number:
我的解法:(HashMap, !containsKey时,put<nums[i],1>; 否则remove; 所以遍历后map里只剩下一个对<tar, 1>; 利用遍历keySet(), rst=num; return rst)
1 public class Solution { 2 public int singleNumber(int[] nums) { 3 HashMap<Integer,Integer> map = new HashMap<>(); 4 for (int i = 0; i < nums.length; i++) { 5 if (!map.containsKey(nums[i])) map.put(nums[i],1); 6 else map.remove(nums[i]); 7 } 8 int rst = 0; 9 for (int num : map.keySet()) { 10 rst = num; 11 } 12 return rst; 13 } 14 }
解法2:<Bit>(XOR--异或,符号是^;1. 0 XOR A = A; 2. A XOR A = 0; 3.XOR可以交换; )(discuss里都是bit解法的……不知道题目还用hashmap标签干啥- -!!)
(1.rst; 2.for()rst^=[i]; 3.return)
1 public class Solution { 2 public int singleNumber(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int rst = 0; 7 for (int i = 0; i < nums.length; i++) { 8 rst ^= nums[i]; 9 } 10 return rst; 11 } 12 }
解法3:<HashSet>(利用set的不可重复, !add则remove; 最后set里只剩下target; 用set方法iterator的属性next()获取set的值;)
1 public int singleNumber(int[] A) { 2 3 Set<Integer> s = new HashSet<Integer>(); 4 for (int i: A){ 5 if(!s.add(i)){ 6 s.remove(i); 7 } 8 } 9 return s.iterator().next(); 10 11 }
202. Happy Number:https://leetcode.com/problems/happy-number/
各个数平方和相加最终结果为1的数:
我的解法:(虽然AC了速度还挺快,但是无限循环部分有问题,用了20次循环作为最大值; i%10--一个数的个位; i=i/10来递归扫描)
1 public class Solution { 2 public boolean isHappy(int n) { 3 if (n == 0) return false; 4 int rst = helper(n); 5 for (int i = 0; i <= 20; i++) { 6 rst = helper(rst); 7 if (rst == 1) return true; 8 } 9 return false; 10 } 11 public int helper(int n) { 12 int rst = 0; 13 while (n != 0) { 14 rst += (n % 10) * (n % 10); 15 n /= 10; 16 } 17 return rst; 18 } 19 }
解法1: <HashSet> (将每次的rst存在set里, 如果!rst=1, return true; 如果不能add了, 说明已经进入endless loop; 基于事实:no-happy number最后都会进入循环)
(1.set,rst; 2.while(add)if(=)true, helper(rst); 3.helper() rst,while(!0),rst+=^2,n/=10;)
1 public class Solution { 2 public boolean isHappy(int n) { 3 HashSet<Integer> set = new HashSet<>(); 4 int rst = helper(n); 5 while (set.add(rst)) { 6 if (rst == 1) return true; 7 rst = helper(rst); 8 } 9 return false; 10 } 11 public int helper(int n) { 12 int rst = 0; 13 while (n != 0) { 14 rst += (n % 10) * (n % 10); 15 n /= 10; 16 } 17 return rst; 18 } 19 }
1 public class Solution { 2 private int getNextHappy(int n) { 3 int sum = 0; 4 while (n != 0) { 5 sum += (n % 10) * (n % 10); 6 n /= 10; 7 } 8 return sum; 9 } 10 11 public boolean isHappy(int n) { 12 HashSet<Integer> hash = new HashSet<Integer>(); 13 while (n != 1) { 14 if (hash.contains(n)) { 15 return false; 16 } 17 hash.add(n); 18 n = getNextHappy(n); 19 } 20 return true; 21 } 22 }
1 public boolean isHappy(int n) { 2 Set<Integer> inLoop = new HashSet<Integer>(); 3 int squareSum,remain; 4 while (inLoop.add(n)) { 5 squareSum = 0; 6 while (n > 0) { 7 remain = n%10; 8 squareSum += remain*remain; 9 n /= 10; 10 } 11 if (squareSum == 1) 12 return true; 13 else 14 n = squareSum; 15 16 } 17 return false; 18 19 }
205. Isomorphic Strings: https://leetcode.com/problems/isomorphic-strings/
同构字符串:
我的解法:<HashMap>(s记为key, t记作value; 遍历s.length(), 如果!containsKey, 那么判断是否containsValue--false, 否则put; else get(s.charAt)!=(t)那么false)(注意要不要漏了不包含key但是已经包含了value的情况;示例"abca""defg"--key同value不同; "ab""aa"--key不同但是还要判断value,如果value已经contain 那么false)
(1.map; 2.for(s.length()) 3.if(!key) if(value)-false,put; 4.esle if(get !=) false;)
1 public class Solution { 2 public boolean isIsomorphic(String s, String t) { 3 HashMap<Character, Character> map = new HashMap<>(); 4 for (int i = 0; i <s.length(); i++) { 5 if (!map.containsKey(s.charAt(i))) { 6 if (map.containsValue(t.charAt(i))) return false; 7 map.put(s.charAt(i), t.charAt(i)); 8 } 9 else 10 if (map.get(s.charAt(i)) != t.charAt(i)) return false; 11 } 12 return true; 13 } 14 }
242. Valid Anagram: https://leetcode.com/problems/valid-anagram/
判断是否由相同字母组成:
我的解法: <sort>(将字符排序, 遍历字符数组, 有不同的则false; 用到method: char[] cs = s.toCharArray();)
(1.if; 2.cs,ct,sort; 3.for()!=-false; 4.true)
1 public class Solution { 2 public boolean isAnagram(String s, String t) { 3 if (s.length() != t.length()) return false; 4 char[] cs = s.toCharArray(); 5 char[] ct = t.toCharArray(); 6 Arrays.sort(cs); 7 Arrays.sort(ct); 8 for (int i = 0; i < cs.length; i++) 9 if (cs[i] != ct[i]) return false; 10 return true; 11 } 12 }
类似的:(用了Arrays.equals(char1,char2))
1 public class Solution { 2 public boolean isAnagram(String s, String t) 3 { 4 char[] sChar = s.toCharArray(); 5 char[] tChar = t.toCharArray(); 6 7 Arrays.sort(sChar); 8 Arrays.sort(tChar); 9 10 return Arrays.equals(sChar, tChar); 11 }
解法2: (创建26的数组; 首先判断长度; s包含某个字母则对应位置s.charAt[i]-'a'增一, t包含则减一; 最后遍历数组,!0则false;)
(1.if,tmp; 2.for()[s-'a']++,[t-'a']--; 3.for()!=false; 4.true)
1 public class Solution { 2 public boolean isAnagram(String s, String t) { 3 if (s.length() != t.length()) return false; 4 int[] tmp = new int[26]; 5 for (int i = 0; i < s.length(); i++) { 6 tmp[s.charAt(i) - 'a']++; 7 tmp[t.charAt(i) - 'a']--; 8 } 9 for (int i = 0; i < 26; i++) { 10 if (tmp[i] != 0) return false; 11 } 12 return true; 13 } 14 }
290. Word Pattern:https://leetcode.com/problems/word-pattern/
字符模版和字符串的匹配:(pattern = "abba", str = "dog cat cat dog" should return true.)
我的解法: (和205解法相同, 注意判断字符串内容是否相同: str1.equals(str2), 字符串按空格分隔: str.split(" ");)
(1.s-split,map,if; 2.for(),if(!key),if(value)-false,put; 3.else if(!equals)-false; 4.true)
1 public class Solution { 2 public boolean wordPattern(String pattern, String str) { 3 String[] s = str.split(" "); 4 Map<Character, String> map = new HashMap<>(); 5 if (pattern.length() != s.length) return false; 6 for (int i = 0; i < pattern.length(); i++) { 7 if (!map.containsKey(pattern.charAt(i))) { 8 if (map.containsValue(s[i])) return false; 9 map.put(pattern.charAt(i), s[i]); 10 } else { 11 if (!map.get(pattern.charAt(i)).equals(s[i])) return false; 12 } 13 } 14 return true; 15 } 16 }
349. Intersection of Two Arrays:https://leetcode.com/problems/intersection-of-two-arrays/
找出两个数组交叉部分(原数组含重复,结果不含重复):
解法1:<HashSet>(第一个set保存a中的数据, 第二个set保存结果; 遍历2,如果set含num2[i]而rstSet不含,那么add; 最后遍历rstSet,把数据复制到数组中)
(1.if,set,for()add; 2.rstSet,for,if(&&)add; 3.rst-[size()],index,for(),[++]; 4.return;)
1 public class Solution { 2 public int[] intersection(int[] nums1, int[] nums2) { 3 if (nums1 == null || nums2 == null) return null; 4 HashSet<Integer> set = new HashSet<>(); 5 for (int num : nums1) { 6 set.add(num); 7 } 8 HashSet<Integer> rstSet = new HashSet<>(); 9 for (int num : nums2) { 10 if (set.contains(num) && !rstSet.contains(num)) { 11 rstSet.add(num); 12 } 13 } 14 int[] rst = new int[rstSet.size()]; 15 int index = 0; 16 for (Integer num : rstSet) { 17 rst[index++] = num; 18 } 19 return rst; 20 } 21 }
350. Intersection of Two Arrays II: https://leetcode.com/problems/intersection-of-two-arrays-ii/
找出两个数组交叉部分(原数组含重复,结果含重复):
解法:<HashMap>(将数组1保存到map里并用value计数; 创建ArrayList, 遍历2, 如果containsKey并且value>0; 那么add, 并且value-1; 最后遍历list,复制到数组中)
(1.if,map; 2.for()if()put,else(get+1); 3.list,for(),if(&&>0)add,get-1; 4.rst,index,for(),[++]; 5.return;)
1 public class Solution { 2 public int[] intersect(int[] nums1, int[] nums2) { 3 if (nums1 == null || nums2 == null) return null; 4 HashMap<Integer, Integer> map = new HashMap<>(); 5 for (int i = 0; i < nums1.length; i++) { 6 if (!map.containsKey(nums1[i])) 7 map.put(nums1[i], 1); 8 else 9 map.replace(nums1[i], map.get(nums1[i]) + 1); 10 } 11 List<Integer> list = new ArrayList<>(); 12 for (int i = 0; i < nums2.length; i++) { 13 if (map.containsKey(nums2[i]) && map.get(nums2[i]) > 0){ 14 list.add(nums2[i]); 15 map.replace(nums2[i], map.get(nums2[i]) - 1); 16 } 17 } 18 int[] rst = new int[list.size()]; 19 int index = 0; 20 for (Integer num : list) { 21 rst[index++] = num; 22 } 23 return rst; 24 } 25 }
389. Find the Difference: https://leetcode.com/problems/find-the-difference/
找出字符串二比字符串一多的一个字符(含重复):
我的解法: <HashMap>(字符串1保存到map里并用value计数; 遍历2: 如果不含key或者含key但是value<=0, 那么就是tar; 否则value-1)
(1.map,for(),if(!)put,else-replace; 2.rst,for(),if(!||(contains&&<=0))rst, else-replace(-1); 3.return)
1 public class Solution { 2 public char findTheDifference(String s, String t) { 3 Map<Character, Integer> map = new HashMap<>(); 4 for (int i = 0; i < s.length(); i++) { 5 if (!map.containsKey(s.charAt(i))) 6 map.put(s.charAt(i), 1); 7 else 8 map.replace(s.charAt(i), map.get(s.charAt(i)) + 1); 9 } 10 char rst = ' '; 11 for (int i = 0; i < t.length(); i++) { 12 if (!map.containsKey(t.charAt(i)) || (map.containsKey(t.charAt(i)) && map.get(t.charAt(i)) <= 0)) 13 rst = t.charAt(i); 14 else if (map.containsKey(t.charAt(i)) && map.get(t.charAt(i)) > 0) 15 map.replace(t.charAt(i), map.get(t.charAt(i)) - 1); 16 } 17 return rst; 18 } 19 }
解法2:<Bit> (遍历s和t, c^, 一直取异或, 最后剩下的就是tar; x^0=x, x^x=0)
(1.char; 2.for()^=; 3.for()^=; 4.return;)
1 public char findTheDifference(String s, String t) { 2 char c = 0; 3 for (int i = 0; i < s.length(); ++i) { 4 c ^= s.charAt(i); 5 } 6 for (int i = 0; i < t.length(); ++i) { 7 c ^= t.charAt(i); 8 } 9 return c; 10 }
1 public char findTheDifference(String s, String t) { 2 int n = t.length(); 3 char c = t.charAt(n - 1); 4 for (int i = 0; i < n - 1; ++i) { 5 c ^= s.charAt(i); 6 c ^= t.charAt(i); 7 } 8 return c; 9 }
409. Longest Palindrome: https://leetcode.com/problems/longest-palindrome/
最长的回文字符串(顺读和倒读相同):
我的解法: <HashMap> (回文字符串的长度=偶数个数的字符*偶数个数 + 奇数个数的字符 * (奇数 - 1) ; 如果存在奇数个数字符,则+1,不存在则不加; 示例:"aaaabb"-"aabbaa"-6, "abcccc"-5; map不包含则put, 包含了value为1则count+2(表明个数由奇数个变成偶数个)value置零, 包含了value=0则置一,count不变)
(1.map,count; 2.for()if(!)put(1),elseif(contains&value=1)count+2 value0, else()value1; 3.if(containsValue1)count+1,else count;)
1 public class Solution { 2 public int longestPalindrome(String s) { 3 HashMap<Character, Integer> map = new HashMap<>(); 4 int count = 0; 5 for (int i = 0; i < s.length(); i++) { 6 if (!map.containsKey(s.charAt(i))) 7 map.put(s.charAt(i), 1); 8 else if (map.containsKey(s.charAt(i)) && (map.get(s.charAt(i)) % 2) != 0) { 9 count = count + 2; 10 map.replace(s.charAt(i), 0); 11 } 12 else if (map.containsKey(s.charAt(i)) && (map.get(s.charAt(i)) % 2) == 0) 13 map.replace(s.charAt(i), 1); 14 } 15 if (map.containsValue(1)) return count + 1; 16 else return count; 17 } 18 }
可以用set简化: <HashSet>(每出现偶数次数时,就把count+2,并remove掉; 相当与每两个一对; 最后判断size>0, 那么count+1,否则count)
(1.set,count; 2.for()if(!)add,else count+2,remove; 3.if(size()>0)count+1,else-count;)
1 public class Solution { 2 public int longestPalindrome(String s) { 3 HashSet<Character> set = new HashSet<>(); 4 int count = 0; 5 for (int i = 0; i < s.length(); i++) { 6 if (!set.contains(s.charAt(i))) 7 set.add(s.charAt(i)); 8 else { 9 count = count + 2; 10 set.remove(s.charAt(i)); 11 } 12 } 13 if (set.size() > 0) return count + 1; 14 else return count; 15 } 16 }
438. Find All Anagrams in a String: https://leetcode.com/problems/find-all-anagrams-in-a-string/
找出字符串2在字符串1中所有相同字符的起始位置:(Input: s: "cbaebabacd" p: "abc" Output: [0, 6]) (Input: s: "abab" p: "ab" Output: [0, 1, 2])
错误代码:(map记录字符串2的key和count, 遍历字符串1; 错误原因:map被改动了,只能得到第一个位置; PS:还有for(j)的范围也写错了orz...)(一个难点是含重复字符,不然就不用修改map或者可以用set来完成了)
1 public class Solution { 2 public List<Integer> findAnagrams(String s, String p) { 3 HashMap<Character, Integer> map = new HashMap<>(); 4 for (int i = 0; i < p.length(); i++) { 5 if (!map.containsKey(p.charAt(i))) 6 map.put(p.charAt(i), 1); 7 else 8 map.replace(p.charAt(i), map.get(p.charAt(i)) + 1); 9 } 10 List<Integer> list = new ArrayList<Integer>(); 11 for (int i = 0; i < s.length() - p.length(); i++) { 12 if (map.containsKey(s.charAt(i))) { 13 int j = i; 14 for (; j < p.length(); j++) { 15 if (!map.containsKey(s.charAt(j)) || (map.containsKey(s.charAt(j)) && map.get(s.charAt(j)) <= 0)) 16 break; 17 else 18 map.replace(s.charAt(j), map.get(s.charAt(j)) - 1); 19 } 20 if (j == i + p.length()) list.add(i); 21 } 22 } 23 return list; 24 } 25 }
修改后的TLE代码: (利用map的putAll方法,每遍历一个字符串1都copy一个map; pass了33/35个case; 大数据测试TLE……)
(1.map,for; 2.list,for(s-p+1) if(contains),tmpMap,putAll; 3.j,for(i,i+p),if(!||(&&<=0))-break,else-1; 4.if(j=i+p())list.add(i); 5.return)
1 public class Solution { 2 public List<Integer> findAnagrams(String s, String p) { 3 HashMap<Character, Integer> map = new HashMap<>(); 4 for (int i = 0; i < p.length(); i++) { 5 if (!map.containsKey(p.charAt(i))) 6 map.put(p.charAt(i), 1); 7 else 8 map.replace(p.charAt(i), map.get(p.charAt(i)) + 1); 9 } 10 List<Integer> list = new ArrayList<Integer>(); 11 for (int i = 0; i < s.length() - p.length() + 1; i++) { 12 if (map.containsKey(s.charAt(i))) { 13 HashMap<Character, Integer> tmpMap = new HashMap<>(); 14 tmpMap.putAll(map); 15 int j = i; 16 for (; j < i + p.length(); j++) { 17 if (!tmpMap.containsKey(s.charAt(j)) || (tmpMap.containsKey(s.charAt(j)) && tmpMap.get(s.charAt(j)) <= 0)) 18 break; 19 else 20 tmpMap.replace(s.charAt(j), tmpMap.get(s.charAt(j)) - 1); 21 } 22 if (j == i + p.length()) list.add(i); 23 } 24 } 25 return list; 26 } 27 }
解法2: <Sliding Window>(初始化字符数组hash[256], 用来记录string2的字符和滑动窗口后字符串的变化情况; 示例[cdabbaa]-[aab]: 首先初始化的hash里保存数据为a-2,b-1; 定义两个指针left和right, right向右遍历; 扫描到c/d时,c/d对应位置-1;扫描到a,count--,对应a-1,b-1; right指向b,count--,a-1,b-0;此时left指向d, r-l=3时, d<0, 所以count不变,left++; 指向第二个b,count=1不变a-1,b-(-1); right指向a,left指向b,此时count=1, ……)
(hash数组长度256是ASCII所有值的长度, 也可以用26, 不过对应的char的位置要用char-'a')
(第一个>=1表明hash数组里还存有改数, 第二个>=0表明该数被right遍历前是1,是原数组里的数;case:[a-2,b-1] [bbbaaa]count的变化和hash的变化;)
(1.list,if,hash,for(),++; 2.left,right,count; 3.while(<),if(>=1)--,--,++; 4.if(0)add; 5.if(=)if(>=0)++,++,++; 6.return)
1 public class Solution { 2 public List<Integer> findAnagrams(String s, String p) { 3 List<Integer> list = new ArrayList<>(); 4 if (s == null || s.length() == 0 || p == null || p.length() == 0) return list; 5 6 int[] hash = new int[256]; //character hash 7 8 //record each character in p to hash 9 for (char c : p.toCharArray()) { 10 hash[c]++; 11 } 12 //two points, initialize count to p's length 13 int left = 0, right = 0, count = p.length(); 14 15 while (right < s.length()) { 16 //move right everytime, if the character exists in p's hash, decrease the count 17 //current hash value >= 1 means the character is existing in p 18 if (hash[s.charAt(right)] >= 1) { 19 count--; 20 } 21 hash[s.charAt(right)]--; 22 right++; 23 24 //when the count is down to 0, means we found the right anagram 25 //then add window's left to result list 26 if (count == 0) { 27 list.add(left); 28 } 29 //if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window 30 //++ to reset the hash because we kicked out the left 31 //only increase the count if the character is in p 32 //the count >= 0 indicate it was original in the hash, cuz it won't go below 0 33 if (right - left == p.length() ) { 34 35 if (hash[s.charAt(left)] >= 0) { 36 count++; 37 } 38 hash[s.charAt(left)]++; 39 left++; 40 } 41 } 42 return list; 43 } 44 }
451. Sort Characters By Frequency: https://leetcode.com/problems/sort-characters-by-frequency/