1.Problem
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
2.Translation
給兩個(gè)各自排好序的數(shù)組育特,然后找出他們兩個(gè)中的中間值壁却,如示例所示。然后給了時(shí)間復(fù)雜度的限制杆故。
3.My View
出去開一個(gè)大會(huì)跑回來還有各種各樣的事要做……但是還是先刷一道算法吧。
回來室友說這個(gè)很簡(jiǎn)單咨堤,然后做了n久埂伦,雖然有了想法,想法是合并->排序泛领,說起來應(yīng)該達(dá)不到n方的復(fù)雜度荒吏,但是無從下手。
然后室友說用了Python的庫(kù)函數(shù)渊鞋,排序(數(shù)組1+數(shù)組2)绰更。
雖然覺得直接調(diào)庫(kù)就沒啥意思了,但是還是寫了一個(gè)調(diào)庫(kù)的锡宋,更高端的有空再研究儡湾。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//構(gòu)建新數(shù)組
int[] nums = new int[nums1.length+nums2.length];
//將數(shù)組合并(采用arraycopy函數(shù))
if(nums1.length>0&&nums2.length>0){
System.arraycopy(nums1, 0, nums, 0, nums1.length);
System.arraycopy(nums2, 0, nums, nums1.length, nums2.length);
}else if(nums1.length>0&&nums2.length==0){
System.arraycopy(nums1, 0, nums, 0, nums1.length);
}else if(nums2.length>0&&nums1.length==0){
System.arraycopy(nums2, 0, nums, 0, nums2.length);
}
//將數(shù)組排序(sort函數(shù))
Arrays.sort(nums);
//返回結(jié)果
return (nums[(nums.length-1)/2]+nums[nums.length/2])/2.0;
}
}
這里主要用了arraycopy和sort函數(shù),用來完成數(shù)組合并和排序执俩。
當(dāng)然徐钠,嗯,路過打個(gè)醬油啦役首!
于是抽空又寫了一個(gè)能說的過去的尝丐。
不過當(dāng)然不能跟大神比啦显拜。
連大眾算法都沒上。
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
//構(gòu)建新數(shù)組
int[] nums = new int[nums1.length+nums2.length];
int num1_len = nums1.length,num2_len = nums2.length;
int i = 0,j = 0,k = 0;
//調(diào)整數(shù)組訪問順序
if(num1_len > num2_len){
return findMedianSortedArrays(nums2,nums1);
}
while(i<num1_len||j<num2_len){
//余數(shù)據(jù)處理
if(i<=nums1.length-1&&j>nums2.length-1){
nums[k] = nums1[i];
i++;
k++;
continue;
}
if(i>nums1.length-1&&j<=nums2.length-1){
nums[k] = nums2[j];
j++;
k++;
continue;
}
//正常數(shù)據(jù)處理
if(nums1[i]<=nums2[j]){
nums[k] = nums1[i];
i++;
}else{
nums[k] = nums2[j];
j++;
}
k++;
}
//結(jié)果
return (nums[(nums.length-1)/2]+nums[nums.length/2])/2.0;
}
期間也是遇到大大小小的錯(cuò)誤爹袁,連續(xù)提交了幾次才成功远荠。算法的理念就是排序合并,這個(gè)想法是源自于數(shù)據(jù)結(jié)構(gòu)鏈表合并排序的題目失息,以前沒仔細(xì)寫過譬淳,今天算是拿數(shù)組練練手了。
真正官方的根时,
NB的在下面瘦赫。
Solution
Put left_A and left_B into one set, and put right_A and right_B into another set.
把A數(shù)組分成左右兩部分,B數(shù)組也分成左右兩部分蛤迎。
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
然后如果我們確保
//左右長(zhǎng)度一致
len(left_part)=len(right_part)
//左部分最大值小于右部分最小值
max(left_part)≤min(right_part)
那么我們就會(huì)很輕易地得到答案
a = (max(left_part)+ min(right_part))/2
那么接下來我們要解決的問題就是如何滿足這兩個(gè)條件
//首先我們要求(i是A數(shù)組左部分确虱,j是B數(shù)組左部分,m是A的長(zhǎng)度替裆,
//n是B的長(zhǎng)度校辩,那么這樣很顯然就是讓A_left + B_left = A_right+B_right)
i+j=m?i+n?j
//為了確保大小,我們結(jié)合剛開始給的表格來看
B[j?1]≤A[i] and A[i?1]≤B[j]
and then辆童?
Searching i in [0,m], to find an object i such that:
//在【0宜咒,m】區(qū)間搜索一個(gè)滿足條件的i
B[j?1]≤A[i] and A[i?1]≤B[j], where j = (m+n+1)/2 - i
這里一定要確保j是非負(fù)數(shù),那么要求就是m要比n小把鉴,否則可能會(huì)因?yàn)閙/2太大導(dǎo)致j是負(fù)數(shù)故黑。
同時(shí)我們?cè)诜治鲞@種情況的時(shí)候,不能忽視了一些極端數(shù)據(jù)庭砍,比如說空數(shù)組场晶,重復(fù)數(shù)據(jù)等
官方給出的解釋是,當(dāng)我們比較這些情況的時(shí)候
B[j?1]≤A[i] and A[i?1]≤B[j], where j = (m+n+1)/2 - i
如果他們不存在(數(shù)據(jù))怠缸,可以直接空過去
那么在搜索的過程中就出現(xiàn)了三種情況
(j=0 or i = m or B[j?1]≤A[i]) and
i = 0 or j=n or A[i?1]≤B[j])
Means ii is perfect, we can stop searching.
(j > 0 and i <m and B[j?1]>A[i])
Means ii is too small, we must increase it.
(i>0 and j<n and A[i?1]>B[j])
Means ii is too big, we must decrease it.
最后是Code
public double findMedianSortedArrays(int[] A, int[] B) {
//獲取長(zhǎng)度
int m = A.length;
int n = B.length;
//確保長(zhǎng)度m<n(當(dāng)然在這里我們也可以用遞歸來實(shí)現(xiàn)诗轻,不過效率會(huì)低一點(diǎn))
if (m > n) {
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
//初始化變量
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
//循環(huán)檢查A數(shù)組
while (iMin <= iMax) {
//i是A數(shù)組中心
int i = (iMin + iMax) / 2;
//J也就是我們公式里的j
int j = halfLen - i;
//接下來就是我們的三種情況
//通過調(diào)整imin和imax兩個(gè)值來確定i,j的位置揭北,
//也就是確保分片的合理性
if (i < iMax && B[j-1] > A[i]){
iMin = iMin + 1; // i is too small
}
else if (i > iMin && A[i-1] > B[j]) {
iMax = iMax - 1; // i is too big
}
//當(dāng)i是一個(gè)合適的切片點(diǎn)的時(shí)候扳炬,開始查找右片最小值和左片最大值
else { // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j-1]; }
else if (j == 0) { maxLeft = A[i-1]; }
else { maxLeft = Math.max(A[i-1], B[j-1]); }
//奇數(shù)個(gè)直接返回中心點(diǎn)
if ( (m + n) % 2 == 1 ) { return maxLeft; }
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.min(B[j], A[i]); }
//返回中值
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
這個(gè)算法核心的地方還是在于分片。
同時(shí)這個(gè)算法也源自于高中的中值概念搔体,通過排除最小最大值來得到中值恨樟。
更多優(yōu)秀算法建議去LeetCode查看。