剑指offer python解题

文章目录

回溯法

67 机器人的运动范围

题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

解题思路

  1. 设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.
  2. 递归实现回溯。依次访问当前位置的上下左右的格子。
# -*- coding:utf-8 -*-
import sys
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        # 记录每个格子的状态
        if rows < 0 and cols < 0:
            return False

        visited = [0] * (rows * cols)
        count = self.calCount(threshold, rows, cols, 0, 0, visited)
        return count

    def calCount(self, threshold, rows, cols, row, col, visited):
        count = 0
        if self.check(threshold, rows, cols, row, col, visited):
            visited[row * cols + col] = True
            count = 1 + self.calCount(threshold, rows, cols, row-1, col, visited) \
                    + self.calCount(threshold, rows, cols, row+1, col, visited) \
                    + self.calCount(threshold, rows, cols, row, col+1, visited) \
                    + self.calCount(threshold, rows, cols, row, col-1, visited)
        return count

    def check(self, threshold, rows, cols, row, col, visited):
        if 0 <= row < rows and 0 <= col < cols and visited[row * cols + col] == 0 \
                and self.getSum(row) + self.getSum(col) <= threshold:
            return True
        return False

    def getSum(self, digit):
        res = 0
        while digit > 0:
            res += digit % 10
            digit //= 10
        return res


if __name__ == '__main__':
    arr = sys.stdin.readline().strip().split(' ')
    threshold, rows, cols = [int(x) for x in arr]
    count = Solution().movingCount(threshold, rows, cols)
    print(count)

66 矩阵中的路径

题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
解题思路

  1. 设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.
  2. index 记录path的元素, 回溯法寻找匹配的元素。如果当前元素符合,寻找当前元素的四周元素。
  3. 如果没有找到, index-1回溯到前一个位置。
# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        if matrix is None and rows <= 0 and cols <= 0:
            return False
        visited = [0] * (rows * cols)
        pathindex = 0
        for row in range(rows):
            for col in range(cols):
                if self.hasPathCore(matrix, rows, cols, row, col, path, pathindex, visited):
                    return True
        return False

    def hasPathCore(self, matrix, rows, cols, row, col, path, pathindex, visited):
        haspath = False
        length = len(path)
        if pathindex == length:
            return True
        if rows > row >= 0 and cols > col >= 0 and visited[row * cols + col] == 0 \
                and matrix[row * cols + col] == path[pathindex]:
            pathindex += 1
            visited[row * cols + col] = 1
            haspath = self.hasPathCore(matrix, rows, cols, row - 1, col, path, pathindex, visited) or \
                      self.hasPathCore(matrix, rows, cols, row + 1, col, path, pathindex, visited) or \
                      self.hasPathCore(matrix, rows, cols, row, col - 1, path, pathindex, visited) or \
                      self.hasPathCore(matrix, rows, cols, row, col + 1, path, pathindex, visited)
            if not haspath:
                pathindex -= 1
                visited[row * cols + col] = 0
        return haspath

栈和队列

65 滑动窗口的最大值

题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
解题思路

  1. 设置一个两头都能进出的数据结构,python里边的list符合。
  2. 存储元素的下标而非元素值,目的是好判断是否在窗口中。与当前元素下标差值大于size的都应该滑出窗口。
  3. 判断当前元素和栈内元素的大小,大于栈尾部元素,尾部元素出栈。
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if num is None or size <= 0:
            return []
        dequeen = []
        windows = []
        for idx, val in enumerate(num):
            if dequeen is []:
                dequeen.append(idx)
            if idx - dequeen[0] >= size:
                dequeen.pop(0)

            while dequeen is not [] and val >= num[dequeen[-1]]:
                dequeen.pop()
            dequeen.append(idx)

            if idx >= size - 1:
                windows.append(num[dequeen[0]])
        return windows

21 包含min函数的栈

#########################################################################
#  21 包含min函数的栈
#########################################################################
# 另外用一个辅助栈存储最小的元素
# 注意判断栈是否为空
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.min_stack = []

    def push(self, node):
        self.stack.append(node)
        if self.min_stack == []:
            self.min_stack.append(node)
        else:
            self.min_stack.append(min(node, self.min_stack[-1]))

    def pop(self):
        if self.stack != [] and self.min_stack != []:
            self.min_stack.pop()
            return self.stack.pop()

    def top(self):
        if self.stack != []:
            return self.stack[-1]

    def min(self):
        if self.min_stack != []:
            return self.min_stack[-1]

