首页 > 试题广场 >

在两个长度相等的排序数组中找到上中位数

[编程题]在两个长度相等的排序数组中找到上中位数
  • 热度指数:1201 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定两个有序数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。
上中位数:假设递增序列长度为n,若n为奇数,则上中位数为第n/2+1个数;否则为第n个数
[要求]
时间复杂度为,额外空间复杂度为

输入描述:
第一行一个整数N,表示数组大小。
接下来一行N个整数,表示arr1内的元素
再接下来一行N个整数,表示arr内的元素


输出描述:
输出一个整数表示答案
示例1

输入

4
1 2 3 4
3 4 5 6

输出

3

说明

总共有8个数,上中位数是第4小的数,所以返回3。
示例2

输入

3
0 1 2
3 4 5

输出

2

说明

总共有6个数,那么上中位数是第3小的数,所以返回2

备注:

#include <bits/stdc++.h>
using namespace std;

int main(){
    int n, l=0, r=0, m;
    cin>>n;
    int a[n], b[n];
    for(int i=0;i<n;i++)
        cin>>a[i];
    for(int i=0;i<n;i++)
        cin>>b[i];
    while(l+r<n){
        if(l<n && r<n)
            m = (a[l]<b[r] ? a[l++]: b[r++]);
        else if(l<n)
            m = a[l++];
        else
            m = b[r++];
    }
    cout<<m<<endl;
    return 0;
}

发表于 2020-04-08 02:39:57 回复(0)
记第一个数组是arr1,第二个数组是arr2。先假设两个数组的长度都为偶数,先取到两个数组的中点arr1[mid1]和arr2[mid2]:
  1. 如果他们两个相等,由于arr1[mid1]前面有mid1个数,arr2[mid2]前面也有mid2个数,假设排完序后arr1[mid1]排前面,那肯定有mid1+mid2=n/2个数压在了arr2[mid2]的前面,因此返回arr1[mid1]就行。
  2. 如果不相等,不妨设arr1[mid1]<arr2[mid2],那么上中位数一定不会是它两之中小的那个,也就不可能在arr1中排在arr1[mid1]前面的数之中,同时不可能在arr2中排在arr2[mid2]之后的数之中。于是可以二分去一半的区间中找,从而达成时间复杂度O(logN)的成就。
当两个数组的长度为奇数时,可能性1和长度为偶数时相同。在可能性2中左神手动做了几次中点的比较,考虑中点有没有可能是上中位数再去重复这个过程。但是我觉得思考起来有点晕,这种边界一不小心就搞错了,那我干脆就认为中点是有可能的然后去递归,这样就可以直接套用数组长度为偶数的过程。base case就是当数组长度为1时,返回arr1和arr2中仅剩的那个元素中小的那个就行了。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        String[] strArr = br.readLine().split(" ");
        int[] arr1 = new int[n];
        for(int i = 0; i < n; i++) arr1[i] = Integer.parseInt(strArr[i]);
        strArr = br.readLine().split(" ");
        int[] arr2 = new int[n];
        for(int i = 0; i < n; i++) arr2[i] = Integer.parseInt(strArr[i]);
        System.out.println(getUpMedian(arr1, 0, n - 1, arr2, 0, n - 1));
    }
    
    // 两个数组的考虑范围大小(等长)必须相同
    private static int getUpMedian(int[] arr1, int l1, int r1, int[] arr2, int l2, int r2) {
        if(l1 == r1) return Math.min(arr1[l1], arr2[l2]);
        int mid1 = l1 + ((r1 - l1) >> 1);
        int mid2 = l2 + ((r2 - l2) >> 1);
        if(arr1[mid1] == arr2[mid2]) return arr1[mid1];
        if((r1 - l1 + 1) % 2 == 0){
            // 长度为偶数
            if(arr1[mid1] < arr2[mid2]){
                return getUpMedian(arr1, mid1 + 1, r1, arr2, l2, mid2);
            }else{
                return getUpMedian(arr1, l1, mid1, arr2, mid2 + 1, r2);
            }
        }else{
            // 长度为奇数
            if(arr1[mid1] < arr2[mid2]){
                return getUpMedian(arr1, mid1, r1, arr2, l2, mid2);
            }else{
                return getUpMedian(arr1, l1, mid1, arr2, mid2, r2);
            }
        }
    }
}

发表于 2021-12-01 11:36:58 回复(0)
import java.util.Scanner;
 
/**
 * @author zhuqiu
 * @date 2020/4/8
 */
