欢迎来到我的博客 链接到标题
力扣速刷
开始写博客 链接到标题
一、哈希 链接到标题
-
两数之和
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { int n = nums.size(); // 外层循环:选定第一个数 nums[i] for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (nums[i] + nums[j] == target) { return {i, j}; // 找到了,直接返回它们的下标 } } } return {}; // 没找到 } };
2.字母异位词分组 3***
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
// 创建一个哈希表
// 键 (key) 是排序后的字符串,值 (value) 是所有属于这个键的原始字符串集合
unordered_map<string, vector<string>> mp;
for (string& str : strs) {
string key = str;
// 对字符串内部的字符进行排序,获取“特征键”
sort(key.begin(), key.end());
// 将原始字符串放入对应键的数组中
mp[key].push_back(str);
}
// 把哈希表里分好组的结果提取出来
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.push_back(it->second);
}
return ans;
}
};
二、双指针 链接到标题
1、移动零 :把所有不是0的数移到最前面就是把所有0移到最后面。
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int slow = 0; // 慢指针,记录下一个非 0 元素存放的位置
int n = nums.size();
// fast 遍历整个数组
for (int fast = 0; fast < n; ++fast) {
// fast 找到了非 0 元素!
if (nums[fast] != 0) {
// 将找到的非 0 元素,交换到 slow 指定的安全位置
std::swap(nums[slow], nums[fast]);
// slow 向前一步,准备接收下一个
slow++;
}
}
}
};
std::swap(nums[slow], nums[fast]);
三、移动窗口 链接到标题
1.无重复字符的最长子串 1*
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> window;
int left = 0, max_length = 0;
int winsize = 0;
for (int right = 0; right < s.size(); right++) {
// 收缩窗口直到无重复
while (window.count(s[right])) {
window.erase(s[left]);
left++;
}
// 扩展窗口
window.insert(s[right]);
winsize = window.size();
// ✅ 记录最长长度(不是保留窗口!)
max_length = max(max_length, winsize);
}
return max_length; // 只返回最长长度
}
};
四、子串 链接到标题
1.和为 K 的子数组 (没看懂)
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
// 哈希表:用来记录【某个前缀和】出现的【次数】
unordered_map<int, int> preSumMap;
// 极其重要的一步初始化!
// 意味着在没有遍历任何元素前,前缀和为 0 的情况已经出现了 1 次。
// 这是为了处理那些“从第 0 个元素开始,刚好等于 k”的子数组。
preSumMap[0] = 1;
int count = 0; // 记录符合条件的子数组个数
int preSum = 0; // 记录当前的累加前缀和
for (int i = 0; i < nums.size(); ++i) {
preSum += nums[i]; // 累加当前数字
// 核心逻辑:去哈希表里找,有没有历史前缀和等于 preSum - k 的?
int target = preSum - k;
if (preSumMap.count(target)) {
// 如果有,说明我们找到了一段(或多段)和为 k 的子数组
// 历史前缀和出现了几次,我们就加上几次
count += preSumMap[target];
}
// 把当前的前缀和也存进哈希表,作为未来元素的“历史”
preSumMap[preSum]=preSumMap[preSum] +1 ;
//对 presum 这个 key 对应的 value 加1
}
return count;
}
};
五、普通数组 链接到标题
1.最大子数组和 1*
class Solution {
public:
int maxSubArray(vector<int>& nums) {
// pre 记录“以当前数字结尾的子数组的最大和” (即当前的 current_sum)
int pre = 0;
// maxAns 记录整个遍历过程中见过的最大的和,初始化为第一个元素
int maxans = nums[0];
for (int i = 0; i < nums.size(); ++i) {
// 核心状态转移方程:
// 比较“我自己单干(nums[i])”和“加入前面的队伍(pre + nums[i])”哪个更大
pre = max(nums[i], pre + nums[i]);
// 每走一步,都更新一下我们见过的历史最高记录
maxans = max(maxans, pre);
}
return maxans;
}
};
第二种暴力解法
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int maxSum = nums[0]; // 至少包含一个元素
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += nums[j]; // 累加,避免重复求和
maxSum = max(maxSum, sum);
}
}
return maxSum;
}
};
pre = max (pre,pre+nums[i])
六、矩阵 链接到标题
1.矩阵置零 2**
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
// 准备两个“记仇本”,初始都没有仇 (false)
vector<bool> row(m, false);
vector<bool> col(n, false);
// 第一遍扫描:记仇
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
row[i] = true; // 记下第 i 行有 0
col[j] = true; // 记下第 j 列有 0
}
}
}
// 第二遍扫描:清算
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 只要行或者列在记仇本上,统统变成 0
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
};
vector row(m, false);
七、链表 链接到标题
1.相交链表
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == nullptr || headB == nullptr) return nullptr;
ListNode *pA = headA;
ListNode *pB = headB;
// 只要两个指针没相遇,就一直走
while (pA != pB) {
// pA 走到底了,就切换到 headB;否则继续走 next
pA = (pA == nullptr) ? headB : pA->next;
// pB 走到底了,就切换到 headA;否则继续走 next
pB = (pB == nullptr) ? headA : pB->next;
if(pa == pb)
{
return pa;
}
}
// 相遇时,要么都在交点,要么都在 null
return nullptr;
}
};
while (pA != pB)
2.反转链表 2*
/**
- Definition for singly-linked list.
- struct ListNode {
- int val;
- ListNode *next;
- ListNode() : val(0), next(nullptr) {}
- ListNode(int x) : val(x), next(nullptr) {}
- ListNode(int x, ListNode *next) : val(x), next(next) {}
- };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr; // 前一个节点,初始为 null
ListNode* curr = head; // 当前节点,初始为头节点
while (curr != nullptr) {
// 1. 探子先去记住下一个节点,防止链表断裂丢失
ListNode* tmp = curr->next;
// 2. 核心反转:当前节点“背叛”,掉头指向前一个节点
curr->next = prev;
// 3. 准备下一步:prev 向前走一步
prev = curr;
// 4. 准备下一步:curr 向前走一步(走到刚才探子记住的位置)
curr = tmp;
}
// 循环结束时,curr 变成了 null,而 prev 刚好停在原本的最后一个节点
// 也就是新链表的头节点!
return prev;
}
};
while (curr != nullptr)
return slow;
八、二分查找 链接到标题
1.搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
// 当 left <= right 时,搜索区间依然有效
while (left <= right) {
// 计算中间位置 (防止直接相加导致整型溢出的标准写法)
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid; // 运气好,直接找到了
} else if (nums[mid] < target) {
left = mid + 1; // 目标更大,去右半边找
} else {
right = mid - 1; // 目标更小,去左半边找
}
}
// 循环结束还没找到?没关系,left 当前的位置就是完美的插入点
return left;
}
};
int mid = left + (right - left) / 2;
2.搜索二维矩阵
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.empty() || matrix[0].empty()) return false;
int m = matrix.size();
int n = matrix[0].size();
// 想象成一维数组的左右边界
int left = 0;
int right = m * n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// 核心映射:将一维下标 mid 转换为二维坐标
int mid_val = matrix[mid / n][mid % n];
if (mid_val == target) {
return true; // 找到了!
} else if (mid_val < target) {
left = mid + 1; // 去右半边找
} else {
right = mid - 1; // 去左半边找
}
}
return false; // 找遍了都没有
}
};
int mid_val = matrix[mid / n][mid % n];
九、动态规划 链接到标题
十、贪心算法 链接到标题
十一、技巧 链接到标题
1.只出现一次的数字
int singleNumber(vector<int>& nums) {
int res = 0;
for (int num : nums) {
res ^= num;
}
return res;
}
持续更新 链接到标题
我会定期更新这个博客,分享更多有趣的内容。
感谢您的访问!
同时在此声明 本次博客网址搭建感谢我的好朋友Gemini提供技术细节支持,感谢GLM与Claude Code提供技术实现支持,感谢王甫12135、刻舟求剑的人、男男等好友提供的GLM密匙与环境搭建。