题目链接
Leetcode.1806 还原排列的最少操作步数
题目描述
给你一个偶数 n n n ,已知存在一个长度为 n n n 的排列 p e r m perm perm ,其中 p e r m [ i ] = i perm[i] = i perm[i]=i(下标 从 0 开始 计数)。
一步操作中,你将创建一个新数组 a r r arr arr ,对于每个 i i i :
如果
i
i
i 是偶数 ,那么
a
r
r
[
i
]
=
p
e
r
m
[
i
/
2
]
arr[i] = perm[i / 2]
arr[i]=perm[i/2]
如果
i
i
i 是奇数 ,那么
a
r
r
[
i
]
=
p
e
r
m
[
n
/
2
+
(
i
−
1
)
/
2
]
arr[i] = perm[n / 2 + (i - 1) / 2]
arr[i]=perm[n/2+(i−1)/2]
然后将
a
r
r
arr
arr 赋值给
p
e
r
m
perm
perm 。
要想使 p e r m 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 2 <= n <= 1000 2<=n<=1000
n 是一个偶数
解法一:由于数据量比较小,我们可以直接进行模拟
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
代码:
class Solution {
public:
int reinitializePermutation(int n) {
vector<int> prem(n),arr(n);
for(int i = 0;i < n;i++) prem[i] = i;
int ans = 0;
while(true){
ans++;
for(int i = 0;i < n;i++){
if(i % 2) arr[i] = prem[n/2 + (i-1)/2];
else arr[i] = prem[i/2];
}
prem = arr;
bool ok = true;
for(int i = 0;i < n;i++){
if(prem[i] != i){
ok = false;
break;
}
}
if(ok) break;
}
return ans;
}
};
解法二:找规律
- 时间复杂度: O ( n ) O(n) O(n)
C++代码:
class Solution {
public:
int reinitializePermutation(int n) {
int ans = 0;
int i = 1;
while(true){
ans++;
if(i < n / 2) i <<= 1;
else i = (i - n/2) << 1 | 1;
if(i == 1) break;
}
return ans;
}
};
Java代码:
class Solution {
public int reinitializePermutation(int n) {
int ans = 0;
int i = 1;
while(true){
ans++;
if(i < n / 2) i <<= 1;
else i = (i - n/2) << 1 | 1;
if(i == 1) break;
}
return ans;
}
}