
Day 7。
今天这两题一个是 字符串前缀匹配,一个是 经典双指针去重题。
表面上看难度差距很大,但它们都在训练同一种能力:
先抓住题目的结构,再选择合适的数据处理方式。
今天的关键词:横向比较、排序、双指针、去重。
🧠 LeetCode 14 – Longest Common Prefix
💡 思路总结
这题要求找出字符串数组中的最长公共前缀。
你的思路是:
- 先拿第一个字符串当“基准串”
- 按字符位置逐个检查
- 对每个位置,去和后面的每个字符串比较
- 一旦有不相同,就直接返回当前结果
这个思路非常自然,本质上就是:
拿第一行当模板,逐列检查所有字符串是否一致
💻 代码实现
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (strs.empty())return "";
string result = "";
int strs_size = strs.size();
for(int i = 0;i<strs[0].size();i++){
for(int j = 1 ;j < strs_size;j++ ){
char c = strs[0][i];
if(c != strs[j][i]){
return result;
}
}
result += strs[0][i];
}
return result;
}
};
📌 知识点总结
1️⃣ 横向扫描思想
这题你当前的做法本质是“按列比较”:
- 看第 0 列是否全相同
- 再看第 1 列是否全相同
- 一直检查下去
一旦某一列不同,公共前缀就到此为止。
2️⃣ 用第一个字符串当参照物
这是很常见的技巧。
因为公共前缀不可能比任意一个字符串更长,所以先拿 strs[0] 来枚举位置,逻辑就很顺。
3️⃣ 这里有一个边界小问题
你这份代码的主要思路是对的,但有一个隐藏风险:
if(c != strs[j][i])
这里默认了 strs[j] 一定有第 i 个字符。
但如果某个字符串长度比 strs[0] 更短,就会越界。
比如:
["ab", "a"]
当 i = 1 时,strs[1][1] 就越界了。
所以更稳的判断应该写成:
if (i >= strs[j].size() || strs[j][i] != strs[0][i])
✅ 更稳一点的版本
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (strs.empty()) return "";
string result = "";
for (int i = 0; i < strs[0].size(); i++) {
for (int j = 1; j < strs.size(); j++) {
if (i >= strs[j].size() || strs[j][i] != strs[0][i]) {
return result;
}
}
result += strs[0][i];
}
return result;
}
};
🔥 LeetCode 15 – 3Sum
💡 思路总结
这题是非常经典的一道题:
找出所有和为
0的三元组,而且不能重复。
如果直接暴力枚举三重循环,时间复杂度会是 O(n^3),太慢。
所以经典做法是:
- 先排序
- 固定第一个数
- 剩下两个数用双指针找
这也是你现在写的标准解法。
💻 代码实现
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
int n = nums.size();
for (int i = 0; i < n; i++) {
// 第一个数去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
result.push_back({nums[i], nums[left], nums[right]});
// 跳过重复的 left
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
// 跳过重复的 right
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
left++;
right--;
}
else if (sum < 0) {
left++;
}
else {
right--;
}
}
}
return result;
}
};
📌 知识点总结
1️⃣ 排序是这题的前提
排序之后,数组有序,双指针才有意义。
因为有序后你才能根据当前和的大小来决定移动方向:
sum < 0:说明需要更大的数,所以左指针右移sum > 0:说明需要更小的数,所以右指针左移
2️⃣ 固定一个数,转成 Two Sum
这题一个非常经典的转换就是:
Three Sum = 固定一个数 + 在剩余区间里做 Two Sum
也就是说:
- 枚举
nums[i] - 在区间
[i+1, n-1]中找两数和为-nums[i]
这就是题目结构化之后的解法。
3️⃣ 去重是灵魂
这题难点不只是找到答案,而是:
不能出现重复三元组
你这里处理得很好,分了三层去重:
i去重left去重right去重
这非常标准。
4️⃣ 双指针题的味道越来越明显了
从 Day 5 的 Container With Most Water 到今天的 3Sum,你已经开始真正接触双指针的不同形态了:
- 容器题:左右夹逼,基于贪心移动
- 三数之和:排序后夹逼,基于和的大小调整
说明你已经不只是“会一个题”,而是在慢慢理解一类题。
🧩 今日总结
| 题目 | 核心思想 |
|---|---|
| LeetCode 14 | 横向比较 + 边界判断 |
| LeetCode 15 | 排序 + 双指针 + 去重 |
今天这两题共同训练了两种很重要的能力:
- 字符串题里,如何按位置逐步比较
- 数组题里,如何借助排序把暴力优化成双指针
🧠 今日收获
今天最值得记住的两个模型是:
1. 公共前缀类问题
思路通常是:
- 选一个基准串
- 按位置比较
- 一旦不一致立即返回
这类题关键在于别漏掉短字符串越界的问题。
2. 多数之和问题
像 2Sum、3Sum、以后你会遇到的 4Sum,都有很强的套路感:
- 排序
- 固定若干个数
- 剩下部分双指针
- 注意去重
这套思维非常重要,后面会反复出现。
💬 写给自己的话
Day 7 了。
一周了。
别小看这一周。
真正有价值的,不只是你做了多少题,
而是你已经在慢慢形成自己的题目理解方式了:
- 看见字符串题,会想比较方式和边界
- 看见数组和问题,会想排序和双指针
- 看见有重复限制,会主动想到去重
这就是成长。
你不是在机械刷题,
你是在一点点建立自己的“做题脑回路”。
继续保持这个节奏。
一天两题,也许不夸张,
但一周、一月、三个月之后,差距就会非常明显。
阿玉,Day 7,已经坚持一周了,很棒。继续冲。
—— 刷题第 7 天
