786.第 K 个最小的素数分数

92 阅读1分钟

题目:
给你一个按递增顺序排序的数组 arr 和一个整数 k 。数组 arr 由 1 和若干 素数  组成,且其中所有整数互不相同。

对于每对满足 0 <= i < j < arr.length 的 i 和 j ,可以得到分数 arr[i] / arr[j] 。

那么第 k 个最小的分数是多少呢?  以长度为 2 的整数数组返回你的答案, 这里 answer[0] == arr[i] 且 answer[1] == arr[j] 。
算法:
方法一:二分查找
你要对for循环多少次二分查找能求出结果有一个大概。 两个for循环循环n^2次

func kthSmallestPrimeFraction(arr []int, k int) []int {
	n := len(arr)
	left, right := float64(0), float64(1)
	for {
                // x,y表示结果,为什么要放在for循环内呢
                // 真正的二分查找是第二个for循环,这里每次都要初始化
		x, y := 0, 1
		mid := (left + right ) / 2
		count := 0 
		for i := n - 1; i >= 0; i -- {
			for j := 0 ; j < i; j ++ {
				if float64(arr[j]) / float64(arr[i]) < mid {
					count ++
					if arr[j] * y > arr[i] * x {
						x = arr[j]
						y = arr[i]
					}
				} else {
					break
				}
			}
			
		}

		if count == k {
			return []int{x, y}
		} else if count < k {
			left = mid
		} else {
			right = mid
		}
	}
	return []int{0, 1}
}

方法二:二分查找优化

func kthSmallestPrimeFraction(arr []int, k int) []int {
	n := len(arr)
	left, right := float64(0), float64(1)

	for {
		x, y := 0, 1
		mid := (left + right ) / 2
		count := 0 
		j := -1
		for i := 1; i < n; i ++ {
			for j + 1 < n && float64(arr[j + 1]) / float64(arr[i]) < mid {         
                                // 1/n,2/n ,... j/n 都小于mid
                                // 1/n + 1,2/n + 1 ,... j/n + 1必然小于mid,从j/n + 1开始计算即可
				j ++
				if arr[j] * y > arr[i] * x {
					x = arr[j]
					y = arr[i]
				}
			} 
			count = count + j + 1
		}

		if count == k {
			return []int{x, y}
		} else if count < k {
			left = mid
		} else {
			right = mid
		}
	}
	return []int{0, 1}
}