leetcode 658.找到K个最接近的元素 Java

题目链接

https://leetcode-cn.com/problems/find-k-closest-elements/

描述

给定一个排序好的数组,两个整数 k 和 x,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。如果有两个数与 x 的差值一样,优先选择数值较小的那个数。

说明:

k 的值为正数,且总是小于给定排序数组的长度。
数组不为空,且长度不超过 104
数组里的每个元素与 x 的绝对值不超过 104
 

更新(2017/9/19):
这个参数 arr 已经被改变为一个整数数组(而不是整数列表)。 请重新加载代码定义以获取最新更改。

示例

示例 1:

输入: [1,2,3,4,5], k=4, x=3
输出: [1,2,3,4]

示例 2:

输入: [1,2,3,4,5], k=4, x=-1
输出: [1,2,3,4]

初始代码模板

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {

    }
}

代码

这个题目,相当棒!
写了半天,也就击败50%,一开始是用二分查找确定元素位置,然后再用双指针添加元素。
以下是我写的,效率并不是很高,建议直接看第二个,我是为了给自己涨个记性。

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int xIndex = binarySearch(arr, x);

        LinkedList<Integer> ans = new LinkedList<>();
        int left = xIndex - 1;
        int right = xIndex;
        while (ans.size() < k) {
            int disLeft = left >= 0 ? x - arr[left] : Integer.MAX_VALUE;
            int disRight = right < arr.length ? arr[right] - x : Integer.MAX_VALUE;

            if (disLeft <= disRight) {
                ans.addFirst(arr[left]);
                left--;
            } else {
                ans.add(arr[right]);
                right++;
            }
        }
        
        return ans;
    }

    private int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] == target) {
                right = mid;
            } else if (arr[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        return left;
    }
}

下面这个是大佬写的,可以去看看解析,写的太棒了:
https://leetcode-cn.com/problems/find-k-closest-elements/solution/pai-chu-fa-shuang-zhi-zhen-er-fen-fa-python-dai-ma/

public class Solution {

    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int size = arr.length;

        int left = 0;
        int right = size - k;

        while (left < right) {
            // int mid = left + (right - left) / 2;
            int mid = (left + right) >>> 1;
            // 尝试从长度为 k + 1 的连续子区间删除一个元素 
            // 从而定位左区间端点的边界值
            if (x - arr[mid] > arr[mid + k] - x) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        List<Integer> res = new ArrayList<>();
        for (int i = left; i < left + k; i++) {
            res.add(arr[i]);
        }
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值