- 面试题31:栈的压入,弹出序列
方法:先判断特殊情况,如果栈1为空或者两个栈的长度不相等的话,直接return False,设置一个辅助栈,设置一个for循环,每次将栈1的数据压入到辅助栈中,然后设置一个while循环,判断辅助栈当前的栈顶元素是否等于栈二的最前面数,如果相等,两个栈都调用pop,一直循环到不等,最后到退出for循环,判断栈1是否为空,如果不是空,return False。
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
if not pushV or len(pushV) != len(popV):
return False
stack = []
for i in pushV:
stack.append(i)
while len(stack) and stack[-1] == popV[0]:
stack.pop()
popV.pop(0)
if len(stack):
return False
return True
- 面试题32:从上到下打印二叉树
方法一:设置一个队列,while循环,挨个取出队列里的数,将它的左右节点挨个放入队列的尾部,停止条件是队列是否为空。
#建立一个队列
def levelorder(root):
if root==None:
return
else:
queue = [root]
ree = []
while queue:
node = queue.pop(0)
res.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return res
方法:需要在上面思路的基础上,while里面需要一个for循环
class Solution:
def levelOrder(self, root):
if not root: return []
res, queue = [],[]
queue.append(root)
while queue:
tmp,tmpnode = [],[]
for node in queue:
tmp.append(node.val)
if node.left: tmpnode.append(node.left)
if node.right: tmpnode.append(node.right)
queue = tmpnode
res.append(tmp)
return res
class Solution:
def levelOrder(self, root):
if not root: return []
res = []
stack1 =[]
stack2 = []
tmp = []
stack1.append(root)
while stack1 :
# 打印奇数层
for _ in range(len(stack1)):
# 从左向右打印
node = stack1.pop()
tmp.append(node.val)
# 先左后右加入下层节点
if node.left: stack2.append(node.left)
if node.right: stack2.append(node.right)
res.append(tmp)
stack1 = []
tmp = []
if not stack2: break # 若为空则提前跳出
# 打印偶数层
for _ in range(len(stack2)):
# 从右向左打印
node = stack2.pop()
tmp.append(node.val)
# 先右后左加入下层节点
if node.right: stack1.append(node.right)
if node.left: stack1.append(node.left)
res.append(tmp)
srack2 = []
tmp = []
return res
- 面试题33:二叉搜索树的后序遍历
方法:二叉搜索树的特点是跟节点的左边都比跟节点的值要小,右边都比它大,后序遍历中,根节点永远在最后,前半部分的值小于跟节点,右边部分的值大于跟节点,所以采用递归,每次取出该部分的最后一个数作为跟节点,将剩下的数分成两部分,如果存在不符合条件的直接return false。
class Solution(object):
def verifyPostorder(self, postorder):
if not postorder:
return True
root = postorder[-1]
length = len(postorder)
for i in range(length): # 找到左子树的区间,此时注意下这样的切分不可能出现左子树中的节点比根节点大
if postorder[i] > root:
break
for j in range(i, length-1):# 如果右子树中存在比根节点的小的值,那么是不符合条件的
if postorder[j] < root:
return False
left = self.verifyPostorder(postorder[:i])#判断左子树是否符合条件
right = self.verifyPostorder(postorder[i:-1])#判断右子树是否符合条件
return left and right
- 面试题34:二叉树中和为某一值的路径
方法:创建一个子函数dfs([], root, expectNumber, res),[]里存放每条路径,res存在符合条件的路径,每次调用self.dfs(list(path), root.left, expectNumber - root.val, res)把期望值减去当前的root值
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
res = []
if root:
self.dfs([], root, expectNumber, res)
return res
def dfs(self, path, root, expectNumber, res):
path.append(root.val)
if (root.val == expectNumber) and (not root.left) and (not root.right):
res.append(path)
if root.left:
self.dfs(list(path), root.left, expectNumber - root.val, res)
if root.right:
self.dfs(list(path), root.right, expectNumber - root.val, res)
- 面试题35:复杂链表的复制
方法一:先复制一份前向链表,利用格外的存储空间建立每个note的哈希对,然后搜索原链表,找到m_pSibling的指向节点,对应的在新链表上添加,太难了!!!
方法二;在原始链表上复制一份一模一样的前向链表,得到a1-a2-c1-c2-d1-d2-w1-w2,然后若a1.m_pSibling=w1,a1.next.m_pSibling=w1.next,这样就可以把所有节点之间的关系全部复制,最后将列表拆成两部分
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
if not pHead:return None
cur = pHead
#insert new node between origin listnode
while cur:
tmp = RandomListNode(cur.label)
tmp.next = cur.next
cur.next = tmp
cur = tmp.next
cur = pHead
# find the random
while cur:
tmp = cur.next
if cur.random:
tmp.random = cur.random.next
cur = tmp.next
# to two listNode
cur = pHead
res = pHead.next
while cur.next:
tmp = cur.next
cur.next = tmp.next
cur = tmp
return res
方法三:python的深拷贝:copy.deepcopy(head)
- 面试题36:二叉搜索树和双向链表
方法:先中序遍历,把结果存到链表中,然后挨个节点遍历,for
i,v in enumerate(self.arr[:-
1]):
v.right = self.arr[i +
1]
self.arr[i +
1
].left = v
class Solution:
def Convert(self, pRootOfTree):
# write code here
if not pRootOfTree:return
self.arr = []
self.midTraversal(pRootOfTree)
for i,v in enumerate(self.arr[:-1]):
v.right = self.arr[i + 1]
self.arr[i + 1].left = v
return self.arr[0]
def midTraversal(self, root):
if not root: return
self.midTraversal(root.left)
self.arr.append(root)
self.midTraversal(root.right)
- 面试题38:序列化二叉树
方法:序列化就是层序遍历,稍微有些不同在于,不需要判断左右节点是否有值直接append,当对每个节点处理时需要判断是否是空,是的话直接输出null;反序列化,需要挨个点遍历,设置一个i记录当前节点的位置
class Codec:
def serialize(self, root):
res = []
listnode = [root]
while listnode:
tmp = []
for i in listnode:
if i:
res.append(i.val)
tmp.append(i.left)
tmp.append(i.right)
else:
res.append('null')
listnode = tmp
return '[' + ( ','.join(str(i) for i in res) )+ ']'
def deserialize(self, data):
if data == '[]': return
vals, i = data[1:-1].split(','), 1
root = TreeNode(int(vals[0]))
queue = collections.deque()
queue.append(root)
while queue:
node = queue.popleft()
if vals[i] != "null":
node.left = TreeNode(int(vals[i]))
queue.append(node.left)
i += 1
if vals[i] != "null":
node.right = TreeNode(int(vals[i]))
queue.append(node.right)
i += 1
return root
面试题39:数组中出现次数超过一半的数字
方法:要找的数字出现的次数比其他所有数字出现次数之和还要多,所以可以把当前数字存下,如果重复出现则次数加一,如果出现的不一样则次数减一,如果次数为0,则保存下新来的数字,次数加一,最后剩下保存的数字即为需要的数字
# -*- coding:utf-8 -*-
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
count = 0
for i in numbers:
if count==0:
temp = i
if i == temp:
count = count+1
else:
count= count-1
return temp
- 面试题40:最小的K个数
方法一:O(n),但是需要修改原始数组,快排的思路,while循环的终止条件是index=k-1
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
# 方法一:partition方法(基于快速排序)
if k > len(arr) or k <= 0:
return []
start = 0
end = len(arr) - 1
index = self.quickSort(arr, start, end)
while index != k-1:
if index > k-1:
end = index - 1
index = self.quickSort(arr, start, end)
if index < k-1:
start = index + 1
index = self.quickSort(arr, start, end)
return arr[:k]
def quickSort(self, arr, left, right):
flag = left
tmp=arr[left]
while left<right:
while left<right and arr[right]>=tmp: #第一步:找右边比左边tmp小的数,移动右边i ndex
right=right-1
while left<right and arr[left]<=tmp: #第三步:找左边比起大的数,移动左边index
left=left+1
arr[right],arr[left] =arr[left],arr[right] #第四步 左边移到右边
arr[left],arr[flag]=arr[flag],arr[left] #标志位和当前的left换
return left
方法二:O(nlogn),特别适用的大规模数据,容器里放k个数,并记录当前最大的数,当新数来的时候进行比较,若小则替换。基于大根堆可以在O(1)时间得到k个数的最大值,nlogn的时间完成最大值的删除和插入。