问题
我有两个整数数组 A[]
和 B[]
.数组 B[]
是固定的,我需要找到 A[]
的排列在字典上小于 B[]
并且排列最接近 B[]
.这里我的意思是:
for i in (0 <= i < n) abs(B[i]-A[i]) is minimum and
A[]
should be smaller thanB[]
lexiographically.
例如:
A[]={1,3,5,6,7}
B[]={7,3,2,4,6}
所以,可能是
A[]
的最近排列至 B[]
是A[]={7,3,1,6,5}
我的方法
尝试
A[]
的所有排列然后将其与 B[]
进行比较.但时间复杂度为 (n! * n)
那么有没有办法优化这个呢?
编辑
n
可以大到10^5
为了更好的理解
最佳答案
首先,构建 A
的不同元素计数的有序映射。 .
然后,向前迭代数组索引(0 到 n-1),从此映射中“撤回”元素。在每一点上,有三种可能性:
i < n-1
, 并且可以选择 A[i] == B[i]
,这样做并继续向前迭代。 A[i] < B[i]
,为 A[i] < B[i]
选择最大的可能值.然后继续为所有后续数组索引选择最大的可用值。 (此时您不再需要担心维护 A[i] <= B[i]
,因为我们已经在索引 where A[i] < B[i]
之后。)返回结果。 A[i] < B[i]
的索引。 ,然后使用上一个要点中的方法。A[i] < B[i]
是可能的,然后使用第二个要点中的逻辑进行最后的前传。 由于维护有序映射的开销,这需要 O(n log m) 时间和 O(m) 额外空间,其中 n 是
A
的元素总数m 是不同元素的数量。 (由于 m ≤ n,我们也可以将其表示为 O(n log n) 时间和 O(n) 额外空间。)请注意,如果没有解决方案,则回溯步骤将一直到达
i == -1
.如果发生这种情况,您可能希望引发异常。编辑添加(2019-02-01):
在现已删除的答案中,גלעד ברקן 以这种方式总结了目标:
To be lexicographically smaller, the array must have an initial optional section from left to right where
A[i] = B[i]
that ends with an elementA[j] < B[j]
. To be closest toB
, we want to maximise the length of that section, and then maximise the remaining part of the array.
所以,考虑到这个总结,另一种方法是做两个单独的循环,其中第一个循环确定初始部分的长度,第二个循环实际上填充
A
.这等效于上述方法,但可能会使代码更清晰。所以:A
的不同元素计数的有序映射. initial_section_length := -1
. A
小于 B
的当前元素, 设置 initial_section_length
等于当前数组索引。 (否则,不要。)A
中尚未使用的元素等于 B
的当前元素,跳出这个循环。 (否则,继续循环。)initial_section_length == -1
,那就没有办法了;引发异常。 initial_section_length-1
的数组索引, 从 map 中“撤回”元素。对于每个索引,选择一个尚未使用的元素 A
等于 B
的当前元素. (第一个循环确保了这样一个元素的存在。)initial_section_length
,选择 A
中最大的尚未使用的元素小于 B
的当前元素(并从 map 中“撤回”它)。 (第一个循环确保了这样一个元素的存在。)initial_section_length+1
的数组索引到 n-1,继续从 map 中“撤回”元素。对于每个索引,选择 A
中最大的元素尚未使用。 这种方法与基于回溯的方法具有相同的时间和空间复杂性。
关于c++ - 给定数组的最近排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54376192/