LeetCode 热题 100
目录
hash
1. 两数之和
hash:
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hash; vector<int> res; for(int i = 0; i < nums.size(); i ++) { auto t = target - nums[i]; if(hash.count(t)) { //已经找到配对,hash[t]存的必定是前一个 res = vector<int> {hash[t], i}; break; } else { hash[nums[i]] = i; } } return res; } };
brute solution:
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> res; for(int i = 0; i < nums.size(); i ++) { for(int j = 0; j < i; j ++) { if(nums[j] + nums[i] == target) { res = vector<int> {j, i}; break; } } } return res; } };
49. 字母异位词分组
可以复制一份字符串,复制的字符串进行排序,一样的复制字符串加入hash表
emplace_back() 和 push_abck() 的区别是:push_back() 在向 vector 尾部添加一个元素时,首先会创建一个临时对象,然后再将这个临时对象移动或拷贝到 vector 中(如果是拷贝的话,事后会自动销毁先前创建的这个临时元素);而 emplace_back() 在实现时,则是直接在 vector 尾部创建这个元素,省去了移动或者拷贝元素的过程。
hash:
class Solution { public: vector<vector<string>> groupAnagrams(vector<string>& strs) { unordered_map<string, vector<string>> map; for(string& str:strs) { string key = str; sort(key.begin(), key.end()); map[key].emplace_back(str); } vector<vector<string>> ans;//变长的变长字符串数组 for(auto it = map.begin(); it != map.end(); it ++) { ans.emplace_back(it->second); } return ans; } };
128. 最长连续序列
hash:
思路和算法
class Solution { public: int longestConsecutive(vector<int>& nums) { unordered_set<int> num_set; for(auto& num:nums) { num_set.insert(num); } int Nmax = 0; for(auto &num:nums) { if(!num_set.count(num - 1)) { int currentNum = num; int currentMax = 1; while(num_set.count(currentNum + 1)) { currentNum ++; currentMax ++; } Nmax = max(Nmax, currentMax); } } return Nmax; } };
brute force:
class Solution { public: int longestConsecutive(vector<int>& nums) { sort(nums.begin(),nums.end()); nums.erase(unique(nums.begin(), nums.end()), nums.end()); int max = 1; int cnt = 1; for(int i = 0; i < nums.size(); i ++) { if(i < nums.size() - 1 && nums[i] == nums[i + 1] - 1) { cnt ++; if(cnt > max) { max = cnt; } } else { cnt = 1; } } if(!nums.size()) return 0; return max; } };
Dual pointers
283. 移动零
Dual pointers:
性质:
-
左指针左边均为非零数;
-
右指针左边直到左指针处均为零。
class Solution { public: void moveZeroes(vector<int>& nums) { int n = nums.size(), left = 0, right = 0; while(right < n){ if(nums[right]) { swap(nums[left], nums[right]); left ++; } right ++; } } };
brute force:
class Solution { public: void moveZeroes(vector<int>& nums) { vector<int> res; int cnt = 0; for(int i = 0; i < nums.size(); i ++) { if(nums[i]) { res.push_back(nums[i]); } else { cnt ++; } } for(int i = 0; i < cnt; i ++) { res.push_back(0); } nums = res; } };
11.盛最多水的容器
性质:
-
面积计算公式:
S(i,j)=min(h[i],h[j])×(j−i)
-
若向内 移动短板 ,下个水槽的面积 可能增大 。
-
若向内 移动长板 ,下个水槽的面积 一定变小 参考解答
class Solution { public: int maxArea(vector<int>& height) { int i = 0, j = height.size() - 1, res = 0; while(i < j) { res = height[i] < height[j] ? max(res, (j - i) * height[i++]): max(res, (j - i) * height[j--]); } return res; } }; //大佬就是叼
dual pointer:
class Solution { public: int maxArea(vector<int>& height) { int left = 0, right = height.size() - 1; int res = 0; while(left < right) { int s = min(height[left], height[right]) * (right - left); if(height[right] < height[left]) { res = max(res, s); right --; } else { res = max(res, s); left ++; } } return res; } };
15. 三数之和
dual pointers:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; int n = nums.size(); if(n < 3) return res; sort(nums.begin(), nums.end()); for(int i = 0; i < n; i ++) { if(nums[i] > 0) return res; if(i > 0 && nums[i] == nums[i - 1]) continue; int L = i + 1; int R = n - 1; while(L < R) { if(nums[i] + nums[L] + nums[R] == 0) { res.push_back({nums[i], nums[L], nums[R]}); while(L < R && nums[L] == nums[L + 1]) { L ++; } while(L < R && nums[R] == nums[R - 1]) { R --; } L ++; R --; } else if(nums[i] + nums[L] + nums[R] > 0) { R --; } else { L ++; } } } return res; } };
42. 接雨水
greedy algorithm:
class Solution { public: int trap(vector<int>& height) { int sum = 0; int n = height.size(); if(n == 0) return 0; vector<int> left_Max(n); left_Max[0] = height[0]; for(int i = 1; i < n; i ++) { left_Max[i] = max(left_Max[i - 1], height[i]); } vector<int> right_max(n); right_max[n - 1] = height[n - 1]; for(int i = n - 2; i >= 0; i --) { right_max[i] = max(right_max[i + 1], height[i]); } for(int i = 0; i < n; i ++) { sum += min(left_Max[i], right_max[i]) - height[i]; } return sum; } };
sliding window
3. 无重复字符的最长子串
sliding window:
class Solution { public: int lengthOfLongestSubstring(string s) { // 哈希集合,记录每个字符是否出现过 unordered_set<char> occ; int n = s.size(); // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动 int rk = -1, ans = 0; // 枚举左指针的位置,初始值隐性地表示为 -1 for (int i = 0; i < n; ++i) { if (i != 0) { // 左指针向右移动一格,移除一个字符 occ.erase(s[i - 1]); } while (rk + 1 < n && !occ.count(s[rk + 1])) { // 不断地移动右指针 occ.insert(s[rk + 1]); ++rk; } // 第 i 到 rk 个字符是一个极长的无重复字符子串 ans = max(ans, rk - i + 1); } return ans; } };
438. 找到字符串中所有字母异位词
判断两个字串是不是异位词
-
长度相同,字母出现的次数相同
S串长度小于P串时,无解
构造一个长度为与字符串 p 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 p 中每种字母的数量相同时,则说明当前窗口为字符串 p 的异位词
以下是力扣大佬的分享
class Solution { public: vector<int> findAnagrams(string s, string p) { vector<int> ans; if(s.size() < p.size()) return vector<int>(); vector<int> sCnt(26); vector<int> pCnt(26); for(int i = 0; i < p.size(); i ++) { sCnt[s[i] - 'a'] ++; pCnt[p[i] - 'a'] ++; } if(sCnt == pCnt) { ans.push_back(0); } for(int i = 0; i < s.size() - p.size(); i ++) { sCnt[s[i] - 'a'] --; sCnt[s[i + p.size()] - 'a'] ++; if(sCnt == pCnt) { ans.push_back(i + 1); } } return ans; } };