JAVA程序设计:第 K 个最小的素数分数(LeetCode:786)

一个已排序好的表 A,其包含 1 和其他一些素数.  当列表中的每一个 p<q 时,我们可以构造一个分数 p/q 。

那么第 k 个最小的分数是多少呢?  以整数数组的形式返回你的答案, 这里 answer[0] = p 且 answer[1] = q.

示例:
输入: A = [1, 2, 3, 5], K = 3
输出: [2, 5]
解释:
已构造好的分数,排序后如下所示:
1/5, 1/3, 2/5, 1/2, 3/5, 2/3.
很明显第三个最小的分数是 2/5.

输入: A = [1, 7], K = 1
输出: [1, 7]
注意:

A 的取值范围在 2 — 2000.
每个 A[i] 的值在 1 —30000.
K 取值范围为 1 —A.length * (A.length - 1) / 2

方法一:二分答案,我们通过枚举第k个分母应该是多少进行二分,知道找到该答案。

class Solution {
    public int[] kthSmallestPrimeFraction(int[] A, int K) {
    	
    	double l=0,r=1;
    	int[] ans= new int[]{0,1};
    	
    	while(r-l>1e-9) {
    		double mid=l+(r-l)/2.0;
    		int[] res=work(mid,A);
    		if(res[0]<K) l=mid;
    		else {
    			ans[0]=res[1];
    			ans[1]=res[2];
    			r=mid;
    		}
    	}
    	
    	return ans;
    }
    
    private int[] work(double x,int[] A) {
    	
    	int numer=0,denom=1,count=0,i=-1;
    	for(int j=1;j<A.length;j++) {
    		while(A[i+1]<A[j]*x) i++;
    		count+=i+1;
    		if(i>=0 && numer*A[j]<denom*A[i]) {
    			numer=A[i];
    			denom=A[j];
    		}
    	}
    	
    	return new int[] {count,numer,denom};
    }
}

方法二:堆,使用一个堆记录所有以 A[j] 为分母且未被弹出的最小分数。依次从堆中弹出 K-1 个元素,此时堆顶的分数就是结果。由于K有n*(n-1)/2这么大,因此方法二的复杂度相对于方法一要高很多。

class Solution {
    public int[] kthSmallestPrimeFraction(int[] A, int K) {
    	
    	PriorityQueue<int[]> q=new PriorityQueue<int[]>((a,b)->A[a[0]]*A[b[1]]-A[a[1]]*A[b[0]]);
    	
    	for(int i=1;i<A.length;i++)
    		q.add(new int[]{0,i});
    	
    	while(--K>0) {
    		int[] res=q.poll();
    		if(res[0]++<res[1])
    			q.add(res);
    	}
    	
    	int[] ans=q.poll();
    	
    	return new int[] {A[ans[0]],A[ans[1]]};
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值