二叉树
一. leetcode 113 路径总和2
前序遍历:
- 先处理当前结点(将该结点push到路径数组中,并且累加其结点值);
- 再进行下一步的遍历;
- 完成当前结点的遍历后,回溯(将该结点pop出路径数组,并且更新结点值和)。
一般代码结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14void preOrder(TreeNode* root, vector<vector<int>>& result, vector<int>& path, int sum, int cur_sum) {
if (root == NULL) return;
path.push_back(root->val); // 更新路径
cur_sum += root->val; // 更新当前和
// 当前和与要求和相同,并且为叶子结点
if (cur_sum == sum && root->left == NULL && root->right == NULL) {
result.push_back(path);
}
preOrder(root->left, result, path, sum, cur_sum);
preOrder(root->right, result, path, sum, cur_sum);
// 左右子树都遍历完成后,在路径中删除当前值
path.pop_back();
cur_sum -= root->val;
}二. leetcode 236 二叉树的最近公共祖先
- 分别以题目给出的两个结点为目标,对二叉树进行前序遍历,直到找到该目标,并且记录路径;
- 从头到尾对比两个路径,遇到的最后一个相同的即为最近公共祖先。
三. leetcode 114 二叉树展开为链表
递归主要讨论的是左子树与右子树都拉直后的连接过程,忽略具体拉直过程,每个递归返回的有用信息是该树右子树的最后一个结点指针。
1 | /** |
图
一. leetcode 199 二叉树的右视图
图的宽度搜索(BFS):
- 使用队列queue,pair存储结点与层数;
- 将当前结点的左右结点分别push到队列中,同时记录层数;
- 按先进先出的顺序访问结点;
- 不断更新该层的最后一个结点;
- 得到结果数组。
一般代码结构为: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/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> ans; // 按层遍历的最后一个结点
queue<pair<TreeNode*, int> > myQueue;
if (!root)return ans;
myQueue.push(make_pair(root, 0));
while (!myQueue.empty()) {
TreeNode* cur_node = myQueue.front().first;
int cur_depth = myQueue.front().second;
myQueue.pop();
if (ans.size() == cur_depth) { // 首次遇到在cur_depth层的结点 将结点值push到数组中
ans.push_back(cur_node->val);
}
else { // 更新ans[cur_depth]的值
ans[cur_depth] = cur_node->val;
}
if (cur_node->left) { // 存在左子树
myQueue.push(make_pair(cur_node->left, cur_depth + 1));
}
if (cur_node->right) { // 存在左子树
myQueue.push(make_pair(cur_node->right, cur_depth + 1));
}
}
return ans;
}
};
二. leetcode 207 课程表
两种方法:
- DFS遍历过程中,没有重复访问正在访问的结点(即存在从该结点返回到初始位置的路径)。
DFS的一般代码结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19bool DFS(GraphNode *node, vector<int> &visit) {
// 标记当前结点值正在访问
visit[node->label] = 0;
// 访问器邻接结点
for (int i = 0; i < node->neighbors.size(); i++) {
// 当前结点未被访问则继续深度遍历
if (visit[node->neighbors[i]->label] == -1) {
if (!DFS(node->neighbors[i], visit))
return false;
}
// 当前结点出现环:访问正在访问的结点
else if (visit[node->neighbors[i]->label] == 0) {
return false;
}
}
// 标记当前结点值访问过
visit[node->label] = 1;
return true;
} - BFS遍历后,无环:所有入度减少为0;有环:存在不为0的入度。
二分查找
一. leetcode 35 搜索插入位置
标准二分查找法(重点:分析出未找到target值时,插入位置索引总是begin);
一般模板:
1 | class Solution { |
二、leetcode 34 在排序数组中查找元素的第一个和最后一个位置
分别找左右边界,二分查找加入相等的处理判断;
1 | // 找左边界 |
三、leetcode 33 搜索旋转排序数组
有点窒息的分类,二分查找的框架,每种情况都要清晰地讨论。
1 | class Solution { |
二叉搜索树
插入结点代码
1 | void BST_insert(TreeNode* root, TreeNode* insert_node) { |
查找结点代码
一、leetcode 449 序列化和反序列化二叉搜索树
二、leetcode 315 计算右侧小于当前元素的个数
在插入的过程中计算小于当前结点值的结点数,不是获取当前结点的count_small值(记录的是整棵树中小于当前结点的值,而不是在插入他之前)。
1 | class Solution { |
哈希表
一、 leetcode 409 最长回文串
- 哈希表存放字符串s中各个不同的字母出现的次数;
- 遍历哈希表,根据出现次数的偶数/奇数,结合回文串的性质,得出最长回文串。
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
27class Solution {
public:
int longestPalindrome(string s) {
map<char, int> mp;
for (int i = 0; i < s.length(); i++) {
mp[s[i]]++;
}
map<char, int>::iterator it;
int sum = 0;
bool flag = false;
for (it = mp.begin(); it != mp.end(); it++) {
if (it->second % 2 == 0) { // 该字母出现次数为偶数次
sum += it->second; // 可构成回文
}
else { // 该字母出现次数为奇数次
if (flag) { // 已存在中间值
sum += it->second - 1; // 除掉中间值外 其他可构成回文
}
else {
sum += it->second;
flag = true;
}
}
}
return sum;
}
};
二、leetcode 290 单词规律
分析字符串与模式字母的正确匹配情况与错误情况:
- map<string, char> mp; // 存储字符串对应的模式字母
bool used[128] = {0}; // 标记模式字母是否出现过 - 模式字母未出现过:当前字符串却曾经出现过,则有字符串对应了多个模式字母,错误;
模式字母出现过:当前字符串不曾出现,或者当前字符串不对应相应模式字母,错误;
三、leetcode 49 字母异位词分组
- map<string, int> mp; // 哈希表:基础字符串,对应在结果中的索引
vector<vector> res; // 结果数组 - 字符串排序,作为map的key.
四、leetcode 3 无重复字符的最长子串
滑动窗口法:
- 确定左边界,遍历右边界,数组存储字母在该窗口中是否出现过;
- 当遍历过程中遇到出现过的字母,则右移左边界,直到找到该字母的位置;
- 当遍历过程中遇到出现过的字母,更新最大无重复子串长度。
五、leetcode 187 重复的DNA序列
ACGT四种情况,即二进制两位数可表示这4种不同的字母;
不同的DNA序列可转化为对应不同的二进制数;
使用哈希表存储出现的次数。六、leetcode 76 最小覆盖子串
滑动窗口法+哈希表:
根据条件更新左边界:当前S窗口s_map[begin_str] < T字符串中的t_map[begin_str];或出现T字符串中没有的字母;
遍历右边界,在每次遍历完成后,判断该窗口是否符合要求。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
45class Solution {
public:
bool is_window_ok(int x[], int y[], vector<int> vec) {
for (int i = 0; i < vec.size(); i++) {
if (x[vec[i]] > y[vec[i]]) return false;
}
return true;
}
string minWindow(string s, string t) {
int t_map[128] = {0}; // 记录t字符串中各字母出现的次数
int s_map[128] = {0}; // 记录s字符串窗口中各字母出现的次数
vector<int> charvec; // 记录t中出现过的字母
for (int i = 0; i < t.length(); i++) {
if (t_map[t[i]] == 0) charvec.push_back(t[i]);
t_map[t[i]]++;
}
int begini = 0; // 窗口左边界
int min_len = s.length() + 1; // 结果字符串长度
string res = "";
// 遍历右边界
for (int i = 0; i < s.length(); i++) {
s_map[s[i]]++;
while (begini < i) {
if (t_map[s[begini]] == 0) { // 窗口首字母在t字符串中不存在
begini++;
}// 窗口首字母在窗口字符串中出现次数>在t字符串出现次数
else if (s_map[s[begini]] > t_map[s[begini]]) {
s_map[s[begini]]--;
begini++;
}
else break;
}
// cout<<s.substr(begini, i - begini + 1)<<endl;
if (is_window_ok(t_map, s_map, charvec)) {
int cur_len = i - begini + 1;
if (res == "" || cur_len < min_len) {
min_len = cur_len;
res = s.substr(begini, cur_len);
}
}
}
return res;
}
};递归
一、 leetcode 78 子集
不考虑递归过程,直接根据结果来实现程序。
求子集: - 考虑当前元素是否应该加到子集中:加或不加,分别递归;
- 递归结束条件是:index>=nums.size()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Solution {
public:
void generate (int i, vector<int> nums, vector<int> items, vector<vector<int>> &res) {
if (i >= nums.size()) { // 当索引超出nums边界
res.push_back(items);
return;
}
items.push_back(nums[i]); // 当前子集选择nums[i]
generate (i + 1, nums, items, res); // 进行下一步递归
items.pop_back(); // 当前子集不选择nums[i]
generate (i + 1, nums, items, res); // 进行下一步递归
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int> > res;
vector<int> items;
generate (0, nums, items, res);
return res;
}
};二、leetcode 90 子集 II
先对nums排序,使用set<vector>对一致的子集去重。 1
2
3
4if (res_set.find(items) == res_set.end()) {
res.push_back(items);
res_set.insert(items);
}三、leetcode 40 组合总和 II
典型的递归题: - 以开始位置start索引遍历候选数组,当当前索引未加入到路径中,并且加入候选值不会大于target值,则选择该索引位置的值,并进行下一步的递归;
- 递归结束条件是path值==target值,并且当前path首次出现(排序 set约束)。
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
27class Solution {
public:
// 递归函数
// 候选数组,开始位置,目标数值,结果数组,当前子集
void backtracking(vector<int> candidates, int start, int target, vector<vector<int> >& res, vector<int>& path, bool help[], set<vector<int> >& res_set) {
// 达到目标
if ( target == 0 && res_set.find(path) == res_set.end()) {
res.push_back(path);
res_set.insert(path);
return;
}
for (int i = start; i < candidates.size() && target-candidates[i] >= 0; i++){
// 满足条件:当前值未使用 并且 子集和仍然小于target
if (!help[i] && target - candidates[i] >= 0) {
path.push_back(candidates[i]); // 将当前值放入子集中
help[i] = true;
backtracking(candidates, i+1, target - candidates[i], res, path, help, res_set);
path.pop_back(); // 取出该值,进行新一轮选择
help[i] = false;
}
}
}
/*
sort(candidates.begin(),candidates.end()); // 将数组排序
backtracking(candidates, 0, target, res, path, help, res_set);
*/
};四、leetcode 22. 括号生成
典型递归题:
给出n对左右括号的合理摆放顺序。 - 每一步有2种选择:’(‘或’)’,对两种选择分别进行下一步递归;
- 递归结束条件为:目标字符串长度到达2*n;
- 剪枝:去除不必要的递归步骤:只有n个左括号与n个右括号,超出的直接不做处理;左括号数不大于右括号数的,不可再选择’)’。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class Solution {
public:
void generate(string item, int left, int right, vector<string>& res) {
if (left == 0 && right == 0) { // 当字符串成功放置n个左括号与n个右括号
res.push_back(item);
return;
}
if (left > 0) // 当左括号尚未完成
generate(item + '(', left - 1, right, res);
if (left < right) // 当左括号数>右括号数
generate(item + ')', left, right - 1, res);
}
vector<string> generateParenthesis(int n) {
vector<string> res;
generate("", n, n, res);
return res;
}
};五、leetcode 51. N皇后
N皇后问题,典型的递归回溯法:
关键点在于在递归之前,对当前mark标记数组与location结果状态的保存,以便在回溯阶段对状态进行复原,以进行下一步的递归。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
58class Solution {
public:
int dir[8][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, // 上下左右
{-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; // 左上 右上 左下 右下
// 在(x,y)位置放置queue
// 在(x,y)位置的八个方向延伸出去 都标志为-1 表示不可放置queue
void put_down_the_queue(int x, int y, vector<vector<int> >& mark) {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < mark.size(); j++) {
int index_x = x + dir[i][0] * j;
int index_y = y + dir[i][1] * j;
if (index_x < 0 || index_x >= mark.size()) continue;
if (index_y < 0 || index_y >= mark[0].size()) continue;
mark[index_x][index_y] = -1;
}
}
}
// 递归函数
// k:完成k个皇后的放置
// n:共n个皇后
// location:当前摆放结果
// res:最终结果
// mark:标记数组
void generate(int k, int n, vector<string>& location, vector<vector<string> >& res, vector<vector<int> >& mark) {
if (k == n) {
res.push_back(location);
return;
}
for (int i = 0; i < n; i++) {
if (mark[k][i] == 0) {
vector<vector<int> > temp_mark = mark; // 存储当前的mark数组(在递归过程中会改变)
put_down_the_queue(k, i, mark);
location[k][i] = 'Q';
generate(k + 1, n, location, res, mark); // 递归
mark = temp_mark; // 返回原本mark数组
location[k][i] = '.'; // 返回原本的location
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string> > res; // 存储最终结果
vector<vector<int> > mark; // 标记棋盘是否可以放置皇后的二维数组
vector<string> location; // 存储某个摆放结果
// 初始化
for (int i = 0; i < n; i++) {
mark.push_back((vector<int>()));
for (int j = 0; j < n; j++) {
mark[i].push_back(0);
}
location.push_back("");
location[i].append(n, '.'); // location初始化为n个"."
}
generate(0, n, location, res, mark);
return res;
}
};六、leetcode 315 计算右侧小于当前元素的个数
归并排序思想:
在merge两个子数组的同时,更新counts数组:
当插入前半部分区间值sub_vec1[x]时,表示后半部分 y之前的所有值都已放置在vec中,
则证明y之前都小于sub_vec1[x],因此对应值索引位置更新+y。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
62class Solution {
public:
void merge_two_vec(vector<pair<int, int> > sub_vec1, vector<pair<int, int> > sub_vec2, vector<pair<int, int> >& vec, vector<int>& ans) {
int x = 0, y = 0;
while (x < sub_vec1.size() && y < sub_vec2.size()) {
// 此时插入前半部分区间值sub_vec1[x]
// y之前的所有值都已放置在vec中
// 证明都小于sub_vec1[x]
// 因此更新+y
if (sub_vec1[x].first <= sub_vec2[y].first) {
ans[sub_vec1[x].second] += y; // 对应索引位置更新
vec.push_back(sub_vec1[x]);
x++;
}
// 此时插入后半部分区间值sub_vec2[x]
else {
vec.push_back(sub_vec2[y]);
y++;
}
}
// 处理剩余元素
while (x < sub_vec1.size()) {
ans[sub_vec1[x].second] += y; // 对应索引位置更新
vec.push_back(sub_vec1[x]);
x++;
}
while (y < sub_vec2.size()) {
vec.push_back(sub_vec2[y]);
y++;
}
}
void merge_sort(vector<pair<int, int> >& vec, vector<int>& ans) {
if (vec.size() < 2) return; // 当拆分后的数组大小<=1,则直接返回
// 拆分为2个数组
int mid = vec.size() / 2;
vector<pair<int, int> > sub_vec1;
vector<pair<int, int> > sub_vec2;
for (int i = 0; i < mid; i++) {
sub_vec1.push_back(vec[i]);
}
for (int i = mid; i < vec.size(); i++) {
sub_vec2.push_back(vec[i]);
}
merge_sort(sub_vec1, ans);
merge_sort(sub_vec2, ans);
vec.clear(); // 清空 以存放归并后的数组
merge_two_vec(sub_vec1, sub_vec2, vec, ans);
}
vector<int> countSmaller(vector<int>& nums) {
vector<int> ans;
if (nums.size() == 0) return ans;
vector<pair<int, int> > vec;
for (int i = 0; i < nums.size(); i++) {
ans.push_back(0); // 初始化结果数组
vec.push_back(make_pair(nums[i], i)); // 存储nums[i]与对应索引i
}
merge_sort(vec, ans);
return ans;
}
};搜索
一、 leetcode 200. 岛屿数量
基础DFS解法:基础BFS解法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// DFS找到从(x,y)出发连接的'1',即一个岛屿
void DFS(vector<vector<char>>& grid, vector<vector<int> >& seen, int x, int y) {
seen[x][y] = 1;
for (int i = 0; i < 4; i++) {
int next_x = x + dirs[i][0];
int next_y = y + dirs[i][1];
// 超出边界
if (next_x < 0 || next_x >= grid.size() || next_y < 0 || next_y >= grid[0].size())
continue;
// 已访问过
if (seen[next_x][next_y]) continue;
// 是岛屿 继续DFS
if (grid[next_x][next_y] == '1') {
DFS(grid, seen, next_x, next_y);
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// BFS找到从(x,y)出发连接的'1',即一个岛屿
void BFS(vector<vector<char>>& grid, vector<vector<int> >& seen, int x, int y) {
queue<pair<int, int> > mq;
mq.push(make_pair(x, y));
seen[x][y] = 1; // 入队标志
while (!mq.empty()) {
int cur_x = mq.front().first;
int cur_y = mq.front().second;
mq.pop();
for (int i = 0; i < 4; i++) {
int next_x = cur_x + dirs[i][0];
int next_y = cur_y + dirs[i][1];
// 超出边界
if (next_x < 0 || next_x >= grid.size() || next_y < 0 || next_y >= grid[0].size())
continue;
// 是岛屿 继续DFS
if (!seen[next_x][next_y] && grid[next_x][next_y] == '1') {
mq.push(make_pair(next_x, next_y)); // 入队
seen[next_x][next_y] = 1;
}
}
}
}二、leetcode 127. 单词接龙
- 建立图关系:差一个字母的单词有关系;
- 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
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
52class Solution {
public:
// 建立单词间关系图:相差一个字母的单词为一组
void construct_graph(map<string, vector<string> >& graph, vector<string>& wordList, int len) {
// 初始化graph
for (int i = 0; i < wordList.size(); i++) {
for (int j = 0; j < len; j++) {
string temp = wordList[i];
temp[j] = '*'; // 替换为‘*’,作为key
if (graph.count(temp) == 0) {
vector<string> vec;
vec.push_back(wordList[i]);
graph[temp] = vec;
}
else graph[temp].push_back(wordList[i]);
}
}
return;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
int len = beginWord.length();
map<string, vector<string> > graph; // 单词,相差一个字母的其他单词表
wordList.push_back(beginWord); // 也需考虑beginWord
construct_graph(graph, wordList, len);
// 进行BFS
queue<pair<string, int> > q; // 队列(单词,当前步数)
set<string> visit; // 是否访问过
q.push(make_pair(beginWord, 1));
visit.insert(beginWord);
while (!q.empty()) {
string cur_s = q.front().first;
int cur_step = q.front().second;
q.pop();
if (cur_s == endWord) {
return cur_step;
}
for (int i = 0; i < len; i++) { // 替换每个字母为'*', 都存在路径
string temp_s = cur_s;
temp_s[i] = '*';
vector<string> neighbors = graph[temp_s];
for (int j = 0; j < neighbors.size(); j++) {
if (visit.find(neighbors[j]) == visit.end()) {
q.push(make_pair(neighbors[j], cur_step + 1));
visit.insert(neighbors[j]);
}
}
}
}
return 0;
}
};升级leetcode 126. 单词接龙 II
记录单词接龙的路径: - 使用vector
作为BFS数组,建立Qitem数据结构,同时存储(word, step, parent_pos); - map<string, int> visit 记录到某单词的最短路径;
三、leetcode 473. 火柴拼正方形
DFS会超时,可使用二进制法。
1 | class Solution { |
动态规划
一、leetcode 70. 爬楼梯
1 | class Solution { |
二、leetcode 198. 打家劫舍
dp[i]表示 [0, i]范围内的最高金额;
1 | class Solution { |
三 leetcode 53. 最大子序和
dp[i]:以nums[i]为结尾的最大子序和;
1 | class Solution { |
四、leetcode 322. 零钱兑换
dp[i]:i元时需要的最少硬币数
五、120. 三角形最小路径和
自底向上;
triangle直接作为状态数组,triangle[i][j]表示从底部到当前位置的最短路径长度;
状态转移方程为triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]);
最终结果为triangle[0][0].
六、300. 最长上升子序列
dp[i]:以nums[i]为结尾的最长上升子序列,结尾需要遍历dp,得出最大长度.
七、64. 最小路径和
自底向上;
grid[i][j]只可能从右侧或者下方回来,
状态转移方程:grid[i][j] += min(grid[i][j + 1], grid[i + 1][j]);
八、leetcode 174. 地下城游戏
1 | class Solution { |
Trie树(字典树)
模板:
1 | # define TRIE_MAX_CHAR_NUM 26 |
一、leetcode 208. 实现 Trie (前缀树)
经典insert、search、startswith
二、leetcode 211. 添加与搜索单词 - 数据结构设计
DFS查找带有“.”的字符串在字典树中是否存在。
1 | bool dfs_search(TrieNode* ptr, string word, int i) { |
并查集
一、leetcode 547. 朋友圈
1 | class Solution { |
线段树
leetcode 307. 区域和检索 - 数组可修改
求数组区间和:建立/更新/查询线段树
1 | class NumArray { |
二、leetcode 1157. 子数组中占绝大多数的元素
线段树中存储 在当前区间中,通过打擂法胜出的值;
在query过程中,找到查询区间中,出现次数最多的值x;
哈希表indices_map存储值与对应的索引数组;
在索引数组中找到在[left, right]区间内的个数,判断是否符合要求即可。
三、leetcode 218. 天际线问题
tree线段树数组存储 离散化x值数组各区间内的高度最大值;
使用懒下传。
贪心
在每一步做出在当前来看的最优选择。
一、leetcode 455. 分发饼干
1 | class Solution { |
二、leetcode 376. 摆动序列
状态机 + 贪心:从左到右的遍历过程中,若持续下降/上升,选取最右边界作为摆动序列的一部分,以使摆动序列最长;
三、leetcode 402. 移掉K位数字
栈 + 贪心:从左到右遍历(高位到低位),如果对应数字大于下一位数字,则应该把该数字去掉,以取得最小数
四、leetcode 55. 跳跃游戏
当前位置cur_pos,当前可以到达的范围nums[cur_pos] + cur_pos,找到该范围中可以到达最远位置的下标值,作为跳跃目标。
升级题:leetcode 45. 跳跃游戏 II
五、leetcode 452. 用最少数量的箭引爆气球
六、leetcode 871. 最低加油次数
贪心+最大堆(有点跳跃游戏的思想:你尽管走,不够了就加)
1 | class Solution { |
其他
leetcode 122 买卖股票的最佳时机 II
leetcode 881 救生艇
leetcode 316. 去除重复字母
leetcode 435. 无重叠区间
贪心(区间调度):优先选择end小的(首先根据end升序排序),使剩下的区间最多,则移除区间最少,与452类似.
leetcode 659. 分割数组为连续子序列
leetcode 861. 翻转矩阵后的得分
(难)321/330/757