public class Main {
 
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int len = in.nextInt();
        int[] nums1 = new int[len];
        int[] nums2 = new int[len];
        for (int i = 0; i < len; i++) {
            nums1[i] = in.nextInt();
        }
        for (int i = 0; i < len; i++) {
            nums2[i] = in.nextInt();
        }
        Main instance = new Main();
        int result = instance.findMedianSortedArrays(nums1, nums2);
        System.out.println(result);
    }
 
    public int findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int left = (m + n + 1) / 2;
        int right = (m + n + 2) / 2;
 
        return findKth(nums1, 0, nums2, 0, left);
    }
 
    public int findKth(int[] nums1, int i, int[] nums2, int j, int k) {
        if (i >= nums1.length) return nums2[j+k-1];
        if (j >= nums2.length) return nums1[i+k-1];
        if (k == 1) {
            return Math.min(nums1[i], nums2[j]);
        }
        int midValue1 = (i + k/2 -1 < nums1.length) ? nums1[i + k/2 -1] : Integer.MAX_VALUE;
        int midValue2 = (j + k/2 -1 < nums2.length) ? nums2[j + k/2 -1] : Integer.MAX_VALUE;
        if (midValue1 < midValue2) {
            return findKth(nums1, i + k/2, nums2, j, k - k/2);
        } else {
            return findKth(nums1, i, nums2, j + k/2, k - k/2);
        }
    }
}

发表于 2020-04-08 15:06:28 回复(0)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    vector<int>arr1(n),arr2(n),arr(n);
    for(int i=0;i<n;i++)
        cin>>arr1[i];
    for(int i=0;i<n;i++)
        cin>>arr2[i];
    int j=0,j1=0,j2=0;
    while(j<n&&j1<n&&j2<n)
    { 
        if(arr1[j1]<=arr2[j2])
        {
            arr[j]=arr1[j1];
            j++;
            j1++;
        }
        else if(arr1[j1]>arr2[j2])
        {
            arr[j]=arr2[j2];
            j++;
            j2++;
        }
    }
    cout<<arr[n-1]<<endl;
    return 0;
}

发表于 2019-09-09 18:34:11 回复(0)
int
发表于 2022-06-22 20:30:00 回复(0)
import java.util.Scanner;
import java.util.Arrays;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int num=2*n;
        int[] arr=new int[num];
        for(int i=0;i<num;i++){
            arr[i]=sc.nextInt();
        }
        Arrays.sort(arr);
        int sum=n/2;
        if(0==sum){
            System.out.print(arr[sum]);
        }else{
            System.out.print(arr[n-1]);
        }
    }
    
}

发表于 2021-03-29 14:06:58 回复(0)
分治策略。主要思想:不断将最小和最大的子表排除(其过程可以看作将它们归位的两张表的合并过程),直到找到中位数:两种情况:1. 两张表的中位数相同;2. 两张表都只剩下一个元素,取较小者。
#include<cstdio>

//    取前半部分,排除后半部分
void prepart (int &low, int &high)
{
    int mid = (low + high) / 2;
    high = mid;
}

//    取后半部分,排除前半部分
void postpart (int &low, int &high)
{
    int mid = (low + high) / 2;
    if ((high-low+1) % 2 == 0)
        low = mid + 1;
    else 
        low = mid;
}

int solve (int *a, int low1, int high1, int *b, int low2, int high2)
{
    if (low1 == high1 && low2 == high2)
        return (a[low1] < b[low2] ? a[low1] : b[low2]);
    else {
        int mid1 = (low1 + high1) / 2;
        int mid2 = (low2 + high2) / 2;
        
        if (a[mid1] == b[mid2])
            return a[mid1];
        else if (a[mid1] > b[mid2]) {
            prepart(low1, high1);
            postpart(low2, high2);
            return solve(a, low1, high1, b, low2, high2);
            
        } else {
            prepart(low2, high2);
            postpart(low1, high1);
            return solve(a, low1, high1, b, low2, high2);
        }
    }
    
}

int main ()
{
    int i, n;
    scanf("%d", &n);
    int a[n], b[n];
    for (i = 0; i < n; ++i)
        scanf("%d", &a[i]);
    for (i = 0; i < n; ++i)
        scanf("%d", &b[i]);
    
    printf("%d", solve(a, 0, n-1, b, 0, n-1));
    return 0;
}
算法分析:由算法逻辑得出递推式:
T(1) = 1;
T(n) = T(n/2) + 1;
因此,由主方法得出T(n) = log2^n

