贪心1
贪心算法通过每步选择局部最优解,期望最终达到全局最优,适用于最优化和排序问题。
贪心1
贪心1
179. 最大数
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
// 暴力方法生成所有可能的排列,其中选出字典序最小的结果
string way1(vector<string> &strs) {
vector<string> res;
fc(strs, 0, res);
sort(res.begin(), res.end());
return res[0];
}
// 全排列
void fc(vector<string> &strs, int i, vector<string> &res) {
if (i == strs.size()) {
string path;
for (const string &s: strs)
path += s;
res.push_back(path);
} else {
for (int j = i; j < strs.size(); j++) {
swap(strs[i], strs[j]);
fc(strs, i + 1, res);
swap(strs[i], strs[j]);
}
}
}
// 正式方法,时间复杂度 O(n*logn)
string way2(vector<string> &strs) {
sort(strs.begin(), strs.end(), [](const string &a, const string &b) {
return (a + b) < (b + a);
});
string path;
for (const string &s: strs)
path += s;
return path;
}
// 生成长度 1~n 的随机字符串数组
vector<string> randomStringArray(int n, int m, int v) {
vector<string> res(rand() % n + 1);
for (int i = 0; i < res.size(); i++)
res[i] = randomString(m, v);
return res;
}
// 生成长度 1~m,字符种类有 v 种,随机字符串
string randomString(int m, int v) {
int len = rand() % m + 1;
string res(len, ' ');
for (int i = 0; i < len; i++)
res[i] = 'a' + rand() % v;
return res;
}
// 最大数
string largestNumber(vector<int> &nums) {
int n = nums.size();
vector<string> strs(n);
for (int i = 0; i < n; i++)
strs[i] = to_string(nums[i]);
sort(strs.begin(), strs.end(), [](const string &a, const string &b) {
return (b + a) < (a + b);
});
if (strs[0] == "0") return "0";
string path;
for (const string &s: strs)
path += s;
return path;
}
};
int main() {
Solution sol;
int n = 8; // 数组中最多几个字符串
int m = 5; // 字符串长度最大多长
int v = 4; // 字符的种类有几种
int testTimes = 2000;
cout << "测试开始" << endl;
for (int i = 1; i <= testTimes; i++) {
vector<string> strs = sol.randomStringArray(n, m, v);
string res1 = sol.way1(strs);
string res2 = sol.way2(strs);
if (res1 != res2) {
cout << "出错了!" << endl;
}
if (i % 100 == 0) {
cout << "测试到第" << i << "组" << endl;
}
}
cout << "测试结束" << endl;
}
1029. 两地调度
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
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
int twoCitySchedCost(vector<vector<int>> &costs) {
int n = costs.size();
// <在原数组中的下标,差值>
vector<pair<int, int>> arr(n);
for (int i = 0; i < n; ++i)
arr[i] = make_pair(i, costs[i][1] - costs[i][0]);
// 根据差值递增排序,差值表示从 a 换到 b 的代价
sort(begin(arr), end(arr),
[](const pair<int, int> &p1, const pair<int, int> &p2) { return p1.second < p2.second; });
int res = 0;
// 前一半的人去 b
for (int i = 0; i < n; ++i) {
res += (i < n / 2) ? costs[arr[i].first][1] : costs[arr[i].first][0];
}
return res;
}
};
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
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
int twoCitySchedCost(vector<vector<int>> &costs) {
int n = costs.size();
int sum = 0;
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
arr[i] = costs[i][1] - costs[i][0];
// 假设全都去 a
sum += costs[i][0];
}
sort(begin(arr), end(arr),
[](const int &p1, const int &p2) { return p1 < p2; });
// 前一半的人从 a 去 b
for (int i = 0; i < n / 2; ++i)
sum += arr[i];
return sum;
}
};
1553. 吃掉 N 个橘子的最少天数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <unordered_map>
#include <algorithm>
using namespace std;
class Solution {
public:
unordered_map<int, int> dp;
int minDays(int n) {
if (n <= 1) return n;
if (dp.find(n) != dp.end()) return dp[n];
// 能按比例吃就按比例吃,每天吃一个只是为了更快的到达能按比例吃
int res = min(n % 2 + 1 + minDays(n / 2), n % 3 + 1 + minDays(n / 3));
dp[n] = res;
return res;
}
};
线段重合
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
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
int fc(vector<vector<int>> &lines) {
int n = lines.size();
// 根据线段的左端点排序
sort(begin(lines), end(lines),
[](const vector<int> &v1, const vector<int> &v2) { return v1[0] < v2[0]; });
// 小顶堆,根据线段的右端点排序
priority_queue<int, vector<int>, greater<int>> heap;
int res = 0;
// 任何一个重合的区域,一定有一个左端点最大的,下面的循环就是考虑这个最大的左端点是谁
// [ ]
// [ ]
// [ ]
// 最大的左端点
for (int i = 0; i < n; ++i) {
// 堆中保存着的线段的右端点比当前线段的左端点还小
// 说明没有重合的地方,也不会与后续的线段重合,全部弹出
while (!heap.empty() && heap.top() <= lines[i][0])
heap.pop();
heap.emplace(lines[i][1]);
res = max(res, (int) heap.size());
}
return res;
}
int main() {
int n;
cin >> n;
vector<vector<int>> lines(n, vector<int>(2, 0));
for (int i = 0; i < n; ++i)
cin >> lines[i][0] >> lines[i][1];
cout << fc(lines) << endl;
}
630. 课程表 III
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
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
class Solution {
public:
int scheduleCourse(vector<vector<int>> &courses) {
// 按照每门课程的截止时间从小到大排序(更早截止的课程排前面)
sort(courses.begin(), courses.end(), [](const vector<int> &a, const vector<int> &b) {
return a[1] < b[1];
});
// 创建一个大根堆(优先队列),用于记录已选课程的耗时
// 堆顶是当前已选课程中耗时最长的那一门
priority_queue<int> heap;
// 记录当前来到的时间点
int time = 0;
for (const auto &c: courses) {
int duration = c[0]; // 课程耗时
int lastDay = c[1]; // 课程必须在这天前完成
if (time + duration <= lastDay) {
// 如果加上这门课程不会超过它的截止日期,就选它
heap.push(duration);
time += duration;
} else {
// 否则,看当前堆中有没有耗时更大的课程可以换掉
if (!heap.empty() && heap.top() > duration) {
time += duration - heap.top();
heap.pop();
heap.push(duration);
}
// 如果当前课程比堆顶课程耗时还大,就直接跳过(因为会更糟)
}
}
// 返回最终能上的课程数,也就是堆的大小
return heap.size();
}
};
P1090 [NOIP 2004 提高组] 合并果子
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
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 哈夫曼树的构造过程
int fc(vector<int> &arr) {
// 小根堆
priority_queue<int, vector<int>, greater<>> heap(arr.begin(), arr.end());
int res = 0;
// 每次弹出两个最小的进行合并,再放回合并后的结果
while (heap.size() > 1) {
int a = heap.top();
heap.pop();
int b = heap.top();
heap.pop();
int merged = a + b;
res += merged;
heap.push(merged);
}
return res;
}
int main() {
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; ++i) cin >> arr[i];
cout << fc(arr) << endl;
}
本文由作者按照 CC BY 4.0 进行授权