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

来源:互联网 发布:阿里斯托芬 云 原文 编辑:程序博客网 时间:2024/05/29 04:37

今天这篇文章是关于实现两个数组的第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
原创粉丝点击