Q:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
A1:遍历整个二位数组(时间复杂度O(n2))
A2:首先选取数组中右上角的数字。如果该数字等于要查找的数字,查找过程结束;如果该数字大于要查找的数字,剔除这个数字所在的列;如果该数字小于要查找的数字,剔除这个数字所在的行。也就是说如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找的范围,直到找到要查找的数字,或者查找范围为空。(左下角同理)(时间复杂度O(n))
class Solution:
def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
if matrix==[]:
return False
else: #左上角元素值最小,右下角最大
i=0
j=len(matrix[0])-1
while i<=len(matrix)-1 and j>=0:
if matrix[i][j]!=target:
if matrix[i][j]>target:
j-=1
else:
i+=1
else:
return True
break
else:
return False
Q:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We arehappy.”,则输出“We%20are%20happy.”。
A1:先遍历一次字符串,这样就能统计出字符串中空格的总数,并可以由此计算出替换之后的字符串的总长度。
首先准备两个指针,P1 和 P2。P1 指向原始字符串的末尾,而 P2 指向替换之后的字符串的末尾。接着向前移动指针 P1,逐个把它指向的字符复制到 P2指向的位置,直到碰到第一个空格为止。碰到第一个空格之后,把P1向前移动1格,在P2之前插入字符串"%20"。由于"%20"的长度为3,同时也要把P2向前移动3格。接着向前复制,直到碰到第二个空格。和上一次一样,再把P1向前移动1格,并把P2向前移动3格插入"%20"。此时P1和P2指向同一位置,表明所有空格都已经替换完毕。
class Solution:
def replaceSpace(self, s: str) -> str:
if s==None or len(s)<=0:
return ''
sumSpace=0
for i in s:
if i==' ':
sumSpace+=1
newLen=len(s)+2*sumSpace
newStr=newLen*[None]
indexOfOriginal,indexOfNew=len(s)-1,newLen-1
while indexOfNew>=0 and indexOfNew>=indexOfOriginal:
if s[indexOfOriginal] == ' ':
newStr[indexOfNew - 2: indexOfNew + 1] = ['%', '2', '0']
indexOfNew -= 3
indexOfOriginal -= 1
else:
newStr[indexOfNew] = s[indexOfOriginal]
indexOfNew -= 1
indexOfOriginal -= 1
return "".join(newStr)
A2:直接使用python内置函数replace
语法:
str.replace(old, new[, max])
参数
•old – 将被替换的子字符串。
•new – 新字符串,用于替换old子字符串。
•max – 可选字符串, 替换不超过 max 次。
class Solution:
def replaceSpace(self, s: str) -> str:
return s.replace(" ","%20")
Q:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。
A:先将链表的结点元素储存进列表,再将列表倒序
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
res=[]
while head:
res.append(head.val)
head=head.next
return res[::-1]
Q:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
A:前序遍历列表:第一个元素永远是 【根节点 (root)】
中序遍历列表:根节点 (root)【左边】的所有元素都在根节点的【左分支】,【右边】的所有元素都在根节点的【右分支】
通过【前序遍历列表】确定【根节点 (root)】
将【中序遍历列表】的节点分割成【左分支节点】和【右分支节点】
递归寻找【左分支节点】中的【根节点 (left child)】和 【右分支节点】中的【根节点 (right child)】
# 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
loc=inorder.index(preorder[0])
root=TreeNode(preorder[0])
root.left=self.buildTree(preorder[1:loc+1],inorder[:loc])
root.right=self.buildTree(preorder[loc+1:],inorder[loc+1:])
return root
Q:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。
A:操作两个“先进后出”的栈实现一个“先进先出”的队列。当 stackout 中不为空时,在stackout中的栈顶元素是最先进入队列的元素,可以弹出。如果stackout为空时,我们把stackin中的元素逐个弹出并压入stackout。由于先进入队列的元素被压到stackin的底端,经过弹出和压入之后就处于stackout的顶端了,又可以直接弹出。
class CQueue:
def __init__(self):
self.stackin=[]
self.stackout=[]
def appendTail(self, value: int) -> None:
self.stackin.append(value)
def deleteHead(self) -> int:
if self.stackout:
return self.stackout.pop()
elif not self.stackin:
return -1
else:
while self.stackin:
self.stackout.append(self.stackin.pop())
return self.stackout.pop()
Q:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
A:旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。最小的元素刚好是这两个子数组的分界线。在排序的数组中可以用二分查找法实现O(logn)的查找。
若中点比末尾元素大,则最小数字出现在后半部分;若中点比末尾元素小,则出现在前半部分。
class Solution:
def minArray(self, numbers: List[int]) -> int:
if len(numbers)==1:
return numbers[0]
mid=(len(numbers)-1)//2
if numbers[mid]>numbers[-1]:
return self.minArray(numbers[mid+1:])
elif numbers[mid]<numbers[-1]:
return self.minArray(numbers[:mid+1])
else:
if len(numbers)>1:
numbers.pop(mid)
return self.minArray(numbers)
Q1:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。
A:用递归方法计算的时间复杂度是以 n 的指数的方式递增的。改进的方法并不复杂。递归代码之所以慢是因为重复的计算太多,只要想办法避免重复计算就行了。比如可以把已经得到的数列中间项保存起来,如果下次需要计算的时候先查找一下,如果前面已经计算过就不用再重复计算了。
class Solution:
def Fibonacci(self, n):
# write code here
num1 = 0
num2 = 1
target = 0
for i in range(1, n+1):
num1 = num2
num2 = target
target = num1 + num2
return target
Q2:一只青蛙一次可以跳上1 级台阶,也可以跳上2 级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
A:跳第n阶有两种情况,由倒数第二阶直接跳到第n阶,倒数第一阶直接跳到第n阶。
class Solution:
def numWays(self, n: int) -> int:
if n==0 :
return 1
elif n<=2:
return n
else:
a=1
b=2
res=0 #a保存f(n-2),b保存f(n-1),res保存f(n-1)+f(n-2)
for i in range(3,n+1):
res=a+b
a=b
b=res
return res
Q:请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
A1:如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。先假设这个数的最右边一位是1,那么减去1时,最后一位变成0而其他所有位都保持不变。也就是最后一位相当于做了取反操作,由1变成了0。接下来假设最后一位不是1 而是0 的情况。如果该整数的二进制表示中最右边1位于第m位,那么减去1时,第m位由1变成0,而第m位之后的所有0都变成1,整数中第m位之前的所有位都保持不变。举个例子:一个二进制数 1100,它的第二位是从最右边数起的一个 1。减去 1 后,第二位变成0,它后面的两位0变成1,而前面的1保持不变,因此得到的结果是1011。在前面两种情况中,我们发现把一个整数减去1,都是把最右边的1变成0。如果它的右边还有0的话,所有的0都变成1,而它左边所有位都保持不变。接下来我们把一个整数和它减去 1 的结果做位与运算,相当于把它最右边的1变成0。还是以前面的1100为例,它减去1的结果是1011。我们再把1100和1011做位与运算,得到的结果是1000。我们把1100最右边的1变成了0,结果刚好就是1000。
把一个整数减去1(都是把最右边的1变成0),再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
class Solution:
def hammingWeight(self, n: int) -> int:
count=0
if n < 0:
n = n & 0xffffffff
while n!= 0:
count += 1
n = (n-1)& n
return count
A2:python内置函数可以直接计算1的个数。
class Solution:
def hammingWeight(self, n: int) -> int:
return bin(n).count('1')
Q:实现函数 double Power(double base, int exponent),求 base 的exponent次方。不得使用库函数,同时不需要考虑大数问题。
A:快速幂的思想。
向下整除 n // 2 等价于 右移一位 n >> 1 ;
取余数 n % 2 等价于 判断二进制最右一位值 n&1 。
class Solution:
def myPow(self, x: float, n: int) -> float:
if x == 0:
return 0
res = 1
if n < 0:
x, n = 1 / x, -n
while n:
if n & 1:
res *= x
x *= x
n >>= 1
return res
Q:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
A1:先求出最大的n位数,然后循环打印输出。
class Solution:
def printNumbers(self, n: int) -> List[int]:
ret=[]
m=pow(10,n)-1
for i in range(1,m+1):
ret.append