关于Leetcode里面求两个数组的第K值问题

今天这篇文章是关于实现两个数组的第K值问 题,也是leetcode的题目,最近做leetcode的题目有点上瘾了,很多题目一开始写完了总感觉不对,然后百度,查下还有什么结题的思路,发现一个问题往往有多个解题方案,从时间复杂度和空间复杂度,抉择出最优的解法。其实做了这么多题,感觉思路最重要,实现的话,其实往往很简单。
其中第二种解法的思路,是网上查看到的,并非自己原创。链接地址:

http://www.07net01.com/2015/07/871155.html

题目地址:

https://leetcode.com/problems/median-of-two-sorted-arrays/

这里介绍两种解题思路:

  • 给两个数组的头插入一个指针,比较两个指针所在位置时数据的大小,来移动指针,最终找到中间数,这种方法的时间复杂度是o((n+m)/2)

  • 采用二分法,假设序列都是从小到大排列,对于第一个序列中前p个元素和第二个序列中前q个元素,我们想要的最终结果是:p+q等于k-1,且一序列第p个元素和二序列第q个元素都小于总序列第k个元素。因为总序列中,必然有k-1个元素小于等于第k个元素。这样第p+1个元素或者第q+1个元素就是我们要找的第k个元素。

第一种实现:

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int location = -1;
        boolean isDouble = false;
        if ((nums1.length + nums2.length) % 2 == 0) {
            // 中位数是两个数的和的一半
            location = (nums1.length + nums2.length) / 2;
            isDouble = true;
        } else {
            location = (nums1.length + nums2.length) / 2;

        }
        return calcResult(nums1, nums2, isDouble, location);
    }

    private double calcResult(int[] nums1, int[] nums2, boolean isDouble,
            int location) {
        int nums1Pointer = 0, nums2Pointer = 0;
        double result_1 = -1, result_2 = -1;
        for (int i = 0; i <= location; i++) {
            boolean IsNum1 = false;
            if (nums1Pointer > nums1.length - 1) {
                IsNum1 = false;
            } else if (nums2Pointer > nums2.length - 1) {
                IsNum1 = true;
            } else if (nums1[nums1Pointer] >= nums2[nums2Pointer]) {
                IsNum1 = false;
            } else {
                IsNum1 = true;
            }
            if (IsNum1) {
                result_1 = nums1[nums1Pointer];
                nums1Pointer++;
            } else {
                result_1 = nums2[nums2Pointer];
                nums2Pointer++;
            }
            if (i == location - 1) {
                result_2 = result_1;
            }
        }
        if (isDouble) {
            result_1 = (result_1 * 1.0 + result_2 * 1.0) / 2;
        }
        return result_1;
    }

第二种实现:

通过二分法将问题规模缩小,假设p=k/2-1,则q=k-p-1,且p+q=k-1。如果第一个序列第p个元素小于第二个序列第q个元素,我们不确定二序列第q个元素是大了还是小了,但一序列的前p个元素肯定都小于目标,所以我们将第一个序列前p个元素全部抛弃,形成一个较短的新序列。然后,用新序列替代原先的第一个序列,再找其中的第k-p个元素(因为我们已经排除了p个元素,k需要更新为k-p),依次递归。同理,如果第一个序列第p个元素大于第二个序列第q个元素,我们则抛弃第二个序列的前q个元素。(PS:来自上面链接的地址)

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//      nums1 = new int[] { 3 };
//      nums2 = new int[] { 1, 2 };
        int m = nums1.length, n = nums2.length;
        int k = (m + n) / 2;
        if ((m + n) % 2 == 0) {
            return (findKth(nums1, nums2, 0, 0, m, n, k) + findKth(nums1,
                    nums2, 0, 0, m, n, k + 1)) / 2;
        } else {
            return findKth(nums1, nums2, 0, 0, m, n, k + 1);
        }

    }

    private double findKth(int[] arr1, int[] arr2, int start1, int start2,
            int len1, int len2, int k) {
        if (len1 > len2) {
            return findKth(arr2, arr1, start2, start1, len2, len1, k);
        }
        if (len1 == 0) {
            return arr2[k - 1 + start2];
        }
        if (k == 1) {
            return Math.min(arr2[start2], arr1[start1]);
        }
        int p1 = Math.min(k / 2, len1);
        int p2 = k - p1;
        if (arr1[start1 + p1 - 1] < arr2[start2 + p2 - 1]) {
            return findKth(arr1, arr2, start1 + p1, start2, len1 - p1, len2, k
                    - p1);
        } else if (arr1[start1 + p1 - 1] > arr2[start2 + p2 - 1]) {
            return findKth(arr1, arr2, start1, start2 + p2, len1, len2 - p2, k
                    - p2);
        } else {
            return arr1[start1 + p1 - 1];
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值