递归:解题思路
Posted 我家大宝最可爱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归:解题思路相关的知识,希望对你有一定的参考价值。
- 子问题与原问题是否是一致的,子问题是否只是缩小了问题的规模
- 如果原问题的解不依赖于子问题的解,这个问题肯定不用递归,否则可以考虑递归
- 假设子问题已经解决了,这个时候如何将入参与子问题的解进行逻辑处理,从而得到原问题的解
- 链表,数组,二叉树这种结构本身就有递归属性
- 列表求和问题
原问题是从头到位对整个链表求和,子问题本质也是求和,只是问题规模缩小了
- 汉诺塔问题
原问题是把N个圆盘由A移动到C,子问题可以变为把N-1个圆盘由A移动到B,然后在把这个N-1个圆盘移动到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.pop())
return
move(n-1, A, C, B) # 子问题
C.append(A.pop()) # 逻辑
move(n-1, B, A, C) # 子问题
n = len(A)
move(n,A,B,C)
- 合并两个有序链表
原问题是合并两个链表,当我们提取出最小值的时候,子问题就可以变成合并缩小规模后的两条链表,例如合并两个链表list1=[1,2,4,8],list2=[2,3,6,7]
,我们提取出当前最小值是list1
的头节点,子问题就变成合并两个链表list1=[2,4,8],list2=[2,3,6,7]
,然后将list1
的头节点拼接上即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
if list1 is None:
return list2
if list2 is None:
return list1
if list1.val <= list2.val:
list1.next = self.mergeTwoLists(list1.next,list2)
return list1
else:
list2.next = self.mergeTwoLists(list1,list2.next)
return list2
- 反转链表
原问题是反转[1,2,2,3,4,6]
,子问题是反转[2,2,3,4,6]
,我们把1拼接到后面即可。
这个就是逻辑处理,然后反复调用自身即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
last = self.reverseList(head.next)
head.next.next = head
head.next = None
return last
链表的递归反转最让我难以理解的就是last的返回,我们知道反转之后需要把最后一个元素最为head节点返回的,但是递归通常是返回上一层的节点
- 两个数组的交集
这个问题并不能使用递归解决,但是因为很像递归,我单独分析一下。假如我们子问题已经求出解了,现在的问题是如何把元素1
和子问题的解[2,4]
合并到一起去,这个逻辑处理应该怎么做?所以这个问题并不好做。
以上是关于递归:解题思路的主要内容,如果未能解决你的问题,请参考以下文章