📜  猜测排列所需的移动次数。(1)

📅  最后修改于: 2023-12-03 15:11:11.457000             🧑  作者: Mango

猜测排列所需的移动次数

猜测排列是指,给出一个长度为n的数列,其中每个数均为1~n之间的整数,且每个数只出现一次。构造一个长度也为n的排列,使得第i个位置上的数是第i小的未出现的数。

例如,给出一个长度为5的数列[2, 3, 1, 5, 4],则一个可能的构造方式是[1, 2, 3, 5, 4],其中第一位1是未出现的最小整数,第二位2是未出现的第二小整数,以此类推。

求出构造该排列所需的最小移动次数。

问题分析

考虑在构造一个长度为n的排列时,每个位置i上应该填充哪个数,可以通过计算数列中有多少个数小于第i小的未出现的数来得到。例如,在构造上面例子中的第二位时,已经有一个数小于2,即1,未出现的最小整数是2,因此在第二位填充2时,需要移动1个未出现的数。

因此,我们可以从左到右扫描数列,记录下已经出现过的数,并计算总共需要移动的次数。具体思路如下:

  1. 定义变量count,记录需要移动的次数。
  2. 定义一个长度为n的布尔类型数组appeared,初始值全为False,表示所有的数都没有出现过。
  3. 从左到右遍历数列,假设当前位置为i。
  4. 对于第i个位置,需要找到第i小的未出现的数,方法是从1开始枚举每个数x,判断x是否已经在appeared数组中出现过,若没有出现过,则将计数器减1,直到计数器为0,则x是第i小的未出现的数,记录下该数,并令appeared[x]为True,表示该数已经出现过。
  5. 在当前位置上填充第i小的未出现的数x,计算此时需要移动的距离,即第i个位置与第x个位置之间的距离,并加入到count中。
代码实现
def guessing_numbers(nums):
    n = len(nums)
    count = 0
    appeared = [False] * (n+1)
    for i in range(n):
        idx = -1
        for x in range(1, n+1):
            if not appeared[x]:
                idx += 1
                if idx == nums[i]-1:
                    appeared[x] = True
                    count += abs(i - (x-1))
                    break
    return count
测试样例

我们还需要通过一些测试样例来验证程序的正确性:

assert guessing_numbers([2, 3, 1, 5, 4]) == 2
assert guessing_numbers([1, 2, 3]) == 0
assert guessing_numbers([3, 2, 1]) == 3
assert guessing_numbers([5, 4, 3, 2, 1]) == 10
assert guessing_numbers([1, 5, 3, 4, 2]) == 1
总结

通过这个问题的分析和代码实现,我们可以加深对于列表、布尔类型数组的操作和计算移动距离的思考。同时,对于比较复杂的问题,我们需要通过分析问题,重新组织思路,以简单而优雅的方式实现程序,让代码更加易于维护和阅读。