Leetcode 1806. 还原排列的最少操作步数
一、题目内容和对应链接
1.题目对应链接
2.题目内容
给你一个偶数 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 是一个偶数
二、我的想法
- 最开始观察了下,发现给的示例里面,第一步操作之后,和原数组不同的值的数量就是返回值,于是按着这个写了。
class Solution:
def reinitializePermutation(self, n: int) -> int:
perm = [i for i in range(n)]
arr = [i for i in range(n)]
returnnum = 0
for i in range(n):
if i % 2 == 0:
arr[i] = perm[int(i//2)]
elif i % 2 == 1:
arr[i] = perm[int(n // 2 + (i - 1) // 2)]
print(arr[i], i)
if arr[i] != i:
returnnum += 1
if returnnum == 0 :
return 1
else:
return returnnum
- 然后没过,我手动写了下 n = 10 时的数组。
【0 1 2 3 4 5 6 7 8 9】
【0 5 1 6 2 7 3 8 4 9】
n =10 的时候返回值为 6。
我想到,
如果 i % 2 == 0 ,那么 arr[i] = perm[i / 2]
如果 i % 2 == 1 ,那么 arr[i] = perm[n / 2 + (i - 1) / 2]
这个其实是固定的,对应的 arr[i] 值一定有一个固定的 perm[]值。
我想了下可能是要从 1 开始手尾相连的个数?
1 - 5,5 - 7,7 - 8,8 - 4, 4 - 2, 2 - 1
而 3 - 6, 6 - 3 每两次循环就换过来了,0 - 0 和 9 - 9永远不变。
那可以经历一次循环取到键值对,然后最后来一个循环看键值对需要经历多少步骤能够得到手尾相连。
class Solution:
def reinitializePermutation(self, n: int) -> int:
if n == 2 :
return 1
perm = [i for i in range(n)]
arr = [i for i in range(n)]
newdict = defaultdict(int)
returnnum = 0
for i in range(n):
if i % 2 == 0:
arr[i] = perm[int(i//2)]
elif i % 2 == 1:
arr[i] = perm[int(n // 2 + (i - 1) // 2)]
newdict[i] = arr[i] # 取到键值对
i = 1
left = 1
while i <= len(newdict):
if newdict[i] != i and newdict[i] != left:
i = newdict[i]
returnnum += 1
if newdict[i] == left:
returnnum += 1
return returnnum
三、其他人的题解
官方 - 模拟 / 数学,数学解法得这个欧拉定理我是一点也不会。
Tizzi - 模拟 / 模拟优化 ,我很喜欢这个模拟优化的想法。
ylb - 找规律 + 模拟,说明了为什么要从1开始算。