我是靠谱客的博主 怡然鸭子,最近开发中收集的这篇文章主要介绍剑指offer刷题记录 python3 Java剑指 Offer 09. 用两个栈实现队列剑指 Offer 10- I. 斐波那契数列剑指 Offer 03. 数组中重复的数字【★】剑指 Offer 04. 二维数组中的查找剑指 Offer 10- II. 青蛙跳台阶问题剑指 Offer 11. 旋转数组的最小数字剑指 Offer 12. 矩阵中的路径剑指 Offer 05. 替换空格剑指 Offer 13. 机器人的运动范围剑指 Offer 06. 从尾到头打印链表剑指 Offer 07. 重,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

剑指offer刷题记录 python3 Java

  • 剑指 Offer 09. 用两个栈实现队列
  • 剑指 Offer 10- I. 斐波那契数列
  • 剑指 Offer 03. 数组中重复的数字
  • 【★】剑指 Offer 04. 二维数组中的查找
  • 剑指 Offer 10- II. 青蛙跳台阶问题
  • 剑指 Offer 11. 旋转数组的最小数字
  • 剑指 Offer 12. 矩阵中的路径
  • 剑指 Offer 05. 替换空格
  • 剑指 Offer 13. 机器人的运动范围
  • 剑指 Offer 06. 从尾到头打印链表
  • 剑指 Offer 07. 重建二叉树
  • 【★】剑指 Offer 14- I. 剪绳子
  • 剑指 Offer 14- II. 剪绳子 II
  • 剑指 Offer 25. 合并两个排序的链表
  • 剑指 Offer 26. 树的子结构
  • 剑指 Offer 27. 二叉树的镜像
  • 剑指 Offer 28. 对称的二叉树
  • 【★】剑指 Offer 20. 表示数值的字符串
  • 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
  • 【★】剑指 Offer 15. 二进制中1的个数
  • 【★】剑指 Offer 29. 顺时针打印矩阵
  • 剑指 Offer 22. 链表中倒数第k个节点
  • 【★】剑指 Offer 16. 数值的整数次方
  • 【★】剑指 Offer 17. 打印从1到最大的n位数
  • 【★】剑指 Offer 19. 正则表达式匹配
  • 剑指 Offer 24. 反转链表
  • 剑指 Offer 18. 删除链表的节点
  • 剑指 Offer 35. 复杂链表的复制
  • 剑指 Offer 40. 最小的k个数

剑指 Offer 09. 用两个栈实现队列

【题目】剑指 Offer 09. 用两个栈实现队列

【思路】

使用两个栈q1、q2:

  • q1用作存储,对于所有的appendTail操作增加的元素都放到q1.append()。
  • q2用作弹出,对于多有的deleteHead操作删除的元素都是q2的pop操作,若q2为空,则将q1的所有元素pop再q2.append(),实现顺序反转,此时q2头部为最先进入的元素。

【代码】

class CQueue:

    def __init__(self):
        self.q1, self.q2 = [], []

    def appendTail(self, value: int) -> None:
        self.q1.append(value)

    def deleteHead(self) -> int:
        if not self.q2:
            while self.q1:
                self.q2.append(self.q1.pop())
        return self.q2.pop() if self.q2 else -1

# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()

剑指 Offer 10- I. 斐波那契数列

【题目】剑指 Offer 10- I. 斐波那契数列

【思路】

  • 使用“递归法”会产生大量重复计算,本题使用“动态规划”。
  • 对于取模操作,在加法过程中取模,而不是在结果返回前取模,防止数据越界。

【代码】

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:
            return 0
        m = int(1e9+7)
        a, b = 0, 1
        for _ in range(n - 1):
            c = b
            b = (a + b) % m
            a = c
        return b

剑指 Offer 03. 数组中重复的数字

【题目】剑指 Offer 03. 数组中重复的数字

【思路】

