
2026-07-18:可排序整数求和。用go语言,给定一个长度为 n 的整数数组 nums。
现在考虑所有的正整数 k,要求 k 能够整除 n(即 k 是 n 的因数)。
对于这样的每个 k,我们把数组按顺序分成若干个长度都为 k 的小段(最后一段不会多余,因为 k 整除 n)。
然后允许我们对每一小段内部,独立地做任意次数的循环平移(可以向左或向右旋转任意步数)。
如果经过这样处理之后,整个数组能够变成非递减的顺序(从小到大排列),那么就称 k 是一个“可排序整数”。
最后,请你找出所有满足条件的 k,并把它们相加,返回这个总和。
1 <= n == nums.length <= 100000。
1 <= nums[i] <= 100000。
输入: nums = [3,1,2]。
输出: 3。
解释:
对于 n = 3,可能的因数是 1 和 3。
对于 k = 1:每个子数组都只有一个元素。无法通过移动使数组排序。
对于 k = 3:单个子数组 [3, 1, 2] 可以通过左移一次得到 [1, 2, 3],从而将数组排序。
只有 k = 3 可排序,因此答案是 3。
题目来自力扣3886。
nums,长度 n。n 的正整数 k(即 n % k == 0)。k 的小段。k 就是“可排序整数”。k,判断其是否可行的核心思路要判断一个 k 是否可行,我们可以一段一段地检查。
每个段内部的元素可以通过循环平移得到任意循环排列,因此我们需要知道每一段经过平移后能形成的最小值和最大值,以及它们之间的相对顺序限制。
比如:
因此,我们需要提前知道每个位置“下一个递减开始的位置”。
代码中有一个数组 nextDec,长度为 n。
nextDec[i] 表示从索引 i 开始,往后第一个满足 nums[j] > nums[j+1] 的位置 j。nextDec[i] 存放的是这个“下降位置”的索引。i 到末尾都是递增的,则 nextDec[i] = n(一个越界标记)。例如:
[3, 1, 2]3 > 1,所以下降位置是 0,nextDec[0] = 01 < 2,后面没有下降,所以 nextDec[1] = 3nextDec[2] = 3这个预处理很方便我们判断一个子数组 [l, r] 是不是“至多只有一个下降点”,并确定哪部分是递增的。
solve(k)这个函数判断长度为 k 的段是否可行,并累计可行的 k。
我们遍历整个数组,按长度 k 分块:
l 和结束位置 r:m = nextDec[l],即从 l 开始的第一个下降位置。m >= rl 到 r 完全递增。nums[l] ≥ 上一段的最大值(因为整体要保持非递减)。nums[r]。k 不可行。m < rm 是第一个下降位置。[l, m] 这一段是递增的,而 [m+1, r] 这一段也应该在原始数组中递增(否则会存在第二个下降点,就无法通过一次旋转变成有序)。nextDec[m+1] < r 表示存在第二个下降点 → 直接失败。nums[m+1] 必须 ≥ 上一段的最大值,否则拼接时会出现下降。nums[r] 必须 ≤ 第一段的最小值 nums[l],因为平移后我们通常把第二段放到前面(相当于旋转)。nums[m](因为平移后第一段在后面)。当所有段都通过检查,则 k 可行,累加到答案中。
因为 k 必须是 n 的因子,我们可以只枚举因子,不用遍历 1..n。
做法:
k = 1 到 sqrt(n),检查 n % k == 0:kk*k != n,再检查 n/k这样就能遍历所有正因子。
所有可行的 k 累加到 ans,最后返回。
nums = [3, 1, 2]nextDec:[0, 3, 3]k = 1
k = 3
答案 = 3。
nextDec 需要 O(n)。nextDec 数组,长度 n,因此额外空间为 O(n)。package main
import (
"fmt"
)
func sortableIntegers(nums []int) (ans int) {
n := len(nums)
nextDec := make([]int, n) // nums[nextDec[i]] > nums[nextDec[i] + 1]
nextDec[n-1] = n
p := n
// 对于每个 i,记录下一个递减的位置
for i := n - 2; i >= 0; i-- {
if nums[i] > nums[i+1] {
p = i
}
nextDec[i] = p
}
solve := func(k int) {
lastMax := 0// 上一段的最大值
for r := k - 1; r < n; r += k {
l := r - k + 1
m := nextDec[l]
if m >= r {
// [l, r] 是递增的,最小值为 nums[l],最大值为 nums[r]
// 最小值必须 >= 上一段的最大值
if nums[l] < lastMax {
return
}
lastMax = nums[r]
} else {
// [l, m] 是第一段,[m+1, r] 是第二段
// 第二段必须是递增的,且第二段的最小值必须 >= 上一段的最大值,且第二段的最大值必须 <= 第一段的最小值
if nextDec[m+1] < r || nums[m+1] < lastMax || nums[r] > nums[l] {
return
}
lastMax = nums[m]
}
}
ans += k // 满足要求
}
// 枚举 n 的因子 k
for k := 1; k*k <= n; k++ {
if n%k == 0 {
solve(k)
if k*k < n {
solve(n / k)
}
}
}
return
}
func main() {
nums := []int{3, 1, 2}
result := sortableIntegers(nums)
fmt.Println(result)
}

