Skip to content

Commit 6b50e4d

Browse files
committed
增加剑指offer python 题解
1 parent 3a2f4d8 commit 6b50e4d

File tree

36 files changed

+2593
-0
lines changed

36 files changed

+2593
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
剑指offer 第三题。从左到右升序从上到下升序数组,判断是否能找到一个值
3+
思路:
4+
从右上角开始找,大于 target 排除当前列。小于 target 排除当前行
5+
"""
6+
7+
8+
class Solution:
9+
def solve(self, matrix, target):
10+
if not matrix or not matrix[0]:
11+
return False
12+
leny = len(matrix)
13+
14+
x = 0
15+
y = leny - 1
16+
17+
while x >= 0 and y >= 0:
18+
if matrix[x][y] == target:
19+
return True
20+
elif matrix[x][y] > target:
21+
y -= 1
22+
else:
23+
x += 1
24+
return False
25+
26+
27+
def test():
28+
s = Solution()
29+
matrix = [
30+
[1, 2, 8, 9],
31+
[2, 4, 9, 12],
32+
[4, 7, 10, 13],
33+
[6, 8, 11, 15],
34+
]
35+
assert s.solve(matrix, 0) is False
36+
assert s.solve(matrix, 1) is True
37+
assert s.solve(matrix, 7) is True
38+
assert s.solve(matrix, 5) is False
39+
40+
# empty
41+
matrix = [
42+
[],
43+
]
44+
assert s.solve(matrix, 0) is False
45+
46+
47+
if __name__ == '__main__':
48+
test()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
替换字符串中的空格
3+
题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”,则输出“We%20are%20happy.”
4+
"""
5+
6+
7+
class Solution:
8+
def solve(self, string):
9+
"""因为 python string 不可变对象,和其他的语言用字符串数组能直接修改有点区别"""
10+
res = []
11+
for char in string:
12+
if char == ' ':
13+
res.append('%20')
14+
else:
15+
res.append(char)
16+
return ''.join(res)
17+
18+
def solve2(self, string):
19+
"""
20+
思路:
21+
先遍历一次计算替换后的总长度
22+
从后往前替换,防止从前往后需要
23+
"""
24+
pass
25+
26+
27+
def test():
28+
s = Solution()
29+
ss = 'We are happy.'
30+
assert s.solve(ss) == 'We%20are%20happy.'
31+
32+
assert s.solve('') == ''
33+
34+
35+
if __name__ == '__main__':
36+
test()
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
面试题5:从尾到头打印链表
3+
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。链表结点定义如下:
4+
"""
5+
from collections import deque
6+
7+
8+
class Stack:
9+
def __init__(self):
10+
self.items = deque()
11+
12+
def push(self, val):
13+
return self.items.append(val)
14+
15+
def pop(self):
16+
return self.items.pop()
17+
18+
def empty(self):
19+
return len(self.items) == 0
20+
21+
22+
class Node:
23+
def __init__(self, val, next=None):
24+
self.val, self.next = val, next
25+
26+
27+
class Solution:
28+
def solve(self, headnode):
29+
"""
30+
思路:用一个栈保存所有节点,之后一个一个 pop
31+
"""
32+
val_s = Stack()
33+
cur_node = headnode
34+
while cur_node:
35+
val_s.push(cur_node.val)
36+
cur_node = cur_node.next
37+
while not val_s.empty():
38+
print(val_s.pop())
39+
40+
def solve2(self, headnode):
41+
"""
42+
能用栈就可以使用递归。这一点需要能联想到
43+
"""
44+
curnode = headnode
45+
if curnode:
46+
self.solve2(curnode.next)
47+
print(curnode.val) # 注意 print 放到 递归之后才是倒序
48+
49+
50+
def test():
51+
s = Solution()
52+
linklist = Node(0, Node(1))
53+
s.solve2(linklist)
54+
55+
# linklist = Node(0)
56+
# s.solve2(linklist)
57+
58+
if __name__ == '__main__':
59+
test()
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
面试题6:重建二叉树
3+
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
4+
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出图2.6所示的二叉树并输出它的头结点。二叉树结点的定义如下:<Paste>
5+
"""
6+
7+
8+
class Node:
9+
def __init__(self, val, left=None, right=None):
10+
self.val, self.left, self.right = val, left, right
11+
12+
13+
class Solution:
14+
def __init__(self):
15+
self.pres = []
16+
self.inorders = []
17+
18+
def solve(self, prevals, invals):
19+
"""
20+
思路:先序找到根,然后可以找到中序遍历根的位置确定左子树和右子树,递归处理
21+
"""
22+
if not prevals or not invals:
23+
return None
24+
root_val = prevals[0]
25+
root = Node(root_val)
26+
inorder_root_idx = invals.index(root_val)
27+
left_length = inorder_root_idx
28+
right_length = len(invals) - inorder_root_idx - 1
29+
30+
if left_length:
31+
root.left = self.solve(prevals[1:1 + left_length], invals[:inorder_root_idx])
32+
33+
if right_length:
34+
root.right = self.solve(prevals[left_length + 1:], invals[inorder_root_idx + 1:])
35+
return root
36+
37+
def inorder(self, subtree):
38+
if subtree:
39+
self.inorder(subtree.left)
40+
self.inorders.append(subtree.val)
41+
self.inorder(subtree.right)
42+
43+
def preorder(self, subtree):
44+
if subtree:
45+
self.pres.append(subtree.val)
46+
self.preorder(subtree.left)
47+
self.preorder(subtree.right)
48+
49+
50+
def test():
51+
s = Solution()
52+
prevals = [1, 2, 4, 7, 3, 5, 6, 8]
53+
invals = [4, 7, 2, 1, 5, 3, 8, 6]
54+
root = s.solve(prevals, invals)
55+
s.inorder(root)
56+
assert s.inorders == invals
57+
58+
s.preorder(root)
59+
assert s.pres == prevals
60+
61+
62+
if __name__ == '__main__':
63+
test()
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
面试题7:用两个栈实现队列
3+
题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。
4+
"""
5+
6+
from collections import deque
7+
8+
9+
class Stack:
10+
def __init__(self):
11+
self.items = deque()
12+
13+
def push(self, val):
14+
return self.items.append(val)
15+
16+
def pop(self):
17+
return self.items.pop()
18+
19+
def empty(self):
20+
return len(self.items) == 0
21+
22+
def __len__(self):
23+
return len(self.items)
24+
25+
26+
class Queue:
27+
def __init__(self):
28+
self.s1 = Stack()
29+
self.s2 = Stack()
30+
31+
def append(self, val):
32+
self.s1.push(val)
33+
34+
def pop(self):
35+
if len(self.s2):
36+
return self.s2.pop()
37+
while len(self.s1):
38+
val = self.s1.pop()
39+
self.s2.push(val)
40+
return self.s2.pop()
41+
42+
43+
def test():
44+
q = Queue()
45+
q.append(1)
46+
q.append(2)
47+
q.append(3)
48+
assert q.pop() == 1
49+
q.append(4)
50+
assert q.pop() == 2
51+
assert q.pop() == 3
52+
assert q.pop() == 4
53+
54+
55+
if __name__ == '__main__':
56+
test()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
面试题8:旋转数组的最小数字
3+
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
4+
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
5+
"""
6+
7+
8+
class Solution:
9+
def findMin(self, array):
10+
"""
11+
思路:二分
12+
关键点:旋转数组的第一个数字是前半部分最小的,也是后半部分最大的
13+
"""
14+
if len(array) == 1:
15+
return array[0]
16+
first = array[0]
17+
size = len(array)
18+
beg = 1
19+
end = size
20+
21+
while beg < end:
22+
mid = (beg + end) // 2
23+
if array[mid] > first:
24+
beg = mid + 1
25+
else:
26+
end = mid
27+
if beg == size:
28+
return first
29+
else:
30+
return array[beg]
31+
32+
33+
def test():
34+
s = Solution()
35+
assert s.findMin([0]) == 0
36+
assert s.findMin([1, 2]) == 1 # 注意这个特殊case
37+
assert s.findMin([3, 4, 5, 1, 2]) == 1
38+
39+
40+
if __name__ == '__main__':
41+
test()
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
面试题10:二进制中1的个数
3+
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。""
4+
"""
5+
6+
7+
class Solution:
8+
def solve_wrong(self, num):
9+
"""
10+
不断右移,每次和1做与运算,结果为1就加1.
11+
NOTE:但是输入负数会死循环。
12+
"""
13+
cnt = 0
14+
while num:
15+
if num & 1:
16+
cnt += 1
17+
num >>= 1
18+
return cnt
19+
20+
def solve(self, num):
21+
"""
22+
不太能想出来:把一个数字不断和它的 num-1 与运算,能做几次就有几个 1
23+
用一条语句判断一个整数是不是2的整数次方。一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,
24+
而其他所有位都是0。根据前面的分析,把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0。
25+
"""
26+
cnt = 0
27+
while num:
28+
num = (num - 1) & num
29+
cnt += 1
30+
return cnt
31+
32+
def solve_py(self, num):
33+
"""python有一种比较 tricky 的方式来做
34+
"""
35+
s = format(num, 'b')
36+
return s.counts('1')
37+
38+
39+
def test():
40+
s = Solution()
41+
assert s.solve(9) == 2
42+
assert s.solve(1) == 1
43+
assert s.solve(8) == 1
44+
assert s.solve(0) == 0
45+
46+
47+
if __name__ == '__main__':
48+
test()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
面试题12:打印1到最大的n位数
3+
题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
4+
5+
思路:不能上来直接模拟。时间复杂度太大。
6+
因为 python 其实支持大数字运算,不需要像其他语言一样使用数组模拟大数。
7+
"""
8+
9+
10+
class Solution:
11+
def solve(self, n):
12+
"""递归的思路输出所有排列"""
13+
nums = [0] * n
14+
self._solve(nums, 0, n)
15+
16+
def _solve(self, nums, beg, end):
17+
if beg == end:
18+
print(nums)
19+
return
20+
for i in range(10):
21+
nums[beg] = i
22+
self._solve(nums, beg + 1, end)
23+
24+
25+
def test():
26+
s = Solution()
27+
s.solve(9)
28+
29+
30+
if __name__ == '__main__':
31+
test()

0 commit comments

Comments
 (0)