其他思路:模拟二路归并过程来做
编辑于 2020-08-03 18:53:57 回复(0)
#include<iostream>
#include<limits.h>
#include<vector>

using namespace std;

class Solution{
  public:
      int find(vector<int> nums1,vector<int> nums2,int k){
        if(k < 1 || k > nums1.size() + nums2.size())
           return -1;
       
        int n = nums1.size();
        int m = nums2.size();
        int low = max(0,k-m);
        int high = min(n,k);
         //确定i的范围
        while(low < high){
            int mid = low + (high - low)/2;
            if(nums2[k-mid-1] > nums1[mid]){//这里的m=i,j=k-m,所以i+j=k,k-m-1相当于j-1即j前一个位置。j-1比i位置的值大,a数组i的位置往右移
                low = mid + 1;
            }else{
                high = mid;
            }
        }
        
        //判断low 是否为 0 或者为k 否者 第k个数为 max(num1[low-1] + num1[k-low -1]));
        int num1leftmax = low==0?INT_MIN:nums1[low-1];
        int num2leftmax = low==k?INT_MIN:nums2[k-low-1];
        
        return max(num1leftmax,num2leftmax);

    }
};

int main(){
    int N,K;
    cin>>N;
    vector<int> arr1(N);
    for(int i=0;i<N;i++){
        cin>>arr1[i];
    }
    vector<int> arr2(N);
    for(int i=0;i<N;i++){
        cin>>arr2[i];
    }
    Solution c1;
    cout<<c1.find(arr1,arr2,N)<<endl;
    
    return 0;
}

发表于 2020-05-25 22:20:03 回复(0)
从leecode看到的思路,同时也考虑了两个数组长度不等的情况
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int len=sc.nextInt();
        int[] nums1=new int[len];
        int[] nums2=new int[len];
        for(int i=0;i<len;i++){
            nums1[i]=sc.nextInt();
        }
        for(int i=0;i<len;i++){
            nums2[i]=sc.nextInt();
        }
        int a=help(nums1,nums2);
        System.out.print(a);
    }
    
    public static int help(int[] nums1,int[] nums2){
        int m=nums1.length;
        int n=nums2.length;
        if(m>n){
            return help(nums2,nums1);
        }
        int iMin=0;
        int iMax=m;
        while(iMin<=iMax){
            int i=(iMin+iMax)/2;
            int j=(m+n+1)/2-i;
            if(j!=0&&i!=m&&nums2[j-1]>nums1[i]){
                iMin=i+1;
            }else if(i!=0&&j!=n&&nums1[i-1]>nums2[j]){
                iMax=i-1;
            }else{
                int maxLeft=0;
                if(i==0){
                    maxLeft=nums2[j-1];
                }else if(j==0){
                    maxLeft=nums1[i-1];
                }else{
                    maxLeft=Math.max(nums1[i-1],nums2[j-1]);
                }
                if((m+n)%2==1){
                    return maxLeft;
                }
                
                int minRight=0;
                if(i==m){
                    minRight=nums2[j];
                }else if(j==n){
                    minRight=nums1[i];
                }else{
                    minRight=Math.min(nums1[i],nums2[j]);
                }
                return Math.min(maxLeft,minRight);
            }
        }
        return 0;
    }
}


发表于 2020-03-01 11:19:33 回复(0)
#include <bits/stdc++.h>
using namespace std;

int getUpmid(vector<int> a, int s1, int e1, vector<int> b, int s2, int e2){
    int mid1 = 0;
    int mid2 = 0;
    int offset = 0;
    while(s1 < e1){
        mid1 = s1+((e1-s1)>>1);
        mid2 = s2+((e2-s2)>>1);
        offset = ((e1 - s1 + 1) & 1) ^ 1;
        if(a[mid1] > b[mid2]){
            e1 = mid1;
            s2 = mid2 + offset;
        } else if(a[mid1] < b[mid2]){
            s1 = mid1 + offset;
            e2 = mid2;
        } else{
            return a[mid1];
        }
    }
    return min(a[s1], b[s2]);
}

int main(){
    int n; scanf("%d", &n);
    vector<int> a(n), b(n);
    for(int i=0; i<2*n; i++){
        if(i<n) scanf("%d", &a[i]);
        else scanf("%d", &b[i-n]);
    }
    int ans = getUpmid(a, 0, n-1, b, 0, n-1);
    cout << ans;
    return 0;
}

发表于 2020-02-15 16:39:29 回复(0)

问题信息

上传者:小小
难度:
10条回答 4998浏览

热门推荐

通过挑战的用户

查看代码