📌  相关文章
📜  数组中缺少某个数字的出现,使得相邻元素的最大绝对差最小(1)

📅  最后修改于: 2023-12-03 15:26:11.651000             🧑  作者: Mango

数组中缺少某个数字的出现,使得相邻元素的最大绝对差最小

问题描述

给出一个长度为n(n>=2)的整数序列,序列中可能缺少某个数字的出现。现在要在序列中插入一个数字,使得相邻元素的最大绝对差最小。

解法
思路

思路一:二分答案

  • 对于一个答案x,可将题目转化为:是否存在一个位置j,满足在j的左边插入一个数k,使得相邻两数间的最大差值不超过x。
  • 预处理出数组中相邻两数绝对值的最大值maxn,我们需要二分答案ans,对于每个ans,判断是否能在原序列中插入一个数满足条件。
  • 二分过程中,取mid,从左往右找,取满足条件最左边的位置j,若存在这样的位置,则可以向左插入一个数,此时更新mid = ans - maxn,继续判断。
  • 若不存在这样的位置,则说明mid太小,需要向右查找,更新left = mid + 1

思路二:贪心

  • 若原数组长度为n,则插入的数k一定在区间[min(nums),max(nums)+1]中。
  • 令mid = (max(nums) + min(nums)) // 2,统计数组nums中<=mid的数的个数cnt1和>mid的数的个数cnt2。
  • 若cnt1 > cnt2,则新插入的数应该在区间[min(nums),mid]中,反之在区间(mid,max(nums)+1)中。
  • 继续二分,在新的区间中寻找答案。
代码实现

以下为二分答案的代码实现:

def searchInsert(nums: List[int], target: int) -> int:
    left, right = 0, len(nums)
    while left < right:
        mid = left + (right - left) // 2
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid
    return left

def insertMissingNumber(nums: List[int]) -> int:
    n = len(nums)
    maxn = max(abs(nums[i] - nums[i-1]) for i in range(1, n))
    left, right = 0, maxn
    while left < right:
        mid = left + (right - left) // 2
        i = searchInsert(nums, nums[0] + mid)
        if i == n or nums[i] > nums[0] + mid:
            i -= 1
        if abs(nums[i] - nums[0] - mid) <= maxn and abs(nums[i+1] - nums[0] - mid) <= maxn:
            return nums[0] + mid
        elif abs(nums[i+1] - nums[0] - mid) > maxn:
            left = mid + 1
        else:
            right = mid
    return nums[0] + left

以下为贪心的代码实现:

def searchCnt(nums: List[int], mid: int) -> Tuple[int, int]:
    cnt1, cnt2 = 0, 0
    for num in nums:
        if num <= mid:
            cnt1 += 1
        else:
            cnt2 += 1
    return cnt1, cnt2

def insertMissingNumber(nums: List[int]) -> int:
    n = len(nums)
    left, right = min(nums), max(nums) + 1
    while left < right:
        mid = (left + right) // 2
        cnt1, cnt2 = searchCnt(nums, mid)
        if cnt1 > cnt2:
            right = mid
        else:
            left = mid + 1
    return left
总结

本题时间复杂度为O(nlogn),空间复杂度为O(1),可以通过本题。二分答案和贪心思路均可解决此问题。