1. 程式人生 > >Java實現O(log(n+m))兩個有序陣列中第K大元素或中位數

Java實現O(log(n+m))兩個有序陣列中第K大元素或中位數

假設有兩個從小到大的有序陣列A和B,他們的元素個數為N和M,那麼怎麼求得其第K大元素呢?同理,求其中位數就是當N+M為奇數求其第(N+M+1)/2大元素,為偶數時求(N+M)/2和(N+M+2)/2大元素的平均值。

那麼我們怎麼才能求得第K大元素呢?

分別取兩個陣列中間索引的數,a[x]和b[y],比較兩個數的大小:

if( a[x] <= a[y] )

如果x+y>k,則可以判斷出b[y]以及b[y]後面的元素都可以排除在外,減小搜尋規模。

如果x+y<=k,則可以判斷出a陣列的前半部分元素都不符合條件,減少a一半的搜尋規模。

if( a[x] > a[y] )

類似

該演算法利用了遞迴的思想,結束條件是:

a中元素排除出去,則選擇b中得第k大元素;

b中元素全部排除,選擇a中第k大元素。

該演算法的思想簡單,但邊界點的情況要考慮清楚。結合具體的示例,減小搜尋範圍時,採取去掉了b[y]和a[x];結合具體的示例,結束遞迴的條件是當a或b中開始位置大於結束位置。

為了便於自己理解,我陣列的資料存放的位置由1開始,程式碼如下:

package com.agorithm;

import java.util.Scanner;

public class Main {
	public static void main(String[] args){
		int i,n,m;
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		int[] arrA=new int[n+1];
		int[] arrB=new int[m+1];
		for(i=1;i<=n;i++){
			arrA[i]=sc.nextInt();
		}
		for(i=1;i<=m;i++){
			arrB[i]=sc.nextInt();
		}
		double median=-1;
		if((n+m)%2==0){
			int t1=getTopK(arrA,1,n,arrB,1,m,(m+n)/2);
			int t2=getTopK(arrA,1,n,arrB,1,m,(m+n+2)/2);
			median=(t1+t2)*1.0/2;
		}
		else{
			median=getTopK(arrA,1,n,arrB,1,m,(m+n+1)/2);
		}
		System.out.println(median);
	}
	//陣列A,A的開始位置,結束位置,陣列B,B的開始位置,結束位置,第K大元素
	private static int getTopK(int[] arrA, int sa, int ea, int[] arrB, int sb,
			int eb, int k) {
		int ma=(sa+ea)/2;
		int mb=(sb+eb)/2;
		if(sa>ea){
			return arrB[sb+k-1];
		}
		if(sb>eb){
			return arrA[sa+k-1];
		}
		if(arrA[ma]>=arrB[mb]){
			if((ma-sa+1)+(mb-sb+1)>k){
				return getTopK(arrA,sa,ma-1,arrB,sb,eb,k);
			}
			else{
				return getTopK(arrA,sa,ea,arrB,mb+1,eb,k-(mb+1-sb));
			}
		}
		else{
			if((ma-sa+1)+(mb-sb+1)>k){
				return getTopK(arrA,sa,ea,arrB,sb,mb-1,k);
			}
			else{
				return getTopK(arrA,ma+1,ea,arrB,sb,eb,k-(ma+1-sa));
			}
		}
	}
}
為了檢驗程式碼的準確性,找到了LeetCode OJ上的

Median of Two Sorted Arrays

 這一題,這上面在提交的時候已經給定了函式頭了而且資料輸入是不用我們管的,所以沒辦法,下標只能有0開始,稍微一改上面的程式碼,提交後Accept
public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        double median=-1;
        int n=A.length;
		int m=B.length;
		if((n+m)%2==0){
			int t1=getTopK(A,0,n-1,B,0,m-1,(m+n)/2);
			int t2=getTopK(A,0,n-1,B,0,m-1,(m+n+2)/2);
			median=(t1+t2)*1.0/2;
		}
		else{
			median=getTopK(A,0,n-1,B,0,m-1,(m+n+1)/2);
		}
		return median;
    }
    private static int getTopK(int[] arrA, int sa, int ea, int[] arrB, int sb,
			int eb, int k) {
		int ma=(sa+ea)/2;
		int mb=(sb+eb)/2;
		if(sa>ea){
			return arrB[sb+k-1];
		}
		if(sb>eb){
			return arrA[sa+k-1];
		}
		if(arrA[ma]>=arrB[mb]){
			if((ma-sa+1)+(mb-sb+1)>k){
				return getTopK(arrA,sa,ma-1,arrB,sb,eb,k);
			}
			else{
				return getTopK(arrA,sa,ea,arrB,mb+1,eb,k-(mb+1-sb));
			}
		}
		else{
			if((ma-sa+1)+(mb-sb+1)>k){
				return getTopK(arrA,sa,ea,arrB,sb,mb-1,k);
			}
			else{
				return getTopK(arrA,ma+1,ea,arrB,sb,eb,k-(ma+1-sa));
			}
		}
	}
}