采用交换的思想,对于nums = [2, 3, 1, 0, 2, 5, 3],第一次操作转换为nums = [1, 3, 2, 0, 2, 5, 3],即把nums[0] = 2放到对应位置nums[2]上(交换nums[0]和nums[2]),然后第二次操作再把nums[0] = 1放到对应位置nums[1]上,转换为nums = [3, 1, 2, 0, 2, 5, 3] … dots 重复操作,知道找到第一个nums[nums[i]] == nums[i]的数。

【代码】

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        for i in range(len(nums)):
            t = i
            while t != nums[t]:
                if nums[t] == nums[nums[t]]:
                    return nums[t]
                nums[nums[t]], nums[t] = nums[t], nums[nums[t]] # python交换赋值为左优先,即先对nums[nums[t]]赋值。nums[nums[t]]和nums[t]位置互换会出错。参考https://stackoverflow.com/questions/21047524/how-does-swapping-of-members-in-tuples-a-b-b-a-work-internally

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

【题目】剑指 Offer 04. 二维数组中的查找

【思路】

  • 矩阵元素排列是有规律的(左至右、上至下为递增),那么共有下列4种搜索方式:
    • 左上角开始,往右递增,往下递增。
    • 右下角开始,往左递减,往上递减。
    • 左下角开始,往右递增,往上递减。
    • 右上角开始,往左递减,往下递增。
  • 只能选取左下角开始右上角开始两种思路。

【代码】

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return False
        
        rows, cols = len(matrix), len(matrix[0])
        row, col = 0, cols - 1

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

剑指 Offer 10- II. 青蛙跳台阶问题

【题目】剑指 Offer 10- II. 青蛙跳台阶问题

【思路】同【剑指 Offer 10- I. 斐波那契数列】

【代码】略

剑指 Offer 11. 旋转数组的最小数字

【题目】剑指 Offer 11. 旋转数组的最小数字

【思路】

  • 这是一个递增数组的旋转,则有两种情况:
    • 某两个相邻元素为递减(旋转长度 > 0),找到这个递减位置的元素即可;
    • 整个数组为递增(旋转长度 = 0),返回第一个元素。

【代码】

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        n = len(numbers)
        if n < 2:
            return numbers[0]
        for i in range(1, len(numbers)):
            if numbers[i - 1] > numbers[i]:
                return numbers[i]
        return numbers[0] # 执行完for循环,但是没有return,说明这是一个递增数组,第一个为最小

剑指 Offer 12. 矩阵中的路径

【题目】剑指 Offer 12. 矩阵中的路径

【思路】

  • 判断是否存在的问题,利用DFS(全部解利用BFS)。
  • 当遍历长度等于str长度时,返回True。
  • 对所有位置遍历一次,防止漏掉正确答案。
  • 当前层遍历完,需要记录遍历过当前位置,这里采用改变内容的方案(也可以使用dp数组)。

【代码】

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m, n, s = len(board), len(board[0]), len(word)
        def dfs(i, j, k):
            if not 0 <= i < m or not 0 <= j < n or board[i][j] != word[k]:
                return False
            if k == s - 1:
                return True
            board[i][j] = ''
            res = dfs(i - 1, j, k + 1) or dfs(i + 1, j, k + 1) or dfs(i, j - 1, k + 1) or dfs(i, j + 1, k + 1)
            board[i][j] = word[k]
            return res
        for i in range(m):
            for j in range(n):
                if dfs(i, j, 0):
                    return True
        return False

剑指 Offer 05. 替换空格

【题目】剑指 Offer 05. 替换空格

【思路】无

【代码】

class Solution:
    def replaceSpace(self, s: str) -> str:
        return s.replace(' ', '%20')

剑指 Offer 13. 机器人的运动范围

【题目】剑指 Offer 13. 机器人的运动范围

【思路】

  • 首先有个函数能够实现根据坐标计算和的功能。
  • 利用dfs进行所有位置的遍历,然后利用dp数组保存遍历过的位置。