# -*-coding:utf-8-*-
defsortableIntegers(nums):
n = len(nums)
ans = 0
# next_dec[i] 表示从 i 开始第一个递减的位置
# 即 nums[next_dec[i]] > nums[next_dec[i] + 1]
next_dec = [n] * n
p = n
for i inrange(n - 2, -1, -1):
if nums[i] > nums[i + 1]:
p = i
next_dec[i] = p
defsolve(k):
nonlocal ans
last_max = 0# 上一段的最大值
for r inrange(k - 1, n, k):
l = r - k + 1
m = next_dec[l]
if m >= r:
# [l, r] 是递增的,最小值为 nums[l],最大值为 nums[r]
# 最小值必须 >= 上一段的最大值
if nums[l] < last_max:
return
last_max = nums[r]
else:
# [l, m] 是第一段,[m+1, r] 是第二段
# 第二段必须是递增的,且第二段的最小值必须 >= 上一段的最大值
# 且第二段的最大值必须 <= 第一段的最小值
if next_dec[m + 1] < r or nums[m + 1] < last_max or nums[r] > nums[l]:
return
last_max = nums[m]
ans += k # 满足要求
# 枚举 n 的因子 k
k = 1
while k * k <= n:
if n % k == 0:
solve(k)
if k * k < n:
solve(n // k)
k += 1
return ans
# 测试
if __name__ == "__main__":
nums = [3, 1, 2]
result = sortableIntegers(nums)
print(result)
#include <iostream>
#include <vector>
usingnamespace std;
int sortableIntegers(vector<int>& nums) {
int n = nums.size();
int ans = 0;
// nextDec[i] 表示从 i 开始第一个递减的位置
// 即 nums[nextDec[i]] > nums[nextDec[i] + 1]
vector<int> nextDec(n, n);
int p = n;
for (int i = n - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1]) {
p = i;
}
nextDec[i] = p;
}
// 使用 lambda 表达式定义 solve 函数
auto solve = [&](int k) {
int lastMax = 0; // 上一段的最大值
for (int r = k - 1; r < n; r += k) {
int l = r - k + 1;
int m = nextDec[l];
if (m >= r) {
// [l, r] 是递增的,最小值为 nums[l],最大值为 nums[r]
// 最小值必须 >= 上一段的最大值
if (nums[l] < lastMax) {
return;
}
lastMax = nums[r];
} else {
// [l, m] 是第一段,[m+1, r] 是第二段
// 第二段必须是递增的,且第二段的最小值必须 >= 上一段的最大值
// 且第二段的最大值必须 <= 第一段的最小值
if (nextDec[m + 1] < r || nums[m + 1] < lastMax || nums[r] > nums[l]) {
return;
}
lastMax = nums[m];
}
}
ans += k; // 满足要求
};
// 枚举 n 的因子 k
for (int k = 1; k * k <= n; k++) {
if (n % k == 0) {
solve(k);
if (k * k < n) {
solve(n / k);
}
}
}
return ans;
}
int main() {
vector<int> nums = {3, 1, 2};
int result = sortableIntegers(nums);
cout << result << endl;
return0;
}
