跳转至

1806. 还原排列的最少操作步数

题目描述

给你一个偶数 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​​​​​​ 是一个偶数

解法

方法一:找规律 + 模拟

我们观察数字的变化规律,发现:

  1. 新数组的偶数位数字依次是原数组的前半段数字;
  2. 新数组的奇数位数字依次是原数组的后半段数字。

即,如果原数组的某个数字下标 $i$ 在 [0, n >> 1) 范围内,那么这个数字的新下标就是 i << 1;否则,新下标就是 (i - (n >> 1)) << 1 | 1

另外,每一轮操作,数字移动的路径都是一样的,只要有一个数字(数字 $0$ 和 $n-1$ 除外)回到了它原来的位置,那么整个序列就和之前的一致了。

因此,我们选择数字 $1$,初始时下标也是 $1$,每次将数字 $1$ 移动到新的位置,直到数字 $1$ 回到原来的位置,就可以得到最小的操作次数。

时间复杂度 $O(n)$,空间复杂度 $O(1)$。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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;
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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;
            }
        }
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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
        }
    }
}

评论