leetcode刷题-106~114/116~122/125/127/129~130

题目106题

从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:

     3
    / \
   9 20
      / \
     15  7

思路

与105题基本一致

实现

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

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        def build(in_left, in_right, po_left, po_right):
            if in_left > in_right:
                return None
            new_root = postorder[po_right]
            root = TreeNode(new_root)
            index = inorder.index(new_root)
            right_len = in_right - index
            root.left = build(in_left, index-1, po_left, po_right - right_len -1)
            root.right = build(index+1, in_right, po_right - right_len,po_right-1)
            return root
        n = len(inorder) - 1
        return build(0,n,0,n)

题目107题

二叉树的层次遍历 II

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

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

  3
     / \
    9 20
   / \
  15 7
返回其自底向上的层次遍历为:

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

思路

与102题完全一致,只是将层数颠倒

实现

# 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: TreeNode) -> List[List[int]]:
        def helper(node: TreeNode, result, lev):
            if node:
                if len(result) <= lev:
                    result.insert(0, [])
                size = len(result)
                result[size - lev -1].append(node.val)
                if node.left:
                    helper(node.left, result,lev+1)
                if node.right:
                    helper(node.right, result,lev+1)

        level = 0
        result = []
        helper(root, result, level)
        return result

题目108题

将有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

  0
   / \
  -3   9
 /   /
-10 5

思路

平衡二叉查找树:简称平衡二叉树。由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树,根据科学家的英文名也称为 AVL 树。它具有如下几个性质:

  1. 可以是空树。
  2. 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过 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 sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        def helper(left,right):
            if left > right:
                return None
            mid = (left + right + 1)//2
            root = TreeNode(nums[mid])
            root.left = helper(left, mid -1)
            root.right = helper(mid+1, right)
            return root
        
        return helper(0, len(nums)-1)

题目109

有序链表转换二叉搜索树

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

        0
       / \
    -3   9
    /    /
-10    5

思路

此题思路与108题完全一致,但是由于这是单项链表,因此需要使用快慢指针法找到中间点

实现

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sortedListToBST(self, head: ListNode) -> TreeNode:
        def midnode(left,right):
            fast = slow = left
            while fast != right and fast.next != right:
                fast = fast.next.next
                slow = slow.next
            return slow

        def helper(left,right):
            if left == right:
                return None
            mid = midnode(left, right)
            root = TreeNode(mid.val)
            root.left = helper(left, mid)
            root.right = helper(mid.next, right)
            return root
        return helper(head, None)

题目110 

平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

思路

1.自顶向下:

计算节点高度的函数,即可判断二叉树是否平衡。计算当前节点高度是否满足平衡二叉树,若满足,则判定节点的子节点。

2.自底向上:

在方法一中,计算节点的高度是消耗时间资源的,因此可以采用自底向上的方法。

对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。

