题目网站:面经总结
1. 二维数组中的查找
Q:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,
每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,
判断数组中是否含有该整数。
- 思路
矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
因此从左下角开始查找,当要查找数字比左下角数字大时。右移
要查找数字比左下角数字小时,上移
def Find(target, array):
row = len(array)-1
cols = len(array[0])#turn lengh to index
col = 0#row=rows and col=0 located at lower left
while(col < cols and row>=0):
if (target < array[row][col]):
row = row - 1
elif(target > array[row][col]):
col = col + 1
else:
return True #equal means find the item
return False
problem1: 将行数或者列数作为index查询列表时,应-1
problem2: 先行后列(二维数组行列数确定),rows = len(array) cols = len(array[0])
problem3: 边界情况(查询终止条件),包不包含0, 这道题中col不包含,因为col是lenth没有-1,而row-1 本身就是index最小情况是0
sum: 思路上,如果是有序2维列表,可以观察规律,从一角开始查询
2. 旋转数组的最小数字
Q:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
- 思路
解法一:按照旋转规则,查询到后面的元素均小于前面元素,且递增,因此返回第一个小于list[0]的元素即可
def minNumberInRotateArray_1(rotateArray):
if len(rotateArray) == 0:
return 0#when the size of array is 0 return 0
for item in rotateArray:
if item < rotateArray[0]:#find the first item which smaller than array[0]
return item
return rotateArray[0]#Maybe the first item is minimum
解法2: 二分查找,一个left指针指向第一个元素,一个right指针指向最后一个元素,若中间元素大于array[0],则属于前增序列
left指向mid,若mid小于array[0],right指向mid,二分下去,直到两个指针相邻,返回最小者。
目的是找到最中间的元素,根据题目设置,可以判断最中间元素是最小的。
def minNumberInRotateArray_2(rotateArray):
left = 0#initialize the point
right = int(len(rotateArray)-1)
if len(rotateArray) == 0:
return 0#when the size of array is 0 return 0
while (rotateArray[left] >= rotateArray[right]):#end condition:when left < right
mid = int(left + (right - left) / 2)
if right - left == 1:
break
elif(rotateArray[mid] > rotateArray[left]):#situation 1
left = mid
elif(rotateArray[mid] < rotateArray[left]):#situation 2
right = mid
return rotateArray[right]
sum: 二分查找中间值
3. 调整数组顺序奇数位于前面
题目1:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,
所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路:遇到偶数记录当前指针,当遇到下一个奇数时,将其与之前偶数交换
def reOrderArray_1(array):
for i in range(0,len(array)):
if (array[i] % 2 == 0):
j=i#记录当前偶数指针
for k in range(i+1,len(array)):
if (array[k] % 2 != 0):#当再次遇到奇数时
array.insert(j,array.pop(k))#奇数删除,并插入到偶数的位置
break
return array
解法二,开辟新数组
def reOrderArray_2(array):
"""思路:开辟新的数组"""
even =[]
odd=[]
for item in array:
if (item % 2==0):
even.append(item)
else:
odd.append(item)
return odd + even#合并
problem 1: 奇偶判断 %2 == 0
problem 2: 列表插入list.insert(index, object) array.insert(j,array.pop(k))
奇数删除,并插入到偶数的位置
problem 3: 合并两个list 用“+ ”号
4. 顺时针打印矩阵(难)
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,
例如,如果输入如下4 X 4矩阵: 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.
思路1: 左上点和右下点 每次走完剥圈函数之后 左上角坐标++,右下角-- 往圈内移
def printMa(matrix, matrix_res, tR, tC, dR, dC):
"""taverse the matrix by the appointed rule"""
cur_C = tC
cur_R = tR
if (tR == dR):
for i in range(cur_C,dC+1):
matrix_res.append(matrix[tR][i])# 只剩一行,把列输完
elif (tC == dC):
for i in range(cur_R, dR+1):
matrix_res.append(matrix[i][tC])# 只剩一列,把行输完
else:
while (cur_C < dC):#当前列向右遍历完
matrix_res.append(matrix[cur_R][cur_C])
cur_C += 1
while (cur_R < dR):#当前行向下遍历完
matrix_res.append(matrix[cur_R][cur_C])
cur_R += 1
while (cur_C > tC):#当前列向左遍历完
matrix_res.append(matrix[cur_R][cur_C])
cur_C -= 1
while (cur_R > tR):#当前列向上遍历完
matrix_res.append(matrix[cur_R][cur_C])
cur_R -= 1
def printMartrix_2(matrix):
"""print and "remove" the printed items"""
tR = 0
tC = 0
dR = len(matrix)-1
dC = len(matrix[0])-1
matrix_res = []
while(tR <= dR and tC <= dC):
printMa(matrix,matrix_res,tR,tC,dR,dC)
tR += 1#每循环一次,剥去一层,tR已输出行数/2(单侧)dC-tC即当前列数
tC += 1#已输出列数/2(单侧)
dC -= 1#剩余为输出列*2
dR -= 1#剩余未输出行*2
return matrix_res
pro1: range用法,最后一个要+1
sum: 有指针思维这道题中,6个参数都是指针,用于记录当前输出过程,和决定接下来的转向
“”“思路2:可以模拟魔方逆时针旋转的方法,一直做取出第一行的操作
例如
1 2 3
4 5 6
7 8 9
输出并删除第一行后,再进行一次逆时针旋转,就变成:
6 9
5 8
4 7
继续重复上述操作即可。”""
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
result = []
while(matrix):
result+=matrix.pop(0)#将matrix 首元素加入result 中
if not matrix or not matrix[0]:#如果行或者列为空停止
break
matrix = self.turn(matrix)#调用旋转函数
return result
def turn(self,matrix):
num_r = len(matrix)
num_c = len(matrix[0])
newmat = []
for i in range(num_c):
newmat2 = []#选装后的行
for j in range(num_r):
newmat2.append(matrix[j][i])#加入第1列元素,实现方法是先遍历列,再遍历行
newmat.append(newmat2)#最终是第一列,第二列顺序放置
newmat.reverse()#逆序符合要求
return newmat
pro1:result = [ ] ; result+=matrix.pop(0)#将matrix 首元素(嵌套列表多个)加入result 中,由于多个不能用append
pro 2: 内部函数调用 matrix = self.turn(matrix)#调用旋转函数
pro3: 按列输出 for i in range(num_c):
newmat2 = []#选装后的行
for j in range(num_r):
newmat2.append(matrix[j][i])#加入第1列元素,实现方法是先遍历列,再遍历行
newmat.append(newmat2)#最终是第一列,第二列顺序放置
pro4:逆序输出 newmat.reverse()#逆序符合要求
5. 数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。
由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
def MoreThanHalfNum_Solution(self,numbers):
"""返回大于一半数组的数字"""
if len(numbers)==0:
return 0
count = 0
numbers.sort()#排序,重复多次且超过数组数一半的数字一定在数组中间
mid_num = numbers[len(numbers)//2]
for number in numbers:
if number==mid_num:
count += 1
if count >= len(numbers)//2:
return mid_num
else:
return 0
pro1:排序方法 list.sort(cmp=None, key=None, reverse=False)
cmp – 可选参数, 如果指定了该参数会使用该参数的方法进行排序。
key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse – 排序规则,reverse = True 降序, reverse = False 升序(默认)。
6. 连续子数组最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,
常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。
但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?
例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。
给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
实际上就是给定有序数组,计算连续子向量的最大和
- 思路
动态规划:
F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变
F(i)=max(F(i-1)+array[i] , array[i])
res:所有子数组的和的最大值
res=max(res,F(i))
个人理解是分为两步:1、加数字后和数字本身大小对比,如果后者大,只能说明前面有负数,应该舍弃。
2、加数字前和加数字后大小对比,之前的res实际上是作为连续最大值的记忆,体现动态规划原理
如数组[6, -3, -2, 7, -15, 1, 2, 2]
初始状态:
F(0)=6
res=6
i=1:
F(1)=max(F(0)-3,-3)=max(6-3,3)=3
res=max(F(1),res)=max(3,6)=6
i=2:
F(2)=max(F(1)-2,-2)=max(3-2,-2)=1
res=max(F(2),res)=max(1,6)=6
i=3:
F(3)=max(F(2)+7,7)=max(1+7,7)=8
res=max(F(2),res)=max(8,6)=8
i=4:
F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7
res=max(F(4),res)=max(-7,8)=8
以此类推
最终res的值为8
def FindGreatestSumOfSubArray(self, array):
if len(array) == 0:
return 0
cur = array[0]#起始为第一个值,之后要比大小
res = array[0]
for i in range(1,len(array)):#分成两个步骤,1、加上array[i],不加array[i]
cur = max(cur + array[i],array[i])#加上array[i]的最大值,分为加上更大和不加更大两种情况,
res = max(cur, res)#比较,加上或者不加array[i]两种情况
return res
pro1: 和初始值比大小,设为array【0】,迭代从array[1]开始,即i=1