文章目录
二叉树前序、中序、后序遍历相互求法
前序遍历:
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树
前序遍历实现(Python)
前序遍历是二叉树遍历的一种方式,顺序为:根节点 -> 左子树 -> 右子树。以下是递归和迭代两种实现方法。
递归实现
递归方法简洁直观,适合理解前序遍历的逻辑。
python
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def preorder_traversal(root):
result = []
def traverse(node):
if not node:
return
result.append(node.val) # 访问根节点
traverse(node.left) # 遍历左子树
traverse(node.right) # 遍历右子树
traverse(root)
return result
迭代实现
迭代方法使用栈模拟递归调用,避免递归的深度限制。
python
def preorder_traversal_iterative(root):
if not root:
return []
stack, result = [root], []
while stack:
node = stack.pop()
result.append(node.val)
if node.right: # 右子节点先入栈(后处理)
stack.append(node.right)
if node.left: # 左子节点后入栈(先处理)
stack.append(node.left)
return result
使用示例
python
# 构建二叉树
# 1
# \
# 2
# /
# 3
root = TreeNode(1, None, TreeNode(2, TreeNode(3), None))
print("递归结果:", preorder_traversal(root)) # 输出: [1, 2, 3]
print("迭代结果:", preorder_traversal_iterative(root)) # 输出: [1, 2, 3]
中序遍历:
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
中序遍历实现方法
中序遍历是二叉树遍历的一种方式,顺序为:左子树、根节点、右子树。以下是Python实现方法:
递归实现
python
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def inorderTraversal(root):
res = []
def inorder(node):
if not node:
return
inorder(node.left)
res.append(node.val)
inorder(node.right)
inorder(root)
return res
迭代实现(使用栈)
python
def inorderTraversal(root):
res = []
stack = []
curr = root
while curr or stack:
while curr:
stack.append(curr)
curr = curr.left
curr = stack.pop()
res.append(curr.val)
curr = curr.right
return res
二叉树构造示例
python
# 构建示例二叉树
# 1
# \
# 2
# /
# 3
root = TreeNode(1)
root.right = TreeNode(2)
root.right.left = TreeNode(3)
print(inorderTraversal(root)) # 输出: [1, 3, 2]
后序遍历:
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点
后序遍历实现
后序遍历是二叉树遍历的一种方式,遍历顺序为左子树、右子树、根节点。以下是递归和非递归两种实现方法。
递归实现
递归方法是最直观的实现方式,直接按照左、右、根的顺序递归调用即可。
python
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def postorder_traversal(root):
result = []
def traverse(node):
if node is None:
return
traverse(node.left)
traverse(node.right)
result.append(node.val)
traverse(root)
return result
非递归实现
非递归方法使用栈来模拟递归过程,需要注意访问节点的顺序和标记已处理节点的状态。
python
def postorder_traversal_iterative(root):
if not root:
return []
stack = []
result = []
last_visited = None
node = root
while stack or node:
if node:
stack.append(node)
node = node.left
else:
peek_node = stack[-1]
if peek_node.right and last_visited != peek_node.right:
node = peek_node.right
else:
result.append(peek_node.val)
last_visited = stack.pop()
return result
示例用法
以下是如何使用上述代码遍历一个简单的二叉树。
python
# 构建二叉树
# 1
# / \
# 2 3
# / \
# 4 5
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
print("递归后序遍历:", postorder_traversal(root))
print("非递归后序遍历:", postorder_traversal_iterative(root))
输出结果:
递归后序遍历: [4, 5, 2, 3, 1]
非递归后序遍历: [4, 5, 2, 3, 1]
python 输出数组中最长递增子序列
最长递增子序列问题
最长递增子序列(Longest Increasing Subsequence, LIS)是一个经典的动态规划问题。以下是一个Python实现,能够找到并输出数组中最长递增子序列的长度和具体序列。
动态规划实现
动态规划方法的时间复杂度为O(n²),适用于中等规模输入。
python
def longest_increasing_subsequence(nums):
if not nums:
return 0, []
n = len(nums)
dp = [1] * n
prev = [-1] * n
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j] and dp[i] < dp[j] + 1:
dp[i] = dp[j] + 1
prev[i] = j
max_length = max(dp)
last_index = dp.index(max_length)
# 回溯构建最长子序列
lis = []
while last_index != -1:
lis.append(nums[last_index])
last_index = prev[last_index]
lis.reverse()
return max_length, lis
# 示例
nums = [10, 9, 2, 5, 3, 7, 101, 18]
length, sequence = longest_increasing_subsequence(nums)
print("Length of LIS:", length)
print("LIS sequence:", sequence)
更高效的二分查找实现
对于大规模数据,可以使用二分查找优化,时间复杂度降低到O(n log n)。
python
import bisect
def longest_increasing_subsequence_optimized(nums):
tails = []
prev_indices = [-1] * len(nums)
indices = []
for i, num in enumerate(nums):
idx = bisect.bisect_left(tails, num)
if idx == len(tails):
tails.append(num)
indices.append(i)
else:
tails[idx] = num
indices[idx] = i
if idx > 0:
prev_indices[i] = indices[idx - 1]
# 回溯重建序列
max_length = len(tails)
if max_length == 0:
return 0, []
lis = []
current = indices[-1]
while current != -1:
lis.append(nums[current])
current = prev_indices[current]
lis.reverse()
return max_length, lis
# 示例
nums = [10, 9, 2, 5, 3, 7, 101, 18]
length, sequence = longest_increasing_subsequence_optimized(nums)
print("Length of LIS:", length)
print("LIS sequence:", sequence)
代码说明
- 动态规划方法使用两个数组:
dp存储以每个元素结尾的LIS长度,prev记录前驱索引以便重建序列。 - 优化方法维护一个
tails数组,其中tails[i]表示长度为i+1的递增子序列的最小末尾元素。 - 两种方法都通过回溯前驱索引来重建实际的LIS序列。
复杂度对比
- 动态规划:O(n²)时间,O(n)空间
- 二分优化:O(n log n)时间,O(n)空间
对于大多数实际应用,二分查找优化版本是更好的选择,特别是当输入规模较大时。
python 反转单链表
单链表的实现
用一组地址任意的存储单元存放线性表中的数据元素。以元素(数据元素的映象) + 指针(指示后继元素存储位置) = 结点。
以"结点的序列"表示线性表,称作线性链表(单链表)。单链表是一种顺序存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
链表的结点结构:
┌──┬──┐
│data│next│
└──┴──┘
data域:存放结点值的数据域
next域:存放结点的直接后继的地址(位置)的指针域(链域)。
注意:①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
所谓的链表就好像火车车厢一样,从火车头开始,每一节车厢之后都连着后一节车厢。
反转单链表的方法
反转单链表是数据结构中的常见操作,可以通过迭代或递归的方式实现。以下是两种方法的详细说明和示例代码。
迭代法
迭代法通过遍历链表,逐个反转节点的指针方向。需要维护三个指针:prev、current 和 next_node。
python
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list(head):
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prev
步骤解析:
- 初始化
prev为None,current为链表头节点head。 - 遍历链表,保存
current的下一个节点到next_node。 - 反转
current的指针方向,使其指向prev。 - 更新
prev和current为下一个节点。 - 最终
prev成为新链表的头节点。
递归法
递归法通过递归调用反转子链表,再将当前节点连接到反转后的子链表末尾。
python
def reverse_list_recursive(head):
if not head or not head.next:
return head
new_head = reverse_list_recursive(head.next)
head.next.next = head
head.next = None
return new_head
步骤解析:
- 递归终止条件是当前节点为空或下一个节点为空。
- 递归调用反转
head.next的子链表,返回的新头节点为new_head。 - 将当前节点
head的下一个节点的指针指向head,完成局部反转。 - 将
head.next设置为None,避免链表成环。 - 最终返回
new_head作为反转后的链表头节点。
复杂度分析
- 时间复杂度:两种方法均为 O(n),需要遍历链表一次。
- 空间复杂度:迭代法为 O(1),递归法为 O(n)(递归调用栈空间)。
部分题目来源网络资源!