滑动窗口
left 是左边界的索引,是在窗口内的最左元素
定长窗口直接算
1
| int left = right - k + 1;//k 是窗口长度
|
不定长用 while
1 2 3 4 5 6 7
| //这个是典型,left初值是0,给0出边界后left进一 //此时left就指向新窗口的左边界了 //窗口长度就是正常的右减左加一,right-left+1 while (n0 > k) { if (nums[left] == 0) n0--; left++; }
|
二分查找
- 查找 target 第一次出现的索引
- ranges::lower_bound C++20 里引入了这个函数,找下界,下面这就是他的具体实现
- 默认比较器用的 less,就是 mid 值 < target,改用 greater 后就是 mid > target
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int n = nums.size(); int left = 0, right = n - 1;//指针初值设为两头 // 循环不变量:整个循环包括结束都会严格满足下面这两个条件 // 循环不变量:看最后左右指针在mid汇合的时候的条件,计算之后左右指针落点 // nums[left-1] < target // nums[right+1] >= target // 因为是二分查找,所以最后两指针是相邻的 while ( left <= right ) {//while循环 int mid = (left + right ) / 2; //如果中间值在target左侧,就更新left,缩小左边界 if (nums[mid] < target) {//这个地方比较的是mid,老错写成left //left要设为mid+1,是闭区间最左边界 left = mid + 1; } //right要设为mid-1 else right = mid - 1; } return left;//最后返回的是target第一次出现的索引,也等于right+1 //也适用于target不存在的情况,只要记住循环不变量就行 //就比如lower_bound(nums, 0);能返回第一个0的索引 //lower_bound(nums,1);若1不存在能返回第一个大于0的索引
|
lower_bound(nums.begin(),nums.(end),target),升序,找到第一个>=target 的值的元素,并返回该元素的迭代器
lower_bound( begin , end , val , less<type>() )升序,找到第一个>=target 的元素,与上面不写的升序功能相同,官方的自定义比较函数
lower_bound( begin , end , val , greater<type>() )降序,找到第一个<=target 的元素
- 返回的值是迭代器,若要获取索引,需要用
- begin
ranges::lower_bound(nums2.begin(),nums2.end(), nums1[i], ranges::greater{}) - nums2.begin();//减去开始获取索引
upper_bound()也是升序,但是是找到第一个>target 的元素
前缀和
s[i]就是前 i 个元素的和
适合求区间和,无论是否有序
1 2 3 4 5 6 7
| vector<int> s; s.resize(nums.size() + 1); for (int i = 0; i < nums.size(); i++) { s[i + 1] = s[i] + nums[i]; }
|
找所有和为 k 的子串
1 2 3 4 5 6 7
| for (int i = 0 ; i < pre.size(); i++) { auto it = map.find(pre[i] - k); if (it != nullptr) ans += it -> second; map[pre[i]]++; }
|
链表 List
翻转链表
1 2 3 4 5 6 7 8 9 10
| ListNode* reverseList(ListNode* node) { ListNode* pre = nullptr, *cur = node; while (cur != nullptr) { ListNode* nxt = cur -> next; cur -> next = pre; pre = cur; cur = nxt; } return pre; }
|
快慢指针法,查看是否存在环型链表
1 2 3 4 5 6 7 8 9 10 11 12
| bool hasCycle(ListNode *head) { ListNode* fast = head, *slow = head; while (fast && fast -> next) { slow = slow -> next; fast = fast -> next -> next; if (fast == slow) return true; } return false; }
|
快慢指针法,找中间节点
1 2 3 4 5 6 7 8
| ListNode* middleNode(ListNode* head) { ListNode* slow = head, *fast = head; while (fast != nullptr && fast -> next != nullptr) { slow = slow -> next; fast = fast -> next -> next; } return slow; }
|
虚拟头结点,头插法,合并两个有序链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { ListNode dummy(0); ListNode* tail = &dummy; while (list1 != nullptr && list2 != nullptr) { if (list1 -> val <= list2 -> val) { tail -> next = list1; list1 = list1 -> next; } else { tail -> next = list2; list2 = list2 -> next; } tail = tail -> next; } tail -> next = list1 ? list1 : list2; return dummy.next; }
|
二叉树
深度优先搜索(DFS),用递归或者栈实现
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
| void Recursion(TreeNode* root, vector<int> &ans) { if (root == nullptr) return; Recursion(root->left, ans); ans.push_back(root->val); Recursion(root->right, ans); }
stack<TreeNode*> stk;
while (root != nullptr || !stk.empty()) { while (root != nullptr) { stk.push(root); root = root->left; } root = stk.top(); ans.push_back(stk.top()->val); stk.pop(); root = root->right; }
|
广度优先搜索(BFS),用队列实现
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
|
queue<TreeNode*> queue;
vector<vector<int>> res; queue.push(root); while (!queue.empty()) { vector<int> vals; for(int n = queue.size(); n > 0; n--) { TreeNode* node = queue.front(); if (node->left) queue.push(node->left); if (node->right) queue.push(node->right); vals.push_back(node->val); queue.pop(); } res.emplace_back(vals); } return res;
|
递归
把原问题化解成一个个和相似的子问题,然后确定好递归的终止条件
数组转换为平衡二叉树
1 2 3 4 5 6 7 8 9 10 11
| // 把 nums[left] 到 nums[right-1] 转成平衡二叉搜索树 TreeNode* dfs(vector<int>& nums, int left, int right) { if (left == right) return nullptr; int m = (left + right) / 2; TreeNode* node = new TreeNode(nums[m]); node->left = dfs(nums, left, m); node->right = dfs(nums, m+1 , right); return node; // 也可以直接用构造函数写返回值,第一个参数是val,第二个是左子树,第二个是右子树 // return new TreeNode(m, dfs(nums, left, m), dfs(nums, m+1, right)) }
|
二叉搜索树,左子树严格小于根节点,右子树严格大于根节点
中序遍历就是升序