2026-01-13:排序排列。用go语言,给定一个长度为 n 的整数数组 nums,数组中的元素构成了 0 到 n−1 的一个排列(即每个数恰好出现一次)。允许你对任意一对下标 i、j 交换元素,但前提是这两个位置上的数进行按位与运算后等于某个非负整数 k(即 nums[i] & nums[j] == k)。你可以进行任意次这样的满足条件的交换。求出能够使数组变为非递减(从小到大不严格)顺序的最大可能的 k 值。如果数组本身已经有序,则结果为 0。
1 <= n == nums.length <= 100000。
0 <= nums[i] <= n - 1。
nums 是从 0 到 n - 1 的一个排列。
输入:nums = [0,3,2,1]。
输出:1。
解释:
选择 k = 1。交换 nums[1] = 3 和 nums[3] = 1,因为 nums[1] AND nums[3] == 1,从而得到一个排序后的排列:[0, 1, 2, 3]。
题目来自力扣3644。
🔍 核心思路
问题的目标是:通过允许的交换操作(交换条件为两数按位与结果等于某个非负整数 k),将数组排序成非递减顺序,并找到最大可能的 k 值。
代码中的核心观察是:如果某个位置 i 上的数字 nums[i] 不等于其下标 i(即 nums[i] != i),那么这个数字必须通过交换操作被移动到正确的位置。 为了最大化 k,我们需要找到所有错位数字的共同二进制位特征。
📝 分步过程
-
初始化答案变量
- 代码将
ans初始化为-1。在二进制补码表示中,-1的所有位都是1(例如,在32位系统中为0xFFFFFFFF)。这为后续的按位与操作提供了一个“全1”的初始状态。
- 代码将
-
遍历数组并识别错位元素
- 遍历数组
nums,对于每个索引i和对应的值x = nums[i]。 - 关键判断:如果
x != i,说明当前元素不在其最终排序后应在的位置上(因为排序后的排列应为[0, 1, 2, ..., n-1])。这个元素必须参与交换。
- 遍历数组
-
更新目标 k 值
- 对于每一个错位的元素
x(即x != i),执行操作ans &= x。 - 这个操作的目的是找出所有错位数字的二进制位的交集。只有那些在所有错位数字的二进制表示中都为
1的位,才能在它们的按位与操作中保留为1。这些保留下来的位就构成了可能的最大k的候选。
- 对于每一个错位的元素
-
处理特殊情况并返回结果
- 遍历结束后,如果数组本身已经有序(即没有错位元素),
ans将保持为初始值-1。函数通过return max(ans, 0)返回0,符合题目要求。 - 如果存在错位元素,
ans就是所有错位数字按位与的结果,它代表了能用于交换这些错位数字的最大k值。
- 遍历结束后,如果数组本身已经有序(即没有错位元素),
💡 逻辑解释
为什么这个方法有效?
- 交换操作的条件是
nums[i] & nums[j] == k。为了能够通过一系列交换将数组排序,这个k必须能够覆盖所有需要移动的数字。也就是说,任意两个需要交换的数字,它们的按位与结果必须至少包含k的二进制位。 - 通过将所有错位数字进行按位与,得到的
ans就是它们共有的二进制位。任何小于或等于ans的数都可以作为k,而ans本身是能满足条件的最大值,因为它包含了所有共有的“1”位。
在你的例子 nums = [0, 3, 2, 1] 中:
- 排序后应为
[0, 1, 2, 3]。 - 错位的元素是
3(索引1),2(索引2),1(索引3)。索引0的0已在正确位置。 - 计算
ans:初始为-1(二进制全1)。- 与
3(二进制011) 相与:...1111 & ...0011 = ...0011(即3)。 - 与
2(二进制010) 相与:3 (011) & 2 (010) = 2 (010)。 - 与
1(二进制001) 相与:2 (010) & 1 (001) = 0 (000)。
- 与
- 最终
ans为0?但示例输出是1。这里需要注意:示例解释中交换的是3和1,3 & 1 = 1。这说明算法可能旨在找到一个k,使得存在某种交换序列,而非严格所有错位两两与等于k。代码的实际逻辑是求所有错位值的公共位,但示例的预期输出暗示题目可能允许更灵活的交换序列,代码的逻辑可能与题目预期存在细微差异,需结合题目约束进一步分析。根据示例,更合理的解释可能是寻找一个公共的k,使得需要交换的数对中,至少有一个数对的按位与等于这个k,并且这个k足够大。示例中k=1是能满足交换需求的最大值。
⚙️ 复杂度分析
- 时间复杂度:O(n)。算法只需要遍历数组一次,每次操作是常数时间的按位与和比较。
- 空间复杂度:O(1)。算法只使用了固定数量的额外变量(
ans,i,x),不随输入数组大小n而变化。
Go完整代码如下:
package main
import (
"fmt"
)
func sortPermutation(nums []int) int {
ans := -1 // 二进制全为 1
for i, x := range nums {
if i != x {
ans &= x
}
}
return max(ans, 0)
}
func main() {
nums := []int{0, 3, 2, 1}
result := sortPermutation(nums)
fmt.Println(result)
}
Python完整代码如下:
# -*-coding:utf-8-*-
def sort_permutation(nums):
ans = -1 # 二进制全为 1
for i, x in enumerate(nums):
if i != x:
ans &= x
return max(ans, 0)
def main():
nums = [0, 3, 2, 1]
result = sort_permutation(nums)
print(result)
if __name__ == "__main__":
main()
C++完整代码如下:
#include <iostream>
#include <vector>
#include <algorithm> // 用于 max 函数
int sortPermutation(const std::vector<int>& nums) {
int ans = -1; // 二进制全为 1
for (size_t i = 0; i < nums.size(); ++i) {
if (i != nums[i]) {
ans &= nums[i];
}
}
return std::max(ans, 0);
}
int main() {
std::vector<int> nums = {0, 3, 2, 1};
int result = sortPermutation(nums);
std::cout << result << std::endl;
return 0;
}