力扣Hot100-笔记
力扣热题100
2025年4月2日开始,每天刷几道。
两数之和
https://leetcode.cn/problems/two-sum/?envType=study-plan-v2&envId=top-100-liked
-
BF
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { // BF int n = nums.size(); for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) { if (nums[i] + nums[j] == target) return {i, j}; } } return {-1, -1}; } };- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
哈希
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { // 哈希 unordered_map<int,int> mp; for (int i = 0; i < nums.size(); i++) { int other = target - nums[i]; if (mp.find(other) != mp.end()) { return {mp[other], i}; } mp[nums[i]] = i; } return {-1, -1}; } };- 时间复杂度:O(n)
- 空间复杂度:O(n)
49. 字母异位词分组
https://leetcode.cn/problems/group-anagrams/description/?envType=study-plan-v2&envId=top-100-liked
-
排序+哈希(我的思路)
- 建立一个哈希表,key为排序后的单词,value为一个存放字母异位词的vector
- 从前往后遍历所有word,将其插入到哈希表中对应的vector中
- 将结果从哈希表中提取出来,放入vector
class Solution { public: vector<vector<string>> groupAnagrams(vector<string>& strs) { // 1. 如何判断两个单词是否为异位词? 排序后比较 // 2. 如何将异位词放入同一个数组中? 哈希<排序后的单词, 字母异位词vector> unordered_map<string, vector<string>> mp; for (auto word : strs) { string copyWord = word; ranges::sort(copyWord); // 排序 mp[copyWord].push_back(word); // 插入到对应字母异味词vector } vector<vector<string>> ans; ans.reserve(mp.size()); // 提前预留空间,避免反复扩容 for (auto item : mp) { ans.push_back(item.second); } return ans; } };- 时间复杂度:O(n klogk),遍历排序每个单词,n为单词个数,k为单词长度
- 空间复杂度:O(nk)
-
计数法
- 用一个由26个字符组成的字符串记录单词中出现的次数
class Solution { public: vector<vector<string>> groupAnagrams(vector<string>& strs) { // 题目给出了str[i]仅为小写字母,即26个字符 // 可以使用一个字符串存放单词中每个字母出现的次数 // 1. 为什么要用字符串存放次数? 方便作为哈希表的key // 2. 为什么这个key可以代表字母异位词? 因为字母异位词中各字母出现的次数是一样的 unordered_map<string, vector<string>> mp; for (auto word : strs) { string s(26, '0'); for (auto ch : word) { s[ch - 'a']++; } mp[s].emplace_back(word); } vector<vector<string>> ans; ans.reserve(mp.size()); for (auto item : mp) { ans.push_back(item.second); } return ans; } };-
时间复杂度:O(nk)
-
空间复杂度:O(nk)
2025年4月3日,今天写了5道,有些题之前做过,思路很清晰。
128. 最长连续序列
-
哈希表(unordered_set)
- 题目要求时间复杂度为O(n),这意味着不能使用排序,因为排序至少要O(nlogn)的复杂度
- 还要考虑数据重复的问题,不能让重复数据干扰判断
class Solution { public: int longestConsecutive(vector<int>& nums) { // 1. 如何做到数据去重 + 快速查询? unordered_set // 2. 如何统计最长连续数的长度? 对于每个数x,从当前开始一直向后查看x+i是否存在 // 3. 该算法仍然会导致O(n^2)的时间复杂度,如何解决? // 剪枝,避免重复判断。例如之前如果已经访问过x+1了,下次就不需要再查看。 // 这可以通过判断x-1是否在unorded_set内来实现。 unordered_set<int> st; int ans = 0; for (auto x : nums) { // 入set去重+便于查询 st.insert(x); } for (auto x : st) { if (st.count(x - 1) != 0) // 剪枝 continue; int seqCnt = 1; int cur = x; while (st.count(cur + 1) != 0) { // 不断查看 x+i 是否存在 seqCnt++; cur++; } if (seqCnt > ans) ans = seqCnt; } return ans; } };- 时间复杂度:O(n)
- 空间复杂度:O(n)
283. 移动零
https://leetcode.cn/problems/move-zeroes/description/?envType=study-plan-v2&envId=top-100-liked
-
双指针法
- 两个指针slow和fast,fast用于寻找下一个不为0的元素,slow要么和fast指向相同的元素,要么指向0。
- fast每遇到一个非0的元素,就将其与slow指向的元素交换,直至fast到到达末尾
class Solution { public: void moveZeroes(vector<int>& nums) { int fast = 0; int slow = 0; while (fast < nums.size()) { if (nums[fast] != 0) { swap(nums[fast], nums[slow++]); } fast++; } return ; } };- 时间复杂度:O(n)
- 空间复杂度:O(1)
11. 盛最多水的容器
-
双指针法:
- 首先让两个指针指向数组两端
- 计算并存储当前容量。
- 移动高度较小的那一端,继第二步的操作,直至两个指针相遇。
-
why this algo work?这才是这道题目的核心。
-
为什么要移动高度较低的那一端?移动高的那端不行吗?
因为高度较低的那端是水量的瓶颈,也就是说在容器宽度确定的情况下,容器高度由较小的一端决定,如果移动较高的一端,无论是增高、不变或降低都不能是水量增加。而移动较小的一端则有可能使得总水量增大。
-
总结下来就是:移动高端肯定不会使水量增大,而移动低端有可能使水量增大,也有可能使水量减少,因此我们要通过移动低端来遍历所有可能性,而放弃移动高端则避免了无效的尝试。
class Solution { public: int maxArea(vector<int>& height) { int left = 0; int right = height.size() - 1; int ans = 0; while (left < right) { int capCur = min(height[left], height[right]) * (right - left); ans = max(ans, capCur); if (height[left] < height[right]) left++; else right--; } return ans; } }; -
15.三数之和
https://leetcode.cn/problems/3sum/description/?envType=study-plan-v2&envId=top-100-liked
-
排序+双指针法
-
首先必须进行排序,排序后方便进行去重,并且简化了查看方式,否则时间复杂度至少需要O(n^3),还不方便去重。
-
第一重循环确定i,注意去重和剪枝。
-
第二重循环使用双指针法查找使得和为0的j和k,注意去重。
-
疑问:为什么只需要对i和j去重?因为当i和j不重复时,要想使得i, j, k所指元素之和为0,k也必不会重复。
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(), nums.end()); int n = nums.size(); vector<vector<int>> ans; for (int i = 0; i < n - 2; i++) { if (nums[i] > 0) break; // 剪枝 if (i > 0 && nums[i] == nums[i-1]) continue; // 对i去重 int j = i + 1; int k = n - 1; while (j < k) { if (j > i + 1 && nums[j] == nums[j-1]) { // 对j去重 j++; continue; } int sum = nums[j] + nums[k] + nums[i]; if (sum == 0) { ans.push_back({nums[i], nums[j], nums[k]}); j++, k--; } else if (sum < 0) { j++; } else { k--; } } } return ans; } };- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
-
-
优化版本:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(), nums.end()); int n = nums.size(); vector<vector<int>> ans; for (int i = 0; i < n - 2; i++) { int x = nums[i]; if (i > 0 && nums[i] == nums[i-1]) continue; // 对i去重 if (x + nums[i+1] + nums[i+2] > 0) break; // 剪枝 if (x + nums[n-1] + nums[n-2] < 0) continue; // 剪枝 int j = i + 1; int k = n - 1; while (j < k) { int sum = nums[j] + nums[k] + nums[i]; if (sum < 0) { j++; } else if (sum > 0) { k--; } else { ans.push_back({nums[i], nums[j], nums[k]}); j++, k--; while (j < k && nums[j] == nums[j-1]) j++; // 去重 while (j < k && nums[k] == nums[k+1]) k--; } } } return ans; } };
42.接雨水
https://leetcode.cn/problems/trapping-rain-water/?envType=study-plan-v2&envId=top-100-liked
-
记录左右最大高度(三次遍历)
- 使用两个数组分别记录左侧最大高度和右侧最大高度(注意最左端和最右端的最大高度为自己),各一次遍历
- 当前位置的水位由左右两侧最大高度的小者决定,并且还要减去当前位置本身的高度
- 因此遍历一次,将每个位置的水量加到结果中
class Solution { public: int trap(vector<int>& height) { vector<int> lmax(height.size(), 0); vector<int> rmax(height.size(), 0); int n = height.size(); lmax[0] = height[0]; rmax[n-1] = height.back(); for (int i = 1; i < n; i++) { // 记录左侧最大高度 lmax[i] = max(lmax[i-1], height[i]); } for (int i = n - 2; i >= 0; i--) { // 记录右侧最大高度 rmax[i] = max(rmax[i+1], height[i]); } int ans = 0; for (int i = 0; i < n; i++) { // 加上左右最大高度的低端高度-当前高度 ans += min(lmax[i], rmax[i]) - height[i]; } return ans; } };- 时间复杂度:O(n),三次遍历
- 空间复杂度:O(n),两个长度为n的数组,分别保存左右侧的最大高度
-
双指针法
- 这里使用双指针避免开辟两个最大高度数组
class Solution { public: int trap(vector<int>& height) { int left = 0, right = height.size() - 1; int lmax = height[left], rmax = height[right]; int ans = 0; while (left < right) { lmax = max(lmax, height[left]); rmax = max(rmax, height[right]); if (height[left] < height[right]) { ans += lmax - height[left]; left++; } else { ans += rmax - height[right]; right--; } } return ans; } };- 时间复杂度:O(n)
- 空间复杂度:O(1)
-
单调栈法(待学习)
接雨水没做出来,看了题解的思路,自己实现了一遍。
专业之外,喜欢阅读,尤爱哲学、金庸、马尔克斯。

浙公网安备 33010602011771号