Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
class Solution {
public:
int componentValue(vector<int>& nums, vector<vector<int>>& edges)
{
int n = nums.size();
if (n==1) return 0;

vector<vector<int>>next(n);
vector<int>indegree(n);

for (auto& edge: edges)
{
int a = edge[0], b = edge[1];
next[a].push_back(b);
next[b].push_back(a);
indegree[b]++;
indegree[a]++;
}

int total = accumulate(nums.begin(), nums.end(), 0);

vector<int>sums;
for (int s=1; s*s <= total; s++)
{
if (total % s!=0) continue;
sums.push_back(s);
sums.push_back(total/s);
}
sort(sums.begin(), sums.end());

for (auto s: sums)
{
vector<int>in = indegree;
queue<int>q;
vector<int>visited(n,0);
vector<int>sum = nums;

for (int i=0; i<n; i++)
if (in[i]==1)
{
q.push(i);
visited[i] = 1;
}

int flag = true;

while (!q.empty())
{
int cur = q.front();
q.pop();

if (sum[cur] > s)
{
flag = false;
break;
}
else if (sum[cur] == s)
sum[cur] = 0;

for (int nxt: next[cur])
{
if (visited[nxt]) continue;
sum[nxt] += sum[cur];
in[nxt]--;

if (in[nxt]==1)
{
visited[nxt] = 1;
q.push(nxt);
}
}
}

if (flag) return total/s-1;
}

return 0;
}
};
10 changes: 10 additions & 0 deletions BFS/2440.Create-Components-With-Same-Value/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
### 2440.Create-Components-With-Same-Value

假设我们想要把这张图平均分成k份,那么每一份联通块的元素和s我们是知道的。假设我们可以实现这样的拆分,从图中我们显然可以发现,每一份符合条件的联通块必然可以从外往内一点一点剥离下来。这就提示我们可以用拓扑排序的方法。我们记录sum[i]表示从外往内“剥洋葱”的过程中,剥到节点i时所对应的“子树”的节点元素之和。
1. 如果`sum[i]==s`,那么说明这棵子树就是符合条件的一个联通块,我们就彻底剥离,节点i不传递信息给它的上级。
2. 如果`sum[i]<s`,那么这棵子树还不能独立,必须把sum[i]传递给节点i的上一级节点,以期待在一棵更大的子树里恰好凑成给一个合法的联通块。
3. 如果`sum[i]>s`,那么说明这棵子树的元素和太大了,不能构成一个合法的联通块,终止基于s的进一步的尝试。

我们重复上述剥洋葱的过程,如果把所有节点都剥完,依然没有报错,那么说明我们恰好把整张图剥离成了一个个元素和为s的子树。

显然,拓扑排序的复杂度是o(N)。那么我们需要尝试多少个s呢?s的个数应该是total的因子个数,即sqrt(total)。其中total是整张图的元素之和。综上,总的时间复杂度恰好就是1e6级别。
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Solution {
public:
int minimizeArrayValue(vector<int>& nums)
{
long long sum = 0;
long long ret = 0;
for (int i=0; i<nums.size(); i++)
{
sum += nums[i];
ret = max(ret, sum%(i+1)==0? sum/(i+1): (sum/(i+1)+1));
}
return ret;
}
};
7 changes: 7 additions & 0 deletions Binary_Search/2439.Minimize-Maximum-of-Array/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

本题的大体思路就是,如果有一个数字特别大,那么我们希望它能与之前的数字们一起“抹匀”,来尽量减少最大值。由于更靠前的数字,只能与更少数量的伙伴一起“抹匀”,所以最终呈现出来的最优解形态,应该是piece-wise constant的递减数列。这个数列的第一个元素的大小,就是最终答案。

#### 解法1:二分搜值

那么这个数字最小是什么呢?并不太容易直接求出来。但是如果我们猜测一个,是容易判断它是否成立的。

我们首先猜测最终答案是x。明显,这个x必然不会小于nums[0],因为nums[0]没有机会向前分摊数值。如果x>nums[0],那么这意味着后面的元素有机会向nums[0]分摊一些数值,我们记做“缓冲值”:`buff = x-nums[0]`.
Expand All @@ -13,3 +15,8 @@
通过二分搜值的讨论,我们可以很容易求出满足条件的最小值。

