目录

1610. 可见点的最大数目

链表

合并链表 148. 排序链表    21. 合并两个有序链表   23. 合并K个升序链表

反转链表  92. 反转链表 II  206. 反转链表  143. 重排链表

二叉树 —二叉搜索树

二叉树和双向链表结合 426. 将二叉搜索树转化为排序的双向链表

遍历二叉树 层序遍历 199. 二叉树的右视图

前序遍历搜索树255. 验证前序遍历序列二叉搜索树

递归求解 1214. 查找两棵二叉搜索树之和

863. 二叉树中所有距离为 K 的结点

完全二叉树 222. 完全二叉树的节点个数

已知二叉树先序遍历跟后序遍历求二叉树的形状有多少种可能

95. 不同的二叉搜索树 II

二叉树的公共祖先 236. 二叉树的最近公共祖先

572. 另一棵树的子树

二分法

搜索旋转数组 33. 搜索旋转排序数组 81. 搜索旋转排序数组 II

寻找分割值、坐标 410. 分割数组的最大值 1011. 在 D 天内送达包裹的能力 1552. 两球之间的磁力

寻找最小间隔匹配值 719. 找出第 k 小的距离对 786. 第 K 个最小的素数分数

排序

快排 179. 最大数

堆排 9-2合并K个升序数组 215. 数组中的第K个最大元素

215. 数组中的第K个最大元素

动态规划

预处理再动规

1235. 规划兼职工作  354. 俄罗斯套娃信封问题 689. 三个无重叠子数组的最大和

132. 分割回文串 II

前缀和

1504. 统计全 1 子矩形

689. 三个无重叠子数组的最大和

直接动规

91. 解码方法

664. 奇怪的打印机 221. 最大正方形 139. 单词拆分

回溯

131. 分割回文串

DFS

200. 岛屿数量 130. 被围绕的区域 329. 矩阵中的最长递增路径

301. 删除无效的括号

291. 单词规律 II

BFS和DFS结合

934. 最短的桥

判断是否是直角三角形

BFS

788 · 迷宫II

127. 单词接龙

1293. 网格中的最短路径

1926. 迷宫中离入口最近的出口286. 墙与门 1926. 迷宫中离入口最近的出口

994. 腐烂的橘子

模拟

224. 基本计算器

单调栈

85. 最大矩形 84. 柱状图中最大的矩形 85可求出前缀行最大矩阵,计算最大的矩阵,调用84的函数

b[i]定义为a[i]左边离自己最近的比自己小的数字的下标

1438. 绝对差不超过限制的最长连续子数组

贪心单调栈

16 .移掉 K 位数字

最小堆

295. 数据流的中位数

扫描线

218. 天际线问题 遇到拐点进行统计

850. 矩形面积 II

贪心

最多可以参加的会议数目

1824. 最少侧跳次数

45. 跳跃游戏 II

1838. 最高频元素的频数

1423. 可获得的最大点数

528. 按权重随机选择

递增数

35 按字典序输出1-n之间的数

投票法

字典序下一个排列

​​​​​​31. 下一个排列

字典序

440. 字典序的第K小数字

智力题

1224. 最大相等频率

判断为树

KMP

滑窗法

​​​​​​通过删除字母匹配到字典里最长单词

340. 至多包含 K 个不同字符的最长子串

给任意 str,删除任意字符后,求出最长的 4k 长度的 PONY(每个字母 k 长度,如 PPOONNYY)是多长。

数学题

10. 判断点在三角形内部

39. 圆内随机取点

概率题 放球

一道机器学习岗位面试题:平均要抛多少次硬币,才能出现连续两次正面向上?

458. 可怜的小猪

圆上等概率的选3个点 构成锐角三角形的概率 (现场推导)


1610. 可见点的最大数目

    int visiblePoints(vector<vector<int>>& points, int ang, vector<int>& location) {int ans = 0;vector<double> angle;for (const auto& point : points) {int x = location[0] - point[0];int y = location[1] - point[1];if (x == 0 && y == 0) {ans++;} else {angle.push_back(atan2(y , x) * 180 / M_PI);}}sort(angle.begin(), angle.end());for(int i = 0, n = angle.size(); i < n; i++) {angle.emplace_back(angle[i] + 360);}int res = ans;for (int i = 0, j = 0; i < angle.size(); i++) {while (j < angle.size() && (angle[j] - angle[i] < ang)) {j++;}res = max(j - i + ans, res);}return res;}

链表

