问题描述
小R有一个长度为n的排列,排列中的数字是1到n的整数。她每次操作可以选择两个数ai和aj进行交换,前提是这两个数的下标i和」的奇偶性相同(即同为奇数或同为偶数)。小R希望通过最少的操作使数组变成升序排列。 请你帮小R计算,最少需要多少次操作才能使得数组有序。如果不能通过这样的操作使数组有序,则输出 -1。
测试样例
样例1: 输入:n=5,a=[1,4,5,2,3]输出:2 样例2: 输入:n=4,a=[4,3,2,1]输出:-1 样例3: 输入:n=6,a=[2,4,6,1,3,5]输出:-1
题目分析:
这个问题要求我们通过最少的交换操作,将一个排列 a(包含数字 1 到 n 的整数)变成升序排列,操作的条件是交换的两个数 a[i] 和 a[j] 必须满足它们的下标 i 和 j 是奇偶性相同的,即两个下标要么都为奇数,要么都为偶数。
首先这道题最基础的部分是:把一个乱序的列表通过元素之间的两两交换实现元素的升序 统一的结论就是: 将这个位置应该出现的元素和这个位置现在的元素交换位置
这里可以通过建立字典进行实现
第二部分就是判断当前列表能否通过两两交换实现升序,对于1-n的数字来说奇数一定要在024下标位置上,偶数一定要在135下标位置上,所以我们通过判段一种即可实现判定。
因此最终在计算交换次数的时候是分为两部分来计算的:将原数组的奇数下标设为一个新的数组、偶数下表设为一个新的数组,最终两个数字进行求和即可。
第一部分的核心代码:
# 记录每个元素的原始索引位置
hashmap = {num: i for i, num in enumerate(nums)}
print(hashmap)
# 遍历数组,进行交换
for i in range(len(nums)):
if nums[i] != i + 1: # 当前位置应该是 i+1
# 找到 i+1 在原数组中的索引
index = hashmap[i + 1]
# 交换 nums[i] 和 nums[index]
nums[i], nums[index] = nums[index], nums[i]
result += 1
第二部分的核心代码:
for i in range(n):
if nums[0] % 2 == 1:
while nums[i] != 2* i + 1: # 当前位置应该是 i+1
index = hashmap[2* i + 1] # 找到 i+1 在原数组中的索引
# 交换 nums[i] 和 nums[index]
nums[i], nums[index] = nums[index], nums[i]
# 更新 hashmap 中的索引信息
hashmap[nums[i]] = i
hashmap[nums[index]] = index
result += 1
-
时间复杂度:
O(n log n)。由于我们需要分别对奇数位置和偶数位置的数组进行排序,并且计算逆序对的时间复杂度为O(n log n),所以总的时间复杂度为O(n log n)。 -
空间复杂度:
O(n)。我们需要额外的空间来存储临时数组和计算排序。