注意本题一定有解(什么都不做就可以返回数组最大值),因此二分搜值的收链解就是最优解。

#### 解法2:贪心
本题有直接的贪心策略。我们考虑前i个元素,最优的方案就是将前i个元素的和均匀分配,那么分配之后的最大值就是`ceil(presum[i]/i)`(假设是1-index)。我们考察所有的i,得到的全局最大值就是答案。

这种贪心策略看上去并不“严谨”。比如说,如果nums[i]相比于之前的所有元素都小,那么我们其实是无法做到让前i个元素均匀分配的。但是这种情况下,意味着前i-1个元素的均匀分配会产生更大的数值,那个数值会overwirte掉最终的答案,而使得“前i个元素均匀分配”这种实际上无法实现的策略不会干扰最终答案。
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### 204.Count-Primes

用倍数筛除法去除所有已知质数的倍数。最高效的容器是bool型的vector
用倍数筛除法去除所有已知质数的倍数。
```cpp
vector<bool>q(n,true);
for (x=2; x<=sqrt(n); x++)
Expand All @@ -14,5 +14,7 @@ for (x=2; x<=sqrt(n); x++)

注意,x的判断范围是从2到sqrt(n)即可,不需要遍历到n。

埃氏筛的时间复杂度是O(NloglogN)

[Leetcode Link](https://leetcode.com/problems/count-primes)

[Leetcode Link](https://leetcode.com/problems/count-primes)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Solution {
public:
int minOperations(vector<int>& nums, vector<int>& numsDivide)
{
int x = numsDivide[0];

for (int i=1; i<numsDivide.size(); i++)
x = gcd(x, numsDivide[i]);

sort(nums.begin(), nums.end());

for (int i=0; i<nums.size(); i++)
{
if (x%nums[i]==0)
return i;
}

return -1;

}
};
3 changes: 3 additions & 0 deletions Math/2344.Minimum-Deletions-to-Make-Array-Divisible/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### 2344.Minimum-Deletions-to-Make-Array-Divisible

非常直观。要numsDivide里面所有的元素都能整除x,充要条件就是`gcd(numsDivide)`也能整除x。所以我们将nums里面所有小于gcd的元素拿走即可。
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Solution {
public:
long long countSubarrays(vector<int>& nums, int minK, int maxK)
{
long long ret = 0;
int prevMin = -1, prevMax = -1, boundary = -1;
for (int i=0; i<nums.size(); i++)
{
if (nums[i]<minK || nums[i]>maxK)
{
boundary = i;
continue;
}

if (nums[i] == minK)
prevMin = i;
if (nums[i] == maxK)
prevMax = i;

ret += max(0, min(prevMin, prevMax) - boundary);
}

return ret;
}
};
5 changes: 5 additions & 0 deletions Others/2444.Count-Subarrays-With-Fixed-Bounds/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### 2444.Count-Subarrays-With-Fixed-Bounds

本题的关键是掌握好“数subarray”的诀窍。我们通常都是固定一个端点,查看另一个端点可以在哪些地方。

我们考虑如果这个subarray的右边是nums[i],那么这个subarray的左端点之后必须包含至少一个minK和maxK。所以我们只要知道i左边最近的minK和maxK,取两者的较小值j,那么[j:i]就是以i结尾的、最短的符合条件的subarray。左端点从j往左延伸的话,这个subarray依然有效。但是特别注意,左端点不能延伸到非法的区域,即小于minK或者大于maxK的地方,所以实际左端点移动的范围是j-boundary,其中boundary是i之前最近的非法位置。
9 changes: 6 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@
[166.Fraction-to-Recurring-Decimal](https://github.com/wisdompeak/LeetCode/tree/master/Hash/166.Fraction-to-Recurring-Decimal) (M)
[170.Two-Sum-III-Data-structure-design](https://github.com/wisdompeak/LeetCode/tree/master/Hash/170.Two-Sum-III-Data-structure-design) (M)
[392.Is-Subsequence](https://github.com/wisdompeak/LeetCode/tree/master/Hash/392.Is-Subsequence) (H-)
[204.Count Primes](https://github.com/wisdompeak/LeetCode/tree/master/Hash/204.Count-Primes) (M)
[274.H-Index](https://github.com/wisdompeak/LeetCode/tree/master/Hash/274.H-Index) (H)
[325.Maximum-Size-Subarray-Sum-Equals-k](https://github.com/wisdompeak/LeetCode/tree/master/Hash/325.Maximum-Size-Subarray-Sum-Equals-k) (M)
[409.Longest-Palindrome](https://github.com/wisdompeak/LeetCode/tree/master/Hash/409.Longest-Palindrome) (M)
Expand Down Expand Up @@ -539,6 +538,7 @@
[2192.All-Ancestors-of-a-Node-in-a-Directed-Acyclic-Graph](https://github.com/wisdompeak/LeetCode/tree/master/BFS/2192.All-Ancestors-of-a-Node-in-a-Directed-Acyclic-Graph) (M)
[2204.Distance-to-a-Cycle-in-Undirected-Graph](https://github.com/wisdompeak/LeetCode/tree/master/BFS/2204.Distance-to-a-Cycle-in-Undirected-Graph) (M)
[2392.Build-a-Matrix-With-Conditions](https://github.com/wisdompeak/LeetCode/tree/master/BFS/2392.Build-a-Matrix-With-Conditions) (M+)
[2440.Create-Components-With-Same-Value](https://github.com/wisdompeak/LeetCode/tree/master/BFS/2440.Create-Components-With-Same-Value) (H-)
* ``Dijkstra (BFS+PQ)``
[743.Network-Delay-Time](https://github.com/wisdompeak/LeetCode/tree/master/BFS/743.Network-Delay-Time) (H)
[407.Trapping-Rain-Water-II](https://github.com/wisdompeak/LeetCode/tree/master/BFS/407.Trapping-Rain-Water-II) (H)
Expand Down Expand Up @@ -1026,7 +1026,6 @@
[1806.Minimum-Number-of-Operations-to-Reinitialize-a-Permutation](https://github.com/wisdompeak/LeetCode/tree/master/Math/1806.Minimum-Number-of-Operations-to-Reinitialize-a-Permutation) (H)
[1969.Minimum-Non-Zero-Product-of-the-Array-Elements](https://github.com/wisdompeak/LeetCode/tree/master/Math/1969.Minimum-Non-Zero-Product-of-the-Array-Elements) (M+)
[2128.Remove-All-Ones-With-Row-and-Column-Flips](https://github.com/wisdompeak/LeetCode/tree/master/Math/2128.Remove-All-Ones-With-Row-and-Column-Flips) (M+)
[2183.Count-Array-Pairs-Divisible-by-K](https://github.com/wisdompeak/LeetCode/tree/master/Math/2183.Count-Array-Pairs-Divisible-by-K) (M+)
[2217.Find-Palindrome-With-Fixed-Length](https://github.com/wisdompeak/LeetCode/tree/master/Math/2217.Find-Palindrome-With-Fixed-Length) (M+)
* ``Distances``
[296.Best-Meeting-Point](https://github.com/wisdompeak/LeetCode/tree/master/Math/296.Best-Meeting-Point) (M+)
Expand Down Expand Up @@ -1073,10 +1072,13 @@
[2221.Find-Triangular-Sum-of-an-Array](https://github.com/wisdompeak/LeetCode/tree/master/Math/2221.Find-Triangular-Sum-of-an-Array) (M)
[2400.Number-of-Ways-to-Reach-a-Position-After-Exactly-k-Steps](https://github.com/wisdompeak/LeetCode/tree/master/Math/2400.Number-of-Ways-to-Reach-a-Position-After-Exactly-k-Steps) (M+)
* ``Numerical Theory``
[204.Count-Primes](https://github.com/wisdompeak/LeetCode/tree/master/Math/204.Count-Primes) (M)
[343.Integer-Break](https://github.com/wisdompeak/LeetCode/tree/master/Math/343.Integer-Break) (H-)
[365.Water-and-Jug-Problem](https://github.com/wisdompeak/LeetCode/tree/master/Math/365.Water-and-Jug-Problem) (H)
[1808.Maximize-Number-of-Nice-Divisors](https://github.com/wisdompeak/LeetCode/tree/master/Math/1808.Maximize-Number-of-Nice-Divisors) (H-)

[1819.Number-of-Different-Subsequences-GCDs](https://github.com/wisdompeak/LeetCode/tree/master/Math/1819.Number-of-Different-Subsequences-GCDs) (H-)
[2183.Count-Array-Pairs-Divisible-by-K](https://github.com/wisdompeak/LeetCode/tree/master/Math/2183.Count-Array-Pairs-Divisible-by-K) (M+)
[2344.Minimum-Deletions-to-Make-Array-Divisible](https://github.com/wisdompeak/LeetCode/tree/master/Math/2344.Minimum-Deletions-to-Make-Array-Divisible) (E)

#### [Greedy](https://github.com/wisdompeak/LeetCode/tree/master/Greedy)
[055.Jump-Game](https://github.com/wisdompeak/LeetCode/tree/master/Greedy/055.Jump-Game) (E+)
Expand Down Expand Up @@ -1293,6 +1295,7 @@
[2262.Total-Appeal-of-A-String](https://github.com/wisdompeak/LeetCode/tree/master/Greedy/2262.Total-Appeal-of-A-String) (M+)
[2281.Sum-of-Total-Strength-of-Wizards](https://github.com/wisdompeak/LeetCode/tree/master/Others/2281.Sum-of-Total-Strength-of-Wizards) (H)
[2302.Count-Subarrays-With-Score-Less-Than-K](https://github.com/wisdompeak/LeetCode/tree/master/Others/2302.Count-Subarrays-With-Score-Less-Than-K) (H-)
[2444.Count-Subarrays-With-Fixed-Bounds](https://github.com/wisdompeak/LeetCode/tree/master/Others/2444.Count-Subarrays-With-Fixed-Bounds) (M+)
* ``扫描线 / 差分数组``
[252.Meeting-Rooms](https://github.com/wisdompeak/LeetCode/tree/master/Others/252.Meeting-Rooms) (M)
[253.Meeting-Rooms-II](https://github.com/wisdompeak/LeetCode/tree/master/Others/253.Meeting-Rooms-II) (M+)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
result = max(result,x.second);
return result;
```
这个解法能够AC,但是比其他答案要慢得多.原因是100000以内的质数筛检非常费事.怎么改进呢?
这个解法能够AC,但是比其他答案要慢得多.原因是100000以内的质数有9592个。对于每个nums[i]要check将近10000次,效率很低。

第二个版本,我们只需要求出sqrt(100000)以内的所有质数Pi,这样预处理的规模就小了很多.但是如果继续按照上面的算法,如何保证得到a的所有质因数Pi并建立联系呢?其实我们只要将a不断除以它在sqrt(100000)以内的所有质因数,如果仍然大于1,那么剩下的必然是它唯一的一个大于sqrt(100000)的质因数.因为任何数不可能含有两个大于sqrt(100000)的质因数的.
第二个版本,我们只需要求出sqrt(100000)以内的所有质数Pi,这样只有70个左右。但是如果继续按照上面的算法,如何保证得到a的所有质因数Pi并建立联系呢?其实我们只要将a不断除以它在sqrt(100000)以内的所有质因数,如果仍然大于1,那么剩下的必然是它唯一的一个大于sqrt(100000)的质因数.因为任何数不可能含有两个大于sqrt(100000)的质因数的.
```cpp
vector<int>primes = makePrimes(sqrt(100000));
for (auto p:primes) Root[p] = p;
Expand Down Expand Up @@ -67,4 +67,4 @@
```


[Leetcode Link](https://leetcode.com/problems/largest-component-size-by-common-factor)
[Leetcode Link](https://leetcode.com/problems/largest-component-size-by-common-factor)