【代码】

# 求解
def digitsum(n):
    ans = 0
    while n:
        ans += n % 10
        n //= 10
    return ans

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        ans = 0
        dp = [[False] * n for _ in range(m)]
        def dfs(i, j):
            if i < m and j < n and not dp[i][j]:
                nonlocal ans
                tmp = digitsum(i) + digitsum(j)
                if tmp <= k:
                    dp[i][j] = True
                    ans += 1
                    dfs(i + 1, j)
                    dfs(i, j + 1)
        dfs(0, 0)
        return ans

剑指 Offer 06. 从尾到头打印链表

【题目】剑指 Offer 06. 从尾到头打印链表

【思路】

  • 思路1:遍历一次,放到数组中,然后reverse再return。
  • 思路2:利用递归,到达最末层就向前递归,同时输出当前层的值。

【代码】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        ans = []
        def backtrack(node):
            if not node:
                return 
            backtrack(node.next)
            ans.append(node.val)
        backtrack(head)
        return ans

剑指 Offer 07. 重建二叉树

【题目】剑指 Offer 07. 重建二叉树

【思路】

  1. preorder中第一个元素就是root。
  2. 再inorder中找到root对应的位置loc,这个位置左边就是左子树,右边就是右子树。
  3. 递归建树。
  4. 优化:可以利用索引坐标进行建树,这样的话减少了新建list的时间和内存。

【代码】

# 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, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return 
        root = TreeNode(preorder[0])
        loc = inorder.index(preorder[0])
        root.left = self.buildTree(preorder[1: loc + 1], inorder[: loc])
        root.right = self.buildTree(preorder[loc + 1: ], inorder[loc + 1: ])
        return root

【★】剑指 Offer 14- I. 剪绳子

【题目】剑指 Offer 14- I. 剪绳子

【思路】

  • n ≤ 3 n leq 3 n3时,按照规则应不切分,但由于题目要求必须剪成m>1段,因此必须剪出一段长度为1的绳子,即返回 n − 1 n - 1 n1
  • n > 3 n > 3 n>3时,求 n 除以 3 的 整数部分 a 和 余数部分 b(即 n = 3 a + b n = 3a + b n=3a+b),并分为以下三种情况:
    • b = 0 b = 0 b=0时,直接返回 3 a 3^a 3a
    • b = 1 b = 1 b=1时,要将一个 1 + 3 1 + 3 1+3转换为 2 + 2 2 + 2 2+2,因此返回 3 a − 1 × 4 3^{a-1} times 4 3a1×4
    • b = 2 b = 2 b=2时,返回 3 a × 2 3^a times 2 3a×2

【代码】

class Solution:
    def cuttingRope(self, n: int) -> int:
        if n <= 3: return n - 1
        a, b = n // 3, n % 3
        if b == 0: return int(pow(3, a))
        if b == 1: return int(pow(3, a - 1) * 4)
        return int(pow(3, a) * 2)

剑指 Offer 14- II. 剪绳子 II

【题目】剑指 Offer 14- II. 剪绳子 II

【思路】

同上。

  • 优化的点:
    • 可以用“快速幂”代替pow()
# 求 (x^a) % p —— 快速幂求余
def remainder(x, a, p):
    rem = 1
    while a > 0:
        if a % 2: rem = (rem * x) % p
        x = x ** 2 % p
        a //= 2
    return rem

【代码】

class Solution:
    def cuttingRope(self, n: int) -> int:
        if n <= 3: return n - 1
        a, b, m = n // 3, n % 3, int(1e9+7)
        if b == 0: return int(pow(3, a, m))
        if b == 1: return int(pow(3, a - 1, m) * 4 % m)
        return int(pow(3, a, m) * 2 % m)

剑指 Offer 25. 合并两个排序的链表

【题目】剑指 Offer 25. 合并两个排序的链表

【思路】略。