合并链表 148. 排序链表    21. 合并两个有序链表   23. 合并K个升序链表

    ListNode* mergeKLists(vector<ListNode*>& lists) {return merge(lists, 0, lists.size()-1);}ListNode* merge(vector<ListNode*>& lists, int l, int r){if (l == r)return lists[l];if (l > r) // 考虑{[]}的情况,l=0, r=-1return nullptr;int mid = (l + r) >> 1;return mergeTwoLists(merge(lists, l, mid), merge(lists, mid+1, r));}ListNode* mergeTwoLists(ListNode* a, ListNode* b) {if (!a) return b;if (!b) return a;if (a->val < b->val) {a->next = mergeTwoLists(a->next, b);return a;} else {b->next = mergeTwoLists(a, b->next);return b;}}

反转链表  92. 反转链表 II  206. 反转链表  143. 重排链表

    ListNode* reverseList(ListNode* head) {ListNode* cur = head;ListNode* pre = nullptr;while (cur) {ListNode* next = cur->next;cur->next = pre;pre = cur;cur = next;}return pre;}
翻转区间链表ListNode* cur = pre->next;ListNode* next = new ListNode();for (int i = 0; i < right - left; i++) {next = cur->next;cur->next = next->next;next->next = pre->next;pre->next = next;}return dummyNode->next;

二叉树 —二叉搜索树

二叉树和双向链表结合 426. 将二叉搜索树转化为排序的双向链表

    Node* first = NULL;Node* last = NULL;Node* treeToDoublyList(Node* root) {if (!root) return NULL;helper(root);last->right = first;first->left = last;return first;        }void helper(Node* node) {if (node) {helper(node->left);if (last) {last->right = node;node->left = last;} else {first = node;}last = node;helper(node->right);}}

遍历二叉树 层序遍历 199. 二叉树的右视图

    vector<int> rightSideView(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push(root);vector<int> result;while (!que.empty()) {int size = que.size();for (int i = 0; i < size; i++) {TreeNode* node = que.front();que.pop();if (i == (size - 1)) result.push_back(node->val); // 将每一层的最后元素放入result数组中if (node->left) que.push(node->left);if (node->right) que.push(node->right);}}return result;}

前序遍历搜索树255. 验证前序遍历序列二叉搜索树

    bool verifyPreorder(vector<int>& preorder) {if(preorder.empty()) return true;stack<int> st;int root = INT_MIN;for(int num: preorder){if(num<root) return false;while(!st.empty() && num > st.top()){root = st.top();st.pop();}st.push(num);}return true;}

递归求解 1214. 查找两棵二叉搜索树之和

    bool twoSumBSTs(TreeNode* root1, TreeNode* root2, int target) {if (root1 == nullptr) return false;return helper(root2, target - root1->val) || twoSumBSTs(root1->left, root2, target) || twoSumBSTs(root1->right, root2, target);}bool helper(TreeNode* root,int target) {if (root) {if (target == root->val) return true;if (target < root->val) {return helper(root->left, target);}if (target > root->val) {return helper(root->right, target);}}return false;}

863. 二叉树中所有距离为 K 的结点

    unordered_map<int, TreeNode*> parents;vector<int> ans;void findParents(TreeNode* node) {if (node->left != nullptr) {parents[node->left->val] = node;findParents(node->left);}if (node->right != nullptr) {parents[node->right->val] = node;findParents(node->right);}}void findAns(TreeNode* node, TreeNode* from, int depth, int k) {if (node == nullptr) {return;}if (depth == k) {ans.push_back(node->val);return;}if (node->left != from) {findAns(node->left, node, depth + 1, k);}if (node->right != from) {findAns(node->right, node, depth + 1, k);}if (parents[node->val] != from) {findAns(parents[node->val], node, depth + 1, k);}}public:vector<int> distanceK(TreeNode* root, TreeNode* target, int k) {// 从 root 出发 DFS,记录每个结点的父结点findParents(root);// 从 target 出发 DFS,寻找所有深度为 k 的结点findAns(target, nullptr, 0, k);return ans;}

完全二叉树 222. 完全二叉树的节点个数

    int countNodes(TreeNode* root) {if (root == nullptr) return 0;TreeNode* left = root->left;TreeNode* right = root->right;int leftHeight = 0, rightHeight = 0; // 这里初始为0是有目的的,为了下面求指数方便while (left) {  // 求左子树深度left = left->left;leftHeight++;}while (right) { // 求右子树深度right = right->right;rightHeight++;}if (leftHeight == rightHeight) {return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0}return countNodes(root->left) + countNodes(root->right) + 1;}

已知二叉树先序遍历跟后序遍历求二叉树的形状有多少种可能

//已知二叉树先序遍历跟后序遍历求二叉树的形状有多少种可能
//思路:
//      ①设共有n个结点;(设二叉树先序遍历序列为A[n],后序遍历序列为B[n])
//      ②遍历二叉树先序遍历,从第i(i>=2)个开始,使用find函数找到后序遍历B[i]中A[i]的位置x
//      ③比较A[i] == B[x] && A[i+1] == B[ x - 1 ](x>=1) 是否成立
//      ③如果成立则证明先序遍历第i+1个位置是一个单叶节点,也即二叉树的情况多了2倍#include <iostream>
#include <string>
using namespace::std;
int main() {string pre, post;cin >> pre >> post;int length = pre.size();int single_leaf_node_num = 1;for (int i = 0; i + 1 < length; ++i) {int j = post.find(pre[i]);if (j < 1) continue;if (pre[i + 1] == post[j - 1])single_leaf_node_num *= 2;}cout << single_leaf_node_num;return 0;
}

95. 不同的二叉搜索树 II

    vector<TreeNode*> generateTrees(int n) {if (!n) {return {};}return generateTrees(1, n);}vector<TreeNode*> generateTrees(int start, int end) {if (start > end) {return {nullptr};}vector<TreeNode*> allTrees;for (int i = start; i <= end; i++) {vector<TreeNode*> left = generateTrees(start, i-1);vector<TreeNode*> right = generateTrees(i+1, end);for (auto& l : left) {for (auto& r : right) {TreeNode* Tree = new TreeNode(i);Tree->left = l;Tree->right = r;allTrees.push_back(Tree);}}}return allTrees;}

二叉树的公共祖先 236. 二叉树的最近公共祖先

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root==NULL){return root;//空的找个屁,既然有那肯定是根}if(root==p||root==q){return root;//既然肯定有,而且有一个就是根,那么直接返回根,}//如果上面都不是,那么肯定在左右两边//根节点往下一层挪,直到根两个中一个相等为止TreeNode* left=lowestCommonAncestor(root->left,p,q);TreeNode* right=lowestCommonAncestor(root->right,p,q);//有三种情况,如果同在左边,那么肯定left不是空,右边为空//如果同在右边,那么right不是空,左边为空//如果两边都不为空。那么肯定是根节点if(left&&right) return root;return left? left:right;}

572. 另一棵树的子树

bool isSubtree(TreeNode* root, TreeNode* subRoot) {if (subRoot == nullptr) return true;if (root == nullptr) return false;return check(root, subRoot) || isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
bool check(TreeNode* root, TreeNode* subRoot) {if (root == nullptr && subRoot == nullptr) return true;if (!root || !subRoot) return false;if (root->val != subRoot->val) return false;return check(root->left, subRoot->left) && check(root->right, subRoot->right);
}

二分法

    int left = 0, right = n-1;int ans = 0;while (left <= right) {int mid = left + (right - left) / 2;if (check(nums, mid, k)) {ans = mid;right = mid - 1;} else {left = mid + 1;}}

搜索旋转数组 33. 搜索旋转排序数组 81. 搜索旋转排序数组 II

      bool search(vector<int> &nums, int target) {int n = nums.size();if (n == 0) {return false;}if (n == 1) {return nums[0] == target;}int l = 0, r = n - 1;while (l <= r) {int mid = (l + r) / 2;if (nums[mid] == target) {return true;}if (nums[l] == nums[mid] && nums[mid] == nums[r]) {++l;--r;} else if (nums[l] <= nums[mid]) {if (nums[l] <= target && target < nums[mid]) {r = mid - 1;} else {l = mid + 1;}} else {if (nums[mid] < target && target <= nums[n - 1]) {l = mid + 1;} else {r = mid - 1;}}}return false;}

寻找分割值、坐标 410. 分割数组的最大值 1011. 在 D 天内送达包裹的能力 1552. 两球之间的磁力

    int splitArray(vector<int>& nums, int m) {int n = nums.size();int maxNum = 0;int sum = 0;for (int i = 0; i < n; i++) {maxNum = max(maxNum, nums[i]);sum += nums[i];}int left = maxNum, right = sum;while (left <= right) {int mid = left + (right - left) / 2;if (check(nums, mid, m)) {right = mid-1;} else {left = mid+1;}}return left;}bool check(vector<int>& nums, int val, int m) {long long sum = 0;int cnt = 1;for (int i = 0; i < nums.size(); i++) {sum += nums[i];if (sum > val) {cnt++;sum = nums[i];}}return cnt <= m;}

寻找最小间隔匹配值 719. 找出第 k 小的距离对 786. 第 K 个最小的素数分数

    vector<int> kthSmallestPrimeFraction(vector<int>& A, int K) {double left = 0.0;double right = 1.0;int n = A.size();while(left<right){double mid = (right+left)/2.0;int cnt = 0;vector<int> maxi = {0, 1};int j = 0;for(int i=0;i<n;i++){while(j<n && A[i]>=mid*A[j])    j++;cnt += n-j;if(j<n && maxi[0]*A[j] < A[i]*maxi[1])  maxi = {A[i], A[j]};}if(cnt==K)  return maxi;if(cnt<K)   left = mid;else right = mid;}return {};}int smallestDistancePair(vector<int>& nums, int k) {sort(nums.begin(), nums.end());int n = nums.size();int left = 0, right = nums[n-1] - nums[0];while (left <= right) {int mid = left + (right - left) / 2;if (check(nums, mid, k)) {right = mid - 1;} else {left = mid + 1;}}return left;} bool check(vector<int>& nums, int dis, int k) {int n = nums.size(), j = 1;int cnt = 0; // 记录小于等于当前构造解 dist 的距离对数量for(int i = 0; i < n; i++) {while(j < n && nums[j] - nums[i] <= dis) j++;cnt += j - i - 1; // 处于 [i + 1, j] 中的数与 a[i]的距离均小于 dist}return cnt >= k;}

排序

快排 179. 最大数

    string largestNumber(vector<int>& nums) {vector<string> str;for (int i = 0; i < nums.size(); i++) {str.push_back(to_string(nums[i]));}quickSort(0, str.size()-1, str);string res = "";for (auto& num : str) {res += num;}int k = 0;while (res[k] == '0' && k < res.size()-1) {k++;}return res.substr(k);}void quickSort(int left, int right, vector<string>& nums) {if (left >= right) {return;}int i = left, j = right;while (i < j) {while (i < j && nums[j] + nums[left] <= nums[left] + nums[j]) {j--;}while (i < j && nums[i] + nums[left] >= nums[left] + nums[i]) {i++;}swap(nums[i], nums[j]);}swap(nums[left], nums[i]);quickSort(left, i-1, nums);quickSort(i+1, right, nums);}

堆排 9-2合并K个升序数组 215. 数组中的第K个最大元素

class Node {
public:      int row, col, val;     Node (int r, int c, int v) : row(r), col(c), val(v) {};     bool operator < (const Node &obj) const {return val > obj.val;     }
};
vector<int> mergekSortedArrays(vector<vector<int>>& arrays) {vector<int> result;         if (arrays.empty()) return result;          priority_queue<Node> queue;         for (int i = 0; i < arrays.size(); i++) {             if (!arrays[i].empty())                 queue.push(Node(i, 0, arrays[i][0]));         }          while (!queue.empty()) {             Node curr = queue.top();             queue.pop();             result.push_back(curr.val);             if (curr.col + 1 < arrays[curr.row].size())queue.push(Node(curr.row, curr.col + 1,arrays[curr.row][curr.col + 1]));         }                  return result;
}

215. 数组中的第K个最大元素

    int findKthLargest(vector<int>& nums, int k) {int heapsize = nums.size();BuildHeap(nums, heapsize);for (int i = nums.size()-1; i >= nums.size() - k + 1; i--) {swap(nums[0], nums[i]);Heapify(nums, 0, --heapsize);}return nums[0];}void Heapify(vector<int>& nums, int index, int heapsize) {int largest = index;int left = index * 2 + 1;int right = index * 2 + 2;if (left < heapsize && nums[left] > nums[largest]) {largest = left;}if (right < heapsize && nums[right] > nums[largest]) {largest = right;}if (largest != index) {swap(nums[largest], nums[index]);Heapify(nums, largest, heapsize);}}void BuildHeap(vector<int>& nums, int heapsize) {for (int i = heapsize / 2; i >= 0; i--) {Heapify(nums, i, heapsize);}}

动态规划

预处理再动规

1235. 规划兼职工作  354. 俄罗斯套娃信封问题 689. 三个无重叠子数组的最大和

    struct Work {int start, end, profit;Work(int _start, int _end, int _profit) : start(_start), end(_end), profit(_profit) {}};
public:int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {int n = startTime.size();vector<Work> mission(n+1, {0, 0, 0});for (int i = 0; i < n; i++) {mission[i] = Work(startTime[i], endTime[i], profit[i]);}sort(mission.begin(), mission.end(), [&](const Work& a, const Work& b) {return a.end < b.end;});vector<int> prev(n+1);for (int i = 1; i <= n; i++) {for (int j = i-1; j >= 0; j--) {if (mission[j].end <= mission[i].start) {prev[i] = j;break;}}}vector<int> dp(n+1);for (int i = 1; i <= n; i++)dp[i] = max(dp[i - 1], mission[i].profit + dp[prev[i]]);return dp[n];}

132. 分割回文串 II

    int minCut(string s) {if (s.size() == 0) return 0;int n = s.size();vector<int> dp(n, n);for (int i = 0; i < n; i++) {helper(dp, s, i, i);helper(dp, s, i, i+1);}return dp[n-1];}void helper(vector<int>& dp, string s, int i, int j) {int n = s.size();while (i >= 0 && j < n && s[i] == s[j]) {dp[j] = min(dp[j], (i==0 ? -1 : dp[i-1]) + 1);i--;j++;}}

前缀和

如果一个串只由1和0组成,并且其中1和0的个数相等,我们称之为偶子串。给出一个只由1和0组成的串,求这个串中的子串中,最长的偶子串。

统计前缀和得值,如果有相同得前缀和,说明这两次相同前缀和之间为0,即最长01字串

int main() {vector<int> nums = {1,0,0,1,1,1,0,1,1,0,0,1};int n = nums.size();for (int i = 0; i < n; i++) {if (nums[i] == 0) nums[i] = -1;}vector<int> sum(n+1, 0);for (int i = 1; i <= n; i++) {sum[i] = sum[i-1] + nums[i-1];}unordered_map<int, int> unmap;int ans = 0;for (int i = 1; i <= n; i++) {if (!unmap.count(sum[i])) unmap[sum[i]] = i;if (sum[i] == 0) {ans = max(ans, i);} else {ans = max(ans, i - unmap[sum[i]]);}}cout << ans;
}

1504. 统计全 1 子矩形

    int numSubmat(vector<vector<int>>& mat) {int m = mat.size();int n = mat[0].size();int sum = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (mat[i][j] == 0) continue;else {// 当mat[i][j]为1, 是该行的第一位时赋1, 否则则为前一位+1mat[i][j] = j >= 1 ? mat[i][j-1]+1 : 1;}}}for (int i = m - 1; i >= 0; i--) {for (int j = n - 1; j >= 0; j--) {if (mat[i][j] == 0) continue;int level = i; //记录层数int minHigh = mat[i][j]; // // 用于记录向上寻找过程中的最小值while (level >= 0 && mat[level][j] != 0) {// 向上寻找直到 处于第一层 或者 遇到0minHigh = min(minHigh, mat[level][j]); // 更新最小值, 即以最短的为标准sum += minHigh;level--;}}}return sum;

689. 三个无重叠子数组的最大和

689. 三个无重叠子数组的最大和 (前缀和)
class Solution {
public:vector<int> maxSumOfThreeSubarrays(vector<int>& nums, int k) {vector<int> sum;int cur = 0;for(int i = 0; i < k; ++i){cur += nums[i];}sum.push_back(cur);for(int i = k; i < nums.size(); ++i){cur += nums[i] - nums[i - k];sum.push_back(cur);}int n = sum.size();vector<int> left(n, 0), right(n, n - 1);for(int i = 1; i < n; ++i){if(sum[i] > sum[left[i - 1]]) left[i] = i;else left[i] = left[i - 1];}for(int i = n - 2; i >= 0; --i){if(sum[i] >= sum[right[i + 1]]) right[i] = i;else right[i] = right[i + 1];}int mx = 0;vector<int> ans(3);for(int i = k; i < n - k; ++i){if(mx < sum[i] + sum[left[i - k]] + sum[right[i + k]]){mx = sum[i] + sum[left[i - k]] + sum[right[i + k]];ans = {left[i - k], i, right[i + k]};}}return ans;}
};

直接动规

91. 解码方法

    int numDecodings(string& s) {int n = s.length();vector<int> dp(n+2);dp[n] = 1;if (s[n-1] != '0') {dp[n-1] = 1;}for (int i = n-2; i >= 0; i--) {if (s[i] == '0') continue;if ((s[i] - '0' ) * 10 + (s[i+1] - '0') <= 26) {dp[i] = dp[i+1] + dp[i+2];} else {dp[i] += dp[i+1];}}return dp[0];}

664. 奇怪的打印机 221. 最大正方形 139. 单词拆分

    int strangePrinter(string s) {int n = s.size();vector<vector<int>> dp(n, vector<int>(n, INT_MAX));for(int i = n-1; i >= 0; --i){dp[i][i] = 1;for(int j = i + 1; j < n; ++j){if(s[i] == s[j])dp[i][j] = dp[i][j-1];else //枚举区间内所有的可能性,取最优for(int k = i; k < j; ++k)dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);}}return dp[0][n-1];}

回溯

131. 分割回文串

class Solution {vector<vector<string>> res;vector<string> path;
public:vector<vector<string>> partition(string s) {backtracking(s, 0);return res;}void backtracking(string& s, int start_index) {if (start_index == s.size()) {res.push_back(path);}for (int i = start_index; i < s.size(); i++) {if (isPartition(s, start_index, i)) {path.push_back(s.substr(start_index, i-start_index+1));} else {continue;}backtracking(s, i+1);path.pop_back();}}bool isPartition(string& s, int start, int end) {while (start < end) {if (s[start] == s[end]) {start++;end--;} else {return false;}}return true;}
};

DFS

200. 岛屿数量 130. 被围绕的区域 329. 矩阵中的最长递增路径

    int numIslands(vector<vector<char>>& grid) {int count = 0;vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));for (int i = 0; i < grid.size(); i++) {for (int j = 0; j < grid[0].size(); j++) {if (grid[i][j] == '1' && !visited[i][j]) {dfs(grid, i, j, visited);count++;}}}return count;}void dfs(vector<vector<char>>& grid, int x, int y, vector<vector<bool>>& visited) {if (x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size() || grid[x][y]  == '0' || visited[x][y]) return ;visited[x][y] = true;dfs(grid, x, y+1, visited);dfs(grid, x, y-1, visited);dfs(grid, x+1, y, visited);dfs(grid, x-1, y, visited);}

301. 删除无效的括号

    unordered_set<string> ans;//答案中可能会重复 需要去重 如(() 删除第一个( 或删除第二个( 都是() 这也提示了优化方法void dfs(string &s, int u, string res, int cnt, int l, int r){//cnt为当前左-右的值 l为需要删除的左括号数量 r为右//cout<<res<<endl;if(u==s.size()){if(!cnt) ans.insert(res);return;}if(s[u]=='('){//在合法的条件下考虑删除dfs(s, u+1, res+'(', cnt+1, l, r);//不删if(l > 0) dfs(s,u+1,res,cnt,l-1,r);//删当前的左括号}else if(s[u]==')'){//在合法的条件下考虑删除if(cnt > 0) dfs(s,u+1,res+')',cnt-1,l,r);//不删if(r > 0) dfs(s,u+1,res,cnt,l,r-1);//删当前的右括号}else dfs(s,u+1,res + s[u],cnt,l,r);}vector<string> removeInvalidParentheses(string s) {int l = 0, r = 0;//l为当前左括号-右括号的值 r为需要删掉的右括号的值for(auto v : s){if(v=='(') l++;else if(v==')'){if(l <= 0) r++;//此时无效 右括号 必删else l--;//右括号+1 则左-右的值需要--   }  }//此时的l为需要删除的左括号数量 r为需要删除的右括号数量dfs(s,0,"",0,l,r);vector<string> ret;for(auto v : ans) ret.push_back(v);return ret;}

291. 单词规律 II

    bool wordPatternMatch(string pattern, string str) {if(pattern.size() > str.size())return false;// 记录字符对应的字符串unordered_map<char, string> hash;// 记录已经匹配的字符串,因为a、b不能匹配一样的字符串unordered_set<string> se;return track_back(pattern, str, 0, 0, hash, se);}bool track_back(string &pattern, string &str, int indexs, int indexp, unordered_map<char, string> &hash, unordered_set<string> &se){// 如果两个索引都达到末尾,那么久说明找到了一个正解// 如果是让你找到所有匹配的情况,那么就将bool换成voidif(indexs == str.size() && indexp == pattern.size())return true;else if(indexs == str.size() || indexp == pattern.size())return false;if(hash.count(pattern[indexp])){//existstring temp = hash[pattern[indexp]];// 将哈希表中的字符串和str中的字符进行匹配for(int i = 0; i < temp.size(); i++)if(indexs + i >= str.size() || str[indexs + i] != temp[i])return false;// 成功匹配,就继续往后进行遍历回溯return track_back(pattern, str, indexs + temp.size(), indexp + 1, hash, se);}else{//don't exist// 尝试各种长度的字符串,但最后要留下的字符串的长度要至少等于pattern中剩下的单词for(int i = 0; i + indexs <= str.size() - (pattern.size() - indexp); i++){string temp = str.substr(indexs, i + 1);// 如果有别的字符匹配了这个字符串,那么这个字符就不能这样匹配if(se.count(temp))continue;// 在匹配过的字符串集合中插入这个字符串se.insert(temp);// 哈希表中插入hash[pattern[indexp]] = temp;// 向后进行遍历if(track_back(pattern, str, indexs + i + 1, indexp + 1, hash, se)){return true;}// 第一个回溯的地方,这个字符匹配方式不对,那么就变换匹配法,将这个匹配法的字符串删除掉se.erase(temp);}// 第二个回溯的地方,将哈希表中的这个字符匹配数据删除掉hash.erase(pattern[indexp]);return false;}}

BFS和DFS结合

934. 最短的桥

class Solution {
public:vector<vector<int>> direction = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};void dfs(queue<pair<int, int>>& points, vector<vector<int>>& grid, int i, int j) {if (i < 0 || j < 0 || i >= grid.size() || j >= grid[0].size() || grid[i][j] == 2) return;if (grid[i][j] == 0) {points.push({i, j});return;}grid[i][j] = 2;dfs(points, grid, i-1, j);dfs(points, grid, i+1, j);dfs(points, grid, i, j-1);dfs(points, grid, i, j+1);}int shortestBridge(vector<vector<int>>& grid) {int m = grid.size();int n = grid[0].size();queue<pair<int, int>> points;bool flag = false;for (int i = 0; i < m; i++) {if (flag) break;for (int j = 0; j < n; j++) {if (grid[i][j] == 1) {dfs(points, grid, i, j);flag = true;break;}}}int step = 0;while (!points.empty()) {step++;int size = points.size();while (size--) {auto [x, y] = points.front();points.pop();for (int i = 0; i < 4; i++) {int nx = x + direction[i][0];int ny = y + direction[i][1];if (nx < 0 || ny < 0 || nx >= m || ny >= n) continue;if (grid[nx][ny] == 2) continue;if (grid[nx][ny] == 1) return step;points.push({nx, ny});grid[nx][ny] = 2;}}}return 0;}
};

判断是否是直角三角形

vector<vector<int>> matrix = {{1, 0, 0, 0, 0},{0, 1, 0, 0, 1},{0, 0, 0, 1, 1},{0, 0, 1, 1, 1},{0, 1, 1, 1, 1},{1, 1, 1, 1, 1}
};void dfs(vector<vector<int>>& grid, int x, int y, vector<vector<bool>>& visited) {if (x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size() || grid[x][y] == 0 || visited[x][y]) return;visited[x][y] = true;dfs(grid, x-1, y, visited);dfs(grid, x+1, y, visited);dfs(grid, x, y-1, visited);dfs(grid, x, y+1, visited);
}int main() {int m = matrix.size();int n = matrix[0].size();vector<vector<bool>> visited(m, vector<bool>(n, false));vector<vector<int>> dp_x = matrix;vector<vector<int>> dp_y = matrix;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (matrix[i][j] && i > 0 && j > 0) {dp_x[i][j] = dp_x[i][j-1] + matrix[i][j];dp_y[i][j] = dp_y[i-1][j] + matrix[i][j];}cout << "[" << dp_x[i][j] << "," << dp_y[i][j] << "]";}cout << "\n";}int count = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (matrix[i][j] != 0 && !visited[i][j]) {dfs(matrix, i, j, visited);count++;}}}cout << count;return 0;
}

BFS

788 · 迷宫II

    int shortestDistance(vector<vector<int>> &maze, vector<int> &start, vector<int> &destination) {int m = maze.size(), n = maze[0].size();queue<pair<int, int>> q;vector<vector<int>> memo(m, vector<int>(n, INT_MAX));vector<vector<int>> dirs {{1, 0}, {0, 1}, {0, -1}, {-1, 0}};q.push({start[0], start[1]});memo[start[0]][start[1]] = 0;while (!q.empty()) {auto pos = q.front();q.pop();for (auto dir : dirs) {int x = pos.first, y = pos.second;int dist = memo[x][y];while (isValid(maze, x + dir[0], y + dir[1])) {x += dir[0];y += dir[1];dist += 1;}if (dist < memo[x][y]) {memo[x][y] = dist;q.push({x, y});}}}return memo[destination[0]][destination[1]] == INT_MAX ?-1 : memo[destination[0]][destination[1]];}bool isValid(vector<vector<int>> &maze, int x, int y) {if (x < 0 || y < 0 || x >= maze.size() || y >= maze[0].size()) {return false;}if (maze[x][y] == 1) {return false;}return true;}

127. 单词接龙

    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {// 将vector转成unordered_set,提高查询速度unordered_set<string> wordSet(wordList.begin(), wordList.end());// 如果endWord没有在wordSet出现,直接返回0if (wordSet.find(endWord) == wordSet.end()) return 0;// 记录word是否访问过unordered_map<string, int> visitMap; // <word, 查询到这个word路径长度>// 初始化队列queue<string> que;que.push(beginWord);// 初始化visitMapvisitMap.insert(pair<string, int>(beginWord, 1));while(!que.empty()) {string word = que.front();que.pop();int path = visitMap[word]; // 这个word的路径长度for (int i = 0; i < word.size(); i++) {string newWord = word; // 用一个新单词替换word,因为每次置换一个字母for (int j = 0 ; j < 26; j++) {newWord[i] = j + 'a';if (newWord == endWord) return path + 1; // 找到了end,返回path+1// wordSet出现了newWord,并且newWord没有被访问过if (wordSet.find(newWord) != wordSet.end()&& visitMap.find(newWord) == visitMap.end()) {// 添加访问信息visitMap.insert(pair<string, int>(newWord, path + 1));que.push(newWord);}}}}return 0;}

1293. 网格中的最短路径

    int shortestPath(vector<vector<int>>& grid,int k){// seen表示访问到grid中点(x, y)经过的最少障碍物数量vector<vector<int>> seen(grid.size(),vector<int>(grid[0].size(),INT_MAX));queue<tuple<int,int,int>> q;  // (x, y, o)表示表示到达点(x,y)的障碍物数量为oint steps=0;q.push({0,0,0});              // 左上角(0,0)障碍物数量为0seen[0][0]=0;                 // 到达(0,0)经过的障碍物数量为0while(!q.empty()) {int size=q.size();while(size--) {auto [cx,cy,co]=q.front();q.pop();// bfs到达右下角的值一定是最短路径if(cx==(grid.size()-1)&&cy==(grid[0].size()-1))return steps;// 上、下、左、右四个方向扩展,得到不同的路径for(auto [dr,dc]:vector<pair<int,int>>{{1,0},{0,1},{-1,0},{0,-1}}) {int x=cx+dr;int y=cy+dc;if(x<0||y<0||x>=grid.size()||y>=grid[0].size()) // 判断边界条件continue;// grid[x][y]=1,在新的坐标点(x,y)处,障碍物数量o=co+1.// grid[x][y]=0,在新的坐标点(x,y)处,障碍物数量不变.int o=co+grid[x][y];// 在同一个steps内,这条路径到达点(x,y)的障碍物数量o// 大于等于之前路径障碍物数量seen[x][y],没有任何帮助,则抛弃该路径// 或者障碍物数量大于题目中给定能移除的障碍物数量k,不合法,抛弃该路径if(o>=seen[x][y]||o>k)continue;seen[x][y]=o;     // 到达(x,y)有一个更小的obstacle,更新(x,y)处seenq.push({x,y,o});  // (x,y,o)加入队列}}steps++;}return -1;}

1926. 迷宫中离入口最近的出口286. 墙与门 1926. 迷宫中离入口最近的出口

class Solution {vector<vector<int>> directions = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};int INF = 2147483647;
public:void wallsAndGates(vector<vector<int>>& rooms) {queue<pair<int, int>> que;int m = rooms.size();int n = rooms[0].size();for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (rooms[i][j] == 0) {que.push({i, j});}}}while (!que.empty()) {auto obj = que.front();que.pop();for (int i = 0; i < directions.size(); i++) {int x = obj.first + directions[i][0];int y = obj.second + directions[i][1];if (x < 0 || x >= m || y < 0 || y >= n || rooms[x][y] !=INF) continue;rooms[x][y] = rooms[obj.first][obj.second]+1;que.push({x, y});}}}
};

994. 腐烂的橘子

class Solution {
public:vector<vector<int>> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};int orangesRotting(vector<vector<int>>& grid) {queue<pair<int, int>> que;vector<vector<int>> dis(grid.size(), vector<int>(grid[0].size(), -1));int cnt = 0;int n = grid.size(), m = grid[0].size(), ans = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == 2) {que.push({i, j});dis[i][j] = 0;} else if (grid[i][j] == 1) cnt+=1;}}while (!que.empty()) {auto obj = que.front(); que.pop();for (int i = 0; i < 4; i++) {int nx = obj.first + directions[i][0];int ny = obj.second + directions[i][1];if (nx < 0 || nx >= n || ny < 0 || ny >= m || ~dis[nx][ny] || !grid[nx][ny]) continue;dis[nx][ny] = dis[obj.first][obj.second]+1;que.push({nx, ny});if (grid[nx][ny] == 1) {cnt -= 1;ans = dis[nx][ny];if (!cnt) break;}}}return cnt ? -1 : ans;}
};

模拟

224. 基本计算器

class Solution {
private:bool isdigit(char c)//判断是否是数字{return c>='0'&&c<='9';}int index;string S;
public:int calcu() {stack<int>stk;long long num=0;char oper='+';//初始符号位为'+'while(index<S.size()){char c=S[index++];if(isdigit(c))num=num*10+c-'0';//因为num先乘10再加c,如果num类型不是long long,则可能会溢出if(c=='(')//遇到左括号,开始递归计算num=calcu();if((!isdigit(c)&&c!=' ')||index>=S.size())//说明遇到了符号位或者到达了字符串的末尾{int tmp;switch(oper)//注意这里参与运算的不是当前遇到的符号位,而是之前放在oper内的符号位!{case '+':stk.push(num);break;case '-':stk.push(-num);break;case '*':tmp=stk.top();tmp*=num;stk.pop();stk.push(tmp);break;case '/':tmp=stk.top();tmp/=num;stk.pop();stk.push(tmp);break;}num=0;oper=c;//更新符号位}if(c==')')//遇到右括号,本轮计算结束break;}int sum=0;while(!stk.empty())//求和{sum+=stk.top();stk.pop();}return sum;}public:int calculate(string s) {index=0;S=s;return calcu();}
};

838. 推多米诺

    string pushDominoes(string dominoes) {int n = dominoes.size();int start = 0, end = 0;dominoes = 'L' + dominoes + 'R';for (; start < dominoes.size(); start++) {if (dominoes[start] != '.') {end = start+1;while (end < dominoes.size() && dominoes[end] == '.') {end++;}if (dominoes[start] == 'L' && dominoes[end] == 'L') {for (int i = start; i <= end; i++) {dominoes[i] = 'L';}} else if (dominoes[start] == 'R' && dominoes[end] == 'R') {for (int i = start; i <= end; i++) {dominoes[i] = 'R';}} else if (dominoes[start] == 'R' && dominoes[end] == 'L') {int r = start;int l = end;while (r < l) {dominoes[r] = 'R';r++;dominoes[l] = 'L';l--;}}start = end-1;}}return dominoes.substr(1, n);}

单调栈

85. 最大矩形 84. 柱状图中最大的矩形 85可求出前缀行最大矩阵,计算最大的矩阵,调用84的函数

b[i]定义为a[i]左边离自己最近的比自己小的数字的下标

    int largestRectangleArea(vector<int>& heights) {int n = heights.size();if (n == 1) return heights[0];stack<int> st;int res = 0;for (int i = 0; i < n; i++) {while (!st.empty() && heights[st.top()] >= heights[i]) {int cur = heights[st.top()];st.pop();int w = i;if (!st.empty()) w = i - st.top() - 1;res = max(w * cur, res);}st.push(i);}while (!st.empty()) {int length = heights[st.top()];st.pop();int weight = n;if (!st.empty()) {weight = n - st.top() - 1;}res = max(res, length * weight);}return res;}

1438. 绝对差不超过限制的最长连续子数组

    int longestSubarray(vector<int>& nums, int limit) {deque<int> max_que, min_que;int n = nums.size();int left = 0, right = 0, res = 0;while (right < n) {while (!max_que.empty() && max_que.back() < nums[right]) {max_que.pop_back();}while (!min_que.empty() && min_que.back() > nums[right]) {min_que.pop_back();}max_que.push_back(nums[right]);min_que.push_back(nums[right]);right++;while (!max_que.empty() && !min_que.empty() && max_que.front() - min_que.front() > limit) {if (max_que.front() == nums[left]) {max_que.pop_front();}if (min_que.front() == nums[left]) {min_que.pop_front();}left++;}res = max(res, right - left);}return res;}

贪心单调栈

16 .移掉 K 位数字

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小

vector<char> stk;
for (auto& digit: num) {while (stk.size() > 0 && stk.back() > digit && k) {stk.pop_back();k -= 1;}stk.push_back(digit);
}
for (; k > 0; --k) {stk.pop_back();
}
string ans = "";
bool isLeadingZero = true;
for (auto& digit: stk) {if (isLeadingZero && digit == '0') {continue;}isLeadingZero = false;ans += digit;
}
return ans == "" ? "0" : ans;
}

最小堆

295. 数据流的中位数

    priority_queue<int, vector<int>, less<int>> maxHeap;priority_queue<int, vector<int>, greater<int>> minHeap;/** initialize your data structure here. */MedianFinder() {}void addNum(int num) {if (maxHeap.empty()) {maxHeap.push(num);} else if (num > maxHeap.top()) {minHeap.push(num);} else {maxHeap.push(num);}if (minHeap.size() > maxHeap.size()) {int rightTop = minHeap.top();minHeap.pop();maxHeap.push(rightTop);} else if (minHeap.size() + 1 < maxHeap.size()) {int leftTop = maxHeap.top();maxHeap.pop();minHeap.push(leftTop);}}double findMedian() {if (maxHeap.size() > minHeap.size()) {return maxHeap.top();} else {return (maxHeap.top() + minHeap.top()) / 2.0;}}

扫描线

218. 天际线问题 遇到拐点进行统计

    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {vector<vector<int>> heights;for (int i = 0; i < buildings.size(); i++) {heights.push_back({buildings[0], -buildings[2]});heights.push_back({buildings[1], buildings[2]});}sort(heights.begin(), heights.end());multiset<int> mulset;vector<vector<int>> res;int cur_height = 0;int pre_height = 0;for (pair<int, int> height : heights) {if (height.second < 0) {mulset.insert(-height.second);} else {mulset.erase(mulset.find(height.second));}cur_height = *mulset.rbegin();if (cur_height != pre_height) {res.push_back({height.first, cur_height});pre_height = cur_height;}}return res;}

850. 矩形面积 II

    const static int MOD = 1e9 + 7;int queryWidth(multiset<pair<int, int>>& activate) {int res = 0;int maxX = -1;for (auto [x1, x2] : activate) {maxX = max(maxX, x1);res += max(0, x2 - maxX);maxX = max(maxX, x2);}return res;}public:int rectangleArea(vector<vector<int>>& rectangles) {vector<vector<int>> rec;for (auto rectangle : rectangles) {rec.push_back({rectangle[1], 0, rectangle[0], rectangle[2]});rec.push_back({rectangle[3], 1, rectangle[0], rectangle[2]});}sort(rec.begin(), rec.end());int res = 0;int lastY = rec[0][0];multiset<pair<int, int>> activate;for (const vector<int>& rectangle : rec) {int y = rectangle[0];int state = rectangle[1];int x1 = rectangle[2];int x2 = rectangle[3];res = (res + (long long)queryWidth(activate) * (y - lastY)) % MOD;lastY = y;if (state == 0) {activate.insert({x1, x2});} else {activate.erase(activate.find({x1, x2}));}}return res;}

贪心

最多可以参加的会议数目

sort(nums.begin(), nums.end(), [](const vector<int>& a, const vector<int>& b) {return a[1] < b[1];
});
int min_d = INT_MAX;
int max_d = INT_MIN;
for (const auto& e : nums) {min_d = min(min_d, e[0]);max_d = max(max_d, e[1]);
}
set<int> s;
for (int i = min_d; i <= max_d; i++) {s.insert(i);
}int ans = 0;
for (const auto& e : nums) {auto it = s.lower_bound(e[0]); // 函数用于在指定区域内查找不小于目标值的第一个元素。if (it == s.end() || *it > e[1]) continue;s.erase(it);ans++;
}
return ans;

1824. 最少侧跳次数

    int minSideJumps(vector<int>& obstacles) {int n = obstacles.size();int num = 2;int res = 0;for(int i = 0; i < n-1;){//若当前跑道无障碍一直前进if(obstacles[i+1] != num){i++;continue;}//other和another为另外两条跑道编号int other = (num + 1) % 3, another = (num + 2) % 3;other = (other == 0)?3:other;another = (another == 0)?3:another;int t = i;//计算测跳道other号跑道时遇到的第一个障碍位置while(t < n && obstacles[t] != other){t++;}//计算测跳道another号跑道时遇到的第一个障碍位置while(i < n && obstacles[i] != another){i++;}//选择靠后的那条跑道,更新当前跑道序号和当前位置。if(t > i){num = other;}else{num = another;}i = max(t, i) - 1;res++;}return res;}

45. 跳跃游戏 II

    int jump(vector<int>& nums) {int cover = 0;int cur_cover = 0;int times = 0;if (nums.size() == 1) return 0;for (int i = 0; i < nums.size() - 1; i++) {cover = max(i + nums[i], cover);if (i == cur_cover) {cur_cover = cover;times++;}}return times;}

1838. 最高频元素的频数

    int maxFrequency(vector<int>& nums, int k) {sort(nums.begin(), nums.end());int n = nums.size();long long total = 0;int l = 0, res = 1;for (int r = 1; r < n; ++r) {total += (long long)(nums[r] - nums[r - 1]) * (r - l);while (total > k) {total -= nums[r] - nums[l];++l;}res = max(res, r - l + 1);}return res;}

1423. 可获得的最大点数

int maxScore(vector<int>& cardPoints, int k) {//每一步拿牌都是从头或者尾拿, 所以最终剩余的牌一定是连续的, 所以本题换个思路://从一个长度为n的数组中找出一个长度为n-k, 累加值最小的连续子序列[i, j], 那么剩余元素[0, i), (j, n)就是本题需要的解.int n = cardPoints.size();int windowsSize = n - k;int sum = 0;for (int i = 0; i < windowsSize; i++) {sum += cardPoints[i];}int all = 0;for (auto& cardPoint : cardPoints) {all += cardPoint;}int min_sum = sum;for (int i = windowsSize; i < n; i++) {sum += cardPoints[i] - cardPoints[i-windowsSize];min_sum = min(min_sum, sum);}return all - min_sum;
}

528. 按权重随机选择

class Solution {
public:int range = 0;vector<int> weights;Solution(vector<int>& w) {for (auto w_ : w) {weights.push_back(range);range += w_;}}int pickIndex() {int rnd = rand() % range;int i = 0;for (i = 1; i < weights.size(); i++) {if (rnd < weights[i]) {break;}}return i-1;}
};链接:https://leetcode-cn.com/problems/random-pick-with-weight/solution/wei-rao-li-lun-ke-neng-shi-gong-cheng-zh-fh0r/

递增数

// 889string strN = to_string(n);         int i = 1;         while (i < strN.length() && strN[i - 1] <= strN[i]) {             i += 1;         }         if (i < strN.length()) {             while (i > 0 && strN[i - 1] > strN[i]) {                 strN[i - 1] -= 1;                 i -= 1;             }             for (i+=1; i < strN.length(); ++i) {                 strN[i] = '9';             }         }         return stoi(strN);
}
// 789
int findIncreaingDigits(long long N) {int pos = 0;if (N < 10) {return N-1;}string s = to_string(N);for(int i  = 1; i < s.size(); i++) {if (s[i] - s[i-1] > 1) {pos = i;} else if (s[i] <= s[i-1]) {break;}}string output = "";int len = s.size();for(int j = 0; j < pos; j++) {output += s[j];}int v = min(9 - (len - pos) + 1, (s[pos]-'0')-1);output += (v + '0');int start = 9 - (len - pos) + 2;for(int j = pos+1; j < len; j++) {output += (start + '0');start++;}return stoi(output);
}

386 按字典序输出1-n之间的数

vector<int> lexicalOrder(int n) {for (int i = 1; i <= 9; i++) {dfs(n, i);}return ans;
}
void dfs(int n, int num) {if (num > n) return;ans.push_back(num);for (int i = 0; i <= 9; i++) {dfs(n, num * 10 + i);}
}

投票法

169. 多数元素

    int majorityElement(vector<int>& nums) {int n = nums.size();int voted = nums[0];int cnt = 1;for(int i = 1; i < n; i++) {if(nums[i] == voted) {cnt++;} else {cnt--;}if(cnt == 0) {cnt = 1;voted = nums[i];}}return voted;}

字典序下一个排列

​​​​​​31. 下一个排列

    void nextPermutation(vector<int>& nums) {int i = nums.size() - 2;while (i >= 0 && nums[i] >= nums[i + 1]) {i--;}if (i >= 0) {int j = nums.size() - 1;while (j >= 0 && nums[i] >= nums[j]) {j--;}swap(nums[i], nums[j]);}reverse(nums.begin() + i + 1, nums.end());}

字典序

440. 字典序的第K小数字

    int findKthNumber(int n, int k) {ll cur = 1; //作为一个指针,指向当前所在位置,当p==k时,也就是到了排位第k的数ll prefix = 1;//前缀while (cur < k) {ll cnt = get_count(prefix, n);//获得当前前缀下所有子节点的和if (cur + cnt > k) {  //第k个数在当前前缀下prefix *= 10; cur++; //把指针指向了第一个子节点的位置,比如11乘10后变成110,指针从11指向了110} else if (cur + cnt <= k) {//第k个数不在当前前缀下prefix++;cur += cnt;//注意这里的操作,把指针指向了下一前缀的起点}}return prefix;}ll get_count(ll prefix, ll n) {ll cnt = 0;ll cur = prefix;ll next = prefix + 1; //下一个前缀for (; cur <= n; cur*=10, next*=10) {cnt += min(n+1, next) - cur;// 如果说刚刚prefix是1,next是2,那么现在分别变成10和20// 1为前缀的子节点增加10个,十叉树增加一层, 变成了两层// 如果说现在prefix是10,next是20,那么现在分别变成100和200,// 1为前缀的子节点增加100个,十叉树又增加了一层,变成了三层}return cnt;}

智力题

1224. 最大相等频率

    int maxEqualFreq(vector<int>& nums) {/*最后一题,考虑四种情况:
1、前缀数组中所有数字的频率只有两种,设为A和B,其中A=B+1,且只有一个数字频率为A;
2、前缀数组中所有数字的频率只有两种,其中只有一个数字的频率为1,其他数字的频率都大于1且相等;
3、整个数组的数字的频率都是1;
4、整个数组都是同一个数字。对应的处理:
1、把前缀数组中频率为A的数字删去1个即可;
2、把前缀数组中频率为1的数字删去即可;
3、整个数组删去任意一个数字都可;
4、整个数组删去任意一个数字都可。或许代码中的 fre[maxcnt]==1&&1+fre[maxcnt-1](maxcnt-1)==i+1) 比较难理解,
我们要先知道fre是怎么存储的,例如我们已经遍历了[5,1,1,5,5],
那此时fre[1]=2(包含了1和5),fre[2]=2(包含了1和5),fre[3]=1(只包含5)。
所以上面的 1+fre[maxcnt-1](maxcnt-1)==i+1 表示为 (fre[maxcnt-1]-1)*(maxcnt-1) + (maxcnt)==i+1 即频率为B的数字总数 + 频率为A的数字总数。*/vector<int> cnt(100001,0),fre(100001,0);    //cnt计算数字出现的频率,fre[i]=j表示有j个数字频率为iint maxcnt=0,ans=0;for(int i=0;i<nums.size();++i){int num=nums[i];++cnt[num];++fre[cnt[num]];maxcnt=max(maxcnt,cnt[num]);//第一、四种情况 || 第二种情况 (i+1就是目前的前缀数组长度)if((fre[maxcnt]==1 && 1+fre[maxcnt-1]*(maxcnt-1)==i+1) || (fre[maxcnt]*maxcnt+1==i+1))ans=i+1;}if(maxcnt==1)   //第三种情况return nums.size();return ans;}

判断为树

class Solution {bool validTree(int n, int[][] edges) {if (edges.length != n-1) return false;int[] roots = new int[n];for(int i=0; i<n; i++) roots[i] = i;for(int i=0; i<edges.length; i++) {int root1 = root(roots, edges[i][0]);int root2 = root(roots, edges[i][1]);if (root1 == root2) return false;roots[root2] = root1;}return true;}int root(int[] roots, int id) {if (id == roots[id]) return id;return root(roots, roots[id]);}
}

KMP

字符串匹配 A串长n B串长为m 以A每个位置为起点长为m的子串 排序后与B串做精确匹配,问有多少次精确匹配

void getNext(int* next, const string& s) {int j = 0;next[0] = 0;for(int i = 1; i < s.size(); i++) {while (j > 0 && s[i] != s[j]) {j = next[j - 1];}if (s[i] == s[j]) {j++;}next[i] = j;}
}
int strStr(string haystack, string needle) {if (needle.size() == 0) {return 0;}int next[needle.size()];getNext(next, needle);int j = 0;for (int i = 0; i < haystack.size(); i++) {while(j > 0 && haystack[i] != needle[j]) {j = next[j - 1];}if (haystack[i] == needle[j]) {j++;}if (j == needle.size() ) {return (i - needle.size() + 1);}}return -1;
}

滑窗法

76. 最小覆盖子串

    string minWindow(string s, string t) {vector<int> need(128);int count = 0;for (char ch : t) {need[ch]++;count++;}int left = 0; int right = 0; int idx = 0; int size = INT_MAX; int start = 0;while (right < s.size()) {if (need[s[right]] > 0) {count--;}need[s[right]]--;if (count == 0) {while (left < right && need[s[left]] < 0) {need[s[left++]]++;}if (right - left + 1 < size) {start = left;size = right - left + 1;}need[s[left++]]++;count++;}right++;}return size == INT_MAX ? "" : s.substr(start, size);}

​​​​​​通过删除字母匹配到字典里最长单词

    string findLongestWord(string s, vector<string>& dictionary) {string res = "";for (string& str : dictionary) {if (isSubstr(s, str)) {if (str.size() > res.size() || (str.size() == res.size() && str < res)) {res = str;}}}return res;}bool isSubstr(string s, string str) {int j = 0; for (int i = 0; i < s.size() && j < str.size(); i++) {if (s[i] == str[j]) j++;}return j == str.size();}

340. 至多包含 K 个不同字符的最长子串

    int lengthOfLongestSubstringKDistinct(string s, int k) {if (k == 0) return 0;int n = s.size();int left = 0;int right = 0;int ans = 0;unordered_map<char, int> dir;for (; right < n; right++) {dir[s[right]]++;while (dir.size() > k) {dir[s[left]]--;if (dir[s[left]] == 0) dir.erase(s[left]);left++;}ans = max(ans, right - left + 1);}return ans;}

给任意 str,删除任意字符后,求出最长的 4k 长度的 PONY(每个字母 k 长度,如 PPOONNYY)是多长。

    string str = "nnpposoonnansssnwnyasaysy";int n = str.size();string pony = "pony";int p = 0;int k = INT_MAX;int i = 0;char pre_char = '0';vector<int> frequency(4, 0);while (i < n) {if (str[i] == pony[p] && pre_char != str[i]) {pre_char = pony[p];p++;}if (str[i] == pony[p-1]) {frequency[p-1]++;}i++;}for (int i = 0; i < frequency.size(); i++) {k = min(k, frequency[i]);}cout << k * 4;

数学题

10. 判断点在三角形内部

struct Point {double x;double y;
};
double product(Point p1,Point p2,Point p3) {//p1p2 向量表示为 (p2.x-p1.x,p2.y-p1.y)//p1p3 向量表示为 (p3.x-p1.x,p3.y-p1.y)return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x);
}
bool isInTriangle(Point p1,Point p2,Point p3,Point o) {//保证p1,p2,p3是逆时针顺序if(product(p1, p2, p3)<0) return isInTriangle(p1,p3,p2,o);if(product(p1, p2, o)>0 && product(p2, p3, o)>0 && product(p3, p1, o)>0)return true;return false;
}

39. 圆内随机取点

class Solution {
public:double rad, xc, yc;//c++11 random floating point number generationmt19937 rng{random_device{}()};uniform_real_distribution<double> uni{0, 1};Solution(double radius, double x_center, double y_center) {rad = radius, xc = x_center, yc = y_center;}vector<double> randPoint() {double d = rad * sqrt(uni(rng));double theta = uni(rng) * (2 * M_PI);return {d * cos(theta) + xc, d * sin(theta) + yc};}
};

概率题 放球

现在有50个红球,50个蓝球,给小明两个袋子,一个袋子能装任意个球(0~100)。 现由小明将这100个球,以一定方法装入这两个袋子。找另找一个不明真相的路人,闭眼,随机从两个袋子中随机选择一个袋子并摸一个球。要使得他摸出红球的概率最高,小明分配这100个球的最佳方案是____。

取到红球的概率为 0.5*bag1+0.5*bag2 =0.5(bag1+bag2)

当两个袋子中取到红球的概率和最大时,路人摸到红球的概率最高

bag1放一个红球概率 bag1=1

bag2放剩下的球概率 bag2=49/99≈0.5

取到红球的概率约为0.5(1+0.5)=3/4 为概率最大情况

一道机器学习岗位面试题:平均要抛多少次硬币,才能出现连续两次正面向上?

458. 可怜的小猪

50桶水,其中1桶有毒。有n头猪,一天可以喝两次水,请问在一天内可以找出有毒的那桶水的最小的n

    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {int states = minutesToTest / minutesToDie + 1;return ceil(log(buckets) / log(states));}

圆上等概率的选3个点 构成锐角三角形的概率 (现场推导)

  1. 求圆上任取三个点组成锐角三角形的概率(答案:1/4,参考:https://zhuanlan.zhihu.com/p/69530841) (每个锐角三角形,将三个顶点依次和圆心做对称可以映射到三个钝角三角形,说明锐角三角形的概率和钝角三角形的概率是1:3,所以是1/4) (等价为:任取三角形,圆心落在三角形内、外、边上的概率各是多少) 圆上任选三点组成三角形,求三角形的面积的数学期望。 (求面积期望可以分成锐角三角形和钝角三角形两种情况,锐角三角形从圆心将三角形分成三份,面积是三份和;钝角三角形分开后,面积是两份和减去一份差。三角形面积sinα / 2,期望值为1/π,所以结果就是(1/4 * 3 + 3/4) / π = 3/(2π)) 强化版:在一个球面任取4个点,请问这4个点构成的4面体会经过球心的概率。(1/8) (面积法,大三角形面积,等于三个小三角形面积之和,注意浮点数,面积由海伦公式求解) (求直线方程,判断点位于三条直线的什么方向) (矢量叉乘,判断点是否在线段AB的左侧)

leetcode总结相关推荐

  1. leetcode 5. Longest Palindromic Substring 字符串中的最长回文数 逐步从O(n^2)优化至线性时间

    题目 解析 思路一 暴力解法 思路二 指针+最大长度 思路3 由中间至两边找回数 思路4 Manacher's algorithm 线性时间 参考文档 题目 链接 给定一个字符串 s,找到 s 中最长 ...

  2. LeetCode 10. Regular Expression Matching python特性、动态规划、递归

    前言 本文主要提供三种不同的解法,分别是利用python的特性.动态规划.递归方法解决这个问题 使用python正则属性 import reclass Solution2:# @return a bo ...

  3. leetcode Longest Substring with At Most Two Distinct Characters 滑动窗口法

    题目解析 代码如下 题目解析 这一题是一道会员的题目,题目介绍如下: Given a string, find the length of the longest substring T that c ...

  4. leetcode 3. Longest Substring Without Repeating Characters 最长非重复子串的长度 滑动窗口法

    题目链接 根据我们之前介绍的滑动窗口法的解法: 滑动窗口法详解 leetcode 438. Find All Anagrams in a String 滑动窗口法 这题,我们不难解决,使用之前的模板. ...

  5. leetcode:2680 Remove Duplicates from Sorted Array 删除数组中的重复元素

    leetcode:26 对数组元素进行去重,使得原数组重复元素最多保留1个 限制: 我们不可以额外分配数组,必须保持空间复杂度为O(1) 这个并不难实现: class Solution(object) ...

  6. LeetCode简单题之二进制表示中质数个计算置位

    题目 给你两个整数 left 和 right ,在闭区间 [left, right] 范围内,统计并返回 计算置位位数为质数 的整数个数. 计算置位位数 就是二进制表示中 1 的个数. 例如, 21 ...

  7. LeetCode简单题之删除字符使字符串变好

    题目 一个字符串如果没有 三个连续 相同字符,那么它就是一个 好字符串 . 给你一个字符串 s ,请你从 s 删除 最少 的字符,使它变成一个 好字符串 . 请你返回删除后的字符串.题目数据保证答案总 ...

  8. LeetCode简单题之找出两数组的不同

    题目 给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,请你返回一个长度为 2 的列表 answer ,其中: answer[0] 是 nums1 中所有 不 存在于 nums2 中的 ...

  9. LeetCode中等题之区域和检索 - 数组可修改

    题目 给你一个数组 nums ,请你完成两类查询. 其中一类查询要求 更新 数组 nums 下标对应的值 另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nu ...

  10. LeetCode简单题之整理字符串

    题目 给你一个由大小写英文字母组成的字符串 s . 一个整理好的字符串中,两个相邻字符 s[i] 和 s[i+1],其中 0<= i <= s.length-2 ,要满足如下条件: 若 s ...

最新文章

  1. 判断字符串不包含某个字符php,java判断字符串是否包含某个字符的方法
  2. 永信至诚CTO张凯:CloudStack+Docker构建云端信息安全实验场
  3. Python 实现类似sed命令的字符串替换小程序
  4. ue4相机_纳格数字创意课程介绍 |UE4虚拟现实技术室内方向
  5. Collections.unmodifiableMap
  6. OA服务器重装操作系统恢复配置
  7. js与java的区别,JavaScript与Java的区别是什么呀?
  8. networkx 标签_networkx绘制BA无标度网络
  9. 武汉大学计算机学院参考书目,2020武汉大学计算机与软件工程考研初试科目、参考书目及复试详情...
  10. windows php apc 安装,php-apc 安装
  11. java dayofweek_Java日期时间API系列22-----Jdk8中java.time包中的新的日期时间API类,Month月份和DayOfWeek星期的计算。...
  12. MSTP拓扑计算过程与实验
  13. express to eSATA卡测试
  14. spring cloud SnakeYAML RCE复现
  15. 计算机打印病历格式要求,计算机打印病历书写要求
  16. SAP PS 第19节 里程碑开票
  17. Java六种异常处理的陋习
  18. JAVA 赛码网|笔试时输入输出的控制
  19. PRBS码是什么?PRBS生成原理介绍(转)
  20. 封神台----尤里的复仇I-第一章:为了女神小芳

热门文章

  1. 人工智能之基于多变量线性回归的房屋销售价格预测详细解决方案
  2. 20. Python的字典嵌套
  3. mysql的partition_MySQL分区(Partition)
  4. ReactNative的SDK打包后给到其他项目集成
  5. 淘宝店群玩法,双十一商家自运营,淘宝店群好处,建淘宝店群门槛条件
  6. 02 【uni-app起步】
  7. 利用定时/计数器T1产生定时时钟,由P1口控制8个发光二极管,使8个提示灯依次一个一个闪动,闪动频率为10次每秒(8个灯亮一遍为一个周期),循环
  8. java 环境变量 locale_locale的设定及其LANG、LC_ALL、LANGUAGE环境变量的区别 zz
  9. 电商平台减少服务器性能,电商平台服务器数据安全灾备方案规划.doc
  10. 第1章第2节:PowerPoint的选项卡 [PowerPoint精美幻灯片实战教程]