玩转算法面试LeetCode算法练习——队列(二叉树层序遍历+BFS和图最短路径)

目录

树:层序遍历

102. 二叉树的层次遍历

107. 二叉树的层次遍历 II

103. 二叉树的锯齿形层次遍历

 199. 二叉树的右视图

图:无权图的最短路径

279. 完全平方数 

127. 单词接龙

2.队列

         队列与栈类似,差别仅在于向队列里添加元素时,元素被加到尾部(入队),而提取元素时则从队列头部开始(出队)。这种机制称作FIFO(first in, first out,先进先出);而栈则被称作LIFO(last in, first out,后进先出)。

         在 Python 的标准库中,有两个类实现了队列。第一是 Queue 类,这是一个同步实现,意味着多个进程可以同时访问同一个对象。它涉及并发机制,因为它在执行同步的时候使用的信号机制会拖慢执行速度。第二是 Deque 类(Double EndedQueue,即双向队列),除了提供标准方法,即在尾部使用append(element) 添加元素和在头部使用 popleft() 提取元素之外,它还提供了额外方法,用于在队列头部使用 appendleft(element) 添加元素和在尾部使用 pop() 提取元素。我们把这种队列称作双向队列。

基本应用-广度优先遍历

-树:层序遍历

-图:无权图的最短路径

树:层序遍历

102. 二叉树的层次遍历

给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def _levelOrder(self, level, result, node):
        if node:
            if level == len(result): #说明当前level层还没有遍历
                result.append([])
                
            result[level].append(node.val)
            self._levelOrder(level+1, result, node.left)
            self._levelOrder(level+1, result, node.right)

    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        level, result = 0, list()
        self._levelOrder(level, result, root)
        return result 

法二:

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

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        q, result = [root], []
        while any(q):
            tmp = list()
            for _ in range(len(q)):
                node = q.pop(0)
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)

            result.append(tmp)
        return result

 

107. 二叉树的层次遍历 II

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其自底向上的层次遍历为:

[
  [15,7],
  [9,20],
  [3]
]

 法一:

改下102二叉树层次遍历 的返回值

return result[::-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 levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        q, result = [root], []
        while any(q):
            tmp = list()
            for _ in range(len(q)):
                node = q.pop(0)
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)

            result.insert(0, tmp)#指定位置插入
        return result

103. 二叉树的锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回锯齿形层次遍历如下:

[
  [3],
  [20,9],
  [15,7]
]
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def zigzagLevelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        q , result = [root] , []
        i = 1
        #any(x)判断x对象是否为空对象,如果都为空、0、false,则返回false,如果不都为空、0、false,则返回true
        #all(x)如果all(x)参数x对象的所有元素不为0、''、False或者x为空对象,则返回True,否则返回False
        while any(q):
            tmp = list()
            for _ in range(len(q)):
                node = q.pop(0)
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            #上面这部分是不变的
            if i%2 == 0:
                tmp.reverse()
            i+=1
            result.append(tmp)
        return result

 199. 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        q, tmp_res = [root] ,[]
        
        while any(q):
            tmp = list()
            #遍历当前层并将值存储在tmp列表,同时将下一层添加到q中
            for _ in range(len(q)):
                node = q.pop(0)
                tmp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            tmp_res.append(tmp)
        
        res = [i[-1] for i in tmp_res]
        return res

图:无权图的最短路径

279. 完全平方数 

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.

示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.
class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
 #思路1:状态转移:dp[n] = min(dp[n-i^2]) + 1,if n不是完全平方数,如果是完全平方数返回1,O(n * sqrt n),在测试用例间保留DP中间结果(通过类属性),
    #思路2:四平方和定理:任何自然数都可以用最多四个平方和数之和表示,三平方和定理:只有当4^a*(8b+7)才需要用四个平方和树之和表示
        """
        # sol 2:
        # BFS广度优先搜索
        # runtime: 230ms
        if n < 2: return n
        
        # store squared nums <= n
        squares = []
        i = 1
        while i*i <= n:
            squares.append(i*i)
            i += 1
        # 
        res, lst = 0, {n}
        while lst:
            res += 1
            tem = set()
            for i in lst:
                for j in squares:
                    if i==j: return res
                    elif i < j: break
                    tem.add(i-j)
            lst = tem
        return res

        dp = [0]
        while len(dp) <= n:
            dp += min(dp[-i*i] for i in range(1, int(len(dp)**0.5+1))) + 1,
        return dp[-1]

127. 单词接龙

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。

示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。
class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordList = set(wordList)
        queue = collections.deque([[beginWord, 1]])
        dic = set(string.ascii_lowercase)
        while queue:
            word, length = queue.popleft()
            if word == endWord:
                return length
            for i in range(len(word)):
                for c in dic:
                    next_word = word[:i] + c + word[i+1:]
                    if next_word in wordList:
                        wordList.remove(next_word)
                        queue.append([next_word, length + 1])
        return 0

 

    原文作者:张文彬彬
    原文地址: https://blog.csdn.net/u012084802/article/details/81082798
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