【代码】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = ListNode(0)
        p = dummy
        while l1 and l2:
            if l1.val < l2.val:
                p.next = l1
                l1 = l1.next
            else:
                p.next = l2
                l2 = l2.next
            p = p.next
        if l1:
            p.next = l1
        if l2:
            p.next = l2
        return dummy.next

剑指 Offer 26. 树的子结构

【题目】剑指 Offer 26. 树的子结构

【思路】

  1. (先序)遍历A,找到与B的根相同的节点,若没找到返回False。
  2. 从相同节点开始dfs(),递归地判断是否为同结构。

【代码】

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

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        def dfs(n, m):
            if not m:
                return True
            if not n or n.val != m.val:
                return False
            return dfs(n.left, m.left) and dfs(n.right, m.right)
        return bool(A and B) and (dfs(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B))

剑指 Offer 27. 二叉树的镜像

【题目】剑指 Offer 27. 二叉树的镜像

【思路】交换左右子树,递归同样操作用在左子树和右子树,直到叶子节点。

【代码】

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

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if root:
            root.left, root.right = root.right, root.left
            self.mirrorTree(root.right)
            self.mirrorTree(root.left)
        return root

剑指 Offer 28. 对称的二叉树

【题目】剑指 Offer 28. 对称的二叉树

【思路】

利用递归,判断左(右)孩子和对应节点的右(左)孩子是否相等,不相等直接返回,不再递归。

【代码】

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

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def dfs(l: TreeNode, r: TreeNode):
            if not l or not r:
                if not l and not r:
                    return True
                return False
            return (l.val == r.val) and dfs(l.left, r.right) and dfs(l.right, r.left)
        return dfs(root.left, root.right) if root else True

【★】剑指 Offer 20. 表示数值的字符串

【题目】剑指 Offer 20. 表示数值的字符串

【思路】

利用有限状态机解决这个问题,如图。

有限状态机转移图

算法流程:

  1. 初始化:
    1. 状态转移表 s t a t e s states states:设 s t a t e s [ i ] states[i] states[i],其中 i i i为所处状态, s t a t e s [ i ] states[i] states[i]使用哈希表存储可转移至的状态。键值对 ( k e y , v a l u e ) (key, value) (key,value)含义:若输入 k e y key key,则可从状态 i i i转移至状态 v a l u e value value
    2. 当前状态 p p p:起始状态初始化为 p = 0 p = 0 p=0
  2. 状态转移循环:遍历字符串 s s s的每个字符 c c c
    1. 记录字符类型 t t t:分为四种情况。
      • c c c为正负号时,执行 t = ′ s ′ t = 's' t=s;
      • c c c为数字时,执行 t = ′ d ′ t = 'd' t=d;
      • c c c e , E e , E e,E时,执行 t = ′ e ′ t = 'e' t=e;
      • c c c . . ., 空格时,执行 t = c t = c t=c(即用字符本身表示字符类型);
      • 否则,执行 t = ′ ? ′ t = '?' t=?,代表为不属于判断范围的非法字符,后续直接返回 F a l s e False False
    2. 终止条件: 若字符类型 t t t不在哈希表 s t a t e s [ p ] states[p] states[p]中,说明无法转移至下一状态,因此直接返回 F a l s e False False
    3. 状态转移: 状态 p p p转移至 s t a t e s [ p ] [ t ] states[p][t] states[p][t]
  3. 返回值: 跳出循环后,若状态 p ∈ 2 , 3 , 7 , 8 p in {2, 3, 7, 8} p2,3,7,8,说明结尾合法,返回 T r u e True True,否则返回 F a l s e False False

【代码】

