📅  最后修改于: 2023-12-03 15:26:26.828000             🧑  作者: Mango
给定一个长度为 $n$ 的数组 $nums$ 和一个整数 $k$,将该数组排列成一个圆形阵列,并使相邻元素的最大绝对差最小。
首先将数组 $nums$ 排序,然后使用二分法查找最小的最大绝对差 $mid$,然后检查是否有一种排列方式,使得相邻元素的最大绝对差不超过 $mid$。如果可以,则将 $mid$ 缩小范围继续查找,否则将 $mid$ 增大范围继续查找。最终可以找到最小的相邻元素的最大绝对差。
将排序后的数组 $nums$ 重复两遍,即将数组复制一份,再将两个数组合并成一个长度为 $2n$ 的数组,并将该数组接下来的 $n$ 个元素翻转。如此一来,我们可以将圆形阵列排列成从数组的中心位置开始,相邻元素一左一右地依次排列。例如,当 $n=6$ 时,$nums$ 数组 “[1,2,5,7,8,10]” 的圆形排列方式如下:
图中标注了从数组中心位置开始的相邻元素。对于该排列方式,相邻元素的最大绝对差为 5,因为相邻元素的差分别为 5、5、3、1、2。我们可以通过比较相邻元素的差和 $mid$ 值来检查是否有一种合法的排列方式。可以使用单调队列来维护前 $k$ 个元素和后 $k$ 个元素之间的最大和最小值。即将前 $k$ 个元素和最后 $k$ 个元素分别插入两个队列,维护队列中的元素按照值从大到小排列。这样,我们可以在 $O(1)$ 的时间复杂度内查找前 $k$ 个元素和后 $k$ 个元素之间的最大和最小值。
Markdown 代码如下:
### 解决方案
首先将数组 $nums$ 排序,然后使用二分法查找最小的最大绝对差 $mid$,然后检查是否有一种排列方式,使得相邻元素的最大绝对差不超过 $mid$。如果可以,则将 $mid$ 缩小范围继续查找,否则将 $mid$ 增大范围继续查找。最终可以找到最小的相邻元素的最大绝对差。
将排序后的数组 $nums$ 重复两遍,即将数组复制一份,再将两个数组合并成一个长度为 $2n$ 的数组,并将该数组接下来的 $n$ 个元素翻转。如此一来,我们可以将圆形阵列排列成从数组的中心位置开始,相邻元素一左一右地依次排列。例如,当 $n=6$ 时,$nums$ 数组 “[1,2,5,7,8,10]” 的圆形排列方式如下:
![example](https://assets.leetcode-cn.com/solution-static/1691/1.png)
图中标注了从数组中心位置开始的相邻元素。对于该排列方式,相邻元素的最大绝对差为 5,因为相邻元素的差分别为 5、5、3、1、2。我们可以通过比较相邻元素的差和 $mid$ 值来检查是否有一种合法的排列方式。可以使用单调队列来维护前 $k$ 个元素和后 $k$ 个元素之间的最大和最小值。即将前 $k$ 个元素和最后 $k$ 个元素分别插入两个队列,维护队列中的元素按照值从大到小排列。这样,我们可以在 $O(1)$ 的时间复杂度内查找前 $k$ 个元素和后 $k$ 个元素之间的最大和最小值。
Python3 代码实现如下:
from typing import List
class Solution:
def check(self, nums: List[int], n: int, k: int, mid: int) -> bool:
qmin = [0] * n
qmax = [0] * n
hh = tt = 0
for i in range(k):
while hh <= tt and qmin[tt] >= nums[i]:
tt -= 1
qmin[tt] = nums[i]
qmax[tt] = nums[i]
for i in range(k, n + k):
while hh <= tt and qmin[tt] >= nums[i]:
tt -= 1
qmin[tt + 1] = nums[i]
qmax[tt + 1] = nums[i]
if qmax[hh] - qmin[hh] > mid:
hh += 1
if i - k + 1 >= 2 * k and qmax[hh] == nums[i - 2 * k] and hh <= tt:
hh += 1
if qmax[hh] - qmin[hh] > mid:
return False
return True
def minimizeTheDifference(self, mat: List[List[int]], target: int) -> int:
m, n = len(mat), len(mat[0])
nums = sorted(list(set(mat[0])))
for i in range(1, m):
arr = sorted(list(set(mat[i])))
j, k = 0, 0
temp = []
while j < len(nums) and k < len(arr):
if nums[j] == arr[k]:
temp.append(nums[j])
j += 1
k += 1
elif nums[j] < arr[k]:
temp.append(nums[j])
j += 1
else:
temp.append(arr[k])
k += 1
while j < len(nums):
temp.append(nums[j])
j += 1
while k < len(arr):
temp.append(arr[k])
k += 1
nums = temp
n = len(nums)
nums *= 2
l, r = 0, nums[-1] - nums[0]
while l < r:
mid = l + (r - l) // 2
if self.check(nums, n, target, mid):
r = mid
else:
l = mid + 1
return l
本题的时间复杂度为 $O(n \log_2 w)$,其中 $n$ 表示数组的长度,$w$ 表示数组元素的范围。