剑指offer合集,主要是记录一下做题过程,给自己以后复习用,借鉴了很多别的大佬的做题思路。
36-75题:下半部分链接https://blog.csdn.net/chuxuezheerer/article/details/107985913
文章目录
- 1.剑指 Offer03. 数组中重复的数字
- 2.剑指 Offer 04. 二维数组中的查找
- 3.剑指 Offer 05. 替换空格
- 4.剑指 Offer 06. 从尾到头打印链表
- 5.剑指 Offer 07. 重建二叉树
- 6.剑指 Offer09. 用两个栈实现队列
- 7.剑指 Offer 10- I. 斐波那契数列
- 8.剑指 Offer 10- II. 青蛙跳台阶问题
- 9.剑指 Offer 11. 旋转数组的最小数字
- 10.剑指 Offer 12. 矩阵中的路径
- *11.剑指 Offer 13. 机器人的运动范围
- 12.剑指 Offer 14- I. 剪绳子
- 13.剑指 Offer 14- II. 剪绳子 II
- *14.面试题15. 二进制中1的个数
- *15.剑指 Offer 16. 数值的整数次方
- *16.剑指 Offer 17. 打印从1到最大的n位数
- 17.剑指 Offer 18. 删除链表的节点
- 18.剑指 Offer 19. 正则表达式匹配
- 19.剑指 Offer 20. 表示数值的字符串
- 20.剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
- 21.剑指 Offer 22. 链表中倒数第k个节点
- 22.剑指 Offer 24. 反转链表
- 23.剑指 Offer 25. 合并两个排序的链表
- *24.剑指 Offer 26. 树的子结构
- 25.剑指 Offer 27. 二叉树的镜像
- 26.剑指 Offer 28. 对称的二叉树
- 27.剑指 Offer 29. 顺时针打印矩阵
- 28.剑指 Offer 30. 包含min函数的栈
- 29.剑指 Offer 31. 栈的压入、弹出序列
- 30.剑指 Offer 32 - I. 从上到下打印二叉树
- 31.剑指 Offer 32 - II. 从上到下打印二叉树 II
- 32.剑指 Offer 32 - III. 从上到下打印二叉树 III
- 33.剑指 Offer 33. 二叉搜索树的后序遍历序列
- 34.剑指 Offer 34. 二叉树中和为某一值的路径
- 35.剑指 Offer 35. 复杂链表的复制
1.剑指 Offer03. 数组中重复的数字
构造哈希表,或者用数组位置记录,如果大于1,则有重复。
(1)小偷懒,用Python内部函数实现:
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
res=collections.Counter(nums)
for key in res:
if res[key]>1:
return key
(2)构造哈希
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
res={
}
for ch in nums:
if ch not in res:
res[ch]=1
else:
return ch
2.剑指 Offer 04. 二维数组中的查找
找到这个二维数组的特点
class Solution:
def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
if not matrix:
return False
#从右上角开始,大于该数向下走,小于向左走
n=len(matrix)
m=len(matrix[0])
i,j=0,m-1
while 0<=i<n and 0<=j<m:
if matrix[i][j]==target:
return True
elif matrix[i][j]<target:
i+=1
else:
j-=1
return False
3.剑指 Offer 05. 替换空格
其实就是把占位一个字符的空格替换为占位三个字符的%20.
要注意使用python语言时,字符串是一个不可变数组,所以最好新建一个list,在list中进行操作。
class Solution:
def replaceSpace(self, s: str) -> str:
res=[]
for ch in s:
if ch==' ':
res.append("%20")
else:
res.append(ch)
return "".join(res)
4.剑指 Offer 06. 从尾到头打印链表
用一个栈来辅助
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
res=[]
while head:
res.append(head.val)
head=head.next
return res[::-1]
5.剑指 Offer 07. 重建二叉树
前序遍历:根左右。中序遍历:左根右。
递归思想,前序遍历中pre_left为结点的根,之后在中序遍历中寻找,获得值为pre_left的下标位置,左边的为左子树,右边的是右子树。
递归,从前序中获得根节点位置,从中序中获得子树长度。
# 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:
#前序:根左右
#中序:左根右
self.preRootDict={
}
self.pre=preorder
for i in range(len(inorder)):
self.preRootDict[inorder[i]]=i #记录中序结点的位置
return self.getRoot(0,0,len(inorder)-1)#根结点,中序遍历范围
def getRoot(self,preRoot,inorderLeft,inorderRight):
if inorderLeft>inorderRight: #中序遍历为空
return
root=TreeNode(self.pre[preRoot]) #建立根结点
i=self.preRootDict[self.pre[preRoot]] #找到前序中根结点在中序中的位置
root.left=self.getRoot(preRoot+1,inorderLeft,i-1)
#preRoot当前的根 左子树的长度 = 左子树的右边-左边 (i-1-inorderLeft+1) 。最后+1就是右子树的根了
root.right=self.getRoot(preRoot+i-inorderLeft+1,i+1,inorderRight)
return root
6.剑指 Offer09. 用两个栈实现队列
class CQueue:
def __init__(self):
self.stack1=[]
self.stack2=[]
def appendTail(self, value: int) -> None:
self.stack1.append(value)
def deleteHead(self) -> int:
if self.stack2:
return self.stack2.pop()
else:
if self.stack1:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
else:
return -1
7.剑指 Offer 10- I. 斐波那契数列
这一看就是动态数组问题。但常规的F(n)=F(n-1)+F(n-2)这种方法输入会超时。所以用一个辅助的字典记录已经算过的值。
class Solution:
def fib(self, n: int) -> int:
if n<=0:
return 0
arr={
}
return self.fibNum(arr,n)%1000000007
def fibNum(self,arr,n):
if n==1 or n==2:
return 1
if n in arr:
return arr[n] #记录以前已经算过的值,若已经存在则直接返回。
arr[n]=self.fibNum(arr,n-1)+self.fibNum(arr,n-2)
return arr[n]
还有一种方法,相对简单。
class Solution:
def fib(self, n: int) -> int:
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a % 1000000007
差不多 …(甩锅给leetcode…)
8.剑指 Offer 10- II. 青蛙跳台阶问题
解题思路同上道题,第n个台阶,不是从n-1个台阶上来就是从n-2个台阶上来。
class Solution:
def numWays(self, n: int) -> int:
if n<=0:
return 1
arr={
}
return (self.f(arr,n))%1000000007
def f(self,arr,n):
if n==1:
return 1
elif n==2:
return 2
if n in arr:
return arr[n]
arr[n]=self.f(arr,n-1)+self.f(arr,n-2)
return arr[n]
9.剑指 Offer 11. 旋转数组的最小数字
借鉴:某位大佬写的更加详细
二分法的思想
class Solution:
def minArray(self, numbers: [int]) -> int:
i, j = 0, len(numbers) - 1
while i < j:
m = (i + j) // 2 #中心点
if numbers[m] > numbers[j]: i = m + 1 #若右侧的点小于中心位置的点,则说明旋转点在中心位置的右侧
elif numbers[m] < numbers[j]: j = m #若右侧的点大于中心位置的点,则说明旋转点在中心位置的左侧
else: j -= 1 #若相等,则情况不明需要进一步判断(比如01011111和123123两种旋转点不一样)
return numbers[i]
10.剑指 Offer 12. 矩阵中的路径
这道题利用深度优先遍历+回溯思想。
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
#用一个临时值存储当前值,用于回溯
tmp,board[i][j]=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]=tmp
return