第8天 广度优先搜索 / 深度优先搜索
注意:DFS、BFS都可以用seen数组记录是否访问。其中图问题一般都要用seen数组,因为图有回路。而二叉树不一定用seen数组,因为树没有回路,不会重复访问陷入无限循环。
617.合并二叉树
1、BFS。不用额外空间,直接在其中一棵树上操作即可。出队时,判断两棵树的左儿子是否都有,只有root1有,只有root2有,都没有这四种情况,右儿子同理。都有就都入队。否则不用入队。
2、DFS。DFS版本,相较于DFS版本,仅做了一处修改,即把pop(0)改成了pop() #即pop(-1).
#BFS版本
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def mergeTrees(self, root1, root2):
"""
:type root1: TreeNode
:type root2: TreeNode
:rtype: TreeNode
"""
if not(root1 and root2):
if not root1:
return root2
else:
return root1
queue = []
queue.append([root1, root2])
root1.val = root1.val + root2.val
while queue:
i,j = queue.pop(0)
if i.left and j.left:
i.left.val = i.left.val + j.left.val
queue.append([i.left,j.left])
elif i.left:
i.left = i.left
elif j.left:
i.left = j.left
else:
i.left = None
if i.right and j.right:
i.right.val = i.right.val + j.right.val
queue.append([i.right,j.right])
elif i.right:
i.right = i.right
elif j.right:
i.right = j.right
else:
i.right = None
return root1
#DFS版本,相较于DFS版本,仅做了一处修改,即把pop(0)改成了pop() #即pop(-1).
#这样就把queue队列变成了stack栈,也就把BFS变成了DFS
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def mergeTrees(self, root1, root2):
"""
:type root1: TreeNode
:type root2: TreeNode
:rtype: TreeNode
"""
if not(root1 and root2):
if not root1:
return root2
else:
return root1
queue = []
queue.append([root1, root2])
root1.val = root1.val + root2.val
while queue:
i,j = queue.pop()
if i.left and j.left:
i.left.val = i.left.val + j.left.val
queue.append([i.left,j.left])
elif i.left:
i.left = i.left
elif j.left:
i.left = j.left
else:
i.left = None
if i.right and j.right:
i.right.val = i.right.val + j.right.val
queue.append([i.right,j.right])
elif i.right:
i.right = i.right
elif j.right:
i.right = j.right
else:
i.right = None
return root1
116.填充每个节点的下一个右侧节点指针
思路:
判断一个数是否为2的幂数。
//将2的幂写成二进制很容易看出,2的幂的二进制只有一个1,其余全是0,如下所示:
//000010000…00
//而将2的幂的二进制减1,其二进制变为:
//000001111…11
//所以判断一个数是不是2的幂的方法为使用按位与操作,如果结果为0,则是2的幂:
//n & (n-1)
//代码如下
//方法1
bool is_2power(int num)
{
return !(num & (num-1));//这里负数也会判断为非2的幂,负数最高位为1
}
//方法2
bool is_2power(int num)
{
if(num < 0) return false; //负数都不会是2的幂
while(num != 1){ //2的0次幂为1
if(num%2 != 0)
return false;
num /= 2;
}
return true;
}
1、BFS,判断一下当前队列的长度是否为2的幂数,如果是当前结点右儿子的next为None,否则为队头结点的左儿子节点。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return root
queue = []
queue.append(root)
while(queue):
tmp = queue.pop(0)
if tmp.left:
queue.append(tmp.left)
tmp.left.next = tmp.right
if tmp.right:
queue.append(tmp.right)
num = len(queue)
flag = (num & (num-1))
if not flag:
tmp.right.next = None
else:
tmp.right.next = queue[0].left
return root
2、层次遍历.
(1)不像BFS一样每次只pop队头,而是把这一层都pop出来。
#层次遍历,每次处理当前层的下一层
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return root
queue = []
queue.append(root)
while(queue):
size = len(queue)
for i in range(size):
tmp = queue.pop(0)
if tmp.left:
queue.append(tmp.left)
tmp.left.next = tmp.right
if tmp.right:
queue.append(tmp.right)
if i == size-1:
tmp.right.next = None
else:
tmp.right.next = queue[0].left
return root
(2)层次遍历,每次处理当前层。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return root
queue = []
queue.append(root)
while(queue):
size = len(queue)
for i in range(size):
tmp = queue.pop(0)
if i <size-1:
tmp.next = queue[0] #一层的直接用next指向队头
if tmp.left:
queue.append(tmp.left)
if tmp.right:
queue.append(tmp.right)
return root
3、递归
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return root
def dfs(Node):
if not (Node.left):
return
Node.left.next = Node.right
dfs(Node.left)
if Node.next: #如果Node有next结点
Node.right.next = Node.next.left #Node右儿子的next结点为Node的next结点的左儿子
dfs(Node.right)
dfs(root)
return root
4、迭代的O(1)空间解法:
#外循环:纵向遍历用ceng=ceng.left向下一层
#内循环:横向遍历用pre=pre.next向右一个
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return root
ceng = root #ceng指示纵向遍历到树的哪一层了
while ceng.left: #直到最后一层
pre = ceng #pre记录当前层,一直遍历到当前层的末尾
while pre:
pre.left.next = pre.right
if pre.next:
pre.right.next = pre.next.left
pre = pre.next
ceng = ceng.left
return root