LeetCode寻找两个有序数组的中位数打败100%人

简介: LeetCode寻找两个有序数组的中位数打败100%人

😀前言

在本文中,我们将深入研究一种复杂的算法问题:查找两个有序数组的中位数。这是一个经典的计算问题,通常出现在编程面试和算法挑战中。我们将首先探讨一种常见的暴力解决方法,然后逐步引入更高效的解决方案,最终理解并实现官方的二分法算法。通过本文,您将获得对这一重要算法问题的深刻理解。

🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉


寻找两个有序数组的中位数

自己思路

就是暴力破解或者是数组合并然后排序

看不得还是分析官方打败100%的吧

class Solution {
       public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int l=nums1.length+nums2.length;
        int[] c = new int[l];
        for (int i = 0; i < nums1.length; i++) {
            c[i]=nums1[i];
        }
        for (int i =0,j=nums1.length; i <nums2.length; i++,j++) {
            c[j]=nums2[i];
        }
        Arrays.sort(c);
        if (l % 2 != 0) {
            return c[l / 2 ];
        } else {
            return (double) (c[l / 2] + c[l / 2 - 1]) / 2.0;
        }
    }
}

官方思路


int midIndex = totalLength / 2; 这个意思是当二个数组的和是奇数时取中间的数


注意为什么后面需要+1 如 1 2 3是合为3但是我们上面/2的结果在java里面是1又因为我们需要中为数 所以我们在调用下面的函数的时候需要+1


当偶数的时候同理

🥰重点分析getKthElement方法


index1和index2官方没有解释说 这里我来分析一下 这个可以指的是老地址 也就是初始地址


因为后面我们需要排除前面的元素怎么排除呢 我们可以通过在增加一个地址 即为新地址


newIndex1和newIndex2来表示新地址


half这个相当于比k还一半的数那来截取


举个例子就明白了


假设两个有序数组如下:



两个有序数组的长度分别是 4 和 9,长度之和是 13,中位数是两个有序数组中的第 7 个元素,因此需要找到第 k=7 个元素。


比较两个有序数组中下标为 k/2−1=2的数,即 A[2] 和 B[2],如下面所示:


在代码中 newIndex1=2 newIndex2=2 index1=0 index2=0


由于 A[2]>B[2],因此排除 B[0] 到 B[2],即数组 B 的下标偏移(offset)变为 3,同时更新 k 的值:k=k−k/2=4。


在代码中就是 k - = (newIndex1 - index1 + 1) ==k=7-3=4 相当于 中位数减去新地址和老地址的个数 比如 0 1 2 算几个 就是 3-0+1=3个


然后老地址移位 就相当于 下标偏移(offset)变为 3 就是 index2 = newIndex2 + 1==index2=2+1=3 在数组2中的值为4 这个+1的意思是截取3为从第4位算


下一步寻找,比较两个有序数组中下标为 k/2−1=1 的数,即 A[1]和 B[4],如下面所示,其中方括号部分表示已经被除的数。


在代码中我们就得 half = k / 2结果为2; 然后 int newIndex2 = Math.min(index2 + half, length2) - 1;这个相当于就是截取了不算中括号的数组2中值为4的就是1号相当于数组中0号 然后新地址 就是 老地址+之前的half-1 相当于不算 [1 2 3] + half=2的元素还多了一个 所以需要减1 才满足 k/2−1=1的元素即为 即 A[1]和 B[4]


由于 A[1]


