递归与分治

匿名 (未验证) 提交于 2019-12-02 23:52:01

递归:思路简单但效率低(建立函数的副本,消耗大量时间和内存)。能用迭代就不用递归。

递推公式+递推终止条件

Fibonacci数列

# 递归 class Solution:     def fib(self, N: int) -> int:         if N <= 1:             return N         return self.fib(N-1) + self.fib(N-2)  # 迭代 class Solution:     def fib(self, N: int) -> int:         if N <= 1:             return N         tmp1 = 0         tmp2 = 1         for i in range(2, N+1):             res = tmp1 + tmp2             tmp1 = tmp2             tmp2 = res         return res 

函数调用自身,注意递归的停止条件。分为调用和回溯两个阶段。

任意长度的字符串反向,递归实现

# 需要额外存储空间 def reverseStr(string):     if string == None or len(string) == 0:         return None     if len(string) == 1:         return string     return reverseStr(string[1:])+string[0] 
#leetcode,O(1)额外空间,原地修改。双指针 class Solution:     def reverseString(self, s: List[str]) -> None:         """         Do not return anything, modify s in-place instead.         """         if s == None or len(s) <= 1:             return None         i, j = 0, len(s)-1         while i<j:             s[i], s[j] = s[j], s[i]             i += 1             j -= 1         return 
# 超时的递归解法 class Solution:     def reverseString(self, s: List[str]) -> None:         """         Do not return anything, modify s in-place instead.         """         if s == None or len(s) <= 1:             return None         cur = s.pop(0)         self.reverseString(s)         s.append(cur) 

汉诺塔问题:

def move(n, a, b, c):     """n个盘子从a借助b移动到c上"""     if n==1:         print(a+'->'+c)     else:         move(n-1, a, c, b)         move(1, a, b, c)         move(n-1, b, a, c) 

八皇后问题:

当在棋盘上放置了几个皇后且不会相互攻击。但是选择的方案不是最优的,因为无法放置下一个皇后。此时该怎么做?回溯:回退一步,来改变最后放置皇后的位置并且接着往下放置。如果还是不行,再回溯。

一行只可能有一个皇后且一列也只可能有一个皇后。这意味着没有必要再棋盘上考虑所有的方格。按行往下找皇后,对于每个皇后的位置只需要按列循环即可。对于所有的主对角线有:行号 - 列号 = 常数,对于所有的次对角线有 行号 + 列号 = 常数。

class Solution:     def solveNQueens(self, n: int) -> List[List[str]]:         def could_place(row, col):             # row这一行是没有放置过的行,要检查col这一列、(row,col)所占两条对角线有没有被放置过,如果都没有,(row,col)可以放皇后             return not (cols[col]+hill_diagonals[row-col]+\                         dale_diagonals[row+col])                   def place_queen(row, col):             queens.add((row, col))  # 放皇后,记录位置,标记列和两对角线             cols[col] = 1             hill_diagonals[row-col] = 1             dale_diagonals[row+col] = 1                  def remove_queen(row, col):             queens.remove((row, col))  # 移除皇后,清空列和两对角线的标记             cols[col] = 0             hill_diagonals[row-col] = 0             dale_diagonals[row+col] = 0                  def add_solution():             # 如果找到一个解,按要求记录下来             solution = []             for _, col in sorted(queens):                 solution.append('.'*col + 'Q' + '.'*(n-col-1))             output.append(solution)                  def backtrack(row):             # 从第一行row=0开始放置皇后,放到n-1行             for col in range(n):  # 对于确定的row,遍历所有列col                 if could_place(row, col):                     place_queen(row, col)  # 如果(row, col)可以放皇后,就放                     if row == n-1:  # 如果已经放了最后一个,说明找到一个解                         add_solution()                     else:  # 没有放到最后一个的话                         backtrack(row+1)  # 去找row行之后所有可能的放置解法                     remove_queen(row, col)  # 不管是哪种情况都要回溯,移除当前皇后,进入(row, col+1)的情况                      cols = [0] * n         hill_diagonals = [0] * (2 * n -1)         dale_diagonals = [0] * (2 * n -1)         queens = set()         output = []         backtrack(0)         return output 

分治:将问题分成几个小模块,逐一解决。  

二分搜索

# 最普通的情况,规定有序数组不重复 class Solution:     def search(self, nums: List[int], target: int) -> int:         if nums == None or len(nums) == 0:             return -1         low = 0         high = len(nums) - 1         while low <= high:   # 双端闭区间[low, high]查找              mid = (low + high) // 2             if nums[mid] == target:                 return mid             elif nums[mid] > target:                 high = mid - 1             elif nums[mid] < target:                 low = mid + 1           return -1 
# 寻找左侧边界的二分搜索。初始化 right = nums.length,决定了「搜索区间」是 [left, right),所以决定了 while (left < right),同时也决定了 left = mid + 1 和 right = mid # 因为需找到 target 的最左侧索引,所以当 nums[mid] == target 时不要立即返回,而要收紧右侧边界以锁定左侧边界。  def search(nums, target):         if nums == None or len(nums) == 0:             return -1         low = 0         high = len(nums)         while low < high:   # [low, high) 上搜索             mid = (low + high) // 2             if nums[mid] == target:                 high = mid   # 找到target之后不要立即返回,缩小搜索区间上界,在[low, mid)中继续搜索,锁定左侧边界low             elif nums[mid] > target:                 high = mid             elif nums[mid] < target:                 low = mid + 1          if low == len(nums): # target 比所有数都大             return -1         return low if nums[low] == target else -1  # 如果找到,low应该指向左侧边界 
# 寻找右侧边界的二分搜索 def search(nums, target):         if nums == None or len(nums) == 0:             return -1         low = 0         high = len(nums)         while low < high:   # [low, high) 上搜索             mid = (low + high) // 2             if nums[mid] == target:                 low = mid + 1   # 找到target之后不要立即返回,缩小搜索区间下界,在[mid+1, high)中继续搜索,锁定右侧边界high-1             elif nums[mid] > target:                 high = mid             elif nums[mid] < target:                 low = mid + 1          if low == len(nums): # target 比所有数都大             return -1         return low-1 if nums[low-1] == target else -1  # 若找到,最后low == high,右侧边界在 high-1 
# 递归实现二分搜索 class Solution:     def search(self, nums: List[int], target: int) -> int:         if nums == None or len(nums) == 0:             return -1         return self.recursiveSearch(nums, 0, len(nums)-1, target)          def recursiveSearch(self, nums, low, high, target):         if low > high:  # 双端闭区间搜索             return -1         mid = (low+high)//2         if nums[mid] == target:             return mid         elif nums[mid] > target:             return self.recursiveSearch(nums, low, mid-1, target)         elif nums[mid] < target:             return self.recursiveSearch(nums, mid+1, high, target)         return -1 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!