22 栈的压入和弹出序列

#########################################################################
#  22 栈的压入和弹出序列
#########################################################################
# 利用辅助栈,判断辅助栈最后能否全部弹出
# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if pushV == None and popV == None:
            return True
        if pushV == None or popV == None:
            return False
        stack = []
        for val in pushV:
            stack.append(val)
            while stack != [] and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
        return True if stack == [] else False

二叉树

58 二叉树的下一个结点

题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解题思路

  1. 中序遍历是左根右。
  2. 如果这个结点有右子树,下一个结点就是右子树的最左结点。
  3. 如果这个结点没有右子树,父节点存在,是父节点的左子结点,那么下一个结点就是此父节点,
  4. 如果不是父节点的左子节点,向上遍历找到一个结点是它父节点的左子节点,此节点的父节点就是下一个结点。
class Solution:
    def GetNext(self, pNode):
        # write code here
        if pNode == None:
            return None
        if pNode.right:
            right = pNode.right
            while right.left != None:
                right = right.left
            return right
        elif pNode.next != None:
            parent = pNode.next
            if pNode == parent.left:
                return parent
            else:
                curNode = pNode
                while parent != None and curNode == parent.right:
                    curNode = parent
                    parent = parent.next
                return parent
        return None

59 对称二叉树

题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路
前序遍历: 根左右
自定义反前序遍历: 根右左
只要两个遍历结果一样,就是对称二叉树。也就是两个树,根节点相等,root1的左子树与oot2 的右子树对称,root1的右子树与oot2 的左子树对称,结果就是True

class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        return self.isSymmetricalCore(pRoot, pRoot)

    def isSymmetricalCore(self, root1, root2):
        if root1 == None and root2 == None:
            return True
        if root1 == None or root2 == None:
            return False
        if root1.val != root2.val:
            return False
        return self.isSymmetricalCore(root1.left, root2.right) and \
               self.isSymmetricalCore(root1.right, root2.left)

60 二叉树打印多行

题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解题思路
层次遍历,另开一个存储空间存储每一层的数值。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        res = []
        queen = [pRoot]
        while queen:
            cur = []
            size = len(queen)
            for _ in range(size):
                root = queen.pop(0)
                cur.append(root.val)
                if root.left:
                    queen.append(root.left)
                if root.right:
                    queen.append(root.right)
            res.append(cur)
        return res

61 之字形打印二叉树

题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解题思路
定义两个栈,当前位置是奇数层时,先存储当前结点的左结点在存右结点到另一个栈中。偶数层时相反。

class Solution:
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        stack_odd = []
        stack_even = []
        res = []
        stack_odd.append(pRoot)
        while stack_odd or stack_even:
            cur = []
            while stack_odd:
                root = stack_odd.pop()
                cur.append(root.val)
                if root.left:
                    stack_even.append(root.left)
                if root.right:
                    stack_even.append(root.right)
            if cur:
                res.append(cur)
            cur = []
            while stack_even:
                root = stack_even.pop()
                cur.append(root.val)
                if root.right:
                    stack_odd.append(root.right)
                if root.left:
                    stack_odd.append(root.left)
            if cur:
                res.append(cur)
        return res

62 序列化二叉树

题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
解题思路
前序遍历序列化,将空值记录成特殊的符号。

class Solution:
    def Serialize(self, root):
        # write code here
        if root == None:
            return "#"
        return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right)

    def Deserialize(self, s):
        # write code here
        lis = s.split(',')
      
        return self.DeserializeTree(lis)

    def DeserializeTree(self, lis):
        if lis == []:
            return None
        val = lis.pop(0)
        root = None
        if val != '#':
            root = TreeNode(int(val))
            root.left = self.DeserializeTree(lis)
            root.right = self.DeserializeTree(lis)
        return root

63 二叉搜索树的第K个结点

#########################################################################
#  63 二叉搜索树的第K个结点
#########################################################################
# 中序遍历 返回第K个
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def KthNode(self, pRoot, k):
        # write code here
        if pRoot == None:
            return None
        stack = []
        res = []
        cur = pRoot
        while stack or cur:
            while cur:
                stack.append(cur)
                cur = cur.left
            cur = stack.pop()
            res.append(cur)
            cur = cur.right
            print(len(res))
            if len(res) == k
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值