剑指Offer

1.用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

class CQueue:

    def __init__(self):
        self.add_stack, self.pop_stack  = [], []

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

    def deleteHead(self) -> int:
        if self.pop_stack:
            return self.pop_stack.pop()   # popstack有则退出
        else:
            if not self.add_stack:      # addstack为空返回-1
                return -1
            while self.add_stack:     # addstack需要全部退完,用while
                self.pop_stack.append(self.add_stack.pop())

        return self.pop_stack.pop()

2.写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        for i in range(n):
            a, b = b, a + b
        return a % 1000000007

3.找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        dic = set()         # 建立一个集合,如果在集合里面,则返回
        for num in nums:
            if num in dic: return num
            dic.add(num)
        return -1

4.在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        flag0 = 0
        flag1 = 1
        for list_ in matrix:
            if target in list_:
                flag0 = 1
                return flag0 == flag1
        if flag0 == 0:
            return flag0 == flag1

5.请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

输入:s = “We are happy.”
输出:“We%20are%20happy.”

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

6.输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

输入:head = [1,3,2]
输出:[2,3,1]

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        stack = []            # 递归就好比栈,先进后出
        while head:
            stack.append(head.val)
            head = head.next
        return stack[::-1]

7.输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

找根节点在先序中找,找左右子树在中序中找。先递归左子树,因为先序是根左右,所以root+1直接就是左子树的根节点,left是左子树在中序中的起始位置,i-1是左子树在中序中的终止位置。然后递归右子树,因为先序是根左右,找右子树的根节点就要只要左子树的长度就是i-left,再加当前根节点,再加1就是右子树根节点,i+1是右子树在中序中的起始位置,right是右子树在中序中的终止位置。

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        def recur(root, left, right):
            # 中止递归的条件
            if left > right:  return
            # 用先序遍历数组root号作为根,生成根节点
            # 这是生成树节点的唯一方法,其他都是确定子树的左右边界来辅助生成节点     
            node = TreeNode(preorder[root])
            # 查询根在中序遍历字典中的位置,目的是计算出子树的左右边界
            i = dic[preorder[root]]
            # 递归左子树,第一个参数用的先序遍历,意思是根,第二三个参数用的中序遍历,意思是子树的左右边界
            node.left = recur(root + 1, left, i - 1)
            # 递归右子树,同上
            node.right = recur(i - left + root + 1, i + 1, right) 
            return node  

        dic = {}
        preorder = preorder
        for i in range(len(inorder)):
            # 用字典来存储**中序**遍历数组,用中序来确定左右子树的位置
            dic[inorder[i]] = i    
        return recur(0, 0, len(inorder) - 1) 

8.一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
输入:n = 7
输出:21

class Solution:
    def numWays(self, n: int) -> int:
        a, b = 1, 1
        for i in range(n):
            a,b = b, a+b
        return a % 1000000007

9.把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

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

class Solution:
    def minArray(self, numbers: List[int]) -> int:
         low, high = 0, len(numbers) - 1
        while low < high:
            pivot = low + (high - low) // 2
            if numbers[pivot] < numbers[high]:    # 如果中间值小于最右侧元素说明最小值在中间值左侧
                high = pivot 
            elif numbers[pivot] > numbers[high]:   # 如果中间值大于最右侧元素说明最小值在中间值右侧
                low = pivot + 1
            else:
                high -= 1
        return numbers[low]

10.给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def dfs(i, j, k):
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]:
            	return False
            if k == len(word) - 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(len(board)):
            for j in range(len(board[0])):
                if dfs(i, j, 0): 
                    return True
        return False

11.编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。

输入:n = 11 (控制台输入 00000000000000000000000000001011)
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。

class Solution:
    def hammingWeight(self, n: int) -> int:
        res = 0
        while n:
            res += 1   # 统计变量加 1
            n &= n - 1   # 消除数字最右边的1
        return res

12.输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

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

13.请完成一个函数,输入一个二叉树,该函数输出它的镜像。

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return
        stack = [root]
        while stack:
            node = stack.pop()
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.append(node.right)
            node.left, node.right = node.right, node.left
        return root

14.请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def recur(L, R):
            if not L and not R:
                return True
            if not L or not R or L.val != R.val:
                return False
            return recur(L.left, R.right) and recur(L.right, R.left)

        return recur(root.left, root.right) if root else True

15.输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        odd = []
        even = []

        for num in nums:
            if num % 2 == 1:
                odd.append(num)
            else:
                even.append(num)
        return odd + even

16.输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

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

17.定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur, pre = head, None
        while cur:
            tmp = cur.next # 暂存后继节点 cur.next
            cur.next = pre # 修改 next 引用指向
            pre = cur      # pre 暂存 cur
            cur = tmp      # cur 访问下一节点
        return pre

18.输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix: return []
        l, r, t, b, res = 0, len(matrix[0]) - 1, 0, len(matrix) - 1, []
        while True:
            for i in range(l, r + 1):
                res.append(matrix[t][i]) # 从左往右
            t += 1
            if t > b: 
                break
            for i in range(t, b + 1):
                res.append(matrix[i][r]) # 从上往下
            r -= 1
            if l > r:
                break
            for i in range(r, l - 1, -1):
                res.append(matrix[b][i]) # 从右往左
            b -= 1
            if t > b:
                break
            for i in range(b, t - 1, -1):
                res.append(matrix[i][l]) # 从下往上
            l += 1
            if l > r:
                break
        return res

19.定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.

class MinStack:
    def __init__(self):
        self.A, self.B = [], []

    def push(self, x: int) -> None:
        self.A.append(x)
        if not self.B or self.B[-1] >= x:
            self.B.append(x)

    def pop(self) -> None:
        if self.A.pop() == self.B[-1]:
            self.B.pop()

    def top(self) -> int:
        return self.A[-1]

    def min(self) -> int:
        return self.B[-1]

20.从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: 
            return []
        res, queue = [], collections.deque()
        queue.append(root)
        while queue:
            tmp = []
            for _ in range(len(queue)):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(tmp)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值