算法训练营08-分治和回溯

分治算法模板

Java

private static int divide_conquer(Problem problem, ) {    

    if (problem == NULL) {    

        int res = process_last_result();    
        return res;       
    }  

    subProblems = split_problem(problem)   

    res0 = divide_conquer(subProblems[0])  
    res1 = divide_conquer(subProblems[1])    

    result = process_result(res0, res1);   

    return result;
}

预习题目
括号生成22
乘方结果50
子集78 这个问题和排列问题,括号生成等可以组合起来看看有没有啥共性

实战题目
多数元素169 (简单、但是高频)
字符和数字17
8皇后问题51

感觉分治和回溯就是对问题的所有可能性进行枚举的过程,一旦一个问题转化为一个可以枚举的问题之后一般都是可以比较方便的实现逻辑了,可以在中间剑指之类的
但是对于一个字符串的全排问题,感觉又有点不像回溯,更像是分治,一种特殊的分治思路,当然也是通过迭代来完成的
像8皇后问题,被称为典型的回溯问题,就是不断判断当前情况是否满足条件,大概明白了,回溯应该是判断当前这一步完了整体是否满足条件,而有些分治问题是没有这一步的,回溯回溯就是每走一步都回过头来看看问题当前的部分结果解法是否依然满足需求。但是比如字符串排列的题,则没有这个回溯的过程,只是不断的分支递归的过程。

1.乘方结果

糟糕的查表,这里第一次实现的时候用了缓存表的方式,非常愚蠢,完全是不需要的啊,因为两侧的子问题是对称的,所以只需要解决一个子问题就行了,所以每个子问题实际上只是计算了一次,并不会计算多次,啊啊啊,晕,这个情况要注意哦

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n<0:
            self.table=[0]*(-n+1)
            return 1/self.pow(x,-n)
        self.table=[0]*(n+1)
        return self.pow(x,n)
    
    def pow(self,x,n) :
        if n == 0 :
            return 1
        if n==1 :
            return  x
        if self.table[n] != 0 :
            return self.table[n]
        half = n//2
        res =  self.pow(x,half)*self.pow(x,(n-half))
        self.table[n]=res
        return res 

正确的解法

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n<0:
            return 1/self.pow(x,-n)
        return self.pow(x,n)
    
    def pow(self,x,n) :
        if n == 0 :
            return 1
        if n == 1 :
            return  x
        left = n % 2
        half = self.pow(x, n//2)
        if left == 1:
            return x * half * half
        return half * half 

2.子集

这个问题让我想到了括号问题,排列组合问题和有重复数据的排列组合问题
有两个角度,一个按照数组的index来进行遍历进行组合,还有一种是从生成结果的第n次操作的角度来看待问题(这个好像不好处理,因为可以不选,很难进行标记处理)
这个就是按照数组的索引index来进行遍历生成数据,想着每次遍历数组的一个位置,这个位置有取或者不取两种操作,直到遍历到数组的结尾等于一次情况结束得到解空间的一个答案

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        one_res = []
        self.sub(0,nums,res,one_res)
        return res 

    def sub(self,index,nums,res,one_res):
        if index == len(nums) :
            res.append(one_res.copy())
            return 
        self.sub(index+1,nums,res,one_res)
        one_res.append(nums[index])
        self.sub(index+1,nums,res,one_res)
        one_res.pop(len(one_res)-1)

数字和字符串

这个的回溯比较简单,因为每次操作都是固定的选择,对其他的不造成影响。像数组的排列组合会更加复杂一些,因为操作之间会相互影响。可以试试比较有重复数组组合和无重复的解法,理论上有重复的可能可以改成无重复的那种操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值