实现

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
1.
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def level(node: TreeNode):
            if not node:
                return 0
            else:
                return max(level(node.left), level(node.right)) + 1
            
        if not root:
            return True
        return abs(level(root.left) - level(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)

2.
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def height(root: TreeNode) -> int:
            if not root:
                return 0
            leftHeight = height(root.left)
            rightHeight = height(root.right)
            if leftHeight == -1 or rightHeight == -1 or abs(leftHeight - rightHeight) > 1:
                return -1
            else:
                return max(leftHeight, rightHeight) + 1

        return height(root) >= 0

题目111

二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

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

     3
    / \
  9   20
      /   \
    15     7
返回它的最小深度  2.

思路

当左孩子和右孩子都为空的情况,说明到达了叶子节点,直接返回1即可

当左孩子和由孩子其中一个为空,那么需要返回比较大的那个孩子的深度

当左右孩子都不为空,返回最小深度+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 minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        l = self.minDepth(root.left)
        r = self.minDepth(root.right)
        if not root.left or not root.right:
            return l + r + 1
        return min(l,r)+1

题目112

路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 
给定如下二叉树,以及目标和 sum = 22,

        5
       / \
     4    8
    /     / \
  11     13  4
/   \          \
7    2           1

思路

递归:若当前节点就是叶子节点,那么我们直接判断 sum 是否等于 val,若不是叶子节点则继续

实现

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

class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        if not root.left and not root.right:
            return sum == root.val
        sum -= root.val
        return self.hasPathSum(root.left, sum) or self.hasPathSum(root.right, sum)

题目113

路径总和II

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

         5
       / \
     4    8
    /     / \
  11     13  4
/   \          \
7    2           1

返回:

[ [5,4,11,2], [5,8,4,5] ]

思路

与上一题完全一致

实现

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

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        result = []
        def hasPathSum(root: TreeNode, sum: int, res):
            if not root:
                return
            if not root.left and not root.right:
                if sum == root.val:
                    result.append(res+[root.val])
            sum -= root.val
            hasPathSum(root.left, sum, res+[root.val])
            hasPathSum(root.right, sum, res+[root.val])
        hasPathSum(root,sum,[])
        return result

题目114

给定一个二叉树,原地将它展开为一个单链表。

 

例如,给定二叉树

    1
   / \
  2   5
 / \    \
3   4    6  
将其展开为:

1
 \
  2
    \
     3
      \
       4
         \
          5
           \
            6

思路

1.前序遍历:前序遍历后放入数组中,再重新组合

2.寻找前驱节点:

实现

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
1.
class Solution:
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        def preorder(node,lis):
            if not node:
                return
            lis.append(node)
            preorder(node.left,lis)
            preorder(node.right,lis)
        res = []
        preorder(root, res)
        size = len(res)
        for i in range(1, size):
            prev, curr = res[i - 1], res[i]
            prev.left = None
            prev.right = curr
2.
class Solution:
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """

        curr = root
        while curr:
            if curr.left:
                pre = next = curr.left
                while pre.right:
                    pre = pre.right
                pre.right = curr.right
                curr.left = None
                curr.right = next
            curr = curr.right


题目116

填充每个节点的下一个右侧节点指针

给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

思路

广度优先遍历:利用广度优先遍历,将每一层的节点都放入队列中,对同一层的元素来进行连接

实现

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""
from collections import deque

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return None
        queue = deque([root])
        while queue:
            size = len(queue)
            for i in range(size):
                node = queue.popleft()
                if i < size -1:
                    node.next = queue[0]
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return root

 

题目116 

填充每个节点的下一个右侧节点指针II

给定一个二叉树。

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

思路

 与上题思路完全一致

实现

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""
from collections import deque
class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return None
        queue = deque([root])
        while queue:
            size = len(queue)
            for i in range(size):
                node = queue.popleft()
                if i < size -1:
                    node.next = queue[0]
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return root

题目118

杨辉三角

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

思路

递归法

实现

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = []
        def ge(numRows):
            if numRows == 1:
                res.append([1])
                return [1]
            else:
                up = [0]+ ge(numRows-1) + [0]
                tmp = []
                for i in range(len(up)-1):
                    val = up[i] + up[i+1]
                    tmp.append(val)
                res.append(tmp)
                return tmp
        if numRows == 0:
            return []
        ge(numRows)
        return res

题目119

杨辉三角II

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 行。

思路

递归法

实现

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        def ge(numRows):
            if numRows == 0:
                return [1]
            else:
                up = [0]+ ge(numRows-1) + [0]
                tmp = []
                for i in range(len(up)-1):
                    val = up[i] + up[i+1]
                    tmp.append(val)
                return tmp
        return ge(rowIndex)

题目120

三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

 

例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

思路

1.递归:遍历所有点,但效率太低

2.动态规划

实现

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        triangle_len = len(triangle)
        result = [0 for i in range(triangle_len)]
        for i in range(0, triangle_len):
            before = result[:]          
            for j in range(1, i):
                temp = before[j-1:j+1]
                result[j] = min(temp) + triangle[i][j]
            if i != 0:
                result[i] = triangle[i][i] + before[i-1]
            result[0] += triangle[i][0]
        return min(result)

题目121

买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。 

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

思路

对于当前天数,最大利润为当天的价格减去之前的最低价格

实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        days = len(prices)
        minprice = int(1e9)
        max_profit = 0
        for day in range(days):
            if prices[day] < minprice:
                minprice = prices[day]
            cur_profit = prices[day] - minprice
            if cur_profit > max_profit:
                max_profit = cur_profit
        return max_profit

题目122

买卖股票的最佳时机2

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

思路

遍历一次数组,当当前元素小于后一个元素时,则可以获得利润差

实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        days = len(prices)
        profit = 0
        for day in range(days-1):
            if prices[day] < prices[day + 1]:
                profit += (prices[day + 1] - prices[day])
        return profit

题目125

验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:

输入: "A man, a plan, a canal: Panama"
输出: true

思路

实现

class Solution:
    def isPalindrome(self, s: str) -> bool:
        strlen = len(s)
        s = s.upper()
        left = 0
        right = strlen -1
        while left < right:
            print(s[left],"+",s[right])
            if not s[left].isalnum():
                left += 1
                continue
            elif not s[right].isalnum():
                right -= 1
                continue
            elif s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True
            

题目127

单词接龙

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

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

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

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

输出: 5

思路

广度优先算法

实现

class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        wordList=set(wordList)
        q=[(beginWord,1)]
        if endWord not in wordList:
            return 0
        while q:
            node,level=q.pop(0)
            if node == endWord:
                return level
            for i in range(len(node)):
                for j in "abcdefghijklmnopqrstuvwxyz":
                    new=node[:i]+j+node[i+1:]
                    if new in wordList:
                        q.append((new,level+1))
                        wordList.remove(new)
        return 0

题目129

求根到叶子节点数字之和

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。

例如,从根到叶子节点路径 1->2->3 代表数字 123。

计算从根到叶子节点生成的所有数字之和。

说明: 叶子节点是指没有子节点的节点。

示例 1:

输入: [1,2,3]
  1
 / \
2  3 
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.

思路

深度优先遍历

实现

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

class Solution:
    def sumNumbers(self, root: TreeNode) -> int:

        def dfs(node,cur_sum):
            if not node:
                return 0
            temp = cur_sum*10 + node.val
            if not node.left and not node.right:
                return temp
            else:
                return dfs(node.left, temp) + dfs(node.right,temp)
        return dfs(root,0)
            

题目130

被围绕的区域

给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。

找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例:

X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:

X X X X
X X X X
X X X X
X O X X

思路

首先对元素进行分类:1.X 2.被包围的O 3.没有被包围的O

此题可以发现在四周边上的O都是不被包围的,因此可以对这些边上的O做深度优先遍历获取所有与其连接的O

实现

class Solution:
    def solve(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        if not board:
            return
        row = len(board)
        col = len(board[0])
        visited = [[False for _ in range(row)] for _ in range(col)]
        def dfs(i,j):
            if 0 <= i < row and 0 <= j < col:
                if board[i][j] != 'O':
                    return
                else:
                    board[i][j] = 'A'
                    dfs(i+1,j)
                    dfs(i-1,j)
                    dfs(i,j+1)
                    dfs(i,j-1)
        for i in range(row):
            dfs(i,0)
            dfs(i,col-1)
        for j in range(col):
            dfs(0,j)
            dfs(row-1, j)

        for i in range(row):
            for j in range(col):
                if board[i][j] == "A":
                    board[i][j] = "O"
                elif board[i][j] == "O":
                    board[i][j] = "X"
posted @ 2020-09-14 17:28  maoguai  阅读(223)  评论(0编辑  收藏  举报