[剑指Offer]05~08
[剑指Offer]05~08
学习使用工具
剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf
LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/
本节阅读文章
https://blog.csdn.net/sinat_28576553/article/details/84404653
剑指Offer 05:替换空格
请实现一个函数,把字符串 s
中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
限制:
0 <= s 的长度 <= 10000
解法:
这么简单的题?难道有什么陷阱?然后半分钟就写完了,真的没有什么陷阱。
def replaceSpace(self, s: str) -> str:
ans = ""
for i in s:
if i == " ":
ans = ans + "%20"
else:
ans = ans + i
return ans
更加简单的一行写法:
def replaceSpace(self, s: str) -> str:
return s.replace(" ","%20");
剑指Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
解法:
递归,递归!递归到链表最尾端,将此处的节点值加入结果数组;之后逐层退出递归,重复这个过程。
def reversePrint(self, head: ListNode) -> List[int]:
ans = []
if not head:
return ans
def reverse(head: ListNode):
if head:
reverse(head.next)
ans.append(head.val)
reverse(head)
return ans
然后发现还有更简单的写法:直接遍历一遍链表加入数组,倒序输出数组即可。
def reversePrint(self, head: ListNode) -> List[int]:
ans = []
while(head):
ans.append(head.val)
head = head.next
return ans[::-1]
这里正好复习一下Python的数组切片使用方法。
切片使用2个冒号分隔的3个数字来完成:
- 第一个数字表示切片的开始位置,默认为0;
- 第二个数字表是切片的截止(但不包含)位置,默认为列表长度;
- 第三个数字表示切片的步长,默认为1。当步长省略时,可以省略第2个冒号。
aList=[3,4,5,6,7,9,11,13,15,17]
print(aList[::]) #[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
print(aList[::-1]) #[17, 15, 13, 11, 9, 7, 6, 5, 4, 3],倒序输出
print(aList[::2]) # [3, 5, 7, 11, 15], 以步长为2进行输出
print(aList[1::2]) #[4, 6, 9, 13, 17], 从1开始步长为2
print(aList[3::]) #[6, 7, 9, 11, 13, 15, 17]
print(aList[3:6]) #[6, 7, 9],省略的是步长,输出位置在[3,6)的元素
剑指Offer 07:重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 1:
https://assets.leetcode.com/uploads/2021/02/19/tree.jpg
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
限制:
0 <= 节点个数 <= 5000
解法:
先来复习一下从前序&中序遍历重建原始二叉树的算法流程。
- 前序遍历结构:根节点→左子树→右子树
- 中序遍历结构:左子树→根节点→右子树
- 前序遍历首位必然为根节点
- 中序遍历中,根节点之前被遍历到的为根节点左子树,根节点之后被遍历到的为根节点右子树
又是递归,脑内模拟的很好,实际写起来还是有点绕的。
# 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 None
length = len(preorder) # 获取数组长度
rot = preorder[0] # 获取根节点值
temp = 0 # 记录根节点在中序遍历中的位置
for i in range(length):
if inorder[i] == rot: # 在中序遍历中找到根节点,记录位置,更新temp
temp = i
break
root = TreeNode(rot) # 以rot为值,建立根节点
preleft = preorder[1 : temp + 1] # 截取前序遍历中的:左子树
preright = preorder[temp + 1 : length] # 截取前序遍历中的:右子树
inleft = inorder[0 : temp] # 截取中序遍历中的:左子树
inright = inorder[temp + 1 : length] #截取中序遍历中的:右子树
root.left = self.buildTree(preleft,inleft) # 递归建立左子树
root.right = self.buildTree(preright,inright) # 递归建立右子树
return root
疑惑,LeetCode上的剑指Offer题单直接从07跳到09了,没有08
剑指Offer 09:用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
示例 1:
输入:
["CQueue","appendTail","deleteHead","deleteHead","deleteHead"]
[[],[3],[],[],[]]
输出:[null,null,3,-1,-1]
示例 2:
输入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
- 最多会对
appendTail、deleteHead
进行10000
次调用
解法:
又是简单题。两个栈分别看作是队尾和队头,进栈元素暂时保留在队尾。
需要出栈时,先判定队头空不空
- 如果空的话就将队尾栈全部pop进队头栈,再从队头栈出栈
- 如果不空直接从队头栈出栈即可
class CQueue:
def __init__(self):
self.Head = []
self.Tail = []
def appendTail(self, value: int) -> None:
self.Tail.append(value)
def deleteHead(self) -> int:
if not self.Head:
if not self.Tail:
return -1
while(self.Tail):
self.Head.append(self.Tail.pop())
return self.Head.pop()
else:
return self.Head.pop()