二叉树基础:
- 树的定义:树(英语:Tree)是一种无向图(undirected graph),其中任意两个顶点间存在唯一一条路径。或者说,只要没有回路的连通图就是树。
- 二叉树(英语:Binary tree)是每个节点最多只有两个分支(不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能颠倒。
- 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
- 平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
- 树的应用:
快速数据检索:①STL的红黑树;②数据库的B+树;
文档结构组织:DOM
人工智能:决策树
游戏:通过构造空间树实现快速碰撞检测(https://www.zhihu.com/question/25111128)
区块链的默克尔树
常用算法:
- 递归:树的深度优先遍历(以前序遍历为例) 模拟遍历如下二叉树:
- 队列:树的广度优先遍历(分层遍历):
leetcode例题:
94.题目:给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
解法:
一、递归法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.ret=[]
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if root is not None:
self.inorderTraversal(root.left)
self.ret.append(root.val)
self.inorderTraversal(root.right)
return self.ret
二、非递归:
def loopVersion(self, root): # 非递归版本
ret, stack = [], []
#如果root不为空或者堆栈有元素:
while root or stack:
#1.root不为空,root压入堆栈
while root:
stack.append(root)
#2.root=root.left
root = root.left
#3.回到1
#4.如果堆栈有元素
if stack:
#5.弹出元素,加入返回队列
root = stack.pop()
ret.append(root.val)
#6.root=root.left继续while循环
root = root.right
return ret
106.题目:根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
解法:
class Solution:
"""
@param inorder : A list of integers that inorder traversal of a tree
@param postorder : A list of integers that postorder traversal of a tree
@return : Root of a tree
"""
def buildTree(self, inorder, postorder):
# write your code here
return self._buildTree(inorder, 0, len(inorder), postorder, 0, len(postorder))
def _buildTree(self, inorder, in_start, in_end, postorder, post_start, post_end):
if in_start >= in_end:
return None
i = in_start
while i < in_end:
if inorder[i] == postorder[post_end -1]: # 找到根节点
break
i += 1
root = TreeNode(inorder[i])
left_len = i - in_start # 左子树元素数量
root.left = self._buildTree(inorder, in_start, i, postorder, post_start, post_start + left_len)
root.right = self._buildTree(inorder, i + 1, in_end, postorder, post_start + left_len, post_end - 1)
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
解法:递归法与中序遍历相似
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if root is not None:
root.left,root.right = root.right,root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
堆的基础知识:
- 堆的定义(from Wiki):堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质:
①任意节点小于(或大于)它的所有后裔,最小元或最大元)在堆的根上(堆序性)。
②堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。 - 建堆的过程:
- 建堆的复杂度分析:
①N个节点的堆高度最大为h=logN,最下面一层非叶子节点最多调整1次,倒数第2层最多2次,…依此类推,根节点最多需要h次。
②最下面一层子节点共有2^(h-1)个,倒数第2层有2^(h-2)个,…依此类推,根节点有2^(h-h)个1个。
③所以总的时间复杂度为1^(h-1) + 2*2^(h-2) + (h-1)*2 + h,得到结果为N*2 –2 –log(N),所以时间复杂度O(n)。 - 堆的应用:
leetcode例题:
题目:堆化
给出一个整数数组,堆化操作就是把它变成一个最小堆数组。
对于堆数组A,A[0]是堆的根,并对于每个A[i],A [i * 2 + 1]是A[i]的左儿子并且A[i * 2 + 2]是A[i]的右儿子。
您在真实的面试中是否遇到过这个题? 是
题目纠错
说明
什么是堆?
- 堆是一种数据结构,它通常有三种方法:push, pop 和 top。其中,“push”添加新的元素进入堆,“pop”删除堆中最小/最大元素,“top”返回堆中最小/最大元素。
什么是堆化?
- 把一个无序整数数组变成一个堆数组。如果是最小堆,每个元素A[i],我们将得到A[i * 2 + 1] >= A[i]和A[i * 2 + 2] >= A[i]
如果有很多种堆化的结果?
- 返回其中任何一个。
样例
给出 [3,2,1,4,5]
,返回[1,2,3,4,5]
或者任何一个合法的堆数组
挑战
O(n)的时间复杂度完成堆化
解法:
class Solution:
"""
@param: A: Given an integer array
@return: nothing
"""
def heapify(self, A):
# write your code here
for i in range(int((len(A)-1)/2),-1,-1):
while i < len(A):
left,right = i*2+1,i*2+2
min_pos = i
if (left<len(A)) and (A[left]<A[min_pos]):
min_pos=left
if (right<len(A)) and (A[right]<A[min_pos]):
min_pos=right
if min_pos!=i:
A[i],A[min_pos]=A[min_pos],A[i]
i = min_pos
else:
break
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
解法:这是别人写的一个解法,我自己没做出来
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
k=len(lists)
if k==0:
return []
if k==1:
return lists[0]
combine_list=lists[0]
aim_list=ListNode(0)
for i in range(1,k):
pointer_aim_list=aim_list
list_1=combine_list
#list_2=lists[i]
pointer_list_2=lists[i]
pointer_list_1=list_1
while pointer_list_1!=None or pointer_list_2!=None:
if pointer_list_1==None:
pointer_aim_list.next=pointer_list_2
break
if pointer_list_2==None:
pointer_aim_list.next=pointer_list_1
break
if pointer_list_1.val<=pointer_list_2.val:
pointer_aim_list.next=pointer_list_1
pointer_list_1=pointer_list_1.next
pointer_aim_list=pointer_aim_list.next
else:
pointer_aim_list.next=pointer_list_2
pointer_list_2=pointer_list_2.next
pointer_aim_list=pointer_aim_list.next
combine_list=aim_list.next
#aim_list=aim_list.next
return aim_list.next
这是另一种,速度更快
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def less(self, a, b):
if a.val < b.val:
return a
else:
return b
def mergeTwoLists(self, l1, l2):
l3 = ListNode(0)
rl3 = l3
while l1 or l2:
if not l1 or not l2:
l3.next = l1 if l1 else l2
break
l3.next = self.less(l1, l2)
if l3.next == l1:
l1 = l1.next
else:
l2 = l2.next
l3 = l3.next
return rl3.next
def mergeKLists(self, lists):
half = int(len(lists)/2)
left = lists[0:half]
right = lists[half:]
if 0 <= len(left) <= 1 and 0 <= len(right) <= 1:
return self.mergeTwoLists(left[0] if left else [], right[0] if right else [])
return self.mergeTwoLists(self.mergeKLists(left), self.mergeKLists(right))
To be continue......