leetcode:找出这两个数组合并并排序后的中位数

寻找两个数组的中位数

package com.wb.magic.leetcode.array;

import java.util.Arrays;

/**
 * 给你两个已经从小到大排好序的数组,请你找出这两个数组合并并排序后的中位数。
 *
 * 你给出的算法的时间复杂度应该为 O(log (m+n)) 。
 */
public class MiddleNumber {

    //方法一双层for循环排序后招中位数
    //方法二 复制数组到一个数组中再排序找中位数
    //方法三

    public static void main(String[] args) {

        int[] num1 ={1,3};
        int[] num2 = {2,4};
        System.out.println(method1(num1, num2));
        System.out.println(method2(num1, num2));
        System.out.println(method3(num1, num2));
//        System.out.println(14&1);
    }

    //合并排序后再找中位数
    public static double method1(int []num1,int [] num2){

        int[] target=new int[num1.length+num2.length];
        System.arraycopy(num1,0,target,0,num1.length);
        for (int i = 0; i < num2.length; i++) {
            target[num1.length+i]=num2[i];
        }
        Arrays.sort(target);
        int nums=target[(num1.length+num2.length)/2];
        if((target.length&1)==1){
            return nums;
        }else {
            return (nums+target[(num1.length+num2.length)/2-1])/2.0;
        }
    }

    //归并方式:直接找中位数,两数组从前往后比较,两指针移动,谁小谁移动

    public static double method2(int []num1,int [] num2){
        int m=num1.length;
        int n=num2.length;
        //无论两数组长度之和是奇数还是偶数,都需要(m+n)/2+1次

        int len=m+n;
        //返回记录数
        int left=0;
        int right=0;
        //两数组指针
        int num1Next=0;
        int num2Next=0;
        for (int i = 0; i <= (m+n)/2; i++) {
            //对于偶数保存上一次记录数字
            left=right;
            //避免num2数组指针越界,||来限制后面就不用执行(使用||运算符排除部分可能,这个可能位于||运算符左边)
            if(num1Next<m&&(num2Next>n||num1[num1Next]<num2[num2Next])){
                right=num1[num1Next++];
            }else {
                right=num2[num2Next++];
            }
        }
        //偶数
        if((len&1)==0){
            return (left+right)/2.0;
        }else {
            return right;
        }

    }


    public static double method3(int []num1,int [] num2){
        int ans1=getKth(num1,0,num1.length-1,num2,0,num2.length-1,(num1.length+num2.length+1)/2);
        int ans2=getKth(num1,0,num1.length-1,num2,0,num2.length-1,(num1.length+num2.length+2)/2);
        return (ans1+ans2)/2.0;
    }
    
  /**
     * int[]num1={2,5,8};
     * int[]num2={3,4,5,6,7,8,9,10};
     * 两数组长度为11,二分法思想找到第六大的数字即可
     * 两个数组均分,6/2=3,让8与5比较,自然5更小,排除3和4,5,k为3
     * ->int[]num1={2,5,8};
     * * int[]num2={6,7,8,9,10}; 排除一个数字 k为2
     * * ->int[]num1={5,8};
     * * * int[]num2={6,7,8,9,10}; 排除一个数字 k为1
     * * ->int[]num1={5,8};
     * * * int[]num2={6,7,8,9,10};
     * k为1直接得到想要的值
     *   //如国两数为奇数,中位数必是奇数,定义找到第k大的数字,k为1时候就是想要数字(n+m+1)/2
    *//如果是偶数的话,中位数就是(n+m+1)/2  (n+m+2)/2 两个数之间的中位数
     *
    //二分法查找中位数位置
    public static int  getKth(int[] nums1,int start1,int end1,int[]nums2,int start2,int end2,int k){
        int size1=end1-start1+1;
        int size2=end2-start2+1;
        if(k==1){
            return Math.min(nums1[start1],nums2[start2]);
        }
        if(size1==0){
            return nums2[start2+k-1];
        }
        int pos1=start1+Math.min(size1,k/2)-1;
        int pos2=start2+Math.min(size2,k/2)-1;
        if(nums1[pos1]>nums2[pos2]){
            return getKth(nums1,start1,end1,nums2,pos2+1,end2,k-(pos2-start2+1));
        }else {
            return getKth(nums1,pos1+1,end1,nums2,start2,end2,k-(pos1-start1+1));
        }
    }

}

package com.wb.magic.leetcode.array;

import java.util.Arrays;

/**
 * 给你两个已经从小到大排好序的数组,请你找出这两个数组合并并排序后的中位数。
 *
 * 你给出的算法的时间复杂度应该为 O(log (m+n)) 。
 */
public class MiddleNumber {

    //方法一双层for循环排序后招中位数
    //方法二 复制数组到一个数组中再排序找中位数
    //方法三

    public static void main(String[] args) {

        int[] num1 ={1,3};
        int[] num2 = {2,4};
        System.out.println(method1(num1, num2));
        System.out.println(method2(num1, num2));
        System.out.println(method3(num1, num2));
//        System.out.println(14&1);
    }

    //合并排序后再找中位数
    public static double method1(int []num1,int [] num2){

        int[] target=new int[num1.length+num2.length];
        System.arraycopy(num1,0,target,0,num1.length);
        for (int i = 0; i < num2.length; i++) {
            target[num1.length+i]=num2[i];
        }
        Arrays.sort(target);
        int nums=target[(num1.length+num2.length)/2];
        if((target.length&1)==1){
            return nums;
        }else {
            return (nums+target[(num1.length+num2.length)/2-1])/2.0;
        }
    }

    //归并方式:直接找中位数

    public static double method2(int []num1,int [] num2){
        int m=num1.length;
        int n=num2.length;
        //无论两数组长度之和是奇数还是偶数,都需要(m+n)/2+1次

        int len=m+n;
        //返回记录数
        int left=0;
        int right=0;
        //两数组指针
        int num1Next=0;
        int num2Next=0;
        for (int i = 0; i <= (m+n)/2; i++) {
            //对于偶数保存上一次记录数字
            left=right;
            //避免num2数组指针越界,||来限制后面就不用执行
            if(num1Next<m&&(num2Next>n||num1[num1Next]<num2[num2Next])){
                right=num1[num1Next++];
            }else {
                right=num2[num2Next++];
            }
        }
        //偶数
        if((len&1)==0){
            return (left+right)/2.0;
        }else {
            return right;
        }

    }


    public static double method3(int []num1,int [] num2){
        int ans1=getKth(num1,0,num1.length-1,num2,0,num2.length-1,(num1.length+num2.length+1)/2);
        int ans2=getKth(num1,0,num1.length-1,num2,0,num2.length-1,(num1.length+num2.length+2)/2);
        return (ans1+ans2)/2.0;
    }

    //二分法查找中位数位置
    public static int  getKth(int[] nums1,int start1,int end1,int[]nums2,int start2,int end2,int k){
        int size1=end1-start1+1;
        int size2=end2-start2+1;
        if(k==1){
            return Math.min(nums1[start1],nums2[start2]);
        }
        if(size1==0){
            return nums2[start2+k-1];
        }
        int pos1=start1+Math.min(size1,k/2)-1;
        int pos2=start2+Math.min(size2,k/2)-1;
        if(nums1[pos1]>nums2[pos2]){
            return getKth(nums1,start1,end1,nums2,pos2+1,end2,k-(pos2-start2+1));
        }else {
            return getKth(nums1,pos1+1,end1,nums2,start2,end2,k-(pos1-start1+1));
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值