视频还讲解了如何手算二元一次不定方程!欢迎点赞!
为方便描述,将
先来解决
根据题意,考虑从
化简得
换句话说:
- ……
按照
让数组
根据中位数贪心,将
证明:设
回到原问题。
比如
根据这个例子,可以猜想一个结论:
一个循环数组如果既有周期
证明:根据 裴蜀定理,有
这样就转换成了不是循环数组的情况。
注:代码中的排序可以换成快速选择,从而做到
的时间复杂度。具体见 C++ 代码。
class Solution:
def makeSubKSumEqual(self, arr: List[int], k: int) -> int:
k = gcd(k, len(arr))
ans = 0
for i in range(k):
b = sorted(arr[i::k])
mid = b[len(b) // 2]
ans += sum(abs(x - mid) for x in b)
return ans
class Solution {
public long makeSubKSumEqual(int[] arr, int k) {
int n = arr.length;
k = gcd(k, n);
long ans = 0;
for (int i = 0; i < k; ++i) {
var b = new ArrayList<Integer>();
for (int j = i; j < n; j += k)
b.add(arr[j]);
Collections.sort(b);
int mid = b.get(b.size() / 2);
for (int x : b)
ans += Math.abs(x - mid);
}
return ans;
}
private int gcd(int a, int b) {
while (a != 0) {
int tmp = a;
a = b % a;
b = tmp;
}
return b;
}
}
class Solution {
public:
long long makeSubKSumEqual(vector<int> &arr, int k) {
int n = arr.size();
k = gcd(k, n);
vector<vector<int>> g(k);
for (int i = 0; i < n; ++i)
g[i % k].push_back(arr[i]);
long long ans = 0;
for (auto &b: g) {
nth_element(b.begin(), b.begin() + b.size() / 2, b.end());
for (int x: b)
ans += abs(x - b[b.size() / 2]);
}
return ans;
}
};
func makeSubKSumEqual(arr []int, k int) (ans int64) {
k = gcd(k, len(arr))
g := make([][]int, k)
for i, x := range arr {
g[i%k] = append(g[i%k], x)
}
for _, b := range g {
sort.Ints(b)
for _, x := range b {
ans += int64(abs(x - b[len(b)/2]))
}
}
return
}
func gcd(a, b int) int {
for a != 0 {
a, b = b%a, a
}
return b
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
- 时间复杂度:$O(n\log n)$ 或
,其中 为 的长度。采用快速选择找中位数可以做到 ,见 C++ 代码。 - 空间复杂度:$O(n)$。