题目链接
https://leetcode-cn.com/problems/minimum-number-of-operations-to-reinitialize-a-permutation/
题目描述
输入是一个偶数n
,对于一个长度为n
的排列perm
,这个排列满足perm[i] == i
(下标从0开始计数),对这个排列进行若干步操作。
对于每一步操作:
(1) 首先将创建一个新数组arr
,对于每个i
:
- 如果
i % 2 == 0
,那么arr[i] == perm[i / 2]
- 如果
i % 2 == 1
,那么arr[i] == perm[n / 2 + (i - 1) / 2]
(2) 然后将arr
赋给perm
。
问最少多少步这样的操作,可以使得perm
回到最初的状态,即perm[i] == i
。
相关知识点[数论]
1. 整除
设
a
,
b
a,b
a,b 均为正数,
b
≠
0
b≠0
b=0. 若存在整数
q
q
q使得
a
=
b
q
a=bq
a=bq则称
b
b
b整除
a
a
a,记为
b
∣
a
b\ |\ a
b ∣ a.
2. 同余
设 m , a , b ∈ Z m,a,b\in\Z m,a,b∈Z(即为整数), m ≠ 0 m\neq0 m=0,如果 m ∣ ( a − b ) m \ |\ (a-b) m ∣ (a−b)则称 a a a与 b b b对模 m m m同余,记为 a ≡ b ( mod m ) a\equiv b(\text{mod}\ m) a≡b(mod m),称 m m m为模.
3. 同余传递性
若 a ≡ b ( mod m ) a\equiv b(\text{mod} \ m) a≡b(mod m), b ≡ c ( mod m ) b\equiv\ c(\text{mod}\ m) b≡ c(mod m),则 a ≡ c ( mod m ) a\equiv\ c(\text{mod}\ m) a≡ c(mod m).
证明
a
≡
b
(
mod
m
)
a\equiv b(\text{mod} \ m)
a≡b(mod m),所以
a
=
b
+
m
k
(
k
∈
Z
)
a=b+mk(k\in\Z)
a=b+mk(k∈Z);同理
b
=
c
+
m
j
(
j
∈
Z
)
.
b=c+mj(j\in\Z).
b=c+mj(j∈Z). 所以
a
=
c
+
m
(
k
+
j
)
a=c+m(k+j)
a=c+m(k+j),其中
(
k
+
j
)
∈
Z
(k+j)\in\Z
(k+j)∈Z. 所以
m
∣
(
a
−
c
)
m\ |\ (a-c)
m ∣ (a−c),所以
a
≡
c
(
mod
m
)
a\equiv\ c(\text{mod}\ m)
a≡ c(mod m).
4. 同余式相乘
若 a ≡ b ( mod m ) a\equiv b(\text{mod}\ m) a≡b(mod m), c ≡ d ( mod m ) c\equiv d(\text{mod}\ m) c≡d(mod m),则 a c ≡ b d ( mod m ) ac\equiv bd(\text{mod}\ m) ac≡bd(mod m).
证明
a
≡
b
(
mod
m
)
a\equiv b(\text{mod}\ m)
a≡b(mod m),所以
a
=
b
+
m
k
(
k
∈
Z
)
a = b + mk(k\in\Z)
a=b+mk(k∈Z);同理
c
=
d
+
m
j
(
j
∈
Z
)
c=d+mj(j\in\Z)
c=d+mj(j∈Z). 二式相乘得
a
c
=
(
b
+
m
k
)
(
d
+
m
j
)
=
b
d
+
(
b
j
+
d
k
)
m
+
j
k
m
2
ac=(b+mk)(d+mj)=bd+(bj+dk)m+jkm^2
ac=(b+mk)(d+mj)=bd+(bj+dk)m+jkm2,所以
a
c
−
b
d
=
m
(
b
j
+
d
k
+
j
k
m
)
ac-bd=m(bj+dk+jkm)
ac−bd=m(bj+dk+jkm),其中
(
b
j
+
d
k
+
j
k
m
)
∈
Z
(bj+dk+jkm)\in\Z
(bj+dk+jkm)∈Z,所以
m
∣
(
a
c
−
b
d
)
m\ |\ (ac-bd)
m ∣ (ac−bd),所以
a
c
≡
b
d
(
mod
m
)
ac\equiv bd(\text{mod}\ m)
ac≡bd(mod m).
由此可推出:
若
a
≡
b
(
mod
m
)
a\equiv b(\text{mod}\ m)
a≡b(mod m),则
a
c
≡
b
c
(
mod
m
)
ac\equiv bc(\text{mod}\ m)
ac≡bc(mod m),
c
∈
Z
c\in\Z
c∈Z.
证明
显然有
c
≡
c
(
mod
m
)
c\equiv c(\text{mod}\ m)
c≡c(mod m),又有
a
≡
b
(
mod
m
)
a\equiv b(\text{mod}\ m)
a≡b(mod m),所以
a
c
≡
b
c
(
mod
m
)
ac\equiv bc(\text{mod}\ m)
ac≡bc(mod m).
5. 欧拉定理
设整数
a
a
a与
m
m
m互素,则
a
φ
(
m
)
≡
1
(
mod
m
)
a^{\varphi(m)}\equiv1\ \ \ (\text{mod}\ m)
aφ(m)≡1 (mod m)其中
φ
\varphi
φ是Euler函数,即
φ
(
m
)
\varphi(m)
φ(m)是"小于
m
m
m且与
m
m
m互素"的正整数个数.
思路
这个题目的步骤模拟起来较为简单,因此可以采用暴力求解的方式。以下分析总结参考自 可爱不是 3 岁的题解(复杂度O(n))。
由于n
是个偶数,所以n
一定可以被2
整除,并且n/2
是一个奇数。
首先分析题目中的操作,设一次操作前的位置为j
,一次操作后的位置为i
(与题目吻合),对于该操作中的两种情况:
(1) 如果 i % 2 == 0
,那么arr[i] == perm[i / 2]
- 这里的
i
取值范围是[0,n-2]
中的偶数(n-1是奇数),其实相当于把原排列的前半部分依次放置在新排列的偶数位置上; - 反过来思考,考虑原排列的前半部分,对于第
j (j<n/2)
个元素,它在一次操作完成后的新位置i
满足j = i / 2
,所以i = 2j
。
(2) 如果i % 2 == 1
,那么arr[i] == perm[n / 2 + (i - 1) / 2]
- 这里的
i
取值范围是[1,n-1]
中的奇数,其实相当于把原排列的后半部分依次放置在新排列的奇数位置上; - 反过来思考,考虑原排列的后半部分,对于第
j (j>=n/2)
个元素,它在一次操作完成后的新位置i
满足j = n / 2 + (i - 1) / 2
,其中n
是偶数,所以i = 2j - (n - 1)
。
可以发现,原排列的第0
个元素和第n-1
个元素的位置在操作前后不会发生变化,所以我们只考虑第1
个元素到第n-2
个元素,也即j
取值为[1,n-2]
。
综合上述两种情况,将
i
i
i 记为
f
(
j
)
f(j)
f(j)
f
(
j
)
=
{
2
j
j
=
1
,
2
,
.
.
.
,
n
2
−
1
2
j
−
(
n
−
1
)
j
=
n
2
,
n
2
+
1
,
.
.
.
,
n
−
2
(1)
\begin{aligned}f(j)=\left\{\begin{matrix}2j & j=1,2,...,{\frac{n}{2}-1}\\2j - (n-1)&j=\frac{n}{2},\frac{n}{2}+1,...,n-2\end{matrix}\right.\end{aligned}\tag{1}
f(j)={2j2j−(n−1)j=1,2,...,2n−1j=2n,2n+1,...,n−2(1)
所以,一定有
2
j
mod
(
n
−
1
)
=
f
(
j
)
j
=
1
,
2
,
.
.
.
,
n
−
2
(2)
2j \ \text{mod}\ (n-1)=f(j)\ \ \ \ \ \ j=1,2,...,n-2\tag{2}
2j mod (n−1)=f(j) j=1,2,...,n−2(2)
因为
f
(
j
)
∈
[
1
,
n
−
2
]
f(j)\in[1,n-2]
f(j)∈[1,n−2](第0个元素和第n-1个元素位置始终不变),所以式(2)等价于
f
(
j
)
f(j)
f(j)与
2
j
2j
2j同余,即
f
(
j
)
≡
2
j
(
mod
(
n
−
1
)
)
(3)
f(j)\equiv2j\ \ \ \left(\text{mod}\ (n-1)\right)\tag{3}
f(j)≡2j (mod (n−1))(3)
将进行 k k k次操作后的下标记为 f k ( j ) f^k(j) fk(j)。
根据式(3)和同余式相乘的性质可得
2
f
(
j
)
≡
4
j
(
mod
(
n
−
1
)
)
(4)
2f(j)\equiv4j\ \ \ \left(\text{mod}\ (n-1)\right)\tag{4}
2f(j)≡4j (mod (n−1))(4)
又有
f
2
(
j
)
≡
2
f
(
j
)
(
mod
(
n
−
1
)
)
(5)
f^2(j)\equiv2f(j)(\text{mod}(n-1))\tag{5}
f2(j)≡2f(j)(mod(n−1))(5)
根据式(4)和式(5)以及同余的传递性可得
f
2
(
j
)
≡
4
j
(
mod
(
n
−
1
)
)
(6)
f^2(j)\equiv4j(\text{mod}(n-1))\tag{6}
f2(j)≡4j(mod(n−1))(6)
同理可得,
f
3
(
j
)
≡
8
j
(
mod
(
n
−
1
)
)
f^3(j)\equiv8j(\text{mod}(n-1))
f3(j)≡8j(mod(n−1))、
f
4
(
j
)
≡
16
j
(
mod
(
n
−
1
)
)
f^4(j)\equiv16j(\text{mod}(n-1))
f4(j)≡16j(mod(n−1))、
f
5
(
j
)
≡
32
j
(
mod
(
n
−
1
)
)
⋯
f^5(j)\equiv32j(\text{mod}(n-1))\cdots
f5(j)≡32j(mod(n−1))⋯
所以,对于
∀
k
≥
1
\forall k\geq1
∀k≥1
f
k
(
j
)
≡
2
k
j
(
mod
(
n
−
1
)
)
(7)
f^k(j)\equiv2^kj \ \ \ \left(\text{mod}\ (n-1)\right)\tag{7}
fk(j)≡2kj (mod (n−1))(7)
如果进行
k
k
k次操作后数列被还原,那么
f
k
(
j
)
=
j
f^k(j)=j
fk(j)=j,代入式(7),得
j
≡
2
k
j
(
mod
(
n
−
1
)
)
(8)
j\equiv2^kj \ \ \ \left(\text{mod}\ (n-1)\right)\tag{8}
j≡2kj (mod (n−1))(8)
将
j
=
1
j=1
j=1带入式(8),得
1
≡
2
k
(
mod
(
n
−
1
)
)
(9)
1\equiv2^k \ \ \ \left(\text{mod}\ (n-1)\right)\tag{9}
1≡2k (mod (n−1))(9)
而对于式(9),两边乘以
j
j
j(根据同余式相乘的性质)即得式(8)。
所以式(8)和式(9)等价,这意味着,如果经过k次操作后排列的第1个元素被复原了(也就是说元素1又回到了位置1),那么整个排列都会被复原,因此程序可以得到简化。
因为
n
−
1
n-1
n−1是奇数,
2
2
2和
n
−
1
n-1
n−1互质,那么根据欧拉定理
2
φ
(
n
−
1
)
≡
1
(
mod
(
n
−
1
)
)
(10)
2^{\varphi(n-1)}\equiv1\ (\text{mod}\ (n-1))\tag{10}
2φ(n−1)≡1 (mod (n−1))(10)所以
φ
(
n
−
1
)
\varphi(n-1)
φ(n−1)步操作后一定可以恢复最初的位置。而
φ
(
n
−
1
)
\varphi(n-1)
φ(n−1)表示"小于n-1且与n-1互素的正整数个数",所以
φ
(
n
−
1
)
<
n
−
1
\varphi(n-1)<n-1
φ(n−1)<n−1,所以最小的能够复原的操作步数一定小于
n
−
1
n-1
n−1,所以复杂度为
O
(
n
)
O(n)
O(n)。
代码
class Solution {
public:
int reinitializePermutation(int n) {
if (n == 2) return 1; // n=2的时候元素1是最后一个元素,没办法用套公式,所以单独拿出来
int cnt = 0; // 操作次数
int ele = 1; // 元素1的位置
do
{
cnt++;
ele = (ele * 2) % (n - 1); // 计算元素1的新位置
}while(ele != 1); // 如果说元素1又回到了位置1,那么整个序列也都被还原了
return cnt;
}
};