在代码中就是 pivot1 <= pivot2 比较值 (对应A[1]


下一步寻找,比较两个有序数组中下标为 k/2−1=0 的数,即比较 A[2]和 B[3],如下面所示,其中方括号部分表示已经被排除的数。


在代码中就是如下图 原因前面已经很清楚了



由于 A[2]=B[3],根据之前的规则,排除 A 中的元素,因此排除 A[2],即数组 A\text{A}A 的下标偏移变为 3,同时更新 k 的值: k=k−k/2=1


在代码中就是


由于 k 的值变成 1,因此比较两个有序数组中的未排除下标范围内的第一个数,其中较小的数即为第 k 个数,由于 A[3]>B[3],因此第 k 个数是 B[3]=4


在代码中就是


有以下三种情况需要特殊处理:

  • 如果 A[k/2−1]或者 B[k/2−1]越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 k 的值,而不能直接将 k 减去 k/2。
  • 如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 k 小的元素。
  • 如果 k=1,我们只要返回两个数组首元素的最小值即可。


对应代码


解释一下为什么减1是因为k是从1开始算的到数组要-1


到此终于结束了 整个流程分析


建议看玩我这个流程在看官方的详细的流程分析虽然抽象一点 但是理解我的了再看官方的也不是很难 如果想多学一种可以去看官方视频建议理解这个之后在去看视频 和挑战 划分数组解法

4. 寻找两个正序数组的中位数 - 力扣(LeetCode)

总结

这个还是很绕了 可以自己debug一个一个的看然后再加上我上面的思路结合自己的理解加上每个变量的作用理解就可以解决了

    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int length1 = nums1.length, length2 = nums2.length;
            int totalLength = length1 + length2;
            if (totalLength % 2 == 1) {
                int midIndex  = totalLength / 2;
                return getKthElement(nums1, nums2, midIndex + 1);
            } else {
                int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;
                return (getKthElement(nums1, nums2, midIndex1 + 1) +
                        getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;
            }
        }
        public static int getKthElement(int[] nums1, int[] nums2, int k) {
            int length1 = nums1.length, length2 = nums2.length;
            int index1 = 0, index2 = 0;
            while (true) {
                // 边界情况
                if (index1 == length1) {
                    return nums2[index2 + k - 1];
                }
                if (index2 == length2) {
                    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, length1) - 1;
                int newIndex2 = Math.min(index2 + half, length2) - 1;
                int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];
                if (pivot1 <= pivot2) {
                    k -= (newIndex1 - index1 + 1);
                    index1 = newIndex1 + 1;
                } else {
                    k -= (newIndex2 - index2 + 1);
                    index2 = newIndex2 + 1;
                }
            }
        }

😄总结

在本文中,我们详细分析了查找两个有序数组的中位数问题。我们首先介绍了一种暴力破解的方法,然后深入研究了官方的二分法解决方案。我们解释了每个步骤的原理,并提供了清晰的代码示例。最后,我们强调了该算法的关键思想和特殊情况的处理方法。通过本文,您现在应该能够更自信地处理这个算法问题,并在面试或编程挑战中取得更好的表现。希望这篇文章对您有所帮助,谢谢您的阅读!

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁

希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻

如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞



目录
相关文章
|
1月前
leetCode(删除有序数组中的重复项)
如何在不使用额外空间的情况下,通过双指针法原地删除有序数组中的重复项。
33 2
|
3月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
|
1月前
【LeetCode 48】108.将有序数组转换为二叉搜索树
【LeetCode 48】108.将有序数组转换为二叉搜索树
38 0
|
3月前
|
算法
LeetCode第26题删除有序数组中的重复项
这篇文章介绍了LeetCode第26题"删除有序数组中的重复项"的解题方法,通过使用双指针技巧,高效地去除数组中的相邻重复元素。
LeetCode第26题删除有序数组中的重复项
|
3月前
|
算法
LeetCode第80题删除有序数组中的重复项 II
文章介绍了LeetCode第80题"删除有序数组中的重复项 II"的解法,利用双指针技术在O(1)空间复杂度内原地删除重复元素,并总结了双指针技术在处理有序数组问题中的应用。
LeetCode第80题删除有序数组中的重复项 II
|
3月前
|
Python
【Leetcode刷题Python】977. 有序数组的平方
解决LeetCode "有序数组的平方" 问题的方法:使用Python内置的快速排序、直接插入排序(但会超时)和双指针技术,并给出了每种方法的Python实现代码。
21 1
【Leetcode刷题Python】977. 有序数组的平方
|
3月前
|
算法
LeetCode第88题合并两个有序数组
文章分享了LeetCode第88题"合并两个有序数组"的解法,通过从后向前的合并策略避免了数组元素的前移,使用三个指针高效地完成了合并过程。
|
3月前
|
Python
【Leetcode刷题Python】108. 将有序数组转换为二叉搜索树
LeetCode上108号问题"将有序数组转换为二叉搜索树"的Python实现,通过递归选取数组中间值作为根节点,构建高度平衡的二叉搜索树。
25 2
|
3月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
54 0
|
3月前
|
Python
【Leetcode刷题Python】26. 删除有序数组中的重复项
本文提供了一种使用快慢指针法在原地删除升序数组中重复元素的Python实现,返回删除后数组的新长度,同时保持元素的相对顺序。
43 0