LeetCode04—寻找两个正序数组的中位数(java版)

题目描述:

标签:数组    二分查找    分治算法

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

代码: 

一、方法一:先合并再查找中位数

思路分析:时间复杂度O(m+n)

① 首先新建一个数组nums,用来存储合并后的数组。

②判断nums1和nums2数组是否有空数组,如果有,则返回非空数组的中位数。

③如果nums1和nums2数组都为非空数组,则设置三个指针count,i,j分别指向nums、nums1、nums2。每次比较nums1[i]和nums2[j]的值,将较小的值放入nums数组。

同时需要注意数组长度不等长的情况,所以要先判断是否有数组已经遍历结束,如果有,则将未遍历结束的数组剩余元素依次添加到nums。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] nums;
        int m = nums1.length;
        int n = nums2.length;
        nums = new int[m + n];

        //如果nums1数组为空
        if(m == 0){
            if(n % 2 == 0){//长度为偶数
                return (nums2[n/2-1] + nums2[n/2]) / 2.0;
            }else{//长度为奇数
                return nums2[n/2];
            }
        }

        //如果nums2数组为空
        if(n == 0){
            if(m % 2 == 0){
                return (nums1[m/2-1] + nums1[m/2]) / 2.0;
            }else{
                return nums1[m/2];
            }
        }
        
        //先合并两个数组
        int count = 0;//指向nums的下标
        int i = 0;//指向nums1的下标
        int j = 0;//指向nums2的下标
        while(count != (m + n)){
            //如果nums1数组已经遍历结束
            if(i == m){
                while(j != n){
                    nums[count++] = nums2[j++];
                }
                break;
            }
            //如果nums2数组已经遍历结束
            if(j == n){
                while(i != m){
                    nums[count++] = nums1[i++];
                }
                break;
            }
            //如果nums1和nums2遍历都未完成
            if(nums1[i] < nums2[j]){
                nums[count++] = nums1[i++];
            }else{
                nums[count++] = nums2[j++];
            }
        }

        if((m+n) % 2 == 0){
            return (nums[(m+n)/2-1] + nums[(m+n)/2]) / 2.0;
        }else{
            return nums[(m+n)/2];
        }
    }
}

、方法二:二分查找(不需要求解合并数组)

思路分析:对时间复杂度的要求有log,通常都需要用到二分查找。(详细解见官方)

fig1

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int total = m + n;
        if(total % 2 == 1){
            int mid = (m + n) / 2;
            double median = getKthElement(nums1,nums2,mid + 1);
            return median;
        }else{
            int mid1 = total / 2 - 1;
            int mid2 = total / 2;
            double median = (getKthElement(nums1,nums2,mid1 + 1) + getKthElement(nums1,nums2,mid2 + 1)) / 2.0;
            return median;
        }
    }

    public int getKthElement(int[] nums1,int[] nums2,int k){
        int len1 = nums1.length;
        int len2 = nums2.length;
        int index1 = 0;
        int index2 = 0;
        int kthElement = 0;

        while(true){
            //边界条件
            if(index1 == len1){
                return nums2[index2 + k - 1];
            }

            if(index2 == len2){
                return nums1[index1 + k -1];
            }

            if(k == 1){
                return Math.min(nums1[index1],nums2[index2]);
            }

            //正常情况
            int half = k / 2;
            int newIndex1 = Math.min(index1 + half,len1) - 1;
            int newIndex2 = Math.min(index2 + half,len2) - 1;
            int val1 = nums1[newIndex1];
            int val2 = nums2[newIndex2];
            if(val1 <= val2){
                k -= (newIndex1 - index1 + 1);
                index1 = newIndex1 + 1;
            }else{
                k -= (newIndex2 - index2 + 1);
                index2 = newIndex2 + 1;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40840749/article/details/112493814