给你一个偶数 n
,已知存在一个长度为 n
的排列 perm
,其中 perm[i] == i
(下标 从 0 开始 计数)。
一步操作中,你将创建一个新数组 arr
,对于每个 i
:
- 如果
i % 2 == 0
,那么arr[i] = perm[i / 2]
- 如果
i % 2 == 1
,那么arr[i] = perm[n / 2 + (i - 1) / 2]
然后将 arr
赋值给 perm
。
要想使 perm
回到排列初始值,至少需要执行多少步操作?返回最小的 非零 操作步数。
示例 1:
输入:n = 2 输出:1 解释:最初,perm = [0,1] 第 1 步操作后,perm = [0,1] 所以,仅需执行 1 步操作
示例 2:
输入:n = 4 输出:2 解释:最初,perm = [0,1,2,3] 第 1 步操作后,perm = [0,2,1,3] 第 2 步操作后,perm = [0,1,2,3] 所以,仅需执行 2 步操作
示例 3:
输入:n = 6 输出:4
提示:
2 <= n <= 1000
n
是一个偶数
方法一:找规律 + 模拟
我们观察数字的变化规律,发现:
- 新数组的偶数位数字依次是原数组的前半段数字;
- 新数组的奇数位数字依次是原数组的后半段数字。
即,如果原数组的某个数字下标 [0, n >> 1)
范围内,那么这个数字的新下标就是 i << 1
;否则,新下标就是 (i - (n >> 1)) << 1 | 1
。
另外,每一轮操作,数字移动的路径都是一样的,只要有一个数字(数字
因此,我们选择数字
时间复杂度
class Solution:
def reinitializePermutation(self, n: int) -> int:
ans, i = 0, 1
while 1:
ans += 1
if i < n >> 1:
i <<= 1
else:
i = (i - (n >> 1)) << 1 | 1
if i == 1:
return ans
class Solution {
public int reinitializePermutation(int n) {
int ans = 0;
for (int i = 1; ; ) {
++ans;
if (i < (n >> 1)) {
i <<= 1;
} else {
i = (i - (n >> 1)) << 1 | 1;
}
if (i == 1) {
return ans;
}
}
}
}
class Solution {
public:
int reinitializePermutation(int n) {
int ans = 0;
for (int i = 1; ; ) {
++ans;
if (i < (n >> 1)) {
i <<= 1;
} else {
i = (i - (n >> 1)) << 1 | 1;
}
if (i == 1) {
return ans;
}
}
}
};
func reinitializePermutation(n int) (ans int) {
for i := 1; ; {
ans++
if i < (n >> 1) {
i <<= 1
} else {
i = (i-(n>>1))<<1 | 1
}
if i == 1 {
return ans
}
}
}