分治法 | Leetcode分类练习 | Datawhale- 打卡(一)

1.主要思想:

将问题递归的分成若干个小问题,直至满足边界条件返回结果,最后将结果合并。

2.使用场景:

各子问题之间相互独立。

3.Leetcode题解:

169.多数元素

  • 题目

    给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于[n/2]的元素。
    你可以假设数组是非空的,并且给定的数组总是存在多数元素。

  • 思路

    • 边界条件:子数组中最少有一个元素
    • 拆分数据:将数组左右二分为两个子数组
    • 合并结果:子数组中只有一个元素时,该元素即为多数元素;左子数组的多数元素left和右子数组的多数元素right相等时,left即为所求;不等时则需要比较right和left在nums中的出现次数获得最终结果
  • 代码

    class Solution:
        def majorityElement(self, nums: List[int]) -> int:
            # 先设置边界条件
            if nums is None:
                return None
            if len(nums) ==1:
                return nums[0]
            # 拆分成小问题
            left = self.majorityElement(nums[:len(nums)//2])
            right = self.majorityElement(nums[len(nums)//2:])
            # 合并结果
            if left == right:
                return left
            else:
                if nums.count(left) > nums.count(right):
                    return left
                else:
                    return right 
    
  • 扩展

    摩尔投票法,前提条件所求元素在数组中出现次数过半

    class Solution:
        def majorityElement(self, nums: List[int]) -> int:
            res_num = nums[0]
            count = 1
            for num in nums[1:]:
                if num == res_num:
                    count += 1
                elif count == 0:
                    count = 1
                    res_num = num
                else:
                    count -= 1
            return res_num
    

    耗时最短的做法

    class Solution:
        def majorityElement(self, nums: List[int]) -> int:
            nums.sort()
            return nums[len(nums)//2]
    

53. 最大子序和

  • 题目

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

  • 思路

    • 边界条件:子数组中最少有一个元素
    • 拆分数据:将数组左右二分为两个子数组
    • 合并结果:子数组中只有一个元素时,该元素即为所求结果;左子数组的结果left,右子数组的结果right和(从右到左计算左边的最大子序和+从左到右计算右边的最大子序和)中最大值即为所求
  • 代码

    class Solution:
        def maxSubArray(self, nums: List[int]) -> int:
            if nums is None:
                return None
            nums_len = len(nums)
            if nums_len ==1:
                return nums[0]
            left = self.maxSubArray(nums[:nums_len//2])
            right = self.maxSubArray(nums[nums_len//2:])
            # 从右至左计算左边子数组的最大子序和
            max_l = nums[nums_len//2-1]
            temp = 0
            for left_i in range(nums_len//2-1,-1,-1):
                temp += nums[left_i]
                max_l = max(temp,max_l) 
            # 从左至右计算右边子数组的最大子序和
            max_r = nums[nums_len//2]
            temp = 0
            for right_i in range(nums_len//2,nums_len):
                temp += nums[right_i]
                max_r = max(temp,max_r) 
            return max(left,right,max_l+max_r)
    
  • 扩展

    因为负数相加,总和会越来越小,所以当子序列和小于等于0时,重新寻找新的连续子序列

    class Solution:
        def maxSubArray(self, nums: List[int]) -> int:
            max_sum = nums[0]
            mysum = 0
            for i in nums:
                if mysum > 0:
                    mysum += i
                else:
                    mysum = i
                max_sum = max(mysum, max_sum)
            return max_sum
    

50. Pow(x, n)

  • 题目

    实现 pow(x, n) ,即计算 x 的 n 次幂函数。

  • 思路

    • 边界条件:n 最后为0时返回1
    • 拆分数据:n除以2的余数为1时 n=n-1;否则n=n/2且x = x*x
    • 合并结果:n除以2的余数为1时计算结果并返回,为0时,更新x值,即将\(x^2\)带入myPow函数中
  • 代码

    class Solution:
        def myPow(self, x: float, n: int) -> float:
            if n < 0:
                x = 1/x
                n = -n
            if n == 0:
                return 1
            if n%2 == 1:
                return x * self.myPow(x,n-1)
            return self.myPow(x*x,n/2)
    
  • 扩展
    快速幂(二进制角度):通过增加底数减少幂运算次数,从而降低时间复杂度O(n)为O(logn)
    eg:Pow(2,10) 10的二进制写法是1010
    \(2^{10} = 2^0 * 2^2 * 2^0 * 2^8 = 2^{2^1}*2^{2^3}\)

     class Solution:
        def myPow(self, x: float, n: int) -> float:
            if n < 0: 
                x,n = 1/x,-n
            if n==0: 
                return 1
            res = 1
            while n > 0:
                # 判断最低位是否是1
                if n&1:
                    res *= x
                # 右移一位,相当于除以2
                n=n>>1
                x *= x
            return res   
    

【参考】https://github.com/datawhalechina/team-learning-program/blob/master/LeetCodeClassification/1.分治.md#算法应用

posted @ 2020-08-19 17:27  柔南青空  阅读(152)  评论(0编辑  收藏  举报