DataWhaleChina 0818-20 leetcode实践 Task1 分治思想与练习题

分治算法是什么

分治算法的主要思想是将原问题递归地分成若干个子问题,直到子问题满足边界条件,停止递归。将子问题逐个击破(一般是同种方法),将已经解决的子问题合并,最后,算法会层层合并得到原问题的答案。
在这里插入图片描述

我的疑问(待解决)

这和动态规划的区别主要是啥呀。。分支的条件不同吗

步骤

分为三步:

  • 分:确定分支条件,比如什么时候终止分支
  • 治:确定处理已分出来支的方法
  • 合:汇总处理后的分支给出局部解直到最终解

练习题

leetcode 50 pow

解题思路

咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕

解题步骤

咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕咕

class Solution(object):
    def myPow(self, x, n):
        if n > 0:#分
            return self.cul(x, n)
        elif n == 0:
            return 1
        else:#分
            return 1/self.cul(x, -n)
        

    def cul(self, x, n):
        
        if n == 1:#分
            return x
        else:#分
            if n%2==0:
                return self.cal(self.myPow(x, n/2))#治
            else:
                return self.cal(self.myPow(x, (n-1)/2))*x#治


    def cal(self, n):#治
        return n*n

leetcode 53

解题思路

哎这题挺难直接想到的。分治思想的重点在于分与治。这个题求最大连续子数组,也就是说找到不管从哪里开始哪里结束的最大数组合。先试想这个场景,将一个数组分为左右两段。如果我想从原来的一个数组中取出一段连续数字,那这串数字只有两种情况:

  • 属于左段或者右段
  • 至少拥有左段的最右一个数字和右端的最左一个数字
    此时再圈定范围缩小条件:最大的连续数字。但此刻我们可以惊讶的发现,情况没变,还是刚刚那两种,属于 或者 跨越。
    此刻的题就好解了起来。先说情况二,这种情况意味着此时情况的求解已经从一个两端不固定的数组变成了两个一端不固定的数组,此刻只要两端分别遍历到头打擂台然后加起来就好。
    情况一更简单,我们需要找到左段或者右段的最大连续数字。这个情况非常耳熟。对,这跟找到原数组的最大连续数字是一个情况。一般这种时候我们称之为子问题,也就是说此刻我们只要跟上面一样分两种情况,属于当前数组的左/右 或者 跨越。
    可能这时候就有人问了:第一种情况还是没有解决呀!丢包给下一层也还得解决呀!
    对,很好,得解决,但不用咱费心思。数组是有确定个数的,当我们一直遍历到左端和右端都只有一个数的时候,最大子序列就很好说:1 左 2 右 3 both。
    至此我们算是倒推了一遍找子序列的过程。总的来说,我们分,分到左端和右端各只有一个数(方便获得当前子情况的最大序列)。治,左右就去递归,跨越就去向两边遍历。合,比较然后得出 左 右 跨越 中最大的子序列和。
解题步骤
  • 分:除非数组长度为一否则继续分
  • 治:情况一,是左段和右段就去看有没有子情况,没有子情况自动返回,有子情况就去子情况然后等子情况喂数。情况二,跨越就去向两边遍历。
  • 合:比较然后得出 左 右 跨越 中最大的子序列和。
class Solution(object):
    def maxSubArray(self, nums):
        n = len(nums)
        print(n)
        mid = int(n / 2)
        if n == 1:#分
            return nums[0]
        else:
            return self.operate(nums[:mid], nums[mid - n:], self.maxSubArray(nums[:mid]), self.maxSubArray(nums[mid - n:]))

    def operate(self, lnums, rnums, lmax, rmax):#合
        mid = self.midsum(lnums, rnums)
        return max(mid, lmax, rmax)


    def midsum(self, lnums, rnums):#治
        mid = self.rightsum(lnums) + self.leftsum(rnums)
        return mid

    def leftsum(self, nums):#治
        sum = 0
        max = nums[0]
        for i in nums:
            sum += i
            if (sum > max) :
                max = sum
        return max

    def rightsum(self, nums):#治
        sum = 0
        max = nums[-1]
        for i in nums[::-1]:
            sum += i
            if (sum > max) :
                max = sum
        return max

leetcode 169 求众数

题目描述

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

解题思路

这题用分治还算好理解。众数意味着这数占总数的一半以上。用分治解题的话,就是不断得将数组二分,然后不断得二选一得出众数。注意众数只有递归到最终轮才能决定就是了。

解题步骤
  • 分:除非数组长度为一否则继续分
  • 治:情况一,如果数组长度是一就直接为当前数组众数。情况二,一般会得到两个众数,送去合为一个众数然后返回
  • 合:比较两众数,一致则过了,不一致则合起来他们的原数组然后统计后二选一返回
class Solution(object):
    def majorityElement(self, nums):
        n = len(nums)
        print(n)
        mid = int(n/2)
        if n==0:#分
            return None#治
        elif n ==1:#分
            return nums[0]#治
        else:#分
            return self.operate(nums, self.majorityElement(nums[:mid]), self.majorityElement(nums[mid-n:]))#治

    def operate(self, nums, m1, m2):#合
        if m1 == m2:
            return m1
        else:
            c1 = nums.count(m1)
            c2 = nums.count(m2)
            return m1 if c1>c2 else m2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值