面试题1:略
面试题2:略
面试题3:数组中重复的数字
题目一:找出数组中重复的数字
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出重复的数字是2或3。
#测试数据
a = [2,3,1,0,2,5,3]
#改变数组
def findRepeatNum(arr):
if arr==None or len(arr) < 2:
return -1
for a in arr:
if a < 0 or a >= len(arr):
return -1
i = 0
while i < len(arr):
if arr[i] == i:
i += 1
else:
if arr[arr[i]] == arr[i]:
for a in arr:
print(a, end=' ')
print()
return arr[i]
else:
tmp = arr[arr[i]]
arr[arr[i]] = arr[i]
arr[i] = tmp
return -1
题目二:不修改数组找出重复的数字
在一个长度为n+1的数组里的所有数字都在1~n范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
#不改变数组
b=[2,3,5,4,3,2,6,7]
c=[2,1,5,4,2,3]
def findRepeatNum2(arr):
if arr==None or len(arr) < 2:
return -1
for a in arr:
if a < 1 or a >= len(arr):
return -1
def rangeCount(arr, lens, start, end):
num = 0
for i in range(lens):
if arr[i] >= start and arr[i] <= end:
num += 1
return num
start = 1
end = len(arr) - 1
while start <= end:
mid = start + ((end - start) >> 1)
count = rangeCount(arr, len(arr), start, mid)
if start == end:
if count > 1:
return start
else:
break
if count > mid - start + 1 :
end = mid
else:
start = mid + 1
return -1
面试题4:二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
#测试数据
m=[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
def findTwoDimensionalArray(twoDiArray, k):
if twoDiArray == None:
return False
import numpy as np
rows = np.shape(twoDiArray)[0]
cols = np.shape(twoDiArray)[1]
if rows == 0 or cols == 0:
return False
if twoDiArray[rows - 1][cols - 1] < k or twoDiArray[0][0] > k:
return False
row = 0
col = cols - 1
while row < rows and col >= 0:
if twoDiArray[row][col] < k:
row += 1
else:
if twoDiArray[row][col] == k:
return True
elif twoDiArray[row][col] > k:
col -= 1
else:
return False
return False
面试题5:替换空格
题目:请实现一个函数,把字符串中的每个空格替换成"%20",例如,输入"We are happy.“,则输出"We%20are%20happy.”
def replaceBlankSpace(strs):
num = 0
lens = len(strs)
for s in strs:
if s == ' ':
num += 1
strs = strs + ' ' * num * 2
strs = list(strs)
i = len(strs) - 1
j = lens - 1
while i >= 0 and j >= 0:
if strs[j] != ' ':
strs[i] = strs[j]
i -= 1
j -= 1
else:
strs[i] = '0'
strs[i - 1] = '2'
strs[i - 2] = '%'
i -= 3
j -= 1
print(''.join(strs))
return ''.join(strs)
replaceBlankSpace("hello world")
面试题6:从尾到头打印链表
题目:输入一个链表的头节点,从尾到头反过来打印每个节点的值。链表节点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
#定义链表节点
class ListNode():
def __init__(self, value, next=None):
self.value = value
self.next = next
#方法一:(通过栈存储值,再依次弹出的方法,此处省略)
#方法二:递归法
def inversePrint(head):
if head != None:
if head.next != None:
inversePrint(head.next)
print(head.value)
return
#递归法之另一种写法
def inversePrint(head):
if head == None:
return
inversePrint(head.next)
print(head.value)
#测试数据
head = ListNode(3)
mid = ListNode(2)
tail = ListNode(1)
head.next = mid
mid.next = tail
inversePrint(head)
面试题7:重建二叉树
题目:输入某二叉树的前序和中序遍历的结果,请重建该二叉树。假设输入的前序和中序遍历的结果中都不含重复数字。例如,输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建如下图(7-1)所示的二叉树并输出它的头节点。二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
1
/ \
2 3
/ / \
4 5 6
\ /
7 8
#定义二叉树节点
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def rebulidTree(preOrder, midOrder):
lens = len(preOrder)
if lens <= 0:
return None
value = preOrder[0]
binaryTree = BinaryTreeNode(value)
idxV = midOrder.index(value)
leftM = midOrder[ : idxV]
rightP = midOrder[idxV + 1 : ]
leftP = preOrder[1 : idxV + 1]
rightM = preOrder[idxV + 1 : ]
lTree = rebulidTree(leftP, leftM)
rTree = rebulidTree(rightP, rightM)
binaryTree.left = lTree
binaryTree.right = rTree
return binaryTree
#测试数据
binaryTree = rebulidTree([1,2,4,7,3,5,6,8], [4,7,2,1,5,3,8,6])
print(binaryTree.value)
print(binaryTree.left.left.right.value)
面试题8:二叉树的下一个节点
题目:给定一棵二叉树和其中的一个节点,如何找出中序遍历的下一个节点?树中的节点除了有两个分别指向左、右子节点的指针,还有一个指向父节点的指针。
图8-1中二叉树的中序遍历序列是{d,b,h,e,i,a,f,c,g}
a
/ \
b c
/ \ / \
d e f g
/ \
h i
#二叉树节点的定义,包含指向父节点的指针
class BinaryTreeNode2():
def __init__(self, value, left = None, right = None, parent = None):
self.value = value
self.left = left
self.right = right
self.parent = parent
#根据题意,给定一个节点,意味着,已经存在一棵树,不用再显性给出一棵树头节点
def findNextTreeNode(treeNode):
nextNode = None
if treeNode == None:
return nextNode
#如果treeNode存在右子节点(即右子节点不为空)(此情况包含treeNode为根节点的情况)
nextNode = treeNode.right
if nextNode != None:
while nextNode.left != None:
nextNode = nextNode.left
return nextNode
#如果为左子节点且该节点的右子节点为空
if treeNode.parent != None and treeNode.parent.left == treeNode:
return treeNode.parent
#如果为右子节点且该节点的右子节点为空
if treeNode.parent != None and treeNode.parent.right == treeNode:
parentNode = treeNode.parent
while parentNode != None and parentNode.right == treeNode:
treeNode = parentNode
parentNode = parentNode.parent
return parentNode
return nextNode
#方法二:递归
def getNextNode(node):
if node == None:
return node
def getNodeFuzhu(node):
if node.left == None:
return node
else:
return getNodeFuzhu(node.left)
if node.right != None:
rightN = node.right
return getNodeFuzhu(rightN)
elif node.parent != None and node.parent.right != node:
return node.parent
else:
return None
#测试数据
a = BinaryTreeNode2('a')
b = BinaryTreeNode2('b')
c = BinaryTreeNode2('c')
d = BinaryTreeNode2('d')
e = BinaryTreeNode2('e')
f = BinaryTreeNode2('f')
g = BinaryTreeNode2('g')
h = BinaryTreeNode2('h')
i = BinaryTreeNode2('i')
a.left = b
a.right = c
b.parent = a
b.left = d
b.right = e
c.parent = a
c.left = f
c.right = g
d.parent = b
e.parent = b
e.left = h
e.right = i
f.parent = c
g.parent = c
h.parent = e
i.parent = e
print(findNextTreeNode(i).value)
面试题9:用两个栈实现队列(答案:略)
题目:用两个栈实现一个队列。队列的声明如下,请实现他的两个函数appendTail和deleteHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能。
面试题10:斐波那契数列
题目一:求斐波那契数列的第n项
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契数列的定义如下:
def fbnq(n):
if n <= 0:
return 0
if n == 1:
return 1
last_second = 0
last_first = 1
res = 0
for x in range(2, n + 1):
res = last_first + last_second
last_second = last_first
last_first = res
return res
#测试数据
print(fbnq(9) + fbnq(10))
print(fbnq(11))
题目二:青蛙跳台阶问题
一个青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法。
def frogJump(n):
if n <= 0:
return 0
if n == 1:
return 1
if n == 2:
return 2
first = 1
second = 2
res = 0
for i in range(3, n + 1):
res = first + second
first = second
second = res
return res
面试题11:旋转数组的最小数字
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
def minRotateArray(arr):
if arr == None:
return
first = 0
last = len(arr) - 1
mid = (last + first) >> 1
def getMin(arr, first, last):
res = arr[first]
for i in range(first , last + 1):
if res > arr[i]:
res = arr[i]
return res
while arr[first] >= arr[last]:
if last - first == 1:
return arr[last]
mid = (last + first) >> 1
if arr[first] == arr[mid] and arr[mid] == arr[last]:
return getMin(arr, first, last)
elif arr[first] <= arr[mid]:
first = mid
elif arr[mid] <= arr[last]:
last = mid
return arr[mid]
面试题12:矩阵中的路径
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串"bfce"的路径(路径中的字母用下划线标出)。但矩阵中不包含字符串"abfb"的路径,因为字符串中的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
a | b | t | g |
---|---|---|---|
c | f | c | s |
j | d | e | h |
def pathInMatrix(matrix, rows, cols, strs):
matrixBool = [[False] * cols for i in range(rows)]
lens = len(strs)
idx = 0
def hasPathCore(matrix, matrixBool, rows, cols, row, col, strs, lens, idx):
if idx == lens:
return True
if row < 0 or row >= rows or col < 0 or col >= cols:
return False
res = False
if matrix[row][col] == strs[idx] and matrixBool[row][col] == False:
matrixBool[row][col] = True
res = hasPathCore(matrix, matrixBool, rows, cols, row + 1, col, strs, lens, idx + 1) or \
hasPathCore(matrix, matrixBool, rows, cols, row - 1, col, strs, lens, idx + 1) or \
hasPathCore(matrix, matrixBool, rows, cols, row, col + 1, strs, lens, idx + 1) or \
hasPathCore(matrix, matrixBool, rows, cols, row, col - 1, strs, lens, idx + 1)
if res == False:
matrixBool[row][col] = False
return res
for row in range(rows):
for col in range(cols):
if hasPathCore(matrix, matrixBool, rows, cols, row, col, strs, lens, idx):
return True
return False
#测试数据
matrix = [['a','b','t','g'],['c','f','c','s'],['j','d','e','h']]
print(pathInMatrix(matrix, 3, 4, 'acjdfb'))
面试题13:机器人的运动范围
题目:地上有一个m行n列的方格。一个机器人从坐标(0, 0)的格子开始移动,它每次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的位数之和k的格子。例如,当k为18时,机器人能够进入方格(35, 37),因为3+5+3+7=18。但它不能进入方格(35, 38),因为3+6+3+8=19。请问该机器人能够到达多少个格子?
def robotRangeBacktrace(rows, cols, threshold):
if rows <= 0 or cols <= 0 or threshold < 0:
return 0
booleans = [[False] * cols for i in range(rows)]
def numSum13(x):
res = 0
while x > 0:
res += (x - x // 10 * 10)
x = x // 10
return res
def robotRangeBacktraceCore(row, col, rows, cols, threshold, booleans):
count = 0
if row >= 0 and col >= 0 and row < rows and col < cols \
and booleans[row][col] == False and numSum13(row) + numSum13(col) <= threshold:
booleans[row][col] = True
count = 1 + robotRangeBacktraceCore(row + 1, col, rows, cols, threshold, booleans)\
+ robotRangeBacktraceCore(row - 1, col, rows, cols, threshold, booleans)\
+ robotRangeBacktraceCore(row, col + 1, rows, cols, threshold, booleans)\
+ robotRangeBacktraceCore(row, col - 1, rows, cols, threshold, booleans)
return count
res = robotRangeBacktraceCore(0, 0, rows, cols, threshold, booleans)
return res
#测试数据
print(robotRangeBacktrace(5,5,7))
面试题14:剪绳子
题目:给你一根长度为n的绳子,请把绳子剪成m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],……,k[n]。请问k[0]×k[1]×……×k[n]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
#递归+贪婪法
def cutRope(n):
if n <= 1:
return 0
if n == 2:
return 1
if n == 3:
return 2
def cutRopCore(n):
if n <= 4:
return n
if n > 3:
return 3 * cutRopCore(n - 3)
if n > 3:
return cutRopCore(n)
#动态规划法
def cutRopeDynamic(n):
if n <= 1:
return 0
if n == 2:
return 1
if n == 3:
return 2
resList = [0 for i in range(n + 1)]
resList[0] = 0
resList[1] = 1
resList[2] = 2
resList[3] = 3
for i in range(4, n + 1):
resList[i] = 0
for j in range(1, i // 2 + 1):
if resList[j] * resList[i - j] > resList[i]:
resList[i] = resList[j] * resList[i - j]
return resList[n]
#测试数据
print(cutRope(9))
print(cutRopeDynamic(9))
面试题15:二进制中1的个数
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,把9表示成二进制1001,有2位是1。因此,如果输入9,则该函数输出2。
def numOfBinaryOne(n):
count = 0
num = 1
digit = 0
while num != 0:
if (n & num) != 0:
count += 1
num = num << 1
digit += 1
#当num向左位移64位后,不管是不是0,都停止
if digit > 64:
break
return count
#测试数据
print(numOfBinaryOne(1001))
面试题16:数值的整数次方
题目:实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
def pow(x, n):
if x == 0:
return 0
if n == 0:
return 1
res = 1
flag = True
if n < 0:
flag = False
n = -n
if n % 2 == 0:
res = pow(x, n >> 1) * pow(x, n >> 1)
else:
res = pow(x, n >> 1) * pow(x, n >> 1) * x
return res if flag else 1.0 / res
#测试数据
print(pow(2.5, 2))
面试题17:打印从1到最大的n位数(答案:略)
题目:输入数字n,按顺序打印从1到最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数999。
面试题18:删除链表的节点
题目一:在O(1)时间内删除链表节点。
给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。链表节点与函数的定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
def deleteNode(head, deleteNode):
if head == None or deleteNode == None:
return
if head == deleteNode:
head = head.next
deleteNode == None
return
if deleteNode.next != None:
nextNode = deleteNode.next
deleteNode.value = nextNode.value
deleteNode.next = nextNode.next
nextNode = None
return
else:
nextNode = head.next
while nextNode != deleteNode:
nextNode = nextNode.next
nextNode = None
return
题目二:删除链表中重复的节点。
在一个排序的链表中,如何删除重复的节点?例如,在下图(a)中重复的节点被删除之后,链表如下图(b)所示。
(a) 1–>2–>3–>4–>5
(b) 1–>2–>5
注:(a) 一个有7个节点的链表;(b) 当重复的节点被删除之后,链表中只剩下3个节点。
class ListNode():
def __init__(self, value, next=None):
self.value = value
self.next = next
def deleteDoubleNode(head):
if head == None:
return head
newNode = head
#去除从头部开始的重复节点
while newNode.next != None and newNode.value == newNode.next.value:
tmp = newNode.next.next
if tmp != None and newNode.next.value == tmp.value:
newNode = newNode.next
else:
newNode = tmp
if newNode == None:
break
if newNode == None:
return newNode
head = newNode
chongfu = head.next
while chongfu != None:
while chongfu.next != None and chongfu.value == chongfu.next.value:
tmp = chongfu.next.next
if tmp != None and chongfu.next.value == tmp.value:
chongfu = chongfu.next
else:
chongfu = tmp
if chongfu == None:
break
newNode.next = chongfu
newNode = newNode.next
if newNode == None:
return head
chongfu = chongfu.next
return head
a = ListNode(1)
b = ListNode(1)
c = ListNode(1)
d = ListNode(2)
e = ListNode(3)
f = ListNode(3)
g = ListNode(4)
h = ListNode(4)
i = ListNode(5)
a.next=b
b.next=c
c.next=d
d.next=e
e.next=f
f.next=g
g.next=h
h.next=i
m = deleteDoubleNode(a)
#print(m.value)
#print(m.next.value)
#打印结果:2,5
面试题19:正则表达式匹配
题目:请实现一个函数用来匹配包含 “·” 和 “*” 的正则表达式。模式中的字符 “·” 表示任意一个字符,而’ “*” 表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 “aaa” 与模式 “a.a” 和 “ab*ac*a” 匹配,但与 “aa.a” 和 “ab*a” 均不匹配。
def regMatch(strs, pattern):
lstr = len(strs)
lpt = len(pattern)
def regMatchFuZhu(strs, pattern, lstr, lpt, idxs, idxp):
if (idxs == lstr and idxp == lpt) or \
(idxs == lstr and idxp == lpt - 2 and pattern[idxp + 1] == '*'):
return True
if (idxs < lstr and idxp >= lpt) or (idxs >= lstr and idxp < lpt):
return False
# while idxs < lstr and idxp < lpt:
if strs[idxs] == pattern[idxp] or pattern[idxp] == '.':
if idxp < lpt - 1 and pattern[idxp + 1] == '*':
return regMatchFuZhu(strs, pattern, lstr, lpt, idxs, idxp + 2) \
or regMatchFuZhu(strs, pattern, lstr, lpt, idxs + 1, idxp) \
or regMatchFuZhu(strs, pattern, lstr, lpt, idxs + 1, idxp + 2)
else:
return regMatchFuZhu(strs, pattern, lstr, lpt, idxs + 1, idxp + 1)
elif idxp < lpt - 1 and pattern[idxp + 1] == '*':
return regMatchFuZhu(strs, pattern, lstr, lpt, idxs, idxp + 2)
else:
return False
return False
return regMatchFuZhu(strs, pattern, lstr, lpt, 0, 0)
#测试数据
print(regMatch('aaa', 'ab*ac*a'))
面试题20:表示数值的字符串(答案:略)
题目:请实现一个函数来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、“-123”、“3.1416"及”-1E-16"都表示数值,但"12e"、“1a3.14”、“1.2.3”、"±5"及"12e+5.4"都不是。
面试题21:调整数组顺序使奇数位于偶数前面
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
def adjustOddEven(arr):
if arr == None or len(arr) <= 0:
return
lens = len(arr)
i = 0
j = lens - 1
def isOdd(x):
if x % 2 == 1:
return True
else:
return False
while i < j:
if isOdd(arr[i]):
i += 1
elif not isOdd(arr[j]):
j -= 1
else:
tmp = arr[i]^arr[j]
arr[i] = tmp^arr[i]
arr[j] = tmp^arr[i]
return
arr = [1,2,3,4,5]
print(arr)
adjustOddEven(arr)
print(arr)
面试题22:链表中倒数第k个节点
题目:输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,他们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。链表节点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
#节点类定义
class ListNode():
def __init__(self, value):
self.value = value
self.next = None
def lastKNode(head, k):
if head == None or k < 1:
return None
lens = 1
tmp = head
while tmp.next != None:
lens += 1
tmp = tmp.next
if lens < k:
return None
head1 = head
head2 = head
k -= 1
while head2.next != None and k > 0:
head2 = head2.next
k -= 1
while head2.next != None and head1.next != None:
head2 = head2.next
head1 = head1.next
return head1
def lastKthNode(head, k):
if head == None or k <= 0:
raise Exception("输入参数不合法!")
lens = 0
newNode = head
while newNode != None:
lens += 1
newNode = newNode.next
if lens < k:
raise Exception("输入的k超过了取值范围!")
newk = lens - k
newNode = head
while newk > 0:
newk -= 1
newNode = newNode.next
if newk == 0:
break
return newNode
#测试数据
head0 = ListNode(1)
head1 = ListNode(2)
head2 = ListNode(3)
head3 = ListNode(4)
head4 = ListNode(5)
head5 = ListNode(6)
head0.next=head1
head1.next=head2
head2.next=head3
head3.next=head4
head4.next=head5
print(lastKNode(head0, 3).value)
面试题23:链表中环的入口节点
题目:如果一个链表中包含环,如何找出环的入口节点?例如,在下图所示的链表中,环的入口节点是节点3。
-------------
↓ ↑
1-->2-->3-->4-->5-->6
3
/ \
4 6
\ /
5
#节点类定义
class ListNode():
def __init__(self, value):
self.value = value
self.next = None
def entryNodeOfRing(head):
if head == None:
return None
head1 = head
head2 = head.next
while head1 != head2 and head1 != None and head2 != None:
head1 = head1.next
head2 = head2.next
if head2.next != None:
head2 = head2.next
if head1 == None or head2 == None:
return None
head1 = head1.next
head2 = head2.next.next
k = 1
while head1 != head2:
head1 = head1.next
head2 = head2.next.next
k += 1
head3 = head
head4 = head
while k > 0:
head4 = head4.next
k -= 1
while head3 != head4:
head3 = head3.next
head4 = head4.next
return head3
#测试数据
head0 = ListNode(1)
head1 = ListNode(2)
head2 = ListNode(3)
head3 = ListNode(4)
head4 = ListNode(5)
head5 = ListNode(6)
head0.next=head1
head1.next=head2
head2.next=head3
head3.next=head4
head4.next=head5
head5.next=head2
print(entryNodeOfRing(head0).value)
面试题24:反转链表
题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。链表节点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
#节点类定义
class ListNode():
def __init__(self, value):
self.value = value
self.next = None
#递归法
def inverseListNodeRecurive(head):
if head.next == None or head == None:
return head
nextNode = head.next
newHead = inverseListNodeRecurive(nextNode)
nextNode.next = head
head.next = None
return newHead
#循环法
def inverseListNodeLoop(head):
if head == None or head.next == None:
return head
newHead = head
nextNode = None
while newHead != None:
tmp = newHead
if newHead.next != None:
newHead = newHead.next
else:
tmp.next = nextNode
return newHead
tmp.next = nextNode
nextNode = tmp
return newHead
#循环法2
def inverseListNodeLoop2(head):
if head == None or head.next == None:
return head
newHead = None
pre = None
while head != None:
next = head.next
if next == None:
newHead = head
head.next = pre
pre = head
head = next
return newHead
#测试数据
head0 = ListNode(1)
head1 = ListNode(2)
head2 = ListNode(3)
head0.next=head1
head1.next=head2
print(inverseListNodeRecurive(head0).value)
print(inverseListNodeRecurive(head0).next.value)
print(inverseListNodeLoop(head0).value)
print(inverseListNodeLoop(head0).next.value)
面试题25:合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。例如,输入下图中的链表1和链表2,则合并之后的升序链表如链表3所示。链表节点定义如下:
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
链表1:1–>3–>5–>7
链表2:2–>4–>6–>8
链表3:1–>2–>3–>4–>5–>6–>7–>8
#节点类定义
class ListNode():
def __init__(self, value):
self.value = value
self.next = None
def mergeNodeList(head1, head2):
if head1 == None:
return head2
if head2 == None:
return head1
newHead = None
if head1.value < head2.value:
newHead = head1
newHead.next = mergeNodeList(head1.next, head2)
else:
newHead = head2
newHead.next = mergeNodeList(head1, head2.next)
return newHead
#测试数据
h1 = ListNode(1)
m1 = ListNode(7)
t1 = ListNode(12)
h1.next = m1
m1.next = t1
h2 = ListNode(2)
m2 = ListNode(3)
t2 = ListNode(12)
h2.next = m2
m2.next = t2
h = mergeNodeList(h1, h2)
print(h.value)
print(h.next.value)
print(h.next.next.value)
面试题26:树的子结构
题目:输入两棵二叉树A和B,判断B是不是A的子结构。二叉树节点的定义如下:
struct BinaryTreeNode
{
double m_dbValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
如下图:B是A的子结构
A B
8 8
/ \ / \
8 7 9 2
/ \
9 2
/ \
4 7
def hasSubtree(bigTree, smallTree):
if bigTree == None:
return False
if smallTree == None:
return True
def hasSubtreeFuzhu(bigTree, smallTree):
if smallTree == None:
return True
if bigTree == None or bigTree.value != smallTree.value:
return False
else:
return hasSubtreeFuzhu(bigTree.left, smallTree.left) \
and hasSubtreeFuzhu(bigTree.right, smallTree.right)
flag = False
if bigTree.value == smallTree.value and flag == False:
flag = hasSubtreeFuzhu(bigTree, smallTree)
if flag == False:
flag = hasSubtree(bigTree.left, smallTree) or hasSubtree(bigTree.right, smallTree)
return flag
#测试数据
rootA = BinaryTreeNode(8)
l1 = BinaryTreeNode(8)
l2 = BinaryTreeNode(9)
l3 = BinaryTreeNode(4)
r1 = BinaryTreeNode(7)
r2 = BinaryTreeNode(2)
r3 = BinaryTreeNode(7)
rootA.left = l1
rootA.right = r1
l1.left = l2
l1.right = r2
r2.left = l3
r2.right = r3
rootB = BinaryTreeNode(8)
lb1 = BinaryTreeNode(9)
rb1 = BinaryTreeNode(2)
rootB.left = lb1
rootB.right = rb1
print(hasSubtree(rootA, rootB))
面试题27:二叉树的镜像
题目:请完成一个函数,输入一棵二叉树,该函数输出它的镜像。二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_dbValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
如下图所示,两棵二叉树互为镜像。
8 8
/ \ / \
6 10 10 6
/ \ / \ / \ / \
5 7 9 11 11 9 7 5
#二叉树节点类定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def mirrorBinaryTree(root):
if root == None or (root.left == None and root.right == None):
return
tmp = root.left
root.left = root.right
root.right = tmp
mirrorBinaryTree(root.left)
mirrorBinaryTree(root.right)
return
#测试数据
rootA = BinaryTreeNode(8)
l1 = BinaryTreeNode(8)
l2 = BinaryTreeNode(9)
l3 = BinaryTreeNode(4)
r1 = BinaryTreeNode(7)
r2 = BinaryTreeNode(2)
r3 = BinaryTreeNode(7)
rootA.left = l1
rootA.right = r1
l1.left = l2
l1.right = r2
r2.left = l3
r2.right = r3
# A
# 8
# / \
# 8 7
# / \
# 9 2
# / \
# 4 7
mirrorBinaryTree(rootA)
print(rootA.right.left.left.value)
print(rootA.right.left.right.value)
面试题28:对称的二叉树
题目:请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。例如,在下图28-1中的三棵二叉树中,第一课二叉树是对称的,而另外两棵不是。
8 8 7
/ \ / \ / \
6 6 6 9 7 7
/ \ / \ / \ / \ / \ /
5 7 7 5 5 7 7 5 7 7 7
#二叉树节点类定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def isSymmetricBinaryTree(root):
def isSymmettical(treeNode1, treeNode2):
if treeNode1 == None and treeNode2 == None:
return True
if treeNode1 == None or treeNode2 == None:
return False
if treeNode1.value != treeNode2.value:
return False
else:
return isSymmettical(treeNode1.left, treeNode2.right) and \
isSymmettical(treeNode1.right, treeNode2.left)
return isSymmettical(root, root)
#测试数据
# 8
# / \
# 6 6
# / \ / \
# 5 7 7 5
rootA = BinaryTreeNode(8)
l1 = BinaryTreeNode(6)
l2 = BinaryTreeNode(5)
l3 = BinaryTreeNode(7)
r1 = BinaryTreeNode(6)
r2 = BinaryTreeNode(5)
r3 = BinaryTreeNode(7)
rootA.left = l1
rootA.right = r1
l1.left = l2
l1.right = r3
r1.left = l3
r1.right = r2
print(isSymmetricBinaryTree(rootA))
面试题29:顺时针打印矩阵(答案:略)
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如,如果输入如下矩阵:
1 | 2 | 3 | 4 |
---|---|---|---|
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
则依次打印出数字:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10。 |
面试题30:包含min函数的栈(答案:略)
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。
面试题31:栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该压栈序列的弹出序列。
#定义栈
class Stack(object):
def __init__(self):
self.stack = []
def push(self, data):
self.stack.append(data)
def pop(self):
if self.stack:
return self.stack.pop()
else:
raise IndexError('pop from an empty stack')
def peek(self):
if self.stack:
return self.stack[-1]
else:
raise IndexError('stack is empty!')
def isEmpty(self):
return not self.stack
def size(self):
return len(self.stack)
#测试栈用数据
stack = Stack()
stack.push(5)
stack.push(4)
stack.push(3)
print(stack.stack)
print(stack.pop())
print(stack.pop())
print(stack.peek())
#正解
def isPopOrder(pushList, popList):
if pushList == None or popList == None or \
len(pushList) == 0 or len(popList) == 0 or len(pushList) != len(popList):
return False
stack = Stack()
idx = 0
for data in pushList:
stack.push(data)
while not stack.isEmpty() and stack.peek() == popList[idx]:
stack.pop()
idx += 1
return stack.isEmpty()
#测试数据
print(isPopOrder([1,2,3,4,5], [4,5,3,2,1]))
面试题32:从上到下打印二叉树
题目一:不分行从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。例如,输入下图(32-1)中的二叉树,则依次打印出8,6,10,5,7,9,11。二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
8
/ \
6 10
/ \ / \
5 7 9 11
#二叉树节点类定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
#队列类定义
class Queue():
def __init__(self):
self.queue = []
def addTail(self, data):
self.queue.append(data)
def pollHead(self):
if self.queue:
return self.queue.pop(0)
else:
raise IndexError('poll from an empty queue')
def peek(self):
if self.queue:
return self.queue[0]
else:
raise IndexError('queue is empty!')
def isEmpty(self):
return not self.queue
def size(self):
return len(self.queue)
def pirntBinaryTreeNodeFromLeftToRight(root):
if root == None:
return
arr = []
arr.append(root)
while len(arr) > 0:
tmp = arr.pop(0)
if tmp.left != None:
arr.append(tmp.left)
if tmp.right != None:
arr.append(tmp.right)
print(tmp.value, end =' ')
print()
return
#测试数据
# 8
# / \
# 6 10
# / \ / \
# 5 7 9 11
rootA = BinaryTreeNode(8)
l1 = BinaryTreeNode(6)
l2 = BinaryTreeNode(5)
l3 = BinaryTreeNode(9)
r1 = BinaryTreeNode(10)
r2 = BinaryTreeNode(11)
r3 = BinaryTreeNode(7)
rootA.left = l1
rootA.right = r1
l1.left = l2
l1.right = r3
r1.left = l3
r1.right = r2
pirntBinaryTreeNodeFromLeftToRight(rootA)
题目二:分行从上到下打印二叉树。
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。例如,打印上图(32-1)中的二叉树的结果为:
8
6 10
5 7 9 11
def pirntBinaryTreeNodeFromLeftToRightByRow(root):
if root == None:
return
arr = [root]
nextLevel = 0
toBePrint = 1
while len(arr) > 0:
tmp = arr.pop(0)
if tmp.left != None:
nextLevel += 1
arr.append(tmp.left)
if tmp.right != None:
nextLevel += 1
arr.append(tmp.right)
print(tmp.value, end = ' ')
toBePrint -= 1
if toBePrint == 0:
print()
toBePrint = nextLevel
nextLevel = 0
return
#测试数据(如题目一)
pirntBinaryTreeNodeFromLeftToRightByRow(rootA)
题目三:之字形打印二叉树
请实现一个函数,按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。例如,按之字形打印下图(图32-3)中二叉树的结果为:
1
3 2
4 5 6 7
15 14 13 12 11 10 9 8
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ / \ / \ / \
8 9 10 11 12 13 14 15
def pirntBinaryTreeNodeFromLeftToRightByZigzag(root):
if root == None:
return
arr1 = [root]
arr2 = []
nextLevel = 0
toBePrint = 1
flag = True
while len(arr1) > 0 or len(arr2) > 0:
if flag:
while len(arr1) > 0:
tmp = arr1.pop()
if tmp.left != None:
nextLevel += 1
arr2.append(tmp.left)
if tmp.right != None:
nextLevel += 1
arr2.append(tmp.right)
print(tmp.value, end = ' ')
toBePrint -= 1
if toBePrint == 0:
print()
toBePrint = nextLevel
nextLevel = 0
flag = not flag
else:
while len(arr2) > 0:
tmp = arr2.pop()
if tmp.right != None:
nextLevel += 1
arr1.append(tmp.right)
if tmp.left != None:
nextLevel += 1
arr1.append(tmp.left)
print(tmp.value, end = ' ')
toBePrint -= 1
if toBePrint == 0:
print()
flag = not flag
toBePrint = nextLevel
nextLevel = 0
return
#测试数据
# 1
# / \
# 2 3
# / \ / \
# 4 5 6 7
# / \ / \ / \ / \
# 8 9 10 11 12 13 14 15
rootB = BinaryTreeNode(1)
l1_1 = BinaryTreeNode(2)
r1_1 = BinaryTreeNode(3)
l2_1 = BinaryTreeNode(4)
l2_2 = BinaryTreeNode(6)
r2_1 = BinaryTreeNode(5)
r2_2 = BinaryTreeNode(7)
l3_1 = BinaryTreeNode(8)
l3_2 = BinaryTreeNode(10)
l3_3 = BinaryTreeNode(12)
l3_4 = BinaryTreeNode(14)
r3_1 = BinaryTreeNode(9)
r3_2 = BinaryTreeNode(11)
r3_3 = BinaryTreeNode(13)
r3_4 = BinaryTreeNode(15)
rootB.left = l1_1
rootB.right = r1_1
l1_1.left = l2_1
l1_1.right = r2_1
r1_1.left = l2_2
r1_1.right = r2_2
l2_1.left = l3_1
l2_1.right = r3_1
r2_1.left = l3_2
r2_1.right = r3_2
l2_2.left = l3_3
l2_2.right = r3_3
r2_2.left = l3_4
r2_2.right = r3_4
pirntBinaryTreeNodeFromLeftToRightByZigzag(rootB)
面试题33:二叉搜索树的后序遍历序列
题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。例如,输入数组{5,7,6,9,11,10,8},则返回true,因为这个整数序列是下图(图33)二叉搜索树的后序遍历结果。如果输入的数组是{7,4,6,5},则由于没有哪棵二叉搜索树的后序遍历结果是这个序列,因此返回false。
8
/ \
6 10
/ \ / \
5 7 9 11
#二叉树节点类定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def isPostOrderResultOfBinaryTree(arr):
if arr == None or len(arr) <= 0:
return False
def isPostOrderResultOfBinaryTreeFuZhu(arr, start, end):
if arr == None or end <= 0:
return False
restart = 0
for i in range(start, end):
if arr[i] > arr[end]:
restart = i
break
for j in range(restart, end):
if arr[j] < arr[end]:
return False
left = True
if start < restart - 1:
left = isPostOrderResultOfBinaryTreeFuZhu(arr, start, restart - 1)
right = True
if restart < end - 1:
right = isPostOrderResultOfBinaryTreeFuZhu(arr, restart, end - 1)
return left and right
return isPostOrderResultOfBinaryTreeFuZhu(arr, 0, len(arr) - 1)
def isPostorder(ls):
if len(ls) <= 0 or ls == None:
return True
mid = ls[-1]
idx = 0
for i in range(len(ls)):
if ls[i] > mid:
idx = i
break
print("idx: %s" %idx)
left = ls[: idx]
right = ls[idx: -1]
for s in right:
if s < mid:
return False
return isPostorder(left) and isPostorder(right)
#测试数据
# 8
# / \
# 6 10
# / \ / \
# 5 7 9 11
arr = [5,7,6,9,11,10,8]
arr = [7,4,6,5]
print(isPostOrderResultOfBinaryTree(arr))
面试题34:二叉树中和为某一值的路径
题目:输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
10
/ \
5 12
/ \
4 7
图34中,二叉树中有两条和为22的路径:一条路径经过节点10、5、7;另一条路径经过节点10、12。
#二叉树节点类定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def findPath(root, target):
if root == None:
return None
def findPathFuZhu(root, target, res, ls):
if root == None:
return res
ls.append(root.value)
target -= root.value
if target == 0 and root.left == None and root.right == None:
newLs = [i for i in ls]
res.append(newLs)
if target > 0:
findPathFuZhu(root.left, target, res, ls)
findPathFuZhu(root.right, target, res, ls)
if target < 0:
return res
# ls.pop() == del(ls[-1])
del(ls[-1])
return res
res = []
ls = []
res = findPathFuZhu(root, target, res, ls)
return res
#测试数据
# 10
# / \
# 5 12
# / \
# 4 7
rootB = BinaryTreeNode(10)
l1_1 = BinaryTreeNode(5)
r1_1 = BinaryTreeNode(12)
l2_1 = BinaryTreeNode(4)
r2_1 = BinaryTreeNode(7)
rootB.left = l1_1
rootB.right = r1_1
l1_1.left = l2_1
l1_1.right = r2_1
面试题35:复杂链表的复制
题目:请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个节点除了有一个m_pNext指针指向下一个节点,还有一个m_pSibling指针指向链表中的任意节点或者nullptr。节点的C++定义如下:
struct ComplexListNode
{
int m_nValue;
ComplexListNode* m_pNext;
ComplexListNode* m_pSibling;
}
---------
↓ ↑
A-->B-->C-->D-->E
↓ | ↑ ↑
----|---- |
↓ |
-------------
#定义复杂链表节点类
class ComplexListNode():
def __init__(self, value, next=None, sibling=None):
self.value = value
self.next = next
self.sibling = sibling
def copyComplexListNode(head):
if head == None:
return
def cloneNodes(head):
if head == None:
return
node = head
while node != None:
newNode = ComplexListNode(node.value)
nextNode = node.next
node.next = newNode
newNode.next = nextNode
node = nextNode
return
def addSiblingNodes(head):
if head == None:
return
node = head
i = 0
while node != None:
if i % 2 == 0:
siblingNode = node.sibling
if siblingNode != None:
node.next.sibling = siblingNode.next
i += 1
node = node.next
return
def splitNodeList(head):
if head == None:
return
oldHead = head
newHead = head.next
oldTmp = oldHead
newTmp = newHead
while oldTmp != None and newTmp != None:
oldTmp.next = newTmp.next
oldTmp = oldTmp.next
if oldTmp != None:
newTmp.next = oldTmp.next
newTmp = newTmp.next
return [oldHead, newHead]
cloneNodes(head)
addSiblingNodes(head)
return splitNodeList(head)
#测试数据
a = ComplexListNode(1)
b = ComplexListNode(2)
c = ComplexListNode(3)
d = ComplexListNode(4)
e = ComplexListNode(5)
a.next = b
b.next = c
c.next = d
d.next = e
a.sibling = c
b.sibling = e
d.sibling = b
oldAndNew = copyComplexListNode(a)
d = oldAndNew[0]
while d != None:
print(d.value)
if d.sibling != None:
print('sibling.value: %s' %d.sibling.value)
d = d.next
面试题36:二叉搜索树与双向链表
题目:输入一个二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的节点,只能调整树中节点指针的方向。比如,输入下图(图36-1)中左边的二叉搜索树,则输出转换之后的排序双向链表。二叉树的节点定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
10
/ \
6 14 --> 4==6==8==10==12==14==16
/ \ / \
4 8 12 16
#定义二叉树节点
class BinaryTreeNode():
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def convertBinaryTreeToListNode(root):
last = None
def turnBinaryTreeToListNode(root, last):
if root == None:
return root
current = root
if current.left != None:
last = turnBinaryTreeToListNode(current.left, last)
current.left = last
if last != None:
last.right = current
last = current
if current.right != None:
last = turnBinaryTreeToListNode(current.right, last)
return last
newHead = turnBinaryTreeToListNode(root, last)
while newHead.left != None:
newHead = newHead.left
return newHead
# 10
# / \
# 5 12
# / \
# 4 7
rootB = BinaryTreeNode(10)
l1_1 = BinaryTreeNode(5)
r1_1 = BinaryTreeNode(12)
l2_1 = BinaryTreeNode(4)
r2_1 = BinaryTreeNode(7)
rootB.left = l1_1
rootB.right = r1_1
l1_1.left = l2_1
l1_1.right = r2_1
newHead = convertBinaryTreeToListNode(rootB)
while newHead != None:
print(newHead.value)
newHead = newHead.right
面试题37:序列化二叉树
题目:请实现两个函数,分别用来序列化和反序列化二叉树。
序列化规则:根据前序遍历的顺序来序列化二叉树,因为前序遍历是从根节点开始的。在遍历二叉树碰到nullptr指针时,这些nullptr指针序列化为一个特殊的字符(如’$‘)。另外,节点的数值之间要用一个特殊字符(如’,')隔开。
根据这样的序列化规则,则下图(图37-1)中的二叉树被序列化成字符串"1,2,4,$,$,$,3,5,$,$,6,$,$"。
1
/ \
2 3
/ / \
4 5 6
#定义二叉树节点
class BinaryTreeNode():
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
#序列化函数
def serializeBinaryTree(root):
if root == None:
return '$,$'
def serializeBinaryTreeSub(root, rlt):
if root == None:
rlt += '$,'
return rlt
rlt += str('%s,' %root.value)
rlt = serializeBinaryTreeSub(root.left, rlt)
rlt = serializeBinaryTreeSub(root.right, rlt)
return rlt
rlt = serializeBinaryTreeSub(root, '')
return rlt[: -1]
#测试数据
# 10
# / \
# 5 12
# / \
# 4 7
rootB = BinaryTreeNode(10)
l1_1 = BinaryTreeNode(5)
r1_1 = BinaryTreeNode(12)
l2_1 = BinaryTreeNode(4)
r2_1 = BinaryTreeNode(7)
rootB.left = l1_1
rootB.right = r1_1
l1_1.left = l2_1
l1_1.right = r2_1
rlt = serializeBinaryTree(rootB)
print(rlt)
#反序列化函数
def deserializeBinaryTree(strs):
if strs == None or len(strs) <= 0 or strs == '$':
return None
queue = Queue()
ls = strs.split(',')
for s in ls:
if s != ',':
queue.addTail(s)
def deserializeBinaryTreeSub(queue):
if queue.isEmpty():
return None
value = str(queue.pollHead())
root = None
if (value != '$'):
root = BinaryTreeNode(value)
root.left = deserializeBinaryTreeSub(queue)
root.right = deserializeBinaryTreeSub(queue)
return root
root = deserializeBinaryTreeSub(queue)
return root
#测试数据
root = deserializeBinaryTree('10,5,4,$,$,7,$,$,12,$,$')
print(root.value)
print(root.left.value)
print(root.left.left.value)
print(root.left.right.value)
面试题38:字符串的排列
题目:输入一个字符串,打印出该字符串中字符的所有排列。例如,输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bca、cab和cba。
扩展:获得字符串的所有组合,例如输入字符串,则其组合包括’a’,‘b’,‘c’,‘ab’,‘ac’,‘bc’,‘abc’。
def printFullPermutation(strs):
if strs == None or len(strs) <= 0:
return
ls = [s for s in strs]
def printFullPermutationSub(ls, idx):
if ls == None or len(ls) <= 0:
return
if idx < 0 or idx > len(ls):
raise Exception("输入参数不合法!")
#以下为核心代码
if idx == len(ls):
print(''.join(ls))
for i in range(idx, len(ls)):
if i == idx or ls[i] == ls[idx]:
printFullPermutationSub(ls, idx + 1)
continue
exchange(ls, i, idx)
printFullPermutationSub(ls, idx + 1)
exchange(ls, i, idx)
return
def exchange(ls, i, j):
a = ls[i]
ls[i] = ls[j]
ls[j] = a
return
printFullPermutationSub(ls, 0)
return
#测试数据
ls = [s for s in 'abc']
printFullPermutation(ls)
#扩展
def getAllCombination(strs):
result = []
if strs == None or len(strs) <= 0:
return result
def getAllCombinationSub(ls, m, res, result):
if m == 0:
result.append(''.join(res))
return
if len(ls) > 0:
res.append(ls[0])
getAllCombinationSub(ls[1:], m - 1, res, result)
res.pop()
getAllCombinationSub(ls[1:], m, res, result)
ls = [s for s in strs]
for i in range(1, len(ls) + 1):
res = []
getAllCombinationSub(ls, i, res, result)
return result
#测试数据
print(getAllCombination('abc'))
面试题39:数组中出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组{1,2,3,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
def MoreThanHalf(arr):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
tmp = [0, 0]
for i in arr:
if tmp[1] == 0:
tmp[0] = i
tmp[1] = 1
elif tmp[0] == i:
tmp[1] += 1
else:
tmp[1] -= 1
res = tmp[0]
num = 0
for i in arr:
if res == i:
num += 1
if num > (len(arr) >> 1):
print(res)
return res
else:
raise Exception("没有符合条件的值!")
#测试数据
MoreThanHalf([1,1,2,1,1,3,3])
面试题40:最小的k个数(答案:略)
题目:输入n个整数,找出其中最小的k个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
面试题41:数据流中的中位数(答案:略)
题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
面试题42:连续子数组的最大和
题目:输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如,输入的数组为{1,-2,3,10,-4,7,2,-5},和最大的子数组为{3,10,-4,7,2},因此输出为该子数组的和18。
def maxSumOfSubarrays(arr):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
import sys
rlt = -sys.maxsize
current = 0
rltArr = []
currentArr = []
for a in arr:
if current + a < a:
current = a
currentArr = [a]
else:
current += a
currentArr.append(a)
if rlt < current:
rlt = current
rltArr = [a for a in cuurentArr]
print(rlt)
return rlt
#测试数据
maxSumOfSubarrays([1,-2,3,10,-4,7,2,-5])
面试题43:1~n整数中1出现的次数
题目:输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包含1的数字有1、10、11和12,1一共出现了5次。
#方法一
def numberOfOne(n):
if n == None or n <= 0:
return 0
num = 0
def numberOfOneSub(n):
num = 0
while n > 0:
tmp = n - n // 10 * 10
if tmp == 1:
num += 1
n = n // 10
return num
for i in range(1, n + 1):
num += numberOfOneSub(i)
return num
#测试数据
print(numberOfOne(1000))
#方法二,利用全排列
def numberOfOneF(n):
if n == None or n <= 0:
return 0
def fenjie(n):
'''
将一个大于10的整数分解为最大位数保留,其他位数全为0,再减去1.及最大位数的值,及其对应的位数。
例如:fenjie(1000) = 999
例如:fenjie(3521) = 2999
'''
if n < 0:
raise Exception("输入参数不合法!")
if n <= 9:
return (n, -1, 0)
num = 0
while n > 9:
n //= 10
num += 1
if n == 1:
return (n * 10 ** num - 1, 9, num - 1)
else:
return (n * 10 ** num - 1, n - 1, num)
num = 0
while n > 0:
tmp = fenjie(n)
num += 10 ** tmp[2] + (tmp[1] + 1) * 10 ** (tmp[2] - 1) * tmp[2]
n -= tmp[0]
return int(num)
#测试数据
print(numberOfOneF(1000))
print(numberOfOneF(7032572))
7032572 == 6999999 + 29999 + 1999 + 499 + 69 + 7
print(1000000 + 700000 * 6 + 10000 + 3000 * 4 + 1000 + 200 * 3 + 100 + 50 * 2 + 10 + 7 * 1 + 1)
面试题44:数字序列中某一位的数字
题目:数字以0123456789101112131415···的格式序列化到一个字符序列中。在这个序列中,第5位(从0开始计数)是5,第13位是1,第19位是4,等等。请写一个函数,求任意第n位对应的数字。
def digitAtIndex(n):
if n <= 10:
return n - 1
weishu = 2
n = n - 10
while n - weishu * (9 * 10 ** (weishu - 1)) > 0:
n -= weishu * (9 * 10 ** (weishu - 1))
weishu += 1
geshu = n // weishu
yushu = n % weishu
value = 10 ** (weishu - 1) + geshu - 1
rlt = -1
if yushu == 0:
rlt = str(value)[-1]
else:
rlt = str(value + 1)[yushu - 1]
print(rlt)
return rlt
#测试数据
# 0-9:10
# 10-99:2*90
# 100-999:3*900
# 1000-9999:4*9000
digitAtIndex(190)
digitAtIndex(191)
digitAtIndex(2890)
面试题45:把数组排成最小的数
题目:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如,输入数组{3,32,321},则打印出这3个数字能排成的最小数字321323。
def getMinNumOfRange(arr):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
def simulationQuickSort(arr):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
first = 0
last = len(arr) - 1
def compareStr(m, n):
mn = '%s%s' %(m, n)
nm = '%s%s' %(n, m)
flag = True
for i,j in zip(mn, nm):
if i < j:
break
elif i == j:
continue
else:
flag = False
break
return flag
def simulationQuickSortSub(arr, first, last):
if arr == None or first >= last:
return
base = arr[first]
start = first
end = last
while start < end:
if compareStr(base, arr[end]):
end -= 1
elif compareStr(arr[start], base):
start += 1
else:
tmp = arr[start]
arr[start] = arr[end]
arr[end] = tmp
arr[first] = arr[start]
arr[start] = base
simulationQuickSortSub(arr, first, start - 1)
simulationQuickSortSub(arr, start + 1, last)
simulationQuickSortSub(arr, first, last)
simulationQuickSort(arr)
print(''.join(map(str,arr)))
#测试数据
arr = [3,32,321]
getMinNumOfRange(arr)
面试题46:把数字翻译成字符串
题目:给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成"a",1翻译成"b",……,11翻译成"l",……,25翻译成"z"。一个数字可能有多个翻译。例如,12258有5种不同的翻译,分别是"bccfi"、“bwfi”、“bczi”、“mcfi"和"mzi”。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
def numOfMethodsTranslateDigitsToliteral(n):
if n == None or n < 0:
raise Exception("输入参数不合法!")
strs = str(n)
lens = len(strs)
def fuzhu(strs, lens, idx):
if idx >= lens:
return 1
if strs[idx] == '0' or strs[idx] >= '3':
return fuzhu(strs, lens, idx + 1)
elif strs[idx] == '1':
if idx < lens - 1:
return fuzhu(strs, lens, idx + 1) + fuzhu(strs, lens, idx + 2)
else:
return fuzhu(strs, lens, idx + 1)
else:
if idx < lens - 1 and strs[idx + 1] < '6':
return fuzhu(strs, lens, idx + 1) + fuzhu(strs, lens, idx + 2)
else:
return fuzhu(strs, lens, idx + 1)
print(fuzhu(strs, lens, 0))
return fuzhu(strs, lens, 0)
#测试数据
numOfMethodsTranslateDigitsToliteral(12258)
#方法二
def translateNumToStr(strN):
arr = []
lens = len(strN)
def fuZhu(strN, arr, res, idx, lens):
if idx >= lens:
arr.append(''.join(res))
return
if strN[idx] in ['0', '1'] or (strN[idx] == '2' and idx + 1 < lens and strN[idx + 1] <= '5'):
if idx + 1 < lens:
res.append(chr(ord('a') + int(strN[idx])))
fuZhu(strN, arr, res, idx + 1, lens)
res.pop()
res.append(chr(ord('a') + int(strN[idx: idx + 2])))
fuZhu(strN, arr, res, idx + 2, lens)
res.pop()
else:
res.append(chr(ord('a') + int(strN[idx])))
fuZhu(strN, arr, res, idx + 1, lens)
res.pop()
else:
res.append(chr(ord('a') + int(strN[idx])))
fuZhu(strN, arr, res, idx + 1, lens)
res.pop()
return
fuZhu(strN, arr, [], 0, lens)
print(arr)
return len(arr)
#测试数据
translateNumToStr('12258')
面试题47:礼物的最大价值
题目:在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格,直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物?
例如,在下面的棋盘中,如果沿着带下划线的数字的线路(1、12、5、7、7、16、5),那么我们能拿到最大价值为53的礼物。
1 | 10 | 3 | 8 |
---|---|---|---|
12 | 2 | 9 | 6 |
5 | 7 | 4 | 11 |
3 | 7 | 16 | 5 |
#方法一
def maxValueOfGift(gifts):
if gifts == None:
return 0
import numpy as np
rows = np.shape(gifts)[0]
cols = np.shape(gifts)[1]
if rows <=0 or cols <= 0:
return 0
values = [[0 for i in range(rows)] for j in range(cols)]
values[0][0] = gifts[0][0]
for i in range(1, rows):
values[0][i] = gifts[0][i] + values[0][i - 1]
for j in range(1, cols):
values[j][0] = gifts[j][0] + values[j - 1][0]
for i in range(1, rows):
for j in range(1, cols):
values[i][j] = gifts[i][j] + max(values[i - 1][j], values[i][j - 1])
return values[rows - 1][cols - 1]
#方法二
def maxValueOfGift2(gifts):
if gifts == None:
return 0
import numpy as np
rows = np.shape(gifts)[0]
cols = np.shape(gifts)[1]
if rows <=0 or cols <= 0:
return 0
values = [0 for i in range(cols)]
for row in range(0, rows):
for col in range(0, cols):
up = 0
left = 0
if row > 0:
up = values[col]
if col > 0:
left = values[col - 1]
values[col] = gifts[row][col] + max(up, left)
return values[cols - 1]
#测试数据
gifts = [[0 for i in range(4)] for j in range(4)]
gifts[0][0] = 1
gifts[0][1] = 10
gifts[0][2] = 3
gifts[0][3] = 8
gifts[1][0] = 12
gifts[1][1] = 2
gifts[1][2] = 9
gifts[1][3] = 6
gifts[2][0] = 5
gifts[2][1] = 7
gifts[2][2] = 4
gifts[2][3] = 11
gifts[3][0] = 3
gifts[3][1] = 7
gifts[3][2] = 16
gifts[3][3] = 5
print(maxValueOfGift(gifts))
print(maxValueOfGift2(gifts))
面试题48:最长不含重复字符的子字符串
题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含’a’~'z’的字符。例如,在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4。
def maxNoRepeatSubStr(strs):
rlt = ''
tmp = ''
for s in strs:
if s not in tmp:
tmp += s
else:
idx = tmp.index(s)
tmp = tmp[idx + 1:]
tmp += s
if len(tmp) >= len(rlt):
rlt = tmp
print('substr: %s; lens: %s' %(rlt, len(rlt)))
return rlt
maxNoRepeatSubStr('arabcacfr')
maxNoRepeatSubStr('abcdefg')
面试题49:丑数
题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如,6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当作第一个丑数。
def nthChoushu(n):
if n <= 5:
print(n)
return n
rltLs = [0 for i in range(n)]
for i in range(1, 6):
rltLs[i - 1] = i
dicts = {2 : 0, 3 : 0, 5 : 0}
for m in range(5, n):
for i in range(dicts[2], m):
if rltLs[i] * 2 > rltLs[m - 1]:
dicts[2] = i
break
for j in range(dicts[3], m):
if rltLs[j] * 3 > rltLs[m - 1]:
dicts[3] = j
break
for k in range(dicts[5], m):
if rltLs[k] * 5 > rltLs[m - 1]:
dicts[5] = k
break
rltLs[m] = min(rltLs[dicts[2]] * 2, rltLs[dicts[3]] * 3, rltLs[dicts[5]] * 5)
print(rltLs[n - 1])
return rltLs[n - 1]
#测试数据
nthChoushu(1500)
面试题50:第一个只出现一次的字符
题目一:字符串中第一个只出现一次的字符。
在字符串中找出第一个只出现一次的字符。如输入"abaccdeff",则输出"b"。
def firstCharNotRepeat(strs):
if strs == None or len(strs) <= 0:
raise Exception("输入参数不合法!")
dicts = {}
rlt = ''
for s in strs:
dicts[s] = 0
for s in strs:
dicts[s] += 1
for s in strs:
if dicts[s] == 1:
rlt = s
break
if rlt == '':
raise Exception("没有符合条件的值!")
print("第一个只出现一次的字符: %s" %rlt)
return rlt
#测试数据
firstCharNotRepeat("abcabefc")
题目二:字符流中第一个只出现一次的字符。(答案:略)
请实现一个函数,用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是’g’;当从该字符流中读出前6个字符"google"时,第一个只出现一次的字符是’l’。
面试题51:数组中的逆序对
题目:在数组中的两个数字,如果前面一个数字大于后面的数字。则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,6)、(7,5)、(7,4)、(6,4)和(5,4)。
#解答
def numOfReversePair(arr):
if arr == None or len(arr) <= 1:
return 0
count = fuzhuReversePair(arr, 0, len(arr) - 1)
print("逆序对个数: %s" %count)
return count
#辅助
def fuzhuReversePair(arr, first, last):
if first >= last:
return 0
mid = (first + last) >> 1
left = fuzhuReversePair(arr, first, mid)
right = fuzhuReversePair(arr, mid + 1, last)
count = merge(arr, first, mid, last)
return count + left + right
#辅助辅助
def merge(arr, first, mid, last):
if first >= last:
return 0
tmparr = [0 for i in range(last - first + 1)]
p = mid
q = last
idx = last - first
count = 0
while p >= first and q >= mid + 1:
if arr[p] > arr[q]:
count += (q - mid)
tmparr[idx] = arr[p]
p -= 1
idx -= 1
else:
tmparr[idx] = arr[q]
q -= 1
idx -= 1
while p >= first:
tmparr[idx] = arr[p]
p -= 1
idx -= 1
while q > mid:
tmparr[idx] = arr[q]
q -= 1
idx -= 1
for a in tmparr:
arr[first] = a
first += 1
return count
#测试数据
arr = [7,5,6,4]
numOfReversePair(arr)
print(arr)
面试题52:两个链表的第一个公共节点
题目:输入两个链表,找出它们的第一个公共节点。链表节点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
#定义链表节点
class ListNode():
def __init__(self, value, next = None):
self.value = value
self.next = next
def findFirstCommonNode(head1, head2):
if head1 == None or head2 == None:
return None
lens1 = 0
lens2 = 0
newHead1 = head1
newHead2 = head2
while newHead1 != None or newHead2 != None:
if newHead1 != None:
lens1 += 1
newHead1 = newHead1.next
if newHead2 != None:
lens2 += 1
newHead2 = newHead2.next
diff = lens1 - lens2
newHead1 = head1
newHead2 = head2
if diff > 0:
while diff > 0:
newHead1 = newHead1.next
diff -= 1
elif diff < 0:
while diff < 0:
newHead2 = newHead2.next
diff += 1
while newHead1 != newHead2 and newHead1 != None and newHead2 != None:
newHead1 = newHead1.next
newHead2 = newHead2.next
if newHead1 == None or newHead2 == None:
return None
print(newHead1.value)
return newHead1
#测试数据
head1 = ListNode(1)
head1_1 = ListNode(0)
head1_2 = ListNode(2)
head2 = ListNode(3)
mid1 = ListNode(5)
mid2 = ListNode(8)
tail = ListNode(9)
head1.next = head1_1
head1_1.next = head1_2
head1_2.next = mid1
mid1.next = mid2
mid2.next = tail
head2.next = mid1
findFirstCommonNode(head1, head2)
面试题53:在排序数组中查找数字
题目一:数字在排序数组中出现的次数。
统计一个数字在排序数组中出现的次数。例如,输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4。
def timesOfNumberKInSortedArray(arr, target):
if arr == None or len(arr) <= 0:
raise Exception("输入的参数不合法!")
if target < arr[0] or target > arr[len(arr) - 1]:
print("%s 总共出现的次数: 0" %target)
return 0
def getFirstK(arr, k):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
start = 0
end = len(arr) - 1
mid = (start + end) >> 1
while start < end:
mid = (start + end) >> 1
if arr[mid] == k:
if mid == 0 or arr[mid - 1] != k:
return mid
else:
end = mid
elif arr[mid] < k:
start = mid + 1
else:
end = mid - 1
return mid
def getLastK(arr, k):
if arr == None or len(arr) <= 0:
raise Exception("输入参数不合法!")
start = 0
end = len(arr) - 1
mid = (start + end) >> 1
while start < end:
mid = (start + end) >> 1
if arr[mid] == k:
if mid == len(arr) - 1 or arr[mid + 1] != k:
print(mid)
return mid
else:
start = mid
elif arr[mid] < k:
start = mid + 1
else:
end = mid - 1
return mid
left = getFirstK(arr, target)
right = getLastK(arr, target)
print("%s 总共出现的次数: %s" %(target, right - left + 1))
return right - left + 1
#测试数据
timesOfNumberKInSortedArray([1,2,3,3,3,3,4,5], 3)
题目二:0~n-1中缺失的数字。
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0n-1之内。在范围0n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
def findLostNumber(arr):
left = 0
right = len(arr) - 1
mid = (left + right) >> 1
while right >= 0 and left < len(arr) and left <= right:
mid = (left + right) >> 1
if arr[mid] == mid:
left = mid + 1
elif arr[mid] > mid:
right = mid - 1
print("缺失的数字: %s" %left)
return left
#测试数据
findLostNumber([0,1,2,4])
题目三:数组中数值和下标相等的元素
假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实现一个函数,找出数组中任意一个数值等于其下标的元素。例如,在数组{-3,-1,1,3,5}中,数字3和它的下标相等。
def findNumberEqualIdx(arr):
left = 0
right = len(arr) - 1
mid = (left + right) >> 1
while right >= 0 and left < len(arr) and left <= right:
mid = (left + right) >> 1
if arr[mid] == mid:
print("符合的数字即索引: %s" %mid)
return mid
elif arr[mid] > mid:
right = mid - 1
else:
left = mid + 1
if arr[mid] == mid:
print("符合的数字即索引: %s" %mid)
return mid
else:
raise Exception("No suitable element!")
#测试数据
findNumberEqualIdx([-3,-1,1,2,4])
面试题54:二叉搜索树的第k大节点
题目:给定一棵二叉搜索树,请找出其中第k大的节点。例如,在下图54-1中的二叉搜索树里,按节点数值大小顺序,第三大节点的值是4。
5
/ \
3 7
/ \ / \
2 4 6 8
#定义二叉树节点
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def findKthNumber(root, k):
arr = []
def findKthNumberFuZhu(root, arr):
if root.left != None:
findKthNumberFuZhu(root.left, arr)
arr.append(root.value)
if root.right != None:
findKthNumberFuZhu(root.right, arr)
return arr
arr = findKthNumberFuZhu(root, arr)
if k > len(arr):
raise Exception("超出范围啦!")
print(arr[k - 1])
return arr[k - 1]
#测试数据
root = BinaryTreeNode(5)
left = BinaryTreeNode(3, BinaryTreeNode(2), BinaryTreeNode(4))
right = BinaryTreeNode(7, BinaryTreeNode(6), BinaryTreeNode(8))
root.left = left
root.right = right
findKthNumber(root, 7)
面试题55:二叉树的深度
题目一:二叉树的深度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
#定义二叉树节点
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
def depthOfTree(root):
if root == None:
return 0
depth = 1 + max(depthOfTree(root.left), depthOfTree(root.right))
return depth
#测试数据
root = BinaryTreeNode(5)
left = BinaryTreeNode(3, BinaryTreeNode(2), BinaryTreeNode(4, BinaryTreeNode(5)))
right = BinaryTreeNode(7, BinaryTreeNode(6), BinaryTreeNode(9, BinaryTreeNode(8, BinaryTreeNode(10))))
root.left = left
root.right = right
depth = depthOfTree(root)
print(depth)
题目二:平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左、右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如,图55-2中的二叉树就是一棵平衡二叉树。
1
/ \
2 3
/ \ \
4 5 6
/
7
#二叉树节点定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
#从上往下遍历,重复遍历
def isBalanceTree(root):
if root == None:
return True
def depthOfTree(root):
if root == None:
return 0
depth = 1 + max(depthOfTree(root.left), depthOfTree(root.right))
return depth
left = 1 + depthOfTree(root.left)
right = 1 + depthOfTree(root.right)
print("abs: %s" %abs(left - right))
if abs(left - right) > 1:
return False
return isBalanceTree(root.left) and isBalanceTree(root.right)
#从下往上遍历
def isBalanceTree2(root):
if root == None:
return True
def isBalanceTreeFuzhu(root):
if root == None:
return 1
left = isBalanceTreeFuzhu(root.left)
right = isBalanceTreeFuzhu(root.right)
if abs(left - right) > 1:
return 0
return max(left, right) + 1
balance = isBalanceTreeFuzhu(root)
return False if balance == 0 else True
#测试数据
root = BinaryTreeNode(1)
left = BinaryTreeNode(2, BinaryTreeNode(4), BinaryTreeNode(5, BinaryTreeNode(7)))
right = BinaryTreeNode(3, None, BinaryTreeNode(6))
root.left = left
root.right = right
print(isBalanceTree(root))
print(isBalanceTree2(root))
面试题56:数组中数字出现的次数
题目一:数组中只出现一次的两个数字
一个整型数组里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
例如,输入数组{2,4,3,6,3,2,5,5},因为只有4和6这两个数字只出现了一次,其他数字都出现了两次,所以输出4和6。
def findTwoUniqueDigits(arr):
if arr == None or len(arr) <=3:
raise Exception("输入的数组不符合要求!")
tmp = 0
for a in arr:
tmp ^= a
x = 1
while tmp & x == 0:
x = x << 1
rlt1, rlt2 = 0, 0
for a in arr:
if a & x:
rlt1 ^= a
else:
rlt2 ^= a
print("rlt1: %s, rlt2: %s." %(rlt1, rlt2))
return [rlt1, rlt2]
#测试数据
findTwoUniqueDigits([2,4,3,6,3,2,5,5])
题目二:数组中唯一只出现一次的数字
在一个数组中除一个数字只出现一次之外,其他数字都出现了三次,请找出那个只出现一次的数字。
def findUniqueDigitsOtherThree(arr):
bits = [0 for i in range(32)]
for a in arr:
x = 1
for j in range(31, 0, -1):
if a & x:
bits[j] += 1
x = x << 1
rlt = 0
for i in range(32):
rlt = rlt << 1
rlt += bits[i] % 3
print(rlt)
return rlt
#测试数据
findUniqueDigitsOtherThree([3,3,3,4,4,4,5,5,5,6])
面试题57:和为s的数字
题目一:和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
def sumEqualS(arr, s):
if arr == None or len(arr) <= 1:
raise Exception("输入的数组不符合要求!")
left = 0
right = len(arr) - 1
while left < right:
if arr[left] + arr[right] < s:
left += 1
elif arr[left] + arr[right] > s:
right -= 1
else:
break
print(arr[left], arr[right])
return [arr[left], arr[right]]
#测试数据
sumEqualS([1,3,5,6,7,8,10,12,25], 18)
题目二:和为s的连续正数序列
输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如,输入15,由于1+2+3+4=4+5+6=7+8=15,所以打印出3个连续序列1~5、4~6和7~8。
def serialSumEqualS(s):
end = (s >> 1) + 1
sum = 0
arr = []
for i in range(1, end + 1):
sum += i
arr.append('%s' %i)
if sum < s:
continue
elif sum > s:
while sum > s and len(arr) >= 2:
sum -= int(arr[0])
arr.pop(0)
if sum == s:
print(', '.join(arr))
sum -= int(arr[0])
arr.pop(0)
else:
print(', '.join(arr))
sum -= int(arr[0])
arr.pop(0)
#测试数据
serialSumEqualS(15)
面试题58:翻转字符串
题目一:翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如,输入字符串"I am a student.“,则输出"student. a am I”。
#python中字符串无法改变(即无法调整字符串内字符的顺序),故需要先把字符串转换为字符列表,再进行旋转操作。
def flipWordOrder(chars):
def flipWordOrderFuzhu(chars, start, end):
while start < end:
tmp = chars[start]
chars[start] = chars[end]
chars[end] = tmp
start += 1
end -= 1
flipWordOrderFuzhu(chars, 0, len(chars) - 1)
start = 0
for i in range(len(chars)):
if chars[i] == ' ':
flipWordOrderFuzhu(chars, start, i - 1)
start = i + 1
elif i == len(chars) - 1:
flipWordOrderFuzhu(chars, start, i)
return
#测试数据
strs ='abcde e fg.'
print(strs)
chars = list(strs)
flipWordOrder(chars)
print(''.join(chars))
题目二:左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
def turnLeftStrs(chars, num):
if len(chars) <= 0 or chars == None or num > len(chars):
raise Exception('输入参数不符合!')
lens = len(chars)
def flipWordOrderFuzhu(chars, start, end):
while start < end:
tmp = chars[start]
chars[start] = chars[end]
chars[end] = tmp
start += 1
end -= 1
flipWordOrderFuzhu(chars, 0, lens - 1)
flipWordOrderFuzhu(chars, 0, lens - num - 1)
flipWordOrderFuzhu(chars, lens - num, lens - 1)
print(''.join(chars))
return
#测试数据
strs = 'abcdefg'
turnLeftStrs(list(strs), 3)
面试题59:队列的最大值
题目一:滑动窗口的最大值
给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,它们的最大值分别为{4,4,6,6,6,5},如表59-1所示。
——————————————————————————————————————
| 数组中的滑动窗口 | 滑动窗口中的最大值|
——————————————————————————————————————
|[2,3,4],2,6,2,5,1| 4 |
|2,[3,4,2],6,2,5,1| 4 |
|2,3,[4,2,6],2,5,1| 6 |
|2,3,4,[2,6,2],5,1| 6 |
|2,3,4,2,[6,2,5],1| 6 |
|2,3,4,2,6,[2,5,1]| 5 |
——————————————————————————————————————
#时间复杂度稍高
def maxVofQueue(arr, size):
import numpy as np
if arr == None or len(arr) <= 0 or len(arr) < size:
raise Exception("输入参数不符合!")
idx = 0
maxV = -np.inf
maxArr = []
for i in range(size):
if arr[i] >= maxV:
maxV = arr[i]
idx = i
maxArr.append(maxV)
for i in range(size, len(arr)):
if i - idx + 1 > size:
idx += 1
maxV = arr[idx]
for j in range(idx, i + 1):
if arr[j] >= maxV:
maxV = arr[j]
idx = j
else:
if arr[i] >= maxV:
maxV = arr[i]
idx = i
maxArr.append(maxV)
print(maxArr)
return maxArr
#测试数据
maxVofQueue([2,3,4,2,6,2,5,1,6], 2)
#维护索引列表,空间复杂度稍高
def maxVofQueue2(arr, size):
if arr == None or len(arr) <= 0 or len(arr) < size:
raise Exception("输入参数不符合!")
idxDeque = []
maxArr = []
for i in range(size):
while idxDeque and arr[i] >= arr[idxDeque[-1]]:
idxDeque.pop()
idxDeque.append(i)
maxArr.append(arr[idxDeque[0]])
for i in range(size, len(arr)):
while idxDeque and arr[i] >= arr[idxDeque[-1]]:
idxDeque.pop()
if idxDeque and idxDeque[0] < i - size + 1:
idxDeque.pop(0)
idxDeque.append(i)
maxArr.append(arr[idxDeque[0]])
print(maxArr)
return maxArr
#测试数据
maxVofQueue2([2,3,4,2,6,2,5,1,6], 2)
题目二:队列的最大值
请定义一个队列,并实现函数max得到队列里的最大值,要求函数max、push_back和pop_front的时间复杂度都是O(1)。
class MaxValueOfQueue():
def __init__(self, idx = 0, deque1 = [], deque2 = []):
self.deque1 = deque1
self.deque2 = deque2
self.idx = idx
class QueueData():
def __init__(self, idx = None, value = None):
self.idx = idx
self.value = value
def push_back(self, e):
import sys
while self.deque2 and e >= self.deque2[-1].value:
self.deque2.pop()
queueData = self.QueueData(self.idx, e)
self.deque1.append(queueData)
self.deque2.append(queueData)
self.idx += 1
if self.idx == sys.maxsize:
self.idx = 0
def pop_first(self):
if not self.deque1:
raise Exception("队列中没有数据啦!")
if self.deque1[0].idx == self.deque2[0].idx:
self.deque2.pop(0)
return self.deque1.pop(0).value
def max(self):
if not self.deque2:
raise Exception("队列中没有数据啦!")
return self.deque2[0].value
#测试数据
que = MaxValueOfQueue()
que.push_back(6)
que.push_back(4)
que.push_back(5)
que.push_back(3)
que.push_back(0)
que.push_back(-1)
print(que.max())
que.pop_first()
print(que.max())
que.pop_first()
print(que.max())
que.pop_first()
print(que.max())
que.pop_first()
print(que.max())
面试题60:n个骰子的点数
把n个骰子扔在地上,所有骰子朝上一面的点数和为s。输入n,打印出s的所有可能的值出现的概率。
#循环法
def probabilityLoop(n):
def getNSumLoop(n, arr):
if n < 1 or len(arr) < 6 * n - n + 1:
return
arr[0] = arr[1] = arr[2] = arr[3] = arr[4] = arr[5] = 1
if n == 1:
return
#骰子的个数
for i in range(2, n + 1):
for sum in range(6 * i, i - 1, -1):
tmp1 = arr[(sum - (i - 1)) - 1] if (sum - (i - 1)) - 1 >= 0 else 0
tmp2 = arr[(sum - (i - 1)) - 2] if (sum - (i - 1)) - 2 >= 0 else 0
tmp3 = arr[(sum - (i - 1)) - 3] if (sum - (i - 1)) - 3 >= 0 else 0
tmp4 = arr[(sum - (i - 1)) - 4] if (sum - (i - 1)) - 4 >= 0 else 0
tmp5 = arr[(sum - (i - 1)) - 5] if (sum - (i - 1)) - 5 >= 0 else 0
tmp6 = arr[(sum - (i - 1)) - 6] if (sum - (i - 1)) - 6 >= 0 else 0
arr[sum - i] = tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6
return
arr = [0 for i in range(n, 6 * n + 1)]
getNSumLoop(n, arr)
for a in arr:
print('%.2f%% ' %(a * 1.0 / sum(arr) * 100), end = ' ')
print()
#测试数据
probabilityLoop(2)
#动态规划
#动态规划公式(n >=2 时)
# F(n, sum) = F(n-1, sum - 1) + F(n-1, sum - 2) + F(n-1, sum - 3) + F(n-1, sum - 4) + F(n-1, sum - 5) + F(n-1, sum - 6)
def probabilityDynamic(n):
def dynamic(n, sum):
if n < 1 or sum < n or sum > 6 * n:
return 0
if n == 1 and sum >= 1 and sum <= 6:
return 1
return dynamic(n - 1, sum - 1) + dynamic(n - 1, sum - 2) + dynamic(n - 1, sum - 3) + dynamic(n - 1, sum - 4) + dynamic(n - 1, sum - 5) + dynamic(n - 1, sum - 6)
arr = [0 for i in range(n, 6 * n + 1)]
for i in range(n, 6 * n + 1):
arr[i - n] = dynamic(n, i)
total = sum(arr)
for a in arr:
print("%.2f%% " %(a *1.0 / total * 100), end = ' ')
print()
#测试数据
probabilityDynamic(2)
面试题61:扑克牌中的顺子
题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
def shunziInPlayingCard(arr):
def quickSort(arr, start, end):
if end <= start or arr == None or len(arr) <= 1:
return
first = start
last = end
a = arr[first]
while start < end:
if arr[end] >= a:
end -= 1
elif arr[start] <= a:
start += 1
else:
tmp = arr[start]
arr[start] = arr[end]
arr[end] = tmp
# if start > first:
arr[first] = arr[start]
arr[start] = a
quickSort(arr, first, start - 1)
quickSort(arr, start + 1, last)
return
quickSort(arr, 0, len(arr) - 1)
numZero = 0
diff = 0
for i in range(0, len(arr) - 1):
if arr[i] == 0:
numZero += 1
else:
diff += arr[i + 1] - arr[i] - 1
print(numZero)
print(diff)
if diff <= numZero:
return True
else:
return False
#测试数据
print(shunziInPlayingCard([0,0,3,4,6]))
面试题62:圆圈中最后剩下的数字
题目:0,1,···,n-1这个n个数字排成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
def theRemainingNumber(m, n):
a = []
tmp = n
for i in range(m):
tmp -= 1
if tmp != 0:
a.append(i)
else:
tmp = n
continue
while len(a) > 1:
tmp -= 1
if tmp != 0:
a.append(a.pop(0))
else:
tmp = n
a.pop(0)
print(a[0])
return a[0]
#测试数据
theRemainingNumber(5, 3)
面试题63:股票的最大利润
题目: 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?例如,一只股票在某些时间节点的价格为{9,11,8,5,7,12,16,14}。如果我们能够在价格为5的时候买入并在价格为16时卖出,则能收获最大的利润11。
def maxProfitOfStock(arr):
import numpy as np
arr_o = [arr[i] - arr[i - 1] for i in range(1, len(arr))]
max_v = -np.inf
acc = 0
for a in arr_o:
acc = max(acc + a, a)
max_v = max(acc, max_v)
print(max_v)
return max_v
#测试数据
maxProfitOfStock([9,11,8,5,7,12,16,14])
面试题64:求 1+2+···+n
题目:求1+2+···+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
def sumSolution1(n):
sum = pow(n, 2) + n
print(sum >> 1)
return sum >> 1
#测试数据
sumSolution1(5)
def sumSolution2(n):
return n and (n + sumSolution2(n - 1))
#测试数据
print(sumSolution2(5))
面试题65:不用加减乘除做加法
题目:写一个函数,求两个整数之和,要求在函数体内不得使用"+“、”-"、“×”、"÷"四则运算符号。
def getSumWithBitOperation(a, b):
sums = a ^ b
while a & b:
a = (a & b) << 1
b = sums
sums = a ^ b
print(sums)
return sums
#测试数据
getSumWithBitOperation(20,301)
面试题66:构建乘积数组
题目:给定一个数组A[0,1,···,n-1],请构建一个数组B[0,1,···,n-1],其中,B中的元素B[i]=A[0]×A[1]×···×A[i-1]×A[i+1]×···×A[n-1]。不能使用除法。
def buildProductArray(A):
n = len(A)
B = [0 for i in range(n)]
C = [0 for i in range(n)]
D = [0 for i in range(n)]
C[0] = A[0]
D[0] = A[n - 1]
for i in range(1, n):
C[i] = C[i - 1] * A[i]
D[i] = D[i - 1] * A[(n - 1) - i]
for i in range(n):
if i == 0:
B[i] = D[(n - 1) - (i + 1)]
elif i == n - 1:
B[i] = C[i - 1]
else:
B[i] = C[i - 1] * D[(n - 1) - (i + 1)]
print(B)
return B
#测试数据
a = [1, 2, 3, 4]
buildProductArray(a)
面试题67:字符串转换成整数
题目:把字符串转换成整数
def changeStrToInt(strs):
sign = False
flag = True
if strs == None or len(strs) <= 0:
raise Exception("输入的字符串为空或者没有输入任何参数!")
if strs[0] == '0':
for i in range(1, len(strs)):
if strs[i] != '0':
raise Exception("以0开头,但是中间出现了不为0的字符!")
print(0)
return 0
elif strs[0] == '+' or strs[0] == '-':
if len(strs) <= 1:
raise Exception("只有正负号,没有数字,不合法!")
sign = True
if strs[0] == '-':
flag = False
for i in range(1, len(strs)):
if strs[i] > '9' or strs[i] < '0':
raise Exception("输入的字符串中含有不能转化为整数的字符!")
else:
for i in range(len(strs)):
if strs[i] > '9' or strs[i] < '0':
raise Exception("输入的字符串中含有不能转化为整数的字符!")
rlt = 0
if sign:
for i in range(1, len(strs)):
rlt = rlt * 10 + ord(strs[i]) - ord('0')
else:
for i in range(len(strs)):
rlt = rlt * 10 + ord(strs[i]) - ord('0')
print(rlt if flag else -rlt)
return rlt if flag else -rlt
#测试数据
changeStrToInt('-456')
面试题68:树中两个节点的最低公共祖先
题目一:求一棵二叉搜索树的两个节点的最低公共祖先,其中二叉搜索树中每个节点的值都不相同。
#二叉树节点定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
#适用于二叉搜索树
def findLowestPNode(root, child1, child2):
if root == None or child1 == None or child2 == None:
return None
if child1.value > child2.value:
tmp = child1
child1 = child2
child2 = tmp
res = None
if root.value > child1.value and root.value < child2.value:
res = root
if root.value > child1.value and root.value > child2.value:
res = findLowestPNode(root.left, child1, child2)
if root.value < child1.value and root.value < child2.value:
res = findLowestPNode(root.right, child1, child2)
if res !=None:
print(res.value)
return res;
#测试数据
root = BinaryTreeNode(8, BinaryTreeNode(6, BinaryTreeNode(5), BinaryTreeNode(7)), BinaryTreeNode(10, BinaryTreeNode(9), BinaryTreeNode(11)))
child1 = BinaryTreeNode(5)
child2 = BinaryTreeNode(7)
findLowestPNode(root, child1, child2)
题目二:求一棵普通二叉树的两个节点的最低公共祖先。
#二叉树节点定义
class BinaryTreeNode():
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
#普通二叉树(没有父指针)
def findLowestPNodeOrdinary(root, child1, child2):
pathOne = []
pathTwo = []
pathOne.append(root)
pathTwo.append(root)
def findPath(root, child, path):
if root == child:
return True
if root.left != None:
path.append(root.left)
if findPath(root.left, child, path):
return True
path.pop()
if root.right != None:
path.append(root.right)
if findPath(root.right, child, path):
return True
path.pop()
return False
findPath(root, child1, pathOne)
findPath(root, child2, pathTwo)
print(len(pathOne))
print(len(pathTwo))
res = None
for i in range(min(len(pathOne), len(pathTwo)) - 1):
if pathOne[i + 1] != pathTwo[i + 1]:
res = pathOne[i]
break
return res
#递归-普通二叉树(没有父指针)
def findLowestPNodeOrdinaryRecursive(root, child1, child2):
if root == None or root == child1 or root == child2:
return root
left = findLowestPNodeOrdinaryRecursive(root.left, child1, child2)
right = findLowestPNodeOrdinaryRecursive(root.right, child1, child2)
if left == None:
return right
if right == None:
return left
return root
#测试数据
root = BinaryTreeNode(8)
left_1_1 = BinaryTreeNode(6)
left_2_1 = BinaryTreeNode(5)
left_2_2 = BinaryTreeNode(9)
right_1_1 = BinaryTreeNode(10)
right_2_1 = BinaryTreeNode(7)
right_2_2 = BinaryTreeNode(11)
root.left = left_1_1
root.right = right_1_1
left_1_1.left = left_2_1
left_1_1.right = right_2_1
right_1_1.left = left_2_2
right_1_1.right = right_2_2
child1 = left_2_1
child2 = right_2_1
res = findLowestPNodeOrdinary(root, child1, child2)
if res != None:
print(res.value)
res = findLowestPNodeOrdinaryRecursive(root, child1, child2)
if res != None:
print(res.value)
如有问题,欢迎批评指正,谢谢!