目录
[1. 移动零(283. Move Zeroes) ](#1. 移动零(283. Move Zeroes))
[2. 盛最多水的容器(11. Container With Most Water) ](#2. 盛最多水的容器(11. Container With Most Water))
[1. 两数之和(1. Two Sum) ](#1. 两数之和(1. Two Sum))
[2. 字母异位词分组(49. Group Anagrams) ](#2. 字母异位词分组(49. Group Anagrams))
[1. 三数之和(15. 3Sum)](#1. 三数之和(15. 3Sum))
[2. 最长连续序列(128. Longest Consecutive Sequence) ](#2. 最长连续序列(128. Longest Consecutive Sequence))
[四、挑战难题篇:接雨水(42. Trapping Rain Water) ](#四、挑战难题篇:接雨水(42. Trapping Rain Water))
作为一名算法爱好者,LeetCode是我提升编程能力、锻炼逻辑思维的绝佳平台。今天,我想分享几道LeetCode经典题目,聊聊它们的解法思路和C++实现,希望能给正在刷题的你带来一些启发。
一、数组操作篇
1. 移动零(283. Move Zeroes)

问题描述:给定一个数组,将所有0移动到数组末尾,同时保持非零元素的相对顺序,要求原地操作。
解题思路:使用双指针法,一个指针 pre 追踪非零元素的位置,另一个指针 cur 遍历数组。当 cur 遇到非零元素时,与 pre 位置的元素交换,然后 pre 和 cur 都后移;若遇到0,仅 cur 后移。
C++实现:
cpp
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int cur = 0, pre = -1;
while (cur < nums.size()) {
if (nums[cur] == 0) cur++;
else {
swap(nums[++pre], nums[cur++]);
}
}
}
};
2. 盛最多水的容器(11. Container With Most Water)

问题描述:给定n条垂线,找到两条线,使得它们与x轴构成的容器能容纳最多的水。
解题思路:双指针从两端向中间移动。容器的容量由较短的垂线高度和两线间距决定。每次移动较短垂线的指针,因为移动较长垂线的指针不会得到更大的容量。
C++实现:
cpp
class Solution {
public:
int maxArea(vector<int>& height) {
int heightSize = height.size(), max_area = 0;
int left = 0, right = heightSize - 1;
while (left < right) {
int area = (right - left) * min(height[left], height[right]);
if (area > max_area) max_area = area;
if (height[left] < height[right]) left++;
else right--;
}
return max_area;
}
};
二、查找与哈希篇
1. 两数之和(1. Two Sum)

问题描述:给定数组和目标值,找出和为目标值的两个整数的下标。
解题思路:暴力法是双重循环遍历所有可能的数对,时间复杂度O(n²)。
C++实现:
cpp
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int numsSize = nums.size();
for (int i = 0; i < numsSize; i++)
for (int j = i + 1; j < numsSize; j++)
if (nums[i] + nums[j] == target)
return {i, j};
return {};
}
};
注:此解法时间复杂度较高,更优的解法是使用哈希表,时间复杂度可降至O(n)。
2. 字母异位词分组(49. Group Anagrams)

问题描述:将字母异位词(字母组成相同,顺序不同的单词)组合在一起。
解题思路:将每个单词排序,排序后的结果作为哈希表的键,相同键的单词属于同一组字母异位词。
C++实现:
cpp
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> hash;
for (auto s : strs) {
string tmp = s;
sort(tmp.begin(), tmp.end());
hash[tmp].push_back(s);
}
vector<vector<string>> ret;
for (auto& [x, y] : hash)
ret.push_back(y);
return ret;
}
};
三、数组进阶篇
1. 三数之和(15. 3Sum)

问题描述:找出数组中所有和为0的三元组,且不重复。
解题思路:先排序,然后固定一个数,用双指针找另外两个数,同时注意去重(包括固定数的去重和双指针移动时的去重)。
C++实现:
cpp
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> v;
sort(nums.begin(), nums.end());
int n = nums.size();
if (n < 3)
return {};
for (int i = 0; i < n - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1])
continue;
int target = -nums[i];
int left = i + 1, right = n - 1;
while (left < right) {
if (nums[left] + nums[right] > target)
right--;
else if (nums[left] + nums[right] < target)
left++;
else {
v.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1])
left++;
while (left < right && nums[right] == nums[right - 1])
right--;
left++;
right--;
}
}
}
return v;
}
};
2. 最长连续序列(128. Longest Consecutive Sequence)

问题描述:给定未排序的整数数组,找出最长连续序列的长度,要求时间复杂度O(n)。
解题思路:先排序,然后遍历数组,统计连续序列的长度,遇到重复元素则跳过。
C++实现:
cpp
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if (nums.empty()) return 0;
sort(nums.begin(), nums.end());
int len = 0, ret = 0;
for (int i = 1; i < nums.size(); i++) {
if (nums[i] - nums[i - 1] == 1) len++;
else if (nums[i] - nums[i - 1] == 0) continue;
else {
ret = max(ret, len);
len = 0;
}
}
ret = max(ret, len);
return ret + 1;
}
};
四、挑战难题篇:接雨水(42. Trapping Rain Water)

问题描述:给定n个非负整数表示柱子的高度图,计算下雨后能接多少雨水。
解题思路:双指针法,分别记录左右的最大高度。如果左最大高度小于右最大高度,当前左柱子能接的雨水由左最大高度决定;否则由右最大高度决定。
C++实现:
cpp
class Solution {
public:
int trap(vector<int>& height) {
int sz = height.size();
if (sz < 3) return 0;
int left = 0, right = sz - 1;
int leftMax = 0, rightMax = 0;
int ret = 0;
while (left < right) {
leftMax = max(leftMax, height[left]);
rightMax = max(rightMax, height[right]);
if (leftMax < rightMax) ret += leftMax - height[left++];
else ret += rightMax - height[right--];
}
return ret;
}
};
总结
通过这些题目的练习,我们可以总结出一些常见的算法思维和技巧:
**- 双指针法:在数组、字符串问题中应用广泛,如两数之和、三数之和、盛最多水的容器、接雨水等。
- 哈希表:用于快速查找、分组,如字母异位词分组、两数之和的优化解法。
- 排序:帮助我们处理重复、连续等问题,如三数之和、最长连续序列。
- 原地操作:通过指针技巧减少空间复杂度,如移动零。**
刷题是一个持续积累的过程,每道题都有其独特的思路和价值。希望这篇博客能帮助大家更好地理解这些经典题目,在算法学习的道路上不断进步!