• 递归 | 二分查找


    主要内容:

    • 1.递归
    • 2.列表查找  - 二分查找

    1. 递归

    1.1 递归的特点

    • 调用自身
    • 结束条件

    判断下列函数是否是递归

    def func(x):
        print(x)
        func(x-1)
    
    #没有结束条件  --> 递归出口
    def func(x):
        if x > 0:
            print (x)
            func(x +1)
    # 递归调用之前对x进行 打印
    def func(x):
        if x > 0:
            print(x)
            func(x-1)
    func(3)
    
    # 输出结果 3,2,1
    #递归调用之后进行调用
    def func(x):
        if x > 0:
            func(x-1)
            print(x)
    func(3)
    
    # 输出结果 1,2,3 

    1.2 递归实例  --  斐波那契问题

    斐波那契数列:

      斐波那契数列数列从第3项开始,每一项都等于前两项之和。 例子:数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ..........

    求解斐波那契第 n 项

    • 使用递归  时间复杂度 O(2^n)
      #使用递归,但是注意此时最后的return 语句不是尾递归
      def func(n):
          if n==1 or n==2:
              return 1
          else:
              return func(n-1) + func(n-2)

      使用递归慢的原因: 由于需要多次的重复计算,导致很慢

    • 使用递归的改进方法 : 通过记录值解决重复计算的问题,但是时间复杂度没有改变
      def func(n):
          #创建一个列表,此时列表中的元素 未被赋值前是-1 ,当赋值后变为正数
          lst = [-1 for i in range(n+1)]
          def fib(n):
              if  n == 0 or n == 1:
                  return 1
              elif lst[n] >= 0:
                  return lst[n]
              else:
                  v = fib(n-1) + fib(n-2)
                  #只是记录一下,下次再用的时候直接扔出去
                  lst[n] = v
                  return lst[n]
          return fib(n)
    • 使用列表,将后一项添加到列表中,return 列表最后一项 时间复杂度O(n)
      def func(n):
          res = [1,1]
          for i in range(2,n+1):
              res.append(res[-1] + res[-2])
              return res[-1]

      上述方式的缺点: 虽然时间复杂度为O(n) ,但是创造了列表 ,空间复杂度增加

    • 使用3变量的方式 ,时间复杂度为 O(n) ,但是省空间
      def func(n):
          if n == 0 or n == 1:
              return 1
          a = 1 
          b = 1
          c = 0  #c可以是任何值
          
          for i in range(2,n+1):
              c = a + b
              a = b
              b = c     
          return c 

      更优化版:

      def func(n):
          a = 1
          b = 1
          c = 1  
          for i in range(2,n+1):
              c = a + b
              a = b
              b = c
          return c

    1.3 递归实例2  -  汉诺塔问题

    问题描述:

    • 假设有三个命名为 A B C 的塔座 ,在塔座A上插有n个直径大小不相同,由小到大编号为1 ,2 ,3 ,··· ,n的圆盘,要求将A座上的圆盘移至塔座C
    • 并按同样的顺序叠排

    圆盘移动规则

    • 每次只能移动一个圆盘
    • 圆盘可以插在任意一个塔座上
    • 任何时刻都不能将一个较大的圆盘放在一个较小的圆盘上

    问题简化 :

    • 将 n - 1  个圆盘 看成一个整体,将其从A经过C移动到B
    • 将第 n个盘子从A移动到C
    • 将开始的n - 1 个盘子从B 经过A移动到C

    代码书写

    • 汉诺塔移动次数的递推式 h(x) = 2h(x-1) +1
      def hanoi(n,A,B,C):
          '''
          :param n: 需要从A移到C 的盘子总数
          :param A: 移动盘子的起始柱子
          :param B: 移动过程中经过的柱子
          :param C: 移动结束的柱子
          '''
          if n > 0 :
              hanoi(n-1,A,C,B)            #将起始A柱子上的n-1个盘子通过C移动到B
              print("%s -> %s" %(A,C))    #将底层的盘子从A放到C
              hanoi(n-1,B,A,C)            #将B上的n-1 个盘子经由A移动到C

    1.4 题目练习

    问题描述:

    • 一段有n个台阶组成的楼梯,小明从楼梯的最底层向最高处前进,
    • 他可以选择一次迈一级台阶或者一次迈两级台阶。问:他有多少种不同的走法?

    2. 列表查找  - 二分查找

    列表查找 :从列表中查找指定元素

    • 输入: 列表,带查找元素
    • 输出: 元素下标或未查找到的元素

    顺序查找:从列表的第一个元素开始,顺序进行搜索,直到找到为止

    # 顺序查找代码,时间复杂度为O(n)
    def linear_search(data,value):
        '''
        :param data: 查找的目标列表
        :param value:目标查找元素
        :return:
        '''
        for i in range(data):
            if data[i] == value:
                return i
        return

    二分查找: 从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半

    def binary_search(lst,val):
        left = 0
        right = len(lst) -1
        while left <= right:
            mid = (left + right) // 2
            if val == lst[mid]:
                return mid
            elif val < lst[mid]:
                right = mid -1
            else:
                left = mid +1
        return

    递归版本的二分查找

    def bin_search(lst,val,left,right):
        if left <= right:
            mid = (left + right) // 2
            if lst[mid] == val:
                return mid
            elif lst[mid] > val:
                return bin_search(lst,val,left,mid-1)
            else:
                return bin_search(lst,val,mid+1,right)
        else:
            return
    
    # 上述return属于尾递归 : 编译器会优化成迭代 但是Python没有针对尾递归进行优化
  • 相关阅读:
    HTTP协议
    DNS解析原理
    数据库 怎么配置多实例
    mysql回表
    Oracle进程说明
    Oracle动态和静态参数文件和控制文件
    Oracle数据库的启动和关闭过程
    Mysql索引
    sqlserver备份还原
    oracle undo表空间异常激增排查
  • 原文地址:https://www.cnblogs.com/wcx666/p/10564361.html
Copyright © 2020-2023  润新知