Median of Two Sorted Arrays(Leetcode 4)| 时间复杂度一定大于空间复杂度?| 题解

5 篇文章 0 订阅
5 篇文章 0 订阅

近日刷到Leetcode 4题目。感觉这个题目作为标记hard的题目,还是很有意思的。

题目如下:

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)).

简单来说,就是在两串已经排序好的数组,找到其中的中位数。

但是这道题中比较反直觉的一点就是它要求了 时间复杂度要是O(log (m+n))。理论上说,任何一个程序的时间复杂度一定大于空间复杂度。因为程序开辟这些空间,或者将这些空间中填入数据,就已经要跟空间复杂度相同的时间了。

解法

那这道题是怎么做的呢。Leetcode只用你写调用的函数就好。所以它的时间复杂度是调用函数的时间复杂度,而不是整个程序的时间复杂度(整个程序的时间复杂度只要是O(m+n))。

解法是很容易想到的。因为题目已经要求时间复杂度是O(log(m+n)),所以显然可以使用二分的思想。这里提供一个找到两个序列中第k大数的思路。

每次比较两个序列的中位数大小。相应的就可以丢掉其中一个数列的一半。比如两个序列A、B长度为10、20,而B的中位数比A的大,这就说明的B的中位数一定大于15个数。如果k<15的话,那就可以直接丢掉B序列的后面一半了。然后再次调用这个函数就可以了。

具体实现还有一些细节要考虑。最后只要找第(m+n)/2大的数就好了。

代码附在最后。

时间复杂度

这里来看时间复杂度。首先程序主体部分复杂度是O(log(n+m))的。但是我开始时候的困惑是数组vector的size这布操作,复杂度是O(n)嘛?

查阅相关资料可以看到,现在vector size()时间复杂度已经是常数了。说明vector的实现方式比string高端了一点。vector本身维护了size,而这也方便了越界检查吧。

第二个巧妙之处在于,数组传参时使用的是地址,而不是把每个参数都拷贝到对应一层。所以数据传参的时间复杂度也是常数了。

参考链接

题解代码

class Solution {
public:
    int find(vector<int>& nums1, vector<int>& nums2, int st1, int ed1, int st2, int ed2, int n) {
        int l1 = ed1-st1+1;
        int l2 = ed2-st2+1;
        int m1=(st1+ed1)/2;
        int m2=(st2+ed2)/2;
        int big= l1+l2-n+1;
        
        if(l1==0)
            return st2+n-1+nums1.size();
        if(l2==0)
            return st1+n-1;
        
        if(n==1)
            return (nums1[st1]<nums2[st2])?st1:st2+nums1.size();
        
        if(l1==1 && l2==1){
            return (nums1[st1]>nums2[st2])?st1:st2+nums1.size();
        }
        
        if(l1==1)
            return (nums2[st2+n-1]<=nums1[st1])?(st2+n-1+nums1.size()):
                (  (nums2[st2+n-2]<=nums1[st1])?st1:( st2+n-2+nums1.size() )
                );
        if(l2==1)
            return (nums1[st1+n-1]<=nums2[st2])?(st1+n-1):
                (  (nums1[st1+n-2]<=nums2[st2])?(st2+nums1.size()):( st1+n-2 )
                );
        
        int small1=m1-st1, small2=m2-st2;
        int large1=ed1-m1, large2=ed2-m2;
        
        
        if(n<=small1){
            return find(nums1,nums2,st1,m1-1,st2,ed2,n);
        }
        if(n<=small2){
            return find(nums1,nums2,st1,ed1,st2,m2-1,n);
        }
        
        if( big<=large1 ){
            return find(nums1,nums2,m1+1,ed1,st2,ed2,n-small1-1);
        }
        if( big<=large2 ){
            return find(nums1,nums2,st1,ed1,m2+1,ed2,n-small2-1);
        }
        
        
        if( n<=(l1+l2)/2 ){
            if(nums1[m1]>nums2[m2]){
                return find(nums1,nums2,st1,m1,st2,ed2,n);
            } else {
                return find(nums1,nums2,st1,ed1,st2,m2,n);
            }
        } else {
            if(nums1[m1]>nums2[m2]){
                return find(nums1,nums2,st1,ed1,m2+1,ed2,n-small2-1);
            } else {
                return find(nums1,nums2,m1+1,ed1,st2,ed2,n-small1-1);
            }
        }    
    }
    
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int s1=nums1.size();
        int s2=nums2.size();
        
        if((s1+s2)%2==1){
            int res=find(nums1,nums2,0,s1-1,0,s2-1,(s1+s2)/2+1);
            if(res<s1)
                return nums1[res];
            else
                return nums2[res-s1];
        } else {
            int res1=find(nums1,nums2,0,s1-1,0,s2-1,(s1+s2)/2);
            int res2=find(nums1,nums2,0,s1-1,0,s2-1,(s1+s2)/2+1);
            double aa,bb;
            if(res1<s1)
                aa= nums1[res1];
            else 
                aa= nums2[res1-s1];
            
            if(res2<s1)
                bb= nums1[res2];
            else 
                bb= nums2[res2-s1];
            return (aa+bb)/2;
        }
    }
};

