Leetcode
二分法
#include vector>
using namespace std;
// 经典二分法模板
int binarySearch(const vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 注意初始边界
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; // 调整右边界
}
}
return -1; // 未找到
}
合并排序
#include <vector>
using namespace std;
template<typename T>
void mergeSort(vector<T>& arr) {
vector<T> temp(arr.size()); // 预分配临时空间减少内存操作
sortHelper(arr, 0, arr.size()-1, temp);
}
template<typename T>
void sortHelper(vector<T>& arr, int left, int right, vector<T>& temp) {
if (left >= right) return;
int mid = left + (right - left)/2;
sortHelper(arr, left, mid, temp);
sortHelper(arr, mid+1, right, temp);
// 优化:当已有序时跳过合并
if (arr[mid] <= arr[mid+1]) return;
merge(arr, left, mid, right, temp);
}
template<typename T>
void merge(vector<T>& arr, int left, int mid, int right, vector<T>& temp) {
int i = left, j = mid+1, k = 0;
while (i <= mid && j <= right) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
// 仅复制需要修改的部分
for (int p = 0; p < k; p++) {
arr[left+p] = temp[p];
}
}
## 快速排序
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;
class QuickSort {
public:
void sort(vector<int>& nums) {
if (nums.size() <= 1) return;
srand(time(nullptr));
quickSort(nums, 0, nums.size() - 1);
}
private:
// 三数取中法选择基准
int medianOfThree(vector<int>& nums, int left, int right) {
int mid = left + (right - left) / 2;
if (nums[left] > nums[mid]) swap(nums[left], nums[mid]);
if (nums[left] > nums[right]) swap(nums[left], nums[right]);
if (nums[mid] > nums[right]) swap(nums[mid], nums[right]);
return mid;
}
// 分区函数
int partition(vector<int>& nums, int left, int right) {
int pivotIndex = medianOfThree(nums, left, right);
int pivot = nums[pivotIndex];
swap(nums[pivotIndex], nums[right]); // 将基准放到最后
int i = left;
for (int j = left; j < right; j++) {
if (nums[j] <= pivot) {
swap(nums[i], nums[j]);
i++;
}
}
swap(nums[i], nums[right]);
return i;
}
void quickSort(vector<int>& nums, int left, int right) {
if (left >= right) return;
int pos = partition(nums, left, right);
quickSort(nums, left, pos - 1);
quickSort(nums, pos + 1, right);
}
};
/* 使用示例:
vector<int> arr = {3,1,4,1,5,9,2,6};
QuickSort().sort(arr);
*/
#include <vector>
#include <cstdlib> // 用于rand()
using namespace std;
class QuickSelect {
public:
int findKthLargest(vector<int>& nums, int k) {
return quickSelect(nums, 0, nums.size()-1, nums.size()-k);
}
private:
int quickSelect(vector<int>& nums, int left, int right, int k_smallest) {
if (left == right) return nums[left];
// 随机选择pivot
int pivot_index = left + rand() % (right - left + 1);
pivot_index = partition(nums, left, right, pivot_index);
if (k_smallest == pivot_index) {
return nums[k_smallest];
} else if (k_smallest < pivot_index) {
return quickSelect(nums, left, pivot_index - 1, k_smallest);
} else {
return quickSelect(nums, pivot_index + 1, right, k_smallest);
}
}
int partition(vector<int>& nums, int left, int right, int pivot_index) {
int pivot = nums[pivot_index];
swap(nums[pivot_index], nums[right]); // 将pivot移到末尾
int store_index = left;
for (int i = left; i < right; i++) {
if (nums[i] < pivot) {
swap(nums[store_index++], nums[i]);
}
}
swap(nums[right], nums[store_index]); // 将pivot放回正确位置
return store_index;
}
};
## 单调栈
#include <vector>
#include <stack>
// 正向遍历模板:寻找下一个更大元素
std::vector<int> nextGreaterElement(const std::vector<int>& nums) {
int n = nums.size();
std::vector<int> res(n, -1);
std::stack<int> st; // 存储下标,保持栈底到栈顶对应值递减
for (int i = 0; i < n; ++i) {
while (!st.empty() && nums[i] > nums[st.top()]) {
res[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
return res;
}
// 反向遍历模板:寻找上一个更小元素
std::vector<int> prevSmallerElement(const std::vector<int>& nums) {
int n = nums.size();
std::vector<int> res(n, -1);
std::stack<int> st; // 存储下标,保持栈底到栈顶对应值递增
for (int i = n-1; i >= 0; --i) {
while (!st.empty() && nums[i] < nums[st.top()]) {
res[st.top()] = nums[i];
st.pop();
}
st.push(i);
}
return res;
}
/* 使用示例:
nums = [2,1,3,4,2,1]
nextGreater 结果:[3,3,4,-1,-1,-1]
prevSmaller 结果:[-1,-1,1,2,1,-1]
*/
单调队列
#include <deque>
#include <vector>
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq; // 存储元素下标(维护单调递减队列)
vector<int> result;
for (int i = 0; i < nums.size(); ++i) {
// 移除超出窗口范围的元素
while (!dq.empty() && dq.front() < i - k + 1) {
dq.pop_front();
}
// 维护单调递减特性
while (!dq.empty() && nums[dq.back()] < nums[i]) {
dq.pop_back();
}
dq.push_back(i);
// 当窗口形成后记录结果
if (i >= k - 1) {
result.push_back(nums[dq.front()]);
}
}
return result;
}
滑动窗口
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> charMap;
int left = 0, maxLen = 0;
for (int right = 0; right < s.size(); right++) {
if (charMap.find(s[right]) != charMap.end()) {
// 确保 left 不会回退
left = max(left, charMap[s[right]] + 1);
}
charMap[s[right]] = right; // 更新字符的最新位置
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
回溯
#include <vector>
#include <algorithm> // 用于排序去重
using namespace std;
class Solution {
private:
vector<vector<int>> result; // 存储结果
vector<int> path; // 当前路径
// 核心回溯函数
void backtrack(int start, vector<int>& nums, vector<bool>& used, int target) {
// 终止条件:根据问题调整
if (target == 0) { // 例如:组合总和问题
result.push_back(path);
return;
}
if (target < 0) return; // 剪枝
for (int i = start; i < nums.size(); ++i) { // 组合问题用start,排列问题i从0开始
// 剪枝条件(根据问题调整)
// 去重:排序后跳过重复元素(需i > start)
if (i > start && nums[i] == nums[i - 1]) continue;
// 跳过已用元素(排列问题)
if (used[i]) continue;
// 做选择
path.push_back(nums[i]);
used[i] = true; // 标记已使用(排列问题需要)
// 递归:参数根据问题调整
// 组合问题:i+1(不可重复)或i(可重复)
// 排列问题:无需start,但需used标记
backtrack(i + 1, nums, used, target - nums[i]);
// 撤销选择
path.pop_back();
used[i] = false;
}
}
public:
vector<vector<int>> solveProblem(vector<int>& nums, int target) {
vector<bool> used(nums.size(), false);
sort(nums.begin(), nums.end()); // 若需去重,先排序
backtrack(0, nums, used, target);
return result;
}
};
动态规划问题
- 带备忘录的递归
-
自下而上的迭代
- 满足这两个条件,就可以用动态规划解题。一般先写一下决策树,观察是否有相同子问题,最后自下而上找到状态转移方程。注意底部直接返回的值的设置和非法路径的及时返回,还有就是动态规划递推数组大小的设置。