📌  相关文章
📜  最小化圆形阵列中相邻元素的最大绝对差(1)

📅  最后修改于: 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]” 的圆形排列方式如下:

example

图中标注了从数组中心位置开始的相邻元素。对于该排列方式,相邻元素的最大绝对差为 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$ 表示数组元素的范围。