LeetCode哈希表 hash_table(共88题)
Posted zhangwanying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode哈希表 hash_table(共88题)相关的知识,希望对你有一定的参考价值。
【1】Two Sum (2018年11月9日,k-sum专题,算法群衍生题)
给了一个数组 nums, 和一个 target 数字,要求返回一个下标的 pair, 使得这两个元素相加等于 target 。
题解:我这次最大范围的优化代码, hash-table + one pass,时间复杂度 O(N),空间复杂度 O(N)。重点在于动态找,一边生成hash-table的同时去找答案,不是先生成hash-table再开始找答案。
1 //这种类似 hash 的能用 unordered_map 就不要用 map, hash-table + one pass 2 class Solution { 3 public: 4 vector<int> twoSum(vector<int>& nums, int target) { 5 const int n = nums.size(); 6 unordered_map<int, int> mp; 7 vector<int> ans(2); 8 for (int i = 0; i < n; ++i) { 9 int key = target - nums[i]; 10 if (mp.find(key) != mp.end()) { 11 ans[0] = mp[key]; 12 ans[1] = i; 13 break; 14 } 15 mp[nums[i]] = i; 16 } 17 return ans; 18 } 19 };
【3】Longest Substring Without Repeating Characters (2019年1月19日,谷歌决战复习,sliding window)
给了一个字符串 s, 返回最长的没有重复字符子串长度。
题解:sliding window, O(N)的算法,同 438题,有一个 unordered_map, 一个 begin,一个end, 开始数就行了。
1 class Solution { 2 public: 3 int lengthOfLongestSubstring(string s) { 4 const int n = s.size(); 5 int begin = 0, end = 0; 6 int ret = 0; 7 unordered_map<char, int> mp; 8 while (end < n) { 9 char c = s[end]; 10 mp[c]++; 11 while (mp[c] > 1) { 12 char tempc = s[begin]; 13 mp[tempc]--; 14 begin++; 15 } 16 ret = max(end - begin + 1, ret); 17 end++; 18 } 19 return ret; 20 } 21 };
【18】4Sum (2018年11月9日,k-sum专题,算法群衍生题)
【30】Substring with Concatenation of All Words (2019年1月19日,谷歌决战复习,sliding window)(提出了一种新的想法)
给了一个 string s,一个 words list, 里面每个 word 一样长,找出 s 中所有子串的位置,子串需要包含 list 中的每个单词。(任意顺序)
Example 1: Input: s = "barfoothefoobarman", words = ["foo","bar"] Output: [0,9] Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively. The output order does not matter, returning [9,0] is fine too. Example 2: Input: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] Output: []
题解:sliding window, 用个map记录单词出现的次数。用2 pointers来滑动窗口。遍历 s 数组,O(N * M) 的复杂度
1 class Solution { 2 public: 3 vector<int> findSubstring(string s, vector<string>& words) { 4 const int n = s.size(), m = words.size(); 5 if (n == 0 || m == 0) { return vector<int>(); } 6 const int size = words[0].size(); 7 if (n < m * size) {return vector<int>();} 8 unordered_map<string, int> mp; 9 for (auto w : words) { 10 mp[w]++; 11 } 12 vector<int> ret; 13 for (int i = 0; i + m * size <= n; ++i) { 14 unordered_map<string, int> mpcopy = mp; 15 int k = 0; 16 int start = i; 17 while (k < m) { 18 string str = s.substr(start, size); 19 if (mpcopy.find(str) == mpcopy.end() || mpcopy[str] < 1) { 20 break; 21 } 22 mpcopy[str]--; 23 ++k; 24 start += size; 25 } 26 if (k == m) { 27 ret.push_back(i); 28 } 29 } 30 return ret; 31 } 32 };
【36】Valid Sudoku
【37】Sudoku Solver
【49】Group Anagrams (2019年1月23日,谷歌tag复习)
给了一个单词列表,给所有的异构词分组。
Input: ["eat", "tea", "tan", "ate", "nat", "bat"]
,
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
题解:我的解法,hashmap + sort。不是最优秀的解法。还有什么用 26个素数代替法,这个更快吧。
代码不贴了。
【76】Minimum Window Substring (2018年1月19日,谷歌决战复习,sliding window)
给了两个字符串,一个 S,一个T,在 S 中找一个子串,包含t中所有的字符,除了包含t中所有的字符之外,还可以用冗余的字符。
Example: Input: S = "ADOBECODEBANC", T = "ABC" Output: "BANC"
题解:还是 hash-map + sliding window,模版套路,先init一个unordered_map, 然后用begin,end,count 这三个变量搞一搞。
1 class Solution { 2 public: 3 string minWindow(string s, string t) { 4 const int ssize = s.size(), tsize = t.size(); 5 if (tsize > ssize) {return "";} 6 unordered_map<char, int> mp; 7 for (auto c : t) { 8 mp[c]++; 9 } 10 int count = 0; 11 int begin = 0, end = 0; 12 string ret = ""; 13 int len = INT_MAX; 14 while (end < ssize) { 15 char tempc = s[end]; 16 if (mp.find(tempc) == mp.end()) { 17 ++end; continue; 18 } 19 mp[tempc]--; 20 if (mp[tempc] == 0) { 21 count++; 22 } 23 while (count == mp.size()) { 24 len = end - begin + 1; 25 string tempAns = s.substr(begin, len); 26 if (ret.empty() || len < ret.size()) { 27 ret = tempAns; 28 } 29 char c = s[begin]; 30 if (mp.find(c) == mp.end()) { 31 ++begin; continue; 32 } 33 mp[c]++; 34 if (mp[c] > 0) { 35 count--; 36 } 37 begin++; 38 } 39 ++end; 40 } 41 return ret; 42 } 43 };
【85】Maximal Rectangle
【94】Binary Tree Inorder Traversal
【136】Single Number
【138】Copy List with Random Pointer
【149】Max Points on a Line (2018年11月10号,算法群)
给了 2D 平面上的 n 个点,两个点能组成一条直线,返回一条直线上最多能有几个点。
题解:本题在数学分类上有,不再这里重复写。math:https://www.cnblogs.com/zhangwanying/p/9790007.html
【159】Longest Substring with At Most Two Distinct Characters (2019年1月19日,谷歌决战复习,sliding window)
给了一个字符串 s,返回一个最长的子串,里面最多包含两个unique的字符。
Example 1: Input: "eceba" Output: 3 Explanation: t is "ece" which its length is 3. Example 2: Input: "ccaabbb" Output: 5 Explanation: t is "aabbb" which its length is 5.
题解:unordered_map + sliding window, 依旧是 一个unordered_map, 三个变量, begin, end, cnt
1 class Solution { 2 public: 3 int lengthOfLongestSubstringTwoDistinct(string s) { 4 const int n = s.size(); 5 if (n <= 2) { return n; } 6 unordered_map<char, int> mp; 7 int begin = 0, end = 0, cnt = 0; 8 int ret = 2; 9 while (end < n) { 10 char c = s[end]; 11 mp[c]++; 12 if (mp[c] == 1) { 13 cnt++; 14 } 15 while (cnt > 2) { 16 char t = s[begin]; //这里写的是t,下面写成了c,debug了好久好久啊,哭死 17 mp[t]--; 18 if (mp[t] == 0) { 19 cnt--; 20 } 21 ++begin; 22 } 23 int len = end - begin + 1; 24 ret = max(len, ret); 25 end++; 26 } 27 return ret; 28 } 29 };
【166】Fraction to Recurring Decimal
【170】Two Sum III - Data structure design
【187】Repeated DNA Sequences
【202】Happy Number
【204】Count Primes
【205】Isomorphic Strings
【217】Contains Duplicate
【219】Contains Duplicate II
【242】Valid Anagram
【244】Shortest Word Distance II
【246】Strobogrammatic Number
给了一个字符串代表一个数字,返回这个数字 upside down 之后是不是和原来数字一样。(返回布尔类型)
Example 1: Input: "69" Output: true Example 2: Input: "88" Output: true Example 3: Input: "962" Output: false
题解:用个 map 表示数字字符上下颠倒后的对应数字字符。务必写全:mp[\'0\'] = \'0\', mp[\'1\'] = \'1\', mp[\'6\'] = \'9\', mp[\'8\'] = \'8\', mp[\'9\'] = \'6\';
1 class Solution { 2 public: 3 bool isStrobogrammatic(string num) { 4 map<char, char> mp; 5 mp[\'0\'] = \'0\', mp[\'1\'] = \'1\', mp[\'6\'] = \'9\', mp[\'8\'] = \'8\', mp[\'9\'] = \'6\'; 6 string temp = num; 7 reverse(temp.begin(), temp.end()); 8 for (auto& p : temp) { 9 if (mp.find(p) == mp.end()) {return false;} 10 p = mp[p]; 11 } 12 return temp == num; 13 } 14 };
【249】Group Shifted Strings
【266】Palindrome Permutation
【274】H-Index
【288】Unique Word Abbreviation
【290】Word Pattern
【299】Bulls and Cows
【311】Sparse Matrix Multiplication
【314】Binary Tree Vertical Order Traversal
【325】Maximum Size Subarray Sum Equals k
【336】Palindrome Pairs
【340】Longest Substring with At Most K Distinct Characters
【347】Top K Frequent Elements
【349】Intersection of Two Arrays (2018年11月6日,算法群相关题)
给了两个数组,返回他们交叠的元素,如果有重复元素的话,只返回一个就行了。
题解:直接用 set 解了。
1 //题意是给了两个数组,返回他们的重复元素. 2 //我是用了两个set去重,然后O(n) 的时间复杂度遍历出结果。 3 class Solution { 4 public: 5 vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { 6 set<int> st1(nums1.begin(), nums1.end()), st2(nums2.begin(), nums2.end()); 7 vector<int> ans; 8 for (auto num : st1) { 9 if (st2.find(num) != st2.end()) { 10 ans.push_back(num); 11 } 12 } 13 return ans; 14 } 15 };
【350】Intersection of Two Arrays II (2018年11月6日,算法群)
给了两个数组,返回他们所有交叠的元素,元素可以任意顺序返回,但是如果一个元素在A,B数组中都出现多次,需要返回公共的多次。
Example 1: Input: nums1 = [1,2,2,1], nums2 = [2,2] Output: [2,2] Example 2: Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] Output: [4,9]
题解:用两个map记录每个数组的元素和元素个数,然后遍历一个map,对于两个数组都存在的元素t, 在ret数组里面插入 min(cnt1[t], cnt2[t]). 时间复杂度是 O(N),肯定是线性的。
1 class Solution { 2 public: 3 vector<int> intersect(vector<int>& nums1, vector<int>& nums2) { 4 vector<int> ans; 5 cnt1 = genMap(nums1); 6 cnt2 = genMap(nums2); 7 for (auto p : cnt1) { 8 int t = p.first, times = min(cnt1[t], cnt2[t]); 9 for (int i = 0; i < times; ++i) { 10 ans.push_back(t); 11 } 12 } 13 return ans; 14 } 15 map<int, int> genMap(vector<int>& nums) { 16 map<int, int> ret; 17 for (auto p : nums) { 18 ret[p]++; 19 } 20 return ret; 21 } 22 map<int, int> cnt1, cnt2; 23 };
还有一种方法就是用元素比较少的数组建立map,然后O(N)的遍历另外一个数组。
1 class Solution { 2 public: 3 vector<int> intersect(vector<int>& nums1, vector<int>& nums2) { 4 const int n = nums1.size(), m = nums2.size(); 5 map<int, int> cnt = n <= m ? genMap(nums1) : genMap(nums2); 6 vector<int> ans = n > m ? genAns(nums1, cnt) : genAns(nums2, cnt); 7 return ans; 8 } 9 map<int, int> genMap(const vector<int>& nums) { 10 map<int, int> ret; 11 for (auto p : nums) { 12 ret[p]++; 13 } 14 return ret; 15 } 16 vector<int> genAns(const vector<int>& nums, map<int, int>& cnt) { 17 vector<int> ans; 18 for (auto p : nums) { 19 if (cnt.find(p) != cnt.end() && cnt[p] > 0) { 20 cnt[p]--; 21 ans.push_back(p); 22 } 23 } 24 return ans; 25 } 26 };
本题还有三个follow up:
(1)What if the given array is already sorted? How would you optimize your algorithm?
如果数组已经排好序了,我就不用map了,每个数组用一个指针遍历,相同元素就加到ans数组中。时间复杂度O(N + M),省掉了map。
(2)What if nums1\'s size is small compared to nums2\'s size? Which algorithm is better?
如果nums1的size很小,那我就用nums1建立map,然后遍历nums2,往答案数组里面加元素。
(3)What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?
nums2用数据流读出来(或者 read chunks of array that fit the memory),nums1计算一个map出来,每次nums2中有个元素在map1中对应,就把map1[x]--。
discuss:如果两个array都巨大,memory读不出来,那就先external sort indivisually,每次从排序好的数组里面读出来两个元素,交叠。就和 follow-up1 一样。
【355】Design Twitter
【356】Line Reflection
【358】Rearrange String k Distance Apart
【359】Logger Rate Limiter
【380】Insert Delete GetRandom O(1)
【381】Insert Delete GetRandom O(1) - Duplicates allowed
【387】First Unique Character in a String
【389】Find the Difference
【409】Longest Palindrome (2018年11月14日,为了冲题数做的简单题)(2019年2月18日打卡群复习)
给了一个字符串包含大小写的英文字母(区分大小写,相当于两个字母),问用这个字符串里面的这些字母最长能组成多长的回文串。
题解:我用了一个 map 记录每个字母出现了几次,如果出现了偶数次就直接加次数,出现了奇数次就加奇数次减一。此外,如果有奇数次的话, 最后答案要加1,因为那个字母可以放中心。
1 class Solution { 2 public: 3 int longestPalindrome(LeetCode哈希表 hash_table(共88题)