class Solution:
    def isNumber(self, s: str) -> bool:
        states = [
            { ' ': 0, 's': 1, 'd': 2, '.': 4 }, # 0. start with 'blank'
            { 'd': 2, '.': 4 } ,                # 1. 'sign' before 'e'
            { 'd': 2, '.': 3, 'e': 5, ' ': 8 }, # 2. 'digit' before 'dot'
            { 'd': 3, 'e': 5, ' ': 8 },         # 3. 'digit' after 'dot'
            { 'd': 3 },                         # 4. 'digit' after 'dot' (‘blank’ before 'dot')
            { 's': 6, 'd': 7 },                 # 5. 'e'
            { 'd': 7 },                         # 6. 'sign' after 'e'
            { 'd': 7, ' ': 8 },                 # 7. 'digit' after 'e'
            { ' ': 8 }                          # 8. end with 'blank'
        ]
        p = 0                           # start with state 0
        for c in s:
            if '0' <= c <= '9': t = 'd' # digit
            elif c in "+-": t = 's'     # sign
            elif c in "eE": t = 'e'     # e or E
            elif c in ". ": t = c       # dot, blank
            else: t = '?'               # unknown
            if t not in states[p]: return False
            p = states[p][t]
        return p in (2, 3, 7, 8)
# python特性
class Solution:
    def isNumber(self, s: str) -> bool:
        try:
            float(s)
            return True
        except Exception:
            return False

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

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

【思路】

  1. 利用左右双指针 l 、 r l、r lr
  2. l l l向右移动,找到偶数;将 r r r向左移动,找到奇数。
  3. 互换这两个位置的数。
  4. 最终,奇数靠前,偶数靠后。

【代码】

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        if nums:
            l, r = 0, len(nums) - 1
            while l < r:
                while l < r and nums[l] % 2 == 1:
                    l += 1
                while l < r and nums[r] % 2 == 0:
                    r -= 1
                nums[l], nums[r] = nums[r], nums[l]
        return nums
        

【★】剑指 Offer 15. 二进制中1的个数

【题目】剑指 Offer 15. 二进制中1的个数

【思路】

  • 利用位运算,每次计算n &= n - 1,这样只会将最后一个1清除掉。
  • n = 0时,说明1都被清除掉了。

也利用Python特点,bin()取得二进制,再str.count()统计'1'的个数。

【代码】

class Solution:
    # Python 特性
    # def hammingWeight(self, n: int) -> int:
    #     return bin(n).count('1')
    
    def hammingWeight(self, n: int) -> int:
        ret = 0
        while n:
            n &= n - 1
            ret += 1
        return ret

【★】剑指 Offer 29. 顺时针打印矩阵

【题目】剑指 Offer 29. 顺时针打印矩阵

【思路】

  • 可以将矩阵看成若干层,首先打印最外层的元素,其次打印次外层的元素,直到打印最内层的元素。
  • 对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于 ( top , left ) (textit{top}, textit{left}) (top,left),右下角位于 ( bottom , right ) (textit{bottom}, textit{right}) (bottom,right),按照如下顺序遍历当前层的元素。
    • 从左到右遍历上侧元素,依次为 ( top , left ) (textit{top}, textit{left}) (top,left) ( top , right ) (textit{top}, textit{right}) (top,right)
    • 从上到下遍历右侧元素,依次为 ( top + 1 , right ) (textit{top} + 1, textit{right}) (top+1,right) ( bottom , right ) (textit{bottom}, textit{right}) (bottom,right)
    • 如果 left < right textit{left} < textit{right} left<right top < bottom textit{top} < textit{bottom} top<bottom,则从右到左遍历下侧元素,依次为 ( bottom , right − 1 ) (textit{bottom}, textit{right} - 1) (bottom,right1) ( bottom , left + 1 ) (textit{bottom}, textit{left} + 1) (bottom,left+1),以及从下到上遍历左侧元素,依次为 ( bottom , left ) (textit{bottom}, textit{left}) (bottom,left) ( top + 1 , left ) (textit{top} + 1, textit{left}) (top+1,left)
  • 遍历完当前层的元素之后,将 left textit{left} left top textit{top} top分别增加 11,将 right textit{right} right bottom textit{bottom} bottom分别减少 1,进入下一层继续遍历,直到遍历完所有元素为止。

