常见五大算法-递归

递归

在数学与计算机科学中,递归(Recursion)是指在函数的定义中使用函数自身的方法。实际上,递归,顾名思义,其包含了两个意思:递 和 归,这正是递归思想的精华所在。

递归伪代码

def recursion(参数):
    if 结束条件:
        return

    处理问题
    recursion(缩小参数)

汉诺塔问题

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

示例1:

 输入:A = [2, 1, 0], B = [], C = []
 输出:C = [2, 1, 0]
示例2:

 输入:A = [1, 0], B = [], C = []
 输出:C = [1, 0]
提示:

A中盘子的数目不大于14个。

汉诺塔

n = 1 时,直接把盘子从 A 移到 C; n > 1 时, 1. 先把上面 n - 1 个盘子从 A 移到 B; 2. 再将最大的盘子从 A 移到 C; 3. 再将 B 上 n - 1 个盘子从 B 移到 C

class Solution:
    def hanota(self, A: List[int], B: List[int], C: List[int]) -> None:
        """
        Do not return anything, modify C in-place instead.
        """

        def move(n, A, B, C):
            if n == 1:
                C.append(A[-1])
                A.pop()
                return

            # 将n-1个盘子从A借助C移动到B上
            move(n - 1, A, C, B)
            # 将A中最后一个盘子放到C中
            C.append(A[-1])
            A.pop()
            # 将n-1个盘子从B借助A放到C上
            move(n - 1, B, A, C)

        n = len(A)
        move(n, A, B, C)

24. 两两·交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

 

示例 1:


输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:

输入:head = []
输出:[]
示例 3:

输入:head = [1]
输出:[1]
 

提示:

链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100

swap_nodes-in-pairs

解题思路

链表很多的问题都会用到递归算法,这个也不例外,既然题目要求我们,我们可以把问题进行拆分,先将前两个节点进行交换,然后递归的将剩余的节点进行反转

答案

# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        # 判断是否有两个合法的节点
        if head is None or head.next is None:
            return head
        # 头结点
        cur = head
        # 下一个节点
        nextNode = head.next
        # 剩余节点
        otherNode = nextNode.next
        # 进行节点交换
        nextNode.next = cur
        # 反转剩余节点
        cur.next = self.swapPairs(otherNode)
        
        return nextNode
        

669. 修剪二叉搜索树

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

提示:

树中节点数在范围 [1, 104] 内
0 <= Node.val <= 104
树中每个节点的值都是唯一的
题目数据保证输入是一棵有效的二叉搜索树
0 <= low <= high <= 104

示例1

trim1

输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]

示例2

trim2

输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3
输出:[3,2,null,1]
示例 3:

输入:root = [1], low = 1, high = 2
输出:[1]

示例 4:`

输入:root = [1,null,2], low = 1, high = 3
输出:[1,null,2]
示例 5:

输入:root = [1,null,2], low = 2, high = 4
输出:[2]

答案

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right


class Solution:
    def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
        if root is None:
            return root

        if root.val < low:
            # 如果当前节点小于low,那根据二叉搜索树特性,那么root的left节点肯定都小于low,不符合条件,要舍弃root和root.left,直接将root的right节点变成root
            root = root.right
            # 进行后面的节点判断
            return self.trimBST(root, low, high)
        elif root.val > high:
            # 反之同理,将root和root.right舍弃
            root = root.left
            return self.trimBST(root, low, high)

        # 当前root.val在区间[low, high]中,分别对left和right节点进行判断
        root.left = self.trimBST(root.left, low, high)
        root.right = self.trimBST(root.right, low, high)
        return root

链表反转

输入:1->2->3->4->5
输出: 5->4->3->2->1
# class Node:
#     def __init__(self, val):
#         self.val = val
#         self.next = None

class Solution:
    def reverse(self, root: Node) -> Node:
        def recursion(prev: Node, cur: Node):
            if not cur:
                # 返回prev节点
                return prev
            nextNode = cur.next
            cur.next = prev
            prev = cur
            return recursion(prev, nextNode)

        prev = None
        cur = root

        return recursion(prev, cur)