【算法分析与设计】【第二周】4.Median of Two Sorted Arrays
2017-09-17 17:48
507 查看
题目来源: https://leetcode.com/problems/median-of-two-sorted-arrays/description/
题目大意:找出两个有序数组(升序)nums1和nums2的中位数。其中nums1的大小为m,nums2的大小为n。
最近两周都在学习分治的思想,所以选了这么一个题作为应用试试手。
思路大致有这么几种:
1.将两个数组直接合并成一个数组,使用快速排序后,直接求解中位数。这种做法很直接暴力,但没什么意思,主要是考察对排序算法的熟悉程度,快排也是利用分治算法的一种排序算法,写一遍算作对快排算法的一次复习。
时间复杂度O(nlogn)。
2.巧妙利用两个数组有序**这一条件,先依次比较两个数组,小的传入新的数组。其中短的数组用完了,即全部放入到新数组中去了,那么长数组中剩下的那一段就可以直接拿来放入到新数组中去了。
时间复杂度O(min{n, m})。
3.利用刚刚学过的分治算法(《算法概论》P54),也是先将两个数组直接合并成一个数组,随机挑选v。
时间复杂度O(m+n)。
4.巧妙利用中位数的定义。根据中位数的特点,中位数最终将原数组分为两个子数组subArr1和subArr2,且**subArr1的所有元素均小于subArr2。
具体来说,对于一个大小为n的数组arr而言,如果n是偶数,则中位数将该数组分为等长且长度为n/2的两个子数组。如果n是奇数,在这里,我们用中位数将该数组分为两个子数组,小的子数组比大的子数组长度小1。
在本题中,我们要找的中位数,将nums1和nums2数组合并后分为两个子数组,那么两个子数组subArr1和subArr2的长度关系满足
len(subArr1)=len(subArr2)=(m+n)∗0.5
或(len(subArr1))+1=len(subArr2)=(m+n)∗0.5+1。
对于子数组subArr1,我们可以理解成由nums1的某一部分和nums2的某一部分合并组成。因此,我们把nums1分成两部分,分别为num1_small和num1_large。nums2同理,分成num2_small和num2_large。由于subArr1中的所有元素均小于subArr2,所以subArr1应该由num1_small和num2_small组成。(当然,也可能出现num1_small或num2_small为空的现象。)
子数组subArr2同理,由num1_large和num2_large组成。
即
用i、j分别把nums1和nums2按上述方式分开。
即
根据上面推出的subArr1和subArr2的长度关系,我们很容易得出
i+j=m−i+n−j=(m+n)∗0.5
或i+j+1=m−i+n−j=(m+n)∗0.5+1。
从而得出关系
j=(m+n+1)∗0.5−i
以简化算法。
比较一下4种方法的时间复杂度:
以上是我对题目4的一些解析。写完这篇博客后,和室友交流,室友说利用分治思想中的归并排序做此题,亦可达到O(log(n, m)) 。分治思想博大精深,我还是需要继续进行探索。
参考:http://www.cnblogs.com/A_ming/archive/2010/04/15/1712313.html
https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/
题目大意:找出两个有序数组(升序)nums1和nums2的中位数。其中nums1的大小为m,nums2的大小为n。
最近两周都在学习分治的思想,所以选了这么一个题作为应用试试手。
思路大致有这么几种:
1.将两个数组直接合并成一个数组,使用快速排序后,直接求解中位数。这种做法很直接暴力,但没什么意思,主要是考察对排序算法的熟悉程度,快排也是利用分治算法的一种排序算法,写一遍算作对快排算法的一次复习。
时间复杂度O(nlogn)。
//快速排序 void quicksort(int* arr, int left, int right) { if (left < right) { int i = left, j = right, x = arr[left]; while (i < j) { while(i < j && arr[j] >= x) // 从右向左找第一个小于x的数 j--; if(i < j) arr[i++] = arr[j]; while(i < j && arr[i] < x) // 从左向右找第一个大于等于x的数 i++; if(i < j) arr[j--] = arr[i]; } arr[i] = x; quicksort(arr, left, i - 1); // 递归调用 quicksort(arr, i + 1, right); } } double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) { int arr[nums1Size+nums2Size]; for (int i = 0; i < nums1Size; i++) { arr[i] = *(nums1+i); } int j = 0; for (int i = nums1Size; i < nums1Size+nums2Size; i++) { arr[i] = *(nums2+(j++)); } quicksort(arr, 0, nums1Size+nums2Size-1); int mid = (nums1Size+nums2Size)*0.5; if ((nums1Size+nums2Size)%2 == 1) return arr[mid]; else return (arr[mid]+arr[mid-1])*0.5; }
2.巧妙利用两个数组有序**这一条件,先依次比较两个数组,小的传入新的数组。其中短的数组用完了,即全部放入到新数组中去了,那么长数组中剩下的那一段就可以直接拿来放入到新数组中去了。
时间复杂度O(min{n, m})。
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) { //两个有序数组的合并函数 int arr[nums1Size+nums2Size]; int i = 0, j = 0, k = 0; while (i < nums1Size && j < nums2Size) { if (*(nums1+i) <= *(nums2+j)) { arr[k] = *(nums1+i); i++; } else { arr[k] = *(nums2+j); j++; } k++; } // 将较长一串的后半截直接放入 while(i < nums1Size) arr[k++] = nums1[i++]; while(j < nums2Size) arr[k++] = nums2[j++]; int mid = (nums1Size+nums2Size)*0.5; if ((nums1Size+nums2Size)%2 == 1) return arr[mid]; else return (arr[mid]+arr[mid-1])*0.5; }
3.利用刚刚学过的分治算法(《算法概论》P54),也是先将两个数组直接合并成一个数组,随机挑选v。
时间复杂度O(m+n)。
4.巧妙利用中位数的定义。根据中位数的特点,中位数最终将原数组分为两个子数组subArr1和subArr2,且**subArr1的所有元素均小于subArr2。
具体来说,对于一个大小为n的数组arr而言,如果n是偶数,则中位数将该数组分为等长且长度为n/2的两个子数组。如果n是奇数,在这里,我们用中位数将该数组分为两个子数组,小的子数组比大的子数组长度小1。
在本题中,我们要找的中位数,将nums1和nums2数组合并后分为两个子数组,那么两个子数组subArr1和subArr2的长度关系满足
len(subArr1)=len(subArr2)=(m+n)∗0.5
或(len(subArr1))+1=len(subArr2)=(m+n)∗0.5+1。
对于子数组subArr1,我们可以理解成由nums1的某一部分和nums2的某一部分合并组成。因此,我们把nums1分成两部分,分别为num1_small和num1_large。nums2同理,分成num2_small和num2_large。由于subArr1中的所有元素均小于subArr2,所以subArr1应该由num1_small和num2_small组成。(当然,也可能出现num1_small或num2_small为空的现象。)
子数组subArr2同理,由num1_large和num2_large组成。
即
subArr1 = num1_small + num2_small subArr2 = num1_large + num2_large
用i、j分别把nums1和nums2按上述方式分开。
num1_small = num1[0]+...+num1[i-1] num1_large = num1[i]+...+num1[m-1] num2_small = num2[0]+...+num2[j-1] num2_large = num2[j]+...+num2[n-1]
即
subArr1 | subArr2 |
---|---|
num1[0]+…+num1[i-1] | num1[i]+…+num1[m-1] |
num2[0]+…+num2[j-1] | num2[j]+…+num2[n-1] |
i+j=m−i+n−j=(m+n)∗0.5
或i+j+1=m−i+n−j=(m+n)∗0.5+1。
从而得出关系
j=(m+n+1)∗0.5−i
以简化算法。
比较一下4种方法的时间复杂度:
方法 | 时间复杂度 | 难度 |
---|---|---|
快排 | O(nlogn) | 应掌握 |
利用两个数组有序 | O(min{n, m}) | 较容易 |
Selection求第k大的数 | O(m+n) | 目前还没写出来 |
巧妙利用中位数的定义 | O(logmin{n, m}) | 难 |
参考:http://www.cnblogs.com/A_ming/archive/2010/04/15/1712313.html
https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/
相关文章推荐
- 算法分析与设计丨第三周丨LeetCode(5)——Median of Two Sorted Arrays(Hard)
- (算法分析Week4)Median of Two Sorted Arrays[Hard]
- 算法分析课每周练习 Median of Two Sorted Arrays
- Median of Two Sorted Arrays (找两个序列的中位数,O(log (m+n))限制) 【面试算法leetcode】
- 【LeetCode-面试算法经典-Java实现】【004-Median of Two Sorted Arrays(两个排序数组的中位数)】
- 算法课第十五周作业 | Median of Two Sorted Arrays
- 【算法导论学习-016】两个已排过序的等长数组的中位数(median of two sorted arrays)
- Leetcode平台上的Median of Two Sorted Arrays题目用Java堆算法实现
- 【算法】【Divide and conquer】Median of Two Sorted Arrays
- 算法练习(3):Median of Two Sorted Arrays
- Median_of_Two_Sorted_Arrays(理论支持和算法总结)
- Median of Two Sorted Arrays (第二周:分治法)
- 算法第三周Median of Two Sorted Arrays[hard]
- leetcode:Median of Two Sorted Arrays (找两个序列的中位数,O(log (m+n))限制) 【面试算法】
- LeetCode算法题目:Median of Two Sorted Arrays
- leetcode——finding Median of Two Sorted Arrays题目分析
- 算法分析与设计——LeetCode Problem.4 Median of Two Sorted Arrays
- Leetcode: Median of Two Sorted Arrays 理解分析
- LeetCode 150 Median of Two Sorted Arrays
- leetcode Median of Two Sorted Arrays python