【代码】

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

剑指 Offer 22. 链表中倒数第k个节点

【题目】剑指 Offer 22. 链表中倒数第k个节点

【思路】

  1. 设置p、q两个指针,初始值为head;
  2. 让p先向后移动k步;
  3. p、q同时向后移动,直到p==None

【代码】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        p = q = head
        if head:
            for _ in range(k):
                p = p.next
            while p:
                p = p.next
                q = q.next
        return q

【★】剑指 Offer 16. 数值的整数次方

【题目】剑指 Offer 16. 数值的整数次方

【思路】

  1. 利用快速幂的思想。
  2. n < 0 n < 0 n<0时:把问题转化至 n ≥ 0 n geq 0 n0的范围内,即执行 x = 1 / x , n = − n x = 1/x,n = - n x=1/xn=n
  3. 循环计算:当 n = 0 n = 0 n=0时跳出;
    1. n & 1 = 1 n & 1 = 1 n&1=1时:将当前 x x x乘入 r e s res res(即 r e s ∗ = x res *= x res=x);
    2. 执行 x = x 2 x = x^2 x=x2(即 x ∗ = x x *= x x=x);
    3. 执行 n n n右移一位(即 n > > = 1 n >>= 1 n>>=1)。

【代码】

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if x == 0: return 0
        res = 1
        if n < 0: x, n = 1 / x, -n
        while n:
            if n & 1: res *= x
            x *= x
            n >>= 1
        return res

【★】剑指 Offer 17. 打印从1到最大的n位数

【题目】剑指 Offer 17. 打印从1到最大的n位数

【思路】

  1. range()解决,但不兼容大数
  2. 解决大数问题:
    1. 变量类型使用string
    2. 生成数字字符集,通过递归完成 n n n 0 − 9 0 - 9 09全排列
    3. 解决高位的 0 0 0,并且让列表从 1 1 1开始。

递归生成解法

【代码】

class Solution:
	# 非大数
    def printNumbers(self, n: int) -> List[int]:
        return list(range(1, 10 ** n))
    # 大数
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(int(s))
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10):
                if i == 9: self.nine += 1
                num[x] = str(i)
                dfs(x + 1)
            self.nine -= 1
        
        num, res = ['0'] * n, []
        self.nine = 0
        self.start = n - 1
        dfs(0)
        return res

【★】剑指 Offer 19. 正则表达式匹配

【题目】剑指 Offer 19. 正则表达式匹配

【思路】

