Leetcode-递归&分治

Posted chaojunwang-ml

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode-递归&分治相关的知识,希望对你有一定的参考价值。

50. Pow(x, n) https://leetcode-cn.com/problems/powx-n/

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

说明:

-100.0 < x < 100.0

n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。

解:

直接调库函数,不过面试中肯定不可以。

暴力,写个循环直接乘,O(N)。

分治,y = x**(n/2)。 n是偶数,两部分一样只计算一边即可,res = y*y。n为奇数,res = y*x*y。一直这样算到x**1 或 x**0。时间复杂度为O(logN)。

递归实现

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if not n:
            return 1
        if n < 0:
            return 1 / self.myPow(x, -n)
        if n % 2:
            return x * self.myPow(x, n-1)   # n为奇数,通过n-1次方去做
        return self.myPow(x*x, n/2)  # n为偶数

  

迭代实现,分治的最小计算乘子为x。 例如,x**(7) = x * x**(6) = x * (x**2)**(3) =  x * (x**2) * ((x**2)**2)**1

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if not n:
            return 1
        if n < 0:     # n小于0的话就转化成n大于0的形式,把x变为1/x即可
            x = 1/x
            n = -n
            
        res = 1
        while n:   # 分治的最小单位是1次方
            if n & 1:   # n 为奇数,先乘多出来的一个x
                res *= x
            x *= x  # 基本乘子从x变为x**2
            n >>= 1  # n = floor(n/2)
        return res

  

169. 求众数  https://leetcode-cn.com/problems/majority-element/

给定一个大小为 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在众数。

解:

暴力,两层嵌套循环,枚举所有x,针对某一个x去数组里面计数。O(N2)

直接排序后取中间元素,肯定是众数。O(NlogN)

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

  

遍历一次,用hashmap存元素计数,最后再去map里面看一下计数最大的元素是哪个。O(N)

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        count = dict()
        for x in nums:
            if x in count:
                count[x] += 1
            else:
                count[x] = 1
max_count = 0 for key, value in count.items(): if value > max_count: max_count = value res = key return res # 或者直接利用字典的get函数,一行就可以 return max(count, key=count.get)

  

分治递归求解,直到所有的子问题都是长度为 1 的数组。由于传输子数组需要额外的时间和空间,所以我们实际上只传输子区间的左右指针 low 和 high 表示相应区间的左右下标。

  长度为 1 的子数组中唯一的数显然是众数,直接返回即可。

  如果回溯后某区间的长度大于 1 ,必须将左右子区间的值合并。如果它们的众数相同,那么显然这一段区间的众数是它们相同的值。否则,需要比较两个众数在整个区间内出现的次数来决定该区间的众数。

  原问题的答案就是下标为 0 和 n 之间的众数这一子问题。

时间复杂度为O(NlogN)

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        return self.helper(nums, 0, len(nums)-1)
    
    def helper(self, nums, low, high):
        if low == high:  # 长度为1的子数组,众数就是那唯一的元素
            return nums[low]
        
        # 子数组长度大于1,递归的去找左右数组的众数
        mid = low + (high - low) // 2
        left = self.helper(nums, low, mid)
        right = self.helper(nums, mid+1, high)
        
        if left == right:  # 判断左右两个众数的关系,如果左右众数相同,那一定是左右总体的众数
            return left  
        
        # 如果不相同,总体上count大的那个是整体的众数
        left_count, right_count = 0, 0
        for i in range(low, high+1):
            if nums[i] == left:
                left_count += 1
            elif nums[i] == right:
                right_count += 1
        
        return left if left_count > right_count else right  

  

 

以上是关于Leetcode-递归&分治的主要内容,如果未能解决你的问题,请参考以下文章

java 两个有序数组求中位数_递归分治_LeetCode_04

LeetCode 分治算法

LeetCode解题总结递归篇

大厂算法面试之leetcode精讲3.动态规划

搞定大厂算法面试之leetcode精讲4.贪心

大厂算法面试之leetcode精讲9.位运算