LeetCode 热题 HOT 100(03,寻找两个正序数组的中位数)

LeetCode 热题 HOT 100(03,寻找两个正序数组的中位数)

不够优秀,发量尚多,千锤百炼,方可成佛。

算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力,这也是面试的必备环节,算法功底的展示往往能让面试官眼前一亮,这也是在大多数竞争者中脱颖而出的重要影响因素。

然而往往大多数人比较注重自身的实操能力,着重于对功能的实现,却忽视了对算法能力的提高。有的时候采用不同的算法来解决同一个问题,运行效率相差还是挺大的,毕竟我们最终还是需要站在客户的角度思考问题嘛,能给用户带来更加极致的体验当然再好不过了。

万法皆空,因果不空。Taoye之前也不怎么情愿花费太多的时间放在算法上,算法功底也是相当的薄弱。这不,进入到了一个新的学习阶段,面对导师的各种“严刑拷打”和与身边人的对比,才开始意识到自己“菜”的事实。

这次的题目是LeeTCode 热题 HOT 100的第四题,难度属于困难,主要考查的是排序问题。

下面,我们就来看看这道题吧。

题目:寻找两个正序数组的中位数

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

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

题目Url: https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

示例

  • 示例1

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

  • 示例2

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

  • 示例3
    输入:nums1 = [0,0], nums2 = [0,0]
    输出:0.00000

  • 示例4

输入:nums1 = [], nums2 = [1]
输出:1.00000

  • 示例5

输入:nums1 = [2], nums2 = []
输出:2.00000

思路

这道题的题目难度级别虽然属于困难,但个人感觉并没有比前面几题难多少。而且之前复习408,使用严奶奶《数据结构》这本书的时候,印象中有这道题的处理方式。

这道题主要考查的是排序,而且题目表明了尽可能使用时间复杂度为\(O(log(m+n))\)的算法。

在没有任何限制条件的情况下,比如可以使用下面这种解法:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        len_nums1, len_nums2 = len(nums1), len(nums2)
        for item in nums2:      #  循环,将nums2添加到nums1中
            nums1.append(item)
        nums1.sort()            # 使用sort对nums1进行排序
        if (len(nums1) % 2 == 0):       # 判断奇偶性,返回目标值
            return (nums1[int(len(nums1) / 2)] + nums1[int(len(nums1) /2) - 1]) / 2
        else: return nums1[int(len(nums1) / 2)]

但是,这种解法使用的是sort接口进行排序,并没有达到题目所要考查的目的——排序,所以这种解法仅提供参考。至于在Python中sort方法采用的是什么排序算法,及其时间复杂度多少,读者可自行前去了解。

第二种算法,我们可以尝试采用时间复杂度为\(O(m + n)\)的算法来解决。这也是我印象中,在严奶奶《数据结构》中有提到的类似方法(这本书暂时不在身边,无法证实印象的准确性)

这种算法的思想也挺简单的,主要采用使用到两个flag,一边比较两个flag对应数组中值的大小,将其append到一个新的数组result_list中,同时修改flag的值。当我们的其中一个flag等于对应数组的长度,则说明该数组的数据已经完全添加完毕,所以退出循环。之后判断剩下的数组中是否还有元素未添加到新数组result_list中,假如有的话,对剩下的数组元素进行遍历,并添加到result_list中。最终,判断result_list的长度的奇偶性,并返回最终的中位数。