### 回答1: 一个 Go 程序,用来查找两个有序数组的中位数,可能如下:func FindMedian(arr1, arr2 []int) float64 { n1 := len(arr1) n2 := len(arr2) if n1 == 0 { return float64(arr2[n2/2]) } if n2 == 0 { return float64(arr1[n1/2]) } if n1 == 1 && n2 == 1 { return float64(arr1[0] + arr2[0]) / 2.0 } if n1 == 1 { if n2 % 2 == 0 { return float64(arr2[n2/2 - 1] + arr2[n2/2]) / 2.0 } else { return float64(arr2[n2/2]) } } if n2 == 1 { if n1 % 2 == 0 { return float64(arr1[n1/2 - 1] + arr1[n1/2]) / 2.0 } else { return float64(arr1[n1/2]) } } i := n1 - 1 j := n2 - 1 var median1, median2 int for i >= 0 && j >= 0 { if arr1[i] > arr2[j] { median1 = arr1[i] i-- } else { median1 = arr2[j] j-- } } if i == -1 { median2 = arr2[j-1] } else { median2 = arr1[i-1] } return float64(median1 + median2) / 2.0 } ### 回答2: 生成一个Go程序来查找两个有序数组的中位数。 首先,我们需要明确中位数的定义。对于一个有序数组,中位数是指位于数组中间位置的元素。如果数组长度为奇数,中位数就是唯一那个中间元素;如果数组长度为偶数,中位数是中间的两个元素的平均值。 接下来,我们可以使用以下步骤生成一个Go程序来找到两个有序数组的中位数: 1. 声明一个函数,例如findMedian,该函数接受两个有序数组作为输入参数。 2. 初始化变量n,用于存储两个有序数组的总长度。 3. 通过将两个有序数组合并为一个新的有序数组,找到中位数所在的位置。可以使用合并排序或使用两个指针的方法来实现这一步骤。 4. 根据总长度n的奇偶性,分别处理中位数的情况: - 如果n为奇数,返回新数组中间位置的元素作为中位数。 - 如果n为偶数,返回新数组中间两个元素的平均值作为中位数。 5. 在主函数中调用findMedian函数,传递两个有序数组作为参数,并打印出中位数结果。 下面是一个示例的Go程序,通过使用合并排序的方法找到两个有序数组的中位数: ```go package main import "fmt" func merge(nums1 []int, nums2 []int) []int { merged := make([]int, len(nums1)+len(nums2)) i, j, k := 0, 0, 0 for i < len(nums1) && j < len(nums2) { if nums1[i] < nums2[j] { merged[k] = nums1[i] i++ } else { merged[k] = nums2[j] j++ } k++ } for i < len(nums1) { merged[k] = nums1[i] i++ k++ } for j < len(nums2) { merged[k] = nums2[j] j++ k++ } return merged } func findMedian(nums1 []int, nums2 []int) float64 { merged := merge(nums1, nums2) n := len(merged) if n%2 == 0 { return float64(merged[n/2-1]+merged[n/2]) / 2.0 } else { return float64(merged[n/2]) } } func main() { nums1 := []int{1, 3} nums2 := []int{2} median := findMedian(nums1, nums2) fmt.Printf("Median is: %.2f", median) } ``` 以上示例展示了如何使用合并排序的方法找到两个有序数组的中位数。你可以根据自己的需求进行扩展和修改,以适应其他情况和更复杂的需求。 ### 回答3: 下面是一个生成 Go 程序以找到两个有序数组的中位数的示例: ```go package main import ( "fmt" ) func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { m, n := len(nums1), len(nums2) if m > n { nums1, nums2, m, n = nums2, nums1, n, m } imin, imax, half_len := 0, m, (m+n+1)/2 var max_of_left, min_of_right int for imin <= imax { i := (imin + imax) / 2 j := half_len - i if i < m && nums2[j-1] > nums1[i] { imin = i + 1 } else if i > 0 && nums1[i-1] > nums2[j] { imax = i - 1 } else { if i == 0 { max_of_left = nums2[j-1] } else if j == 0 { max_of_left = nums1[i-1] } else { max_of_left = max(nums1[i-1], nums2[j-1]) } break } } if (m+n)%2 == 1 { return float64(max_of_left) } if i == m { min_of_right = nums2[j] } else if j == n { min_of_right = nums1[i] } else { min_of_right = min(nums1[i], nums2[j]) } return float64(max_of_left+min_of_right) / 2.0 } func max(a, b int) int { if a > b { return a } return b } func min(a, b int) int { if a < b { return a } return b } func main() { nums1 := []int{1, 3} nums2 := []int{2} median := findMedianSortedArrays(nums1, nums2) fmt.Printf("The median is: %.2f\n", median) } ``` 这个程序实现了在合并后的有序数组中找到中位数的逻辑。它首先判断数组的大小,然后使用二分查找的方法从较小的数组开始分割,保证左边的元素数量等于右边(或比右边多1)。然后通过比较左侧的最大值和右侧的最小值来确定中位数。如果数组长度是奇数,则直接返回中位数的值;如果是偶数,则计算左侧最大值和右侧最小值的平均值作为中位数的值。 在 main 函数中,我们定义了两个示例的有序数组 `nums1` 和 `nums2`,然后调用 `findMedianSortedArrays` 函数计算它们的中位数,并打印结果。 请注意,这只是一个示例程序,您可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值