前缀和|并查集
lc1722
用并查集 合并可交换下标成连通块
统计各连通块内 source 和 target 元素
计算不匹配元素数量总和,得到最小汉明距离
struct DSU {
DSU(int n) : data(n, -1), cnt(n) {}
bool unionSet(int x, int y) {
x = root(x);
y = root(y);
if (x == y) return false;
if (data[x] > data[y]) {
swap(x, y);
}
data[x] += data[y];
data[y] = x;
cnt--;
return true;
}
bool same(int x, int y) {
return root(x) == root(y);
}
int root(int x) {
return data[x] < 0 ? x : data[x] = root(data[x]);
}
int size(int x) {
return -data[root(x)];
}
vector<int> data;
int cnt = 0;
};
class Solution {
public:
int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
int n = source.size();
DSU dsu(n);
for (auto& swapPair : allowedSwaps) {
dsu.unionSet(swapPair[0], swapPair[1]);
}
unordered_map<int, multiset<int>> s, t;
for (int i = 0; i < n; ++i) {
int root = dsu.root(i);
s[root].insert(source[i]);
t[root].insert(target[i]);
}
int res = 0;
for (int i = 0; i < n; ++i) {
if (s.find(i) == s.end()) continue;
for (int num : s[i])
{
auto it = t[i].find(num);
if (it == t[i].end())
res++;
else
t[i].erase(it);
}
}
return res;
}
};
lc839
模板
struct DSU {
DSU(int n) : data(n, -1), cnt(n) {}
bool unionSet(int x, int y) {
x = root(x);
y = root(y);
if (x == y) return false;
if (data[x] > data[y]) {
swap(x, y);
}
data[x] += data[y];
data[y] = x;
cnt--;
return true;
}
bool same(int x, int y) {
return root(x) == root(y);
}
int root(int x) {
return data[x] < 0 ? x : data[x] = root(data[x]);
}
int size(int x) {
return -data[root(x)];
}
vector<int> data;
int cnt = 0;
};
解题
class Solution {
public:
int numSimilarGroups(vector<string>& strs)
{
DSU dsu(strs.size());
for (int i = 0; i < strs.size(); i++) {
for (int j = i + 1; j < strs.size(); j++) {
if (dsu.same(i, j)) continue;
if (!check(strs[i], strs[j])) continue;
dsu.unionSet(i, j);
}
}
return dsu.cnt;
}
bool check(string& s1, string& s2)
{
int dif = 0;
for (int i = 0; i < s1.size(); i++) {
dif += (s1[i] != s2[i]);
}
return (dif == 0 || dif == 2);
}
};
lc1744
class Solution {
private:
using LL = long long;
public:
vector<bool> canEat(vector<int>& candiesCount, vector<vector<int>>& queries)
{
int n = candiesCount.size();
// 前缀和
vector<LL> sum(n);
sum[0] = candiesCount[0];
for (int i = 1; i < n; ++i) {
sum[i] = sum[i - 1] + candiesCount[i];
}
vector<bool> ans;
for (const auto& q: queries)
{
int favoriteType = q[0], favoriteDay = q[1], dailyCap = q[2];
LL x1 = favoriteDay + 1, y1 = (LL)(favoriteDay + 1) * dailyCap;
LL x2 = (favoriteType == 0 ? 1 : sum[favoriteType - 1] + 1), y2 = sum[favoriteType];
ans.push_back(!(x1 > y2 || y1 < x2));
}
return ans;
}
};
lc2055
二分+前缀和
预处理每个位置左右最近蜡烛
查询时取有效蜡烛区间
用前缀和快速算出区间内盘子数
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& qs) {
vector<int> ans(qs.size(), 0);
vector<int> sum(s.length() + 1, 0);
vector<int> list;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '|') list.push_back(i);
sum[i + 1] = sum[i] + (s[i] == '*' ? 1 : 0);
}
if (list.empty()) return ans;
for (int i = 0; i < qs.size(); i++) {
int a = qs[i][0], b = qs[i][1];
int c = -1, d = -1;
// 找到 a 右边最近的蜡烛
int l = 0, r = list.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (list[mid] >= a) r = mid;
else l = mid + 1;
}
if (list[r] >= a) c = list[r];
else continue;
// 找到 b 左边最近的蜡烛
l = 0; r = list.size() - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (list[mid] <= b) l = mid;
else r = mid - 1;
}
if (list[r] <= b) d = list[r];
else continue;
if (c <= d) ans[i] = sum[d + 1] - sum[c];
}
return ans;
}
};