658. 找到 K 个最接近的元素(二分法)

320 阅读2分钟

image.jpeg

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

测试岗位也越来卷了,除了基本的功能测试外,还要有编程基础、脚本经验才脱颖而出。

怎么才能提高我们的编程能力呢,刷LeetCode是最佳的途径之一,话不多数,刷题走起~

一、题目描述:

  • 题目内容

    image.png

  • 题目示例

    image.png

  • 题目解析

    • 1 <= k <= arr.length
    • 1 <= arr.length <= 104
    • arr 按 升序 排列
    • 104 <= arr[i], x <= 104

二、思路分析:

我们今天做一道Leetcode 中等 难度的题 找到K个最接近到元素。题目要求如同题目标题,找到按照指定规则的K元素,数组中元素a,b与之间需要满足如下:

  • |a-x| < |b-x|
  • |a - x| == |b - x| 且 a < b

根据题目要求,有如下五种方法可以进行解答,思路如下所示:

  • 方法一:排序

    • 题目要求找到最接近x的元素,因此可以对arr元素按照abs(a-x)进行排序
    • arr按照绝对值排序后,对arr进行截取前k-1个数
    • 本题要求返回的结果要按照升序排序,再调用sorted(arr[:k])
    class Solution(object):
        def findClosestElements(self, arr, k, x):
            arr.sort(key= lambda a : abs(a-x))
            return sorted(arr[:k])
    
  • 方法二:删除最远的数

    • 本题中要求出满足在x数组最近的k元素,我们可以逆向思路
    • 删除掉|a-x| > |b-x|的元素,当arr的长度等于k时,则返回arr的结果
    class Solution(object):
        def findClosestElements(self, arr, k, x):
            n = len(arr)
            while True:
                if n == k:
                    return arr
                if abs(arr[0]-x) > abs(arr[n-1]-x):
                    arr.remove(arr[0])
                else:
                    arr.remove(arr[n-1])
                n -=1
    
  • 方式三:双指针二分查找

    • 由于数组arr是升序遍历的,我们可以借助双指针方法,找到|a-x| <=|b-x|的零界点
    • [0,left]是小于x的,[right,n-1]是大于x的
    • 当left和right指针分别指向arr索引位置0,n-1位置,mid则取(left+right)/2
    • x-arr[left]>arr[right]-x时则left被赋值为mid+1,否则right指针向左移一步
    • 直到right指针小于left时,退出循环返回arr[left:left+k]
    class Solution(object):
        def findClosestElements(self, arr, k, x):
            left = 0
            right = len(arr)-k
            while left < right:
                mid = (left + right)/2
                if x-arr[mid] > arr[mid+k]-x :
                    left = mid +1
                else:
                    right = mid    
            return arr[left:left+k]
    
  • 方法四:bisect_left()二分查找

    • 在python中,我们可以借用bisect_left()方法找到x数在arr最近的索引位置,赋值给right
    • left指针则赋值right指针左边一位
    • 使用for循环遍历取k次,找到left,right的位置
    • 当left小于0时,则right指针向右边移一位
    • 当right指针大于等于len(arr)或者x-arr[left]<=arr[right]-x时,则left-1
    class Solution(object):
        def findClosestElements(self, arr, k, x):
            right = bisect_left(arr, x)
            left = right - 1
            for _ in range(k):
                if left < 0:
                    right += 1
                elif right >= len(arr) or x - arr[left] <= arr[right] - x:
                    left -= 1
                else:
                    right += 1
    
            return arr[left+1:right]
    

三、总结:

本题考察在数组中使用二分法运用,需要找到满足要求的双指针位置,AC提交记录如下:

image.png

  • 时间复杂度:O(logn+k),n为arr的长度
  • 空间复杂度:O(1),没有使用额外空间

以上是本期内容,欢迎大佬们点赞评论,下期见~~~