求模运算的性质:
(a * b) % k = (a % k)(b % k) % k;
result = []
def backtrack(路径, 选择列表):
if 满足条件列表:
result.add(路径)
return
for选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
int binarySearch(int[] nums, int target) {
int left = 0, right = ...;
while (...) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
void slidingWindow(string s, string t) {
unordered_map need, window;
for (char c: t) {
need[c]++;
}
int left = 0, right = 0;
int valid = 0;
while (right < s.size()) {
char c = s[right++];
... // 进行窗口更新的操作
// debug的位置
// 判断左窗口是否要收缩。
while (window needs shrink) {
char d = s[left++];
...// 进行窗口内数据的一系列更新
}
}
}
int BFS(Node start, Node target) {
queue q;
set visited;
q.push(start);
visited.insert(start);
int step = 0;
while (!q.empty()) {
int sz = q.size();
for (int i = 0; i < sz; ++i) {
Node cur = q.front();
if (cur == target) {
return step;
}
// 将cur的相邻节点加入队列
for (Node x : cur.adj()) {
if (x not in visited) {
q.push(x);
visited.insert(x);
}
}
}
++step;
}
}
for 状态1 in 状态1的所有状态:
for 状态2 in 状态2的所有状态:
for ...
dp[状态1][状态2][...] = 择优(选择1, 选择2, ...)
int n = array.size();
int[] dp = new int[n];
for (int i = 1; i < n; ++i) {
for (int j = 1; j < i; ++j) {
dp[i] = 最值(dp[i], dp[j] + ...)
}
}
// dp[i]的定义:针对单个字符串/数组,如最长递增子序列。
// 在子数组arr[0...i]中,我们要求的子序列(例如:最长递增子序列)的长度是dp[i].
int n = array.size();
int[] dp = new int[n][n];
for (int i = 1; i < n; ++i) {
for (int j = 1; j < n; ++j) {
if (arr[i] == arr[j]) {
dp[i][j] = dp[i][j] + ...;
} else {
dp[i][j] = 最值(...);
}
}
}
//dp[i][j]的含义:
// case1:涉及两个字符串/数组时:
// 在子数字arr1[0...i]和子数组arr2[0...j]中,我们要求的子序列(如最长公共子序列)的长度为dp[i][j];
// case2:只设计一个字符串/数组时:
// 在arr[i...j]中,我们要求的子序列(例如最长回文子序列)的长度为dp[i][j].
int intervalSchedule(vector> intvs) {
if (intvs.empty()) {
return 0;
}
// 按end升序排序
sotr(intvs.begin(), intvs.end(), [](vector a, vector b) {
return b[1] > a[1];
});
// 至少有一个区间不相交
int count = 1;
// 排序后,第一个区间就是x
int x_end = intvs[0][1];
for (auto interval : intvs) {
int start = interval[0];
if (start >= x_end) {
// 找到下一个选择区间
++count;
x_end = interval[1];
}
}
return count;
}
class Solution {
public:
int maxProfit(int k, vector& prices) {
// 备注:买进来和卖出去合起来算交易一次。
if (k < 1 || prices.size() < 2) {
return 0;
}
// dp[i][j][0]:第i天,经过最多j次交易,手里未持有股票的利润。
// dp[i][j][1]:第i天,经过最多j次交易,手里持有股票的利润。
vector>> dp(prices.size(),
vector>(k + 1, make_pair(0, 0)));
for (int i = 1; i <= k; ++i) {
dp[0][i].second = -prices[0];
}
for (int i = 1; i < prices.size(); ++i) {
for (int j = 1; j <= k; ++j) {
dp[i][j].first = max(dp[i - 1][j].first,
dp[i - 1][j].second + prices[i]);
dp[i][j].second = max(dp[i - 1][j].second,
dp[i - 1][j - 1].first - prices[i]);
}
}
return dp[prices.size() - 1][k].first;
}
};
class Node {
public:
int key, val;
Node* next, prev;
Node(int k, int v) {
key = k;
val = v;
}
};
// 构建双向链表
class DoubleList {
public:
// 在链表头部添加节点x
void addFirst(Node *x);
// 删除链表中的x节点
void remove(Node *x);
// 删除链表中最后一个节点,并返回
Node* removeLast();
// 返回链表长度
int size();
};
class LRUCache {
private:
Map my_map; // 映射表
DoubleList cache; // 双向链表
int cap; // 最大容量
public:
LRUCache(int capacity) {
this.cap = capacity;
}
int get(int key) {
if (my_map.count(key) == 0) {
return -1;
}
int val = my_may.get(key)->val;
// 利用put方法把该数据提前
put(key, val);
return val;
}
void put(int key, int val) {
// 先把新节点做出了
Node* x = new Node(key, val);
if (my_map.count(key)) {
// 删除旧的节点,新的插到头部
cache.remove(my_map.get(key));
cache.addFirst(x);
// 更新map中的数据
map.put(key, x);
} else {
if (cap == cache.size()) {
// 删链表最后一个数据
Node* last = cache.removeLast();
my_map.remove(last->key);
}
// 添加到头部
cache.addFirst(x);
map.put(key, x);
}
}
};
// 通用框架
void traverse(TreeNode* root) {
// root需要做什么,在这里做
// 其他不用root操心,抛给框架
traverse(root->left);
traverse(root->right);
}
// BST(二叉搜索树)的框架
void BST(TreeNode* root, int target) {
if (root->val == target) {
// 找到目标,做点什么
}
if (root->val < target) {
BST(root->right, target);
} else {
BST(root->right, target);
}
}
vector nextGreaterElement(vector &nums) {
vector ans(nums.size()); // 存放答案的数组
stack s;
for (int i = nums.size() - 1; i >= 0; --i) {
while (!s.empty() && s.top() <= nums[i]) {
s.pop(); //小的数字弹出,
}
ans[i] = s.empty() ? -1 : s.top(); //这个元素后面第一个比他大的值
s.push(nums[i]); // 进栈
}
return ans;
}
class MonotonicQueue {
private:
deque data;
public:
void push(int n) {
while (!data.empty() && data.back() < n) {
data.pop_back();
}
data.push_back(n);
}
int max() {
return data.front();
}
void pop(int n) {
if (!data.empty() && data.front() == n) {
data.pop_front();
}
}
};
vector maxSlidingWindow(vector& nums, int k) {
MonotonicQueue Window;
vector res;
fof (int i = 0; i < nums.size(); ++i) {
if (i < k - 1) {
window.push(nums[i]);
} else {
window.push(nums[i]);
res.push_back(window.max());
window.pop(nums[i - k + 1]);
}
}
return res;
}
// 利用哈希表优化时间负责度,用空间换取时间。
class TwoSum {
private:
map freq;
public:
void add(int number) {
freq.insert(make_pair(number, freq[number]++));
}
bool find(int value) {
for (auto key : freq) {
int other = value - key.first;
// 情况1
if (other == key.first && key.second > 1) {
return true;
}
// 情况2
if (other != key && freq.count(other) > 0) {
return true;
}
}
return false;
}
};
// 利用或操作和空格将英文字母转化为小写
('a' | ' ') = 'a';
// 利用与操作和下划线将英文字母转换为大写
('b' & '_') = 'B';
// 利用异或操作和空格进行英文字符大小写互换
('d' ^ ' ') = 'D';
// 判断两个数是否异号
int x = -1, y = 2;
bool f = ((x ^ y) < 0); // true
int x = 3, y = 2;
bool f = ((x ^ y) < 0); // false
// 交换两个数
int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// 现在a = 2, b = 1;
// 加一
int n = 1;
n = -~n; //n = 2;
// 减一
int n = 2;
n = ~-n; // n = 1;
// 消除数字n的二进制表示中的最后一个1
n & (n - 1);
int n = nums.length;
vector pre_sum(n + 1, 0);
pre_sum[0] = 0;
for (int i = 0; i < n; ++i) {
pre_sum[i + 1] = pre_sum[i] + nums[i];
}
// (x, y)为坐标位置
void fill(int x, int y) {
fill(x - 1, y); // 上
fill(x + 1, y); // 下
fill(x, y - 1); // 左
fill(x, y + 1); // 右
}
class UF {
private:
int count;
vector parent;
vector size;
public:
UF(int n) {
this->count = n;
for (int i = 0; i < n; ++i) {
parent.push_back(i);
size[i] = 1;
}
}
void union(int p, int q) {
int root_p = find(p);
int root_q = find(q);
if (root_p == root_q) {
return;
}
if (size[root_p] > size[root_q]) {
parent[root_p] = root_p;
size[root_p] += size[root_q];
} else {
parent[root_p] = root_q;
size[root_q] += size[root_p];
}
--count;
}
bool connected(int p, int q) {
int root_p = find(p);
int root_q = find(q);
return (root_p == root_q);
}
int find(int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
int count() {
return count;
}
};