知识点:暴力枚举
感觉是有啥规律,但没发现~ 所以还是直接暴力枚举吧
class Solution {
public:
int xorOperation(int n, int start) {
int anw = 0;
for(int i = 0; i < n; i++) {
anw ^= (start + 2*i);
}
return anw;
}
};
知识点:正则表达式,hashmap
文件命名规则:
有两个比较烦人的地方:
为了解决上述问题,先明确几个概念:
还需要几个容器:
接下来枚举 names 即可:
class Solution {
unordered_map<string, unordered_set<int>> diff;
unordered_map<string, int> next;
unordered_set<string> mark;
int getNext(const string &name) {
auto it = next.find(name);
if(it == next.end()) {
return 0;
}
return it->second;
}
void update(const string &name, int id) {
diff[name].insert(id);
auto it = next.find(name);
if(it == next.end()) {
it = next.insert(make_pair(name, 0)).first;
}
while(diff[name].find(it->second) != diff[name].end()) {
it->second ++;
}
}
public:
vector<string> getFolderNames(vector<string>& names) {
vector<string> anw;
regex re("(.*)\\(([0-9]+)\\)$");
smatch res;
for(const auto &file : names) {
cout << file << endl;
bool found = regex_search(file, res, re);
string name;
int id;
if(found) {
name = res.str(1);
sscanf(res.str(2).c_str(), "%d", &id);
} else {
name = file;
id = 0;
}
if(mark.find(file) == mark.end()) {
anw.push_back(file);
mark.insert(file);
update(name, id);
update(file, 0);
} else {
int next = getNext(file);
char buff[40];
sprintf(buff, "%s(%d)", file.c_str(), next);
string tmp = buff;
update(tmp, 0);
update(file, next);
anw.push_back(tmp);
mark.insert(tmp);
}
}
return anw;
}
};
知识点:lower_bound,贪心
出题人又开了上帝视角,可以在还没到第 i 天时就知道第 i 天下不下雨,以及下在哪里~
根据题意,当第 i 天下雨时要保证 rains[i] 是干的,需要知道 rains[i] 在第 i 天之前是否下过雨,以及是否有机会将其抽干。
针对第一点,可以在枚举过程中使用 hashmap 记录每个湖泊的最后一次下雨的时间。
针对第二点,可以在枚举过程中使用 set 记录没有下雨的天数。
当枚举到 rains[i] 时:
为什么要选不小于 hashmap[rains[i]] 的最小正整数 x ?
class Solution {
set<int> free;
unordered_map<int, int> mark;
map<int, int> anw;
public:
vector<int> avoidFlood(vector<int>& rains) {
for(int i = 0; i < rains.size(); i++) {
if(rains[i] == 0) {
free.insert(i);
} else {
if(mark.find(rains[i]) != mark.end()) {
auto it = free.lower_bound(mark[rains[i]]);
if(it == free.end()) {
return vector<int>{};
}
anw.insert(make_pair(*it, rains[i]));
free.erase(it);
}
anw.insert(make_pair(i, -1));
mark[rains[i]] = i;
}
}
vector<int> res;
for(int i = 0; i < rains.size(); i++) {
if(anw[i] == 0) {
if(rains[i] == 0) {
anw[i] = 1;
} else {
anw[i] = -1;
}
}
res.push_back(anw[i]);
}
return res;
}
};
知识点:最小生成树,并查集
特别的,如果给出的图不存在MST,那么答案为空。下面仅讨论存在MST的情况。
Kruskal算法是将一个连通块当做一个集合。Kruskal首先将所有的边按从小到大顺序排序(一般使用快排),并认为每一个点都是孤立的,分属于n个独立的集合。
然后按顺序枚举每一条边。如果这条边连接着两个不同的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合(这就是一条边);
如果这条边连接的两个点属于同一集合(说明这条边找过了),就跳过。直到选取了n-1条边为止。
Kruskal算法每次都选择一条最小的,且能合并两个不同集合的边,一张n个点的图总共选取n-1次边。因为每次我们选的都是最小的边,所以最后的生成树一定是最小生成树。每次我们选的边都能够合并两个集合,最后n个点一定会合并成一个集合。通过这样的贪心策略,Kruskal算法就能得到一棵有n-1条边,连接着n个点的最小生成树。
先明确三个概念:
由定义可知,三者的交集为空,三者的并集就是图的所有边。
设MST的权值和为 minVal。
如果删除一个边之后,其MST不存在或者权值和发生了变化,那么这条边肯定是关键边。
如果先将一条边加入到MST中,然后再按照MST算法处理剩余的边,如果权值和发生变化,那么这条边就是冗余边。
既不是关键边也不是冗余边的那些边就是伪关键边咯。
class Solution {
struct Edge {
int u, v, w, p;
bool operator < (const Edge &rhs) const {
if(p == rhs.p) {
return w < rhs.w;
}
return p < rhs.p;
}
};
int find(int *fa, int u) {
int t = u;
while(t != fa[t]) {
t = fa[t];
}
while(u != fa[u]) {
int tmp = fa[u];
fa[u] = t;
u = tmp;
}
return t;
}
bool merge(int *fa, int u, int v) {
int fu = find(fa, u);
int fv = find(fa, v);
if(fu == fv) {
return false;
}
fa[fu] = fv;
return true;
}
int create(int n, vector<Edge> &edges) {
sort(edges.begin(), edges.end());
int fa[100];
for(int i = 0; i < n; i++) {
fa[i] = i;
}
int sum = 0;
int cnt = n;
for(const auto &edge : edges) {
if(merge(fa, edge.u, edge.v)) {
cnt--;
sum += edge.w;
}
}
if(cnt == 1) {
return sum;
}
return -1;
}
public:
vector<vector<int>> findCriticalAndPseudoCriticalEdges(int n, vector<vector<int>>& edges) {
vector<Edge> tmpEdges;
for(int i = 0; i < edges.size(); i++) {
tmpEdges.push_back(Edge{edges[i][0], edges[i][1], edges[i][2], 0});
}
int minVal = create(n, tmpEdges);
if(minVal == -1) {
return vector<vector<int>>{};
}
vector<int> keyEdges;
unordered_set<int> edgeMark;
for(int i = 0; i < edges.size(); i++) {
vector<Edge> vec;
for(int j = 0; j < edges.size(); j++) {
if(i == j) {
continue;
}
vec.push_back(Edge{edges[j][0], edges[j][1], edges[j][2], 0});
}
int tmpVal = create(n, vec);
if(tmpVal != minVal) {
keyEdges.push_back(i);
edgeMark.insert(i);
}
}
unordered_set<int> garbageEdges;
for(int i = 0; i < edges.size(); i++) {
vector<Edge> vec;
for(int j = 0; j < edges.size(); j++) {
if(i == j) {
vec.push_back(Edge{edges[j][0], edges[j][1], edges[j][2], 0});
} else {
vec.push_back(Edge{edges[j][0], edges[j][1], edges[j][2], 1});
}
}
int tmpVal = create(n, vec);
if(tmpVal > minVal) {
edgeMark.insert(i);
}
}
vector<int> falseKeyEdges;
for(int i = 0; i < edges.size(); i++) {
if(edgeMark.find(i) == edgeMark.end()) {
falseKeyEdges.push_back(i);
}
}
return vector<vector<int>> {keyEdges, falseKeyEdges};
}
};