热题系列章节7

发布于:2024-06-30 ⋅ 阅读:(10) ⋅ 点赞:(0)

剑指 Offer 04. 二维数组中的查找

题目描述:
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

示例:

现有矩阵 matrix 如下:
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。

限制:
0 <= n <= 1000
0 <= m <= 1000
由于存在矩阵每行和每列的数据都是递增的,所以我们可以从最小的元素所在的位置或是最大的元素所在的位置,即二维数组的左下角或是右上角开始查找。若当前位置的元素小于查找的数时,行数加1;否则列数加1。如下所示:

下三角寻找:

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if matrix is None or matrix == []: return False

        rows, cols = len(matrix), len(matrix[0])

        row, col = rows - 1, 0
        while row >= 0 and col <= cols - 1:
            if matrix[row][col] == target:
                return True
            elif matrix[row][col] > target:
                row -= 1
            else:
                col += 1
        
        return False

上三角寻找:


class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if matrix is None or matrix == []: return False

        rows, cols = len(matrix), len(matrix[0])

        row, col = 0, cols - 1
        while col >= 0 and row <= rows - 1:
            if matrix[row][col] == target:
                return True
            elif matrix[row][col] < target:
                row += 1
            else:
                col -= 1
        
        return False


440. 字典序的第K小数字

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。

示例 :
输入:
n: 13 k: 2

输出:
10

解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。

补充题2. 圆环回原点问题

91. 解码方法

一条包含字母 A-Z 的消息通过以下方式进行了编码:

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。

示例 1:
输入: “12”
输出: 2
解释: 它可以解码为 “AB”(1 2)或者 “L”(12)。

示例 2:
输入: “226”
输出: 3
解释: 它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。

dp[i]表示到第i-1位时解码的方法数
两种情况:
1.s[i-1]单独解码,方法数为dp[i-1]
2.s[i-2:i]拼接成双字符解码,若10<=s[i-2:i]<26,双字符合格,解码的方法数位dp[i-2],否则为0
综合两种情况,得到状态转移矩阵:
dp[i] = dp[i-1] + (dp[i-2] if 双字符合格 else 0)

为什么dp[i]表示的使i-1位?
例如 216,在判断第二位‘1’时,i-2<0了,状态转移矩阵不能用了,故在前加一位,即dp[0]为1

class Solution(object):
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        dp = [0]*(n+1)
        dp[0] = 1
        dp[1] = 1 if s[0]!='0' else 0
        for i in range(2,n+1):
            if s[i-1]!='0':
                dp[i] = dp[i-1]
             
            if 9< int(s[i-2:i])<27:
                dp[i] += dp[i-2]
            
        return dp[-1]

230. 二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

输入: root = [3,1,4,null,2], k = 1

   3
  / \
 1   4
  \
   2

输出: 1
示例 2:

输入: root = [5,3,6,2,4,null,null,1], k = 3

       5
      / \
     3   6
    / \
   2   4
  /
 1

输出: 3

代码

# 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 kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """
        inorder = list()
        self.inorderTra(root, inorder)
        print inorder
        
        return inorder[k-1]
    
    def inorderTra(self, node, path):
        if not node:
            return 
        self.inorderTra(node.left, path)
        path.append(node.val)
        self.inorderTra(node.right, path)

572. 另一个树的子树

给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

示例 1:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2

给定的树 t:

   4 
  / \
 1   2

返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。

示例 2:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2
    /
   0

给定的树 t:

   4
  / \
 1   2

返回 false。

思路:深度优先搜索

在这里,先分析题意:

一个二叉树若为另一个树的子树,则它含有与另外一个树的子树相同结构和节点值。
根据示例 2 可知,判断是否为子树,必须有完全相同结构和节点值。
以下 s、t 表示两个二叉树,题目要求判断 t 是否是 s 的子树
现在将题意转换为可实现代码书写的思路,判断两个树是否相等,那么下面的条件必须同时成立:

当前两个树根节点值相同;
s 的左子树与 t 的左子树相同;
s 的右子树与 t 的右子树相同。
根据上面的思路,本篇幅考虑使用深度优化搜索的方法,枚举 s 的每个节点,判断这个点的子树是否与 t 相等。使用深度优先搜索检查,从根出发,同步移动遍历两个树,判断相应的位置是否相等。

# 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 isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
        return self.dfs(s, t)
    
    def dfs(self, c, t):
        # c 子树为空时,返回 False
        if not c:
            return False
        return self.is_same(c, t) or self.dfs(c.left, t) or self.dfs(c.right, t)
    
    def is_same(self, c, t):
        # 两个树都为空时,也认为是相同
        if (not c) and (not t):
            return True
        # 当其中一个树为空,但另外一个树不为空时,此时则为不同
        if (not c and t) or (c and not t):
            return False
        # 两个树都不为空,若值不同,也为不同
        if (c.val != t.val):
            return False
        # 上面的情况都不符合时,继续向下检查
        return self.is_same(c.left, t.left) and self.is_same(c.right, t.right)
        

114. 二叉树展开为链表

在这里插入图片描述

# 递归
# 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 flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        def unflod(node):
            if not node:
                return None

            unflod(node.left)
            unflod(node.right)

            # 后序遍历
            if node.left:
                pre = node.left
                # 找到左子树的最右子节点,用以连接根的右子树
                while pre.right:
                    pre = pre.right
                # 当找到左子树的最右子节点,令其指向根的右子树
                pre.right = node.right
                # 然后令根的右子树指向根的左子树,令根的左子树为空
                node.right = node.left
                node.left = None
            # 循环
            node = node.right

        unflod(root)

# 非递归
# 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 flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        while root:
            if root.left:
                pre_node = root.left
                # 同样先找到左子树的最右节点
                while pre_node.right:
                    pre_node = pre_node.right
                # 最右节点指向根节点的右子树
                pre_node.right = root.right
                # 根的右子树指向根的左子树,同时置空左子树
                root.right = root.left
                root.left = None
            root = root.right



剑指 Offer 62. 圆圈中最后剩下的数字

445. 两数相加 II

在这里插入图片描述

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverse(self, head):   # 链表反转
        pre = head
        cur = head.next
        pre.next = None
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        l1 = self.reverse(l1)
        l2 = self.reverse(l2)

        h = ListNode((l1.val + l2.val) % 10)   # 额外记下头结点,方便后续反转链表
        flag = (l1.val + l2.val) // 10
        p = h
        l1 = l1.next
        l2 = l2.next
        while l1 or l2 or flag:
            if l1 and l2:
                node = ListNode((l1.val + l2.val + flag) % 10)
                flag = (l1.val + l2.val + flag) // 10
                l1 = l1.next
                l2 = l2.next
            elif l1:
                node = ListNode((l1.val + flag) % 10)
                flag = (l1.val + flag) // 10
                l1 = l1.next
            elif l2:
                node = ListNode((l2.val + flag) % 10)
                flag = (l2.val + flag) // 10
                l2 = l2.next
            elif flag:
                node = ListNode(flag)
                flag = 0
            p.next = node
            p = node
           
        return self.reverse(h)

295. 数据流的中位数

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

9. 回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是
输入:x = 121
输出:true

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数

def isPalindrome(x: int) -> bool:
    """不满足进阶要求"""
    if x < 0:
        return False
    if 0 <= x <= 9:
        return True
    if x % 10 == 0:
        return False
    rev_x = int(''.join(list(str(x))[::-1]))
    if rev_x == x:
        return True
    else:
        return False

384. 打乱数组

208. 实现 Trie (前缀树)

328. 奇偶链表