相關推薦

Java實現O(log(n+m))有序陣列K元素位數

假設有兩個從小到大的有序陣列A和B,他們的元素個數為N和M,那麼怎麼求得其第K大元素呢?同理,求其中位數就是當N+M為奇數求其第(N+M+1)/2大元素,為偶數時求(N+M)/2和(N+M+2)/2大元素的平均值。 那麼我們怎麼才能求得第K大元素呢? 分別取兩個陣列中間索

有序陣列k元素

思路:二分查詢func findKth(nums1,nums2[]int,start1,start2,k int)int{ if start1>=len(nums1){ return nums2[start2+k-1] } if start2>=len(

有序陣列,A[k]和B[k]長度都為k。求前k最小的(a[i]+b[j])

設A={A1,A2,A3,A4,A5,A6,.......} ,B={B1,B2,B3,B4,B5,B6,.......} 因為A和B都是有序的陣列,必須充分的利用這點,可能有同學,看到有同學覺得這個題目比較容易,直接將所有的組合都計算出來,然後取最小的K個,其實出題的人是

劍指Offer/滴滴2018校招筆試題-找出陣列K元素-雙路快排實現

程式設計題例項 滴滴2018校招筆試題程式設計題2: 找出陣列中第K大的元素 輸入 45,66,58,22 2 輸出 45 程式設計原理 這道題與

【死磕演算法之1刷Leetcode】——找出有序陣列位數【Median of Two Sorted Arrays】O(log(m+n))

Median of Two Sorted Arrays 題目難度:hard 題目要求: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two s

劍指offer-Java實現:題目5、利用實現佇列

題目描述 用兩個棧來實現一個佇列,完成佇列的Push和Pop操作。 佇列中的元素為int型別。   思路:棧的特點:先進後出 。 佇列特點:先進先出。自己畫了畫圖,看的比較秦楚,大概是每次進佇列操作都進stack1棧,出佇列時必須先把stack1彈棧到stack2中,這樣剛好就

Java 實現和為S的數字

輸入一個遞增排序的陣列和一個數字S,在陣列中查詢兩個數,是的他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。 輸出描述: 對應每個測試案例,輸出兩個數,小的先輸出。程式碼解法一暴力法

合併有序陣列Java實現

兩個已經排序的陣列A和B,A的陣列前M項有值,A的空間足夠大足夠大能容納A+B中的所有元素,將B中所有元素插入A中使合併後的陣列有序; 剛開始接觸題就想到暴力解法,先將B加入到A的後面,然後對組合後的陣列進行排序,假設A和B的長度分別是M,N,那麼用快排平均也需要nlog

合併有序陣列,要求時間複雜度為On),且只要到O(1)的輔助空間

i= 0表示有序陣列arr1的首元素,j = 未知,表示有序陣列arr2的首元素 ①首先比較第一個有序陣列arr1和第二個有序陣列arr2第一個元素的大小 如果arr1[i] < arr[j]

LeetCode 88. 合併有序陣列java 實現

給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。 說明: 初始化 nums1 和 nums2 的元素數量分別為 m 和 n。 你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n

Algorithm 04 : 尋找有序陣列N個數,要求時間複雜度為O(logm+logn)

Question : Give a divide and conquer algorithm for the following problem : you are given two sorted lists of size m and n

合併有序陣列的golang實現

給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。 說明: 初始化 nums1 和 nums2 的元素數量分別為 m 和 n。 你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來儲存 nums2 中的

LeetCode演算法4:java 尋找有序陣列位數

題目描述 給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2。 請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 O(log(m + n))。 你可以假設 nums1 和 nums2 不會同時為空。 示例 1: nums1 = [1, 3] n

【C++實現k元素 時間複雜度為O(n),空間複雜度為O(1)

解題思路: 二基準快速排序,在排序時判斷每次找到的標記點下標 p 與 n-k 的大小,若小於n-k,則只需在p的右側繼續遞迴,若大於 p 則只需在p 的左側遞迴,直至 p 與 n-k 相等 vs可執行程式碼 #include<ctime> #includ

leetcode(2)尋找有序陣列位數的js實現

一.題目描述: 給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2。 請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 O(log(m + n))。 你可以假設 nums1 和 nums2 不會同時為空。 示例 1: nums1 = [1, 3

領釦--合併有序陣列--Python實現

給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。 說明: 初始化 nums1 和 nums2 的元素數量分別為 m 和 n。 你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來儲存 nums2 中的

順序表 | 根據有序表查找合並後的位數

num for 合並 return pre ret 代碼 else while 王道 P18 T11 : 寫的O(n)的代碼: int get_midNum_of_mergedList(int a[],int an,int b[],int bn){ int mid

leetcode88 合併有序陣列

給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。 說明: 初始化 nums1 和 nums2 的元素數量分別為 m 和 n。 你可以假設&nbs

LeetCode 之合併有序陣列

問題描述: 給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為一個有序陣列。 說明: 初始化 nums1 和&n