📅  最后修改于: 2023-12-03 15:40:13.877000             🧑  作者: Mango
题目描述:
给定一个长度为 n 的序列,将最多 k 次的交换操作应用于序列中的任意两个元素,得到一个新的序列。请问,在所有可能的新序列中,字典序最大的序列是哪一个?
输入格式:
输出格式:
示例:
输入:
3 1
3 1 2
输出:
3 2 1
算法一:并查集
采用并查集的思路,将相邻且可以交换的数合并在一起,交换两个数只会影响它们所在连通块的相对顺序,不会影响其它连通块内部的顺序。因此,问题转化为将每个连通块内的数按降序排序即可,排序时只需要记录每个位置是否已经被遍历过了。
时间复杂度 O(nlogn)。
python 代码如下:
from typing import List
class UnionFind:
def __init__(self, n: int):
self.parent = list(range(n))
self.size = [1] * n
def find(self, x: int) -> int:
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x: int, y: int) -> bool:
x_parent, y_parent = self.find(x), self.find(y)
if x_parent == y_parent:
return False
if self.size[x_parent] < self.size[y_parent]:
x_parent, y_parent = y_parent, x_parent
self.parent[y_parent] = x_parent
self.size[x_parent] += self.size[y_parent]
return True
class Solution:
def maxPermutation(self, n: int, k: int, nums: List[int]) -> List[int]:
uf = UnionFind(n)
for i in range(n):
uf.union(i, nums[i] - 1)
pos = [[] for _ in range(n)]
for i in range(n):
pos[uf.find(i)].append(i)
res = [0] * n
for i in range(n):
index = pos[uf.find(i)].pop()
res[index] = n - i
return res
算法二:堆
采用堆排序的思路,不断选择当前最大值,并将它与前面的数不断交换,直到它到达合适的位置或已经超过限制次数。交换时使用堆保存所有可以合法交换的数,取最大值保证当前字典序最大,离散化后数组可直接用树状数组维护。
时间复杂度 O(nlog^2n)。
python 代码如下:
from typing import List
class BinaryIndexTree:
def __init__(self, n: int):
self.sums = [0] * (n + 1)
def lowbit(self, index: int) -> int:
return index & (-index)
def update(self, index: int, delta: int):
while index < len(self.sums):
self.sums[index] += delta
index += self.lowbit(index)
def query(self, index: int) -> int:
res = 0
while index > 0:
res += self.sums[index]
index -= self.lowbit(index)
return res
class Solution:
def maxPermutation(self, n: int, k: int, nums: List[int]) -> List[int]:
pos = [0] * (n + 1)
for i in range(n):
pos[nums[i]] = i
res = [0] * n
bit = BinaryIndexTree(n)
for i in range(n)[::-1]:
if k == 0:
res[i:] = nums[i:]
break
j = pos[n - i]
if j == i:
res[i] = nums[i]
continue
bit.update(j + 1, 1)
cnt = bit.query(n) - bit.query(i)
if cnt <= k:
k -= cnt
res[i:j+1] = nums[j:i-1:-1]
else:
bit.update(j + 1, -1)
while k > 0:
mx_idx = 0
for t in range(i, j+1):
if bit.query(t) - bit.query(mx_idx) > k:
break
mx_idx = t
res[mx_idx], res[mx_idx-1] = res[mx_idx-1], res[mx_idx]
bit.update(mx_idx, -1)
k -= 1
res[i:j+1] = nums[j:i-1:-1]
return res