add heap sort, quick sort
双指针 快慢指针 左右指针 滑动窗口 经典模板
1 2 3 4 5 6 7 8 9 int left=0 , right=0 ;while (right < s.size ()){ windows.add (s[right]); right++; while (windows需要收缩){ windows.remove (s[left]); left++; } }
回溯 解决⼀个回溯问题,实际上就是⼀个决策树的遍历过程。
你只需要思考个问题:
路径 :也就是已经做出的选择。
选择列表 :也就是你当前可以做的选择。
结束条件 :也就是到达决策树底层,⽆法再做选择的条件。
经典模板框架
1 2 3 4 5 6 7 8 9 10 11 12 result = [] void backtrace (路径,选择列表){ if (满足结束条件){ result.add (路径) return ; } for (选择&: 选择列表){ 做选择,当前选择加入选择路径 backtrace (路径,选择列表) 撤销选择,当前选择移除出选择路径 } }
动态规划 树 字典树 TODO
图 DFS TODO
BFS TODO
栈 TODO
单调栈 单调栈的核心规则 就是:
➡️ 往栈里压元素时,如果破坏了单调性,就弹出栈顶直到恢复单调 。
假设我们要维护“单调递减栈”(栈顶最小):
要么 push,要么 pop 若干次,再 push ,永远保持“单调递减”。
类型
栈里从栈底到栈顶
作用
单调递增栈
值越来越大
适用于找「下一个更大元素」
单调递减栈
值越来越小
适用于找「下一个更小元素」
它的核心思想是:
用单调性过滤掉无用元素,保证“最近的有效元素”在栈顶
题目
矩阵 差分与前缀和
题目
排序 快速排序 Lomuto partition 每次partition确定一个值的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <vector> #include <algorithm> using std::vector;int partition (vector<int > &arr, int start, int end) { int pivot = arr[end]; int i = start; for (int j = start; j < end; j++) { if (arr[j] < pivot) { std::swap (arr[i], arr[j]); i++; } } std::swap (arr[i], arr[end]); return i; } void quick_sort (vector<int > &arr, int start, int end) { if (start >= end) return ; int p = partition (arr, start, end); quick_sort (arr, start, p - 1 ); quick_sort (arr, p + 1 , end); } #include <stdio.h> int main () { vector<int > arr = { 1 , 3 , 6 , 2 , 3 , 8 , 4 , 9 , 0 }; quick_sort (arr, 0 , arr.size () - 1 ); for (int num: arr){ printf ("%d " , num); } printf ("\n" ); }
Hoare partition 它并不要求 pivot 最终落在正确位置,而是保证:
$[start .. left-1] < pivot$
$[left .. end] >= pivot$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <vector> using std::vector;int partition (vector<int > &arr, int start, int end) { int pivot = arr[start]; int left = start, right = end; while (left <= right) { while (arr[left] < pivot) { left++; } while (arr[right] > pivot) { right--; } if (left <= right) { std::swap (arr[left], arr[right]); left++; right--; } } return left; } void quick_sort (vector<int > &arr, int start, int end) { if (start >= end) { return ; } int p; p = partition (arr, start, end); quick_sort (arr, start, p - 1 ); quick_sort (arr, p, end); } #include <stdio.h> int main () { vector<int > arr = { 1 , 3 , 6 , 2 , 3 , 8 , 4 , 9 , 0 }; quick_sort (arr, 0 , arr.size () - 1 ); for (int num: arr){ printf ("%d " , num); } printf ("\n" ); }
也可以这样写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 void quickSort (vector<int >& nums, int l, int r) { if (l >= r) return ; int i = l - 1 , j = r + 1 ; int x = nums[(l + r) >> 1 ]; while (i < j) { do i++; while (nums[i] < x); do j--; while (nums[j] > x); if (i < j) swap (nums[i], nums[j]); } quickSort (nums, l, j); quickSort (nums, j + 1 , r); }
堆排序 对完全二叉树 结点进行编号,有如下关系
项目
1-based 编号 (根=1)
0-based 编号 (根=0)
左孩子
$\text{left}(i)=2i $
$ \text{left}(i)=2i+1 $
右孩子
$ \text{right}(i)=2i+1 $
$ \text{right}(i)=2i+2 $
父节点
$ \text{parent}(i)=\lfloor i/2 \rfloor(i>1)$
$ \text{parent}(i)=\lfloor (i-1)/2 \rfloor(i>0)$
至少有左孩子的条件
$ 2i \le n $
$ 2i+1 < n $
右孩子存在条件
$ 2i+1 \le n $
$ 2i+2 < n $
叶节点条件
$i > \lfloor n/2 \rfloor$
$ i > \lfloor (n-2)/2 \rfloor $或 $2i+1 \ge n$
只有左孩子条件
$2i = n $
$ 2i+1 < n $ 且 $ 2i+2 \ge n $
深度(root 层=1)
$ \lfloor \log_2 i \rfloor +1 $
$ \lfloor \log_2 (i+1) \rfloor +1 $
深度(root 层=0)
$ \lfloor \log_2 i \rfloor $
$ \lfloor \log_2 (i+1) \rfloor $
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <vector> using std ::vector ; void heapify (vector <int > &vec, int curr, int n) { int left = curr * 2 + 1 ; int right = curr * 2 + 2 ; int largest = curr; if (left < n && vec[left] > vec[largest]) { largest = left; } if (right < n && vec[right] > vec[largest]) { largest = right; } if (largest != curr) { std ::swap(vec[largest], vec[curr]); heapify(vec, largest, n); } } void buildMaxHeap (vector <int > &vec) { int n = vec.size(); for (int i = (n - 2 ) / 2 ; i >= 0 ; i--) { heapify(vec, i, n); } } #include <stdio.h> int main () { vector <int > nums = { 9 , 8 , 2 , 1 , 5 , 3 , 0 , 10 , 22 , 5 }; int n = nums.size(); buildMaxHeap(nums); for (int i = 0 ; i < n; i++) { std ::swap(nums[0 ], nums[n - i - 1 ]); heapify(nums, 0 , n - i - 1 ); } for (int i = 0 ; i < n; i++) printf ("%d " , nums[i]); printf ("\n" ); }