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

LeetCode 1806 | 最小操作步数让排列回到初始状态 — 数学与置换周期的巧妙应用


题目描述

给定一个偶数 n,存在一个长度为 n 的排列 perm,其中 perm[i] == i(下标从0开始)。

定义一个操作步骤:

  • 新建数组 arr,对每个索引 i
    • i 是偶数,则 arr[i] = perm[i / 2]
    • i 是奇数,则 arr[i] = perm[n / 2 + (i - 1) / 2]

arr 赋值给 perm

问题: 经过多少次该操作后,perm 才会回到初始状态?返回最小的非零操作步数。


解题分析

这个问题的关键在于理解操作过程实际上是对数组下标的一种置换(Permutation),即每次操作相当于对元素的索引位置进行重排。题目问的是,这个置换重复多少次后,整个数组才回到原始排列。

本质问题转化: 找到这个置换的周期(cycle length),即最小的 k 使得对所有 i,经过 k 次变换,i 回到原点。


置换函数定义

定义一个函数 f(i) 表示一次操作后,索引 i 变换后的位置:

def f(i):
    if i % 2 == 0:
        return i // 2
    else:
        return n // 2 + (i - 1) // 2

例如:

  • 对偶数索引 i,新位置是 i/2
  • 对奇数索引 i,新位置是 n/2 + (i - 1)/2

求置换周期的思路

排列经过操作后,每个元素的索引都发生了置换。一个排列可以拆解为若干个互不交叉的置换环(cycles)。最终排列恢复初始状态的条件是每个环上的元素都回到原位置。

因此问题转化为:

  • 找出所有环的长度(循环节)
  • 计算这些环长度的 最小公倍数(LCM)

这个最小公倍数即为让整体排列回到原状所需的最少操作次数。


详细算法步骤

  1. 初始化一个布尔数组 visited,标记索引是否已被访问。
  2. 遍历数组索引 i
    • 如果未访问,开始从 i 出发,沿着置换函数 f 走,直到回到 i,计算环长度 count
  3. 将所有环的长度 count 求最小公倍数,得到最终答案。

代码实现(Python)

import math

class Solution:
    def reinitializePermutation(self, n: int) -> int:
        def f(i):
            if i % 2 == 0:
                return i // 2
            else:
                return n // 2 + (i - 1) // 2

        visited = [False] * n
        lcm = 1

        for i in range(n):
            if not visited[i]:
                count = 0
                j = i
                while not visited[j]:
                    visited[j] = True
                    j = f(j)
                    count += 1
                if count > 0:
                    lcm = math.lcm(lcm, count)

        return lcm

示例说明

示例 1:n = 2

初始 perm = [0, 1]

操作一次:

  • arr[0] = perm[0] = 0
  • arr[1] = perm[1] = 1

perm 不变,周期为 1。

输出:1


示例 2:n = 4

初始:perm = [0, 1, 2, 3]

操作后:

  • arr[0] = perm[0] = 0
  • arr[1] = perm[2] = 2
  • arr[2] = perm[1] = 1
  • arr[3] = perm[3] = 3

变为 [0, 2, 1, 3]

再操作一次:

  • arr[0] = perm[0] = 0
  • arr[1] = perm[2] = 1
  • arr[2] = perm[1] = 2
  • arr[3] = perm[3] = 3

变回 [0, 1, 2, 3]

周期为 2。


复杂度分析

  • 时间复杂度:O(n log n)
    主要因为每个元素访问一次,计算 LCM 可能涉及较大数的计算。
  • 空间复杂度:O(n)
    用于 visited 数组。

进一步分析与比较

  • 直接模拟:如果直接模拟每一步操作,直到恢复原状态,时间复杂度可能较高(最坏 O(n!))。
  • 数学置换周期方法:通过分析置换结构,快速找到周期,效率大幅提升。
  • 最小公倍数计算:对于分解出的每个环长,取 LCM 是数学保证周期正确性的关键。

小结

  • 本题通过对置换周期的理解,将看似复杂的数组变换问题转化为数学问题。
  • 利用函数映射构建置换,求环长,最后计算最小公倍数求周期。
  • 这种思路不仅解决本题,也适用于类似置换周期求解问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值