我们用 f [ i ] [ j ] f[i][j] f[i][j]表示 s s s的前 i i i个字符与 p p p中的前 j j j个字符是否能够匹配。在进行状态转移时,我们考虑 p p p的第 j j j个字符的匹配情况:

  • 如果 p p p的第 j j j个字符是一个小写字母,那么我们必须在 s s s中匹配一个相同的小写字母,即
    f [ i ] [ j ] = { f [ i − 1 ] [ j − 1 ] , s [ i ] = p [ j ] F a l s e , s [ i ] ≠ p [ j ] f[i][j]= begin{cases} f[i - 1][j - 1] & , {s[i] = p[j]}\ False & , {s[i] neq p[j]} end{cases} f[i][j]={f[i1][j1]False,s[i]=p[j],s[i]=p[j]
    也就是说,如果 s s s的第 i i i个字符与 p p p的第 j j j个字符不相同,那么无法进行匹配;否则我们可以匹配两个字符串的最后一个字符,完整的匹配结果取决于两个字符串前面的部分。
  • 如果 p p p的第 j j j个字符是*,那么就表示我们可以对 p p p的第 j − 1 j−1 j1个字符匹配任意自然数次。
    • 匹配 s s s末尾的一个字符,将该字符扔掉,而该组合还可以继续进行匹配;
    • 不匹配字符,将该组合扔掉,不再进行匹配。
      f [ i ] [ j ] = { f [ i − 1 ] [ j ]   o r   f [ i ] [ j − 2 ] , s [ i ] = p [ j − 1 ] f [ i ] [ j − 2 ] , s [ i ] ≠ p [ j − 1 ] f[i][j]= begin{cases} f[i - 1][j] space or space f[i][j - 2] & , {s[i] = p[j - 1]}\ f[i][j - 2] & , {s[i] neq p[j - 1]} end{cases} f[i][j]={f[i1][j] or f[i][j2]f[i][j2],s[i]=p[j1],s[i]=p[j1]
  • 在任意情况下,只要 p [ j ] p[j] p[j].,那么 p [ j ] p[j] p[j]一定成功匹配 s s s中的任意一个小写字母。

最终的状态转移方程如下:
f [ i ] [ j ] = { i f ( p [ j ] ≠ ‘ ∗ ’ ) = { f [ i − 1 ] [ j − 1 ] , m a t c h e s ( s [ i ] , p [ j ] ) F a l s e , o t h e r w i s e o t h e r w i s e = { f [ i − 1 ] [ j ]   o r   f [ i ] [ j − 2 ] , m a t c h e s ( s [ i ] , p [ j − 1 ] ) f [ i ] [ j − 2 ] , o t h e r w i s e f[i][j]= begin{cases} if (p[j] neq ‘*’) = begin{cases} f[i - 1][j - 1] & ,{matches(s[i], p[j])}\ False & ,{otherwise} end{cases} \ otherwise = begin{cases} f[i - 1][j] space or space f[i][j - 2] & ,{matches(s[i], p[j - 1])}\ f[i][j - 2] & ,{otherwise} end{cases} end{cases} f[i][j]=if(p[j]=)={f[i1][j1]False,matches(s[i],p[j]),otherwiseotherwise={f[i1][j] or f[i][j2]f[i][j2],matches(s[i],p[j1]),otherwise
其中 matches ( x , y ) textit{matches}(x, y) matches(x,y)判断两个字符是否匹配的辅助函数。只有当 y y y.或者 x x x y y y本身相同时,这两个字符才会匹配。

【代码】

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)
        def matches(i: int, j: int) -> bool:
            if i == 0:
                return False
            if p[j - 1] == '.':
                return True
            return s[i - 1] == p[j - 1]

        f = [[False] * (n + 1) for _ in range(m + 1)]
        f[0][0] = True
        for i in range(m + 1):
            for j in range(1, n + 1):
                if p[j - 1] == '*':
                    f[i][j] |= f[i][j - 2]
                    if matches(i, j - 1):
                        f[i][j] |= f[i - 1][j]
                else:
                    if matches(i, j):
                        f[i][j] |= f[i - 1][j - 1]
        return f[m][n]

剑指 Offer 24. 反转链表

【题目】剑指 Offer 24. 反转链表

【思路】

递归 or 迭代。

【代码】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# 迭代
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
            return head
        pre, p = None, head
        while p.next:
            nxt = p.next
            p.next = pre
            pre = p
            p = nxt
        p.next = pre
        return p
# 递归
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        newhead = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return newhead

剑指 Offer 18. 删除链表的节点

【题目】剑指 Offer 18. 删除链表的节点

【思路】略。

【代码】

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        if not head:
            return head
        dummy = ListNode(0)
        dummy.next = head
        p = dummy
        while p and p.next:
            if p.next.val == val:
                p.next = p.next.next
            p = p.next
        return dummy.next

剑指 Offer 35. 复杂链表的复制

【题目】剑指 Offer 35. 复杂链表的复制

【思路】

穿针引线法。
对 于 链 表 A → B → C A → B → C , 我 们 可 以 将 其 拆 分 为 A → A ′ → B → B ′ → C → C ′ 。 对 于 任 意 一 个 原 节 点 S , 其 拷 贝 节 点 S ′ 即 为 其 后 继 节 点 。 对于链表 A rightarrow B rightarrow CA→B→C,我们可以将其拆分为 A rightarrow A' rightarrow B rightarrow B' rightarrow C rightarrow C'。对于任意一个原节点 S,其拷贝节点 S'即为其后继节点。 ABCABCAABBCCSS
然后再进行遍历,将random域next域修正即可。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

【代码】

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        for (Node node = head; node != null; node = node.next.next) {
            Node nodeNew = new Node(node.val);
            nodeNew.next = node.next;
            node.next = nodeNew;
        }
        for (Node node = head; node != null; node = node.next.next) {
            Node nodeNew = node.next;
            nodeNew.random = (node.random != null) ? node.random.next : null;
        }
        Node headNew = head.next;
        for (Node node = head; node != null; node = node.next) {
            Node nodeNew = node.next;
            node.next = nodeNew.next;
            nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
        }
        return headNew;
    }
}

剑指 Offer 40. 最小的k个数

【题目】剑指 Offer 40. 最小的k个数

【思路】

  1. 方法一:
    维护一个 s i z e = k size = k size=k的大顶堆,插入数据的过程中, s i z e > k size > k size>k就取掉顶部元素(最大元素)。
  2. 方法二:
    利用快排思想,当一次划分partition()后,基准元素位置在第k个位置,则该位置之前的元素是数组中最小的k个值。

【代码】

// 堆
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] vec = new int[k];
        if (k == 0) {
            return vec;
        }
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
            public int compare(Integer n1, Integer n2) {
                return n2 - n1; // 大顶堆 (小顶堆是n1 - n2)
            }
        });
        for (int i = 0; i < k; ++i) {
            queue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; ++i) {
            if (queue.peek() > arr[i]) {
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; ++i) {
            vec[i] = queue.poll();
        }
        return vec;
    }
}
// 快排
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k == 0) {
            return new int[]{};
        }
        return Arrays.copyOfRange(arr, 0, quickSort(arr, 0, arr.length - 1, k - 1) + 1);
    }
    public int quickSort(int[] nums, int l, int r, int index) {
        int q = partition(nums, l, r);
        if (q == index) {
            return q;
        }
        return (q > index) ? quickSort(nums, l, q - 1, index) : quickSort(nums, q + 1, r, index);
    }
    public int partition(int[] nums, int l, int r) {
        int x = nums[r], i = l - 1;
        for (int j = l; j < r; ++j) {
            if (nums[j] < x) {
                swap(nums, ++i, j);
            }
        }
        swap(nums, i + 1, r);
        return i + 1;
    }
    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

最后

以上就是怡然鸭子为你收集整理的剑指offer刷题记录 python3 Java剑指 Offer 09. 用两个栈实现队列剑指 Offer 10- I. 斐波那契数列剑指 Offer 03. 数组中重复的数字【★】剑指 Offer 04. 二维数组中的查找剑指 Offer 10- II. 青蛙跳台阶问题剑指 Offer 11. 旋转数组的最小数字剑指 Offer 12. 矩阵中的路径剑指 Offer 05. 替换空格剑指 Offer 13. 机器人的运动范围剑指 Offer 06. 从尾到头打印链表剑指 Offer 07. 重的全部内容,希望文章能够帮你解决剑指offer刷题记录 python3 Java剑指 Offer 09. 用两个栈实现队列剑指 Offer 10- I. 斐波那契数列剑指 Offer 03. 数组中重复的数字【★】剑指 Offer 04. 二维数组中的查找剑指 Offer 10- II. 青蛙跳台阶问题剑指 Offer 11. 旋转数组的最小数字剑指 Offer 12. 矩阵中的路径剑指 Offer 05. 替换空格剑指 Offer 13. 机器人的运动范围剑指 Offer 06. 从尾到头打印链表剑指 Offer 07. 重所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部