实现的Python代码:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        len_nums1, len_nums2, result_list = len(nums1), len(nums2), list()  # 初始化

        flag1 = 0; flag2 = 0;   # 初始化flag
        while(flag1 != len_nums1) and (flag2 != len_nums2):     # while循环,直至其中一个数组遍历完成
            if (nums1[flag1] < nums2[flag2]): result_list.append(nums1[flag1]); flag1 += 1
            else: result_list.append(nums2[flag2]); flag2 += 1

        if (flag1 < len_nums1):         # 如果nums1中还剩有元素
            for i in range(flag1, len_nums1): 
                result_list.append(nums1[i])
        if (flag2 < len_nums2):         # 如果nums2中还剩有元素
            for j in range(flag2, len_nums2): 
                result_list.append(nums2[j])
        
        result_len = len_nums1 + len_nums2  
        if (result_len % 2 == 0):       # 返回目标中位数
            return (result_list[int(result_len / 2)] + result_list[int(result_len /2) - 1]) / 2
        else: return result_list[int(result_len / 2)]

实现的C++代码:

尴尬死了,C++代码写的不是很熟练,调试了好一会,才调试成功,代码写的也不够优雅,暂时先这样吧,后面再回过头来优化。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len_nums1 = nums1.size(); 
        int len_nums2 = nums2.size(); 
        vector<int> result_list = {};

        int flag1 = 0; 
        int flag2 = 0;
        while (1) {
            if (flag1 != len_nums1) {
                if (flag2 != len_nums2) {
                    if (nums1[flag1] < nums2[flag2]) {
                        result_list.push_back(nums1[flag1]); 
                        flag1 += 1;
                    }
                    else {
                        result_list.push_back(nums2[flag2]); 
                        flag2 += 1;
                    }
                }else { break; }
            }else { break; }
        }

        if (flag1 < len_nums1) {
            for (int i=flag1; i < len_nums1; i++) {
                result_list.push_back(nums1[i]);
            }
        }
        if (flag2 < len_nums2) {
            for (int i=flag2; i < len_nums2; i++) {
                result_list.push_back(nums2[i]);
            }
        }

        int result_len = len_nums1 + len_nums2;
        if (result_len % 2 == 0) {
            return (result_list[int(result_len / 2)] + result_list[int(result_len /2) - 1]) / 2;
        }
        else { 
            return result_list[int(result_len / 2)]; 
        }
    }
};

至于时间复杂度为\(O(log(m+n))\)的算法,主要看了下讨论区中大佬的解法,的确挺巧妙的,主要采用了二分法的思想,关于具体细节,可以参考下方的原算法Url:

"""
    Author: jimmy00745
    Url: https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/dong-yong-er-fen-cha-zhao-mo-ban-lai-qiao-miao-jie/
"""
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:

        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        len1, len2 = len(nums1), len(nums2)
        
        left, right, half_len = 0, len1, (len1 + len2 + 1) // 2
        mid1 = (left + right) // 2
        mid2 = half_len - mid1
        
        while left < right:
            if mid1 < len1 and nums2[mid2-1] > nums1[mid1]:
                left = mid1 + 1
            else:
                right = mid1
            mid1 = (left + right) // 2
            mid2 = half_len - mid1
        
        if mid1 == 0: 
            max_of_left = nums2[mid2-1]
        elif mid2 == 0: 
            max_of_left = nums1[mid1-1]
        else: 
            max_of_left = max(nums1[mid1-1], nums2[mid2-1])

        if (len1 + len2) % 2 == 1:
            return max_of_left

        if mid1 == len1: 
            min_of_right = nums2[mid2]
        elif mid2 == len2: 
            min_of_right = nums1[mid1]
        else: 
            min_of_right = min(nums1[mid1], nums2[mid2])

        return (max_of_left + min_of_right) / 2

我是Taoye,爱专研,爱分享,热衷于各种技术,学习之余喜欢下象棋、听音乐、聊动漫,希望借此一亩三分地记录自己的成长过程以及生活点滴,也希望能结实更多志同道合的圈内朋友,更多内容欢迎来访微信公主号:玩世不恭的Coder

推荐阅读:

LeetCode 热题 HOT 100(00,两数之和)
LeetCode 热题 HOT 100(01,两数相加)
LeetCode 热题 HOT 100(02,无重复字符的最长子串)

分类:

技术点:

相关文章: