原題目:
給定兩個大小為m,n的有序數組nums1和nums2,找出這兩個有序數組的中位數,要求時間復雜度為O(log(m+n)).
eg:nums1=[1,3];nums2=[2];中位數是2.0
nums1=[1,2];nums2=[3,4];中位數是(2+3)/2=2.5
不考慮時間復雜度,簡單做法就是把nums1和nums2兩個數組的並集重新排序,取得中位數。
基本思想:
需要求的中位數mid是把兩個數組並集構成的數組num3的元素分為數目相等的兩部分。設小於mid的元素構成集合C。
計算兩個數組元素總長度sumLen
需要向C中添加的元素長度為(sumLen+1)/2 向下取整
最開始仍需要添加到C中元素的長度為want=(sumLen+1)/2 向下取整,取索引值為indexa=indexb=want/2;
比較nums1[indexa]與nums2[indexb]的大小(誰數值大,誰索引二分),假設nums1[indexa]<nums2[indexb],就對nums2再次進行二分找元素,直到nums1[indexa]>nums2[indexb],
假設indexb連續二分兩次過后(indexb=indexb/2),nums1[indexa]>nums2[indexb],
然后把nums1索引z為indexa和indexa之前的indexa+1個元素和nums2索引為indexb和indexb之前的indexb+1個元素添加到數組C中,
更新want的值,計算want=(sumLen+1)/2-indexa-1-indexb-1。
記錄上一次indexa和indexb的值為,indexa1=indexa,indexb1=indexb
更新indexa,indexb,indexa=indexa1+want/2,indexb=indexb+want/2
假設nums1[indexa]還是小於nums2[indexb],就對nums2再次進行二分找元素,直到nums1[indexa]>nums2[indexb],
假設indexb一次二分過后,nums1[indexa]>nums2[indexb],然后把nums1索引為indexa1之后和indexa之前的元素(左開右閉)和nums2索引為indexb1之后和indexb之前的元素(左開右閉)添加到數組C中,
重復做下去,直到indexa+1+indexb+1 = sumLen/2
如果sumLen為奇數,說明nums[index+1]與nums2[indexb+1]兩個元素較小的那個元素就是最終數組nums3的中位數,結束。
如果sumLen為偶數,記錄nums[indexa]與nums[indexb]中較大的值為c1,記錄nums[indexa+1]與nums[indexb+1]中較小的值為c2,最終數組nums3的中位數為(c1+c2)/2
思路: 假設兩個數組nums1與nums2都不為空(其中一個數組為空就比較簡單) 第零步:計算兩個數組的總長度sumLen=nums1.length+nums2.length int indexa=-1,indexb=-1; int indexa1=-1,,indexb1=-1; 設nums1與nums2合並后得到的數組為nums3,nums3中位數之前的元素構成數組C,C最終的的長度為(sumLen+1)/2 計算仍需向數組C添加元素的個數為want(最開始want=(sumLen+1)/2-indexa-1-indexb-1), 第一步:判斷兩個數組的中位數是否相等? 相等,兩個有序數組的中位數就是原來各自數組的中位數。 不相等,進入第二步。 第二步: 從nums1和nums2中各自取出indexa和indexb后面的want/2個元素進行比較(這兒需要判斷indexa和indexb后面總數組元素長度和want/2的大小關系),再計算indexa或者indexb //更新indexa與indexb的值 if(nums1.length-1<indexa+want/2){//eg: 0,9 1,7 2,3 3,2 4,4。length=5 want/2=5,indexa=-1,不滿足,直接進入第三種情況 indexb=indexb+want-(nums1.length-1-indexa);//當indexa=nums1.length-1;indexb=indexb+want; indexa=nums1.length-1; }else if( (indexb+want/2) > (nums2.length-1)){ indexa=indexa+want-(nums2.length-1-indexb); indexb=nums2.length-1; }else{ indexa=indexa+want/2; indexb=indexb+want/2; } 第三步:比較nums1[indexa]與nums2[indexb]的大小(誰大誰二分), ①如果,nums1[indexa]<nums2[indexb],就對nums2再次進行二分找元素(if indexb=indexb1+1,indexb=indexb1,else indexb=(indexb-indexb1+1)/2-1),直到nums1[indexa]>nums2[indexb], ①退出循環時,當indexb>=indexb1+1,證明能找到一個nums2[indexb],然后把nums1索引為indexa1+1到indexa的indexa+1個元素和nums2索引為indexb+1到indexb的indexb+1個元素添加到數組C中, 計算want=(sumLen+1)/2-indexa-1-indexb-1。 更新indexa1,indexb1;indexa1=indexa;indexb1=indexb; ②退出循環時,當indexb=indexb1,說明nums1[indexa]小於等於nums2還沒有添加到C中的那部分元素的第一個元素,就把nums1數組的nums1[indexa1+1]到nums1[indexa]之前的元素添加到C中, 計算want=(sumLen+1)/2-indexa-1-indexb-1. 更新indexa1,indexb1;indexa1=indexa;indexb1=indexb; ②如果,nums2[indexb]<nums1[indexa],就對nums1再次進行二分查找元素,同理。 第四步:判斷sumLen的奇偶性 ①如果sumLen為奇數,判斷indexa+1+indexb+1與(sumLen-1)/2大小,或者與sumLen/2的大小,因為奇數時,(sumLen-1)/2=sumLen/2 ①indexa+1+indexb+1 = (sumLen-1)/2 ,說明nums[index+1]與nums2[indexb+1]兩個元素較小的那個元素就是最終數組nums3的中位數,結束。 ②indexa+1+indexb+1 < (sumLen-1)/2, indexa1=indexa;indexb1=indexb;//記錄上次indexa、indexb的值 回到第二步 //更新indexa、indexb的值 if( (indexa+want/2) > (nums1.length-1) ){ indexb=indexb+want-(nums1.length-1-indexa); indexa=nums1.length-1; }else if( (indexb+want/2) > (nums2.length-1)){ indexa=indexa+want-(nums2.length-1-indexb); indexb=nums2.length-1; }else{ indexa=indexa+want/2; indexb=indexb+want/2; } 比較nums1[indexa]與nums2[indexb]的大小(誰大誰二分), ②如果sumLen為偶數,判斷indexa+1+indexb+1與sumLen/2大小 ①indexa+1+indexb+1 = sumLen/2,記錄nums[indexa]與nums[indexb]中較大的值為c1,記錄nums[indexa+1]與nums[indexb+1]中較小的值為c2,最終數組nums3的中位數為(c1+c2)/2,結束。 ②indexa+1+indexb+1 < sumLen/2, indexa1=indexa;indexb1=indexb;//記錄上次indexa、indexb的值 回到第二步
時間復雜度好像不滿足O(log(m+n)),不過這應該是一種可行的求解辦法,有錯誤不足之處歡迎留言批評指正。