Contents
  1. 1. 题目
  2. 2. 思路
  3. 3. 解题过程

题目

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

说明:

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

思路

首先这是一个有序的数组,那就可以先二分法查找x,然后返回对于的索引,这个分几种情况
1)找到等于x的值,直接返回索引
2)找不到具体等于x的值,就只能找到离x最近且最小的索引值

根据上面返回的索引值,作为第二步的初始索引。分别判断前后的是不是到上下边界了,
1)没到边界,分别找前后离x最近的边界,左或右移一位
2)到边界,只能反向移动,左移或右移动一位

结束条件是k,每次移动边界,k递减

解题过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class Solution {
public int binarySearch(int[] arr,int x){
int left = 0;
int right = arr.length -1;
while(left <= right){
int index = (right -left)/2+left;
int value = arr[index];

if(value == x){
return index;
}else if(value > x){
right = index - 1;
}else if(value < x){
if(index + 1 < (arr.length -1)){
int next = arr[index+1];
if(next < x){
left = index + 1;
continue;
}
int comp = (next - x) - (x - value);
if(comp >= 0){
return index;
}else{
return index+1;
}
}else{
return index;
}

}
}
return -1;
}
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int flag = binarySearch(arr,x);
if(flag == -1){
List<Integer> list = new ArrayList<Integer>();
for(int i = 0 ; i<k;i++){
list.add(arr[i]);
}
return list;
}
int nums = k-1;
int left = flag;
int right = flag;
int size = arr.length;
while(nums != 0){
int innerLeft = left;
int innerRight = right;
if(right + 1 > size -1){
left = innerLeft -1;
nums--;
continue;
}else if(left -1 < 0){
right = innerRight + 1;
nums--;
continue;
}else{
if( right + 1 <= size - 1 ){
innerRight = innerRight + 1;
}
if(left -1 >= 0){
innerLeft = innerLeft -1;
}
}
int leftValue = arr[innerLeft];
int rightValue = arr[innerRight];
int leftDiv = x - leftValue;
int rightDiv = rightValue - x;
if(leftDiv <= rightDiv){
left = innerLeft;
}else{
right = innerRight;
}
nums--;
}
List<Integer> list2 = new ArrayList<Integer>();
for(int i = left ; i<= right;i++){
list2.add(arr[i]);
}
return list2;
}
}

比较容易出错的有几点
1.二分查找不光要找出等于的值,也要查找离的最近最小的值
2.第二次进行查询的时候,可能会有相等数字重复多次的情况,也要考虑
3.第二次查找,比较大小左右边界移动的判断条件很复杂,很容易出错。

Contents
  1. 1. 题目
  2. 2. 思路
  3. 3. 解题过程