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

73 阅读1分钟

题目:
给定一个 排序好 的数组 arr ,两个整数 k 和 x ,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。

整数 a 比整数 b 更接近 x 需要满足:

  • |a - x| < |b - x| 或者
  • |a - x| == |b - x| 且 a < b
    算法:
func findClosestElements(arr []int, k int, x int) []int {
	left, right := 0, len(arr) - 1
	ans := make([]int, 0)
	// 先找到最接近x的数的位置index
	for left < right {
		mid := left + (right - left) / 2
		if arr[mid] < x {
			left = mid + 1
		} else {
			right = mid
		}
	}
	// 最终left,right的位置index是大于等于x的位置
	// 将left,right定位到离x最小的位置


	if arr[left] != x && left > 0 && abs(arr[left - 1], x) < abs(arr[left], x) {
		left --
		right = left
	} 
	
	for right - left < k {
		// fmt.Println(left - 1,right + 1,"val:",arr[left:right+1], "abs:", abs(arr[left-1],x), abs(arr[right+1],x))

		if lessDistance(arr, left - 1, right + 1, x) {
			left --
		} else {
			right ++	
		}
	}
	
	if lessDistance(arr, left, right, x) {
		right --
	} else {
		left ++
	}

	for left <= right {
		ans = append(ans, arr[left])
		left ++
	}
	return ans
}

func abs(a, b int) int {
	if a > b {
		return a - b
	}
	return b - a
}

// arr[left]到val比arr[right]到val更近
func lessDistance(arr []int, left, right, val int) bool {
	if left < 0 {
		return false
	}
	if right > len(arr) - 1 {
		return true
	}
	abs1 := abs(arr[left], val)
	abs2 := abs(arr[right], val)
	if abs1 == abs2 {
		return left < right
	}
	return abs1 < abs2
}