题目:nums为非空排序数组, 要求return所有subset。比如[1,2,3], 答案是
[
[3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], []
]
def solution(self, nums):
res = [] # res 用来存储答案
subset = [] # subset用来存储subset,相当于一个cache
self.setset(res,nums)
return res
解法1: 属于recursive的遍历DFS,遍历到最后一位的时候把subset记录在答案里,subset就是便利的时候携带的笔记本。
def subset1(self,subset,res,index,nums):
if index == len(nums):
res.append(subset[:])
return
subset.append(nums[index])
self.subset1(subset,res,index+1,nums) # 这种情况就是用第idx个数字
subset.pop(-1)
self.subset1(subset,res,index+1,nums) # 这种情况就是不用idx
解法2: 在进行到index的时候把subset记录在res里,这个思路有点类似于Divide and concur,divide的两组分别是index之前和之后。
def subset2(self,subset,res,index,nums):
res.append(subset[:])
for i in range(index,len(nums)):
subset.append(nums[i])
self.subset2(subset,res,i+1,nums)
subset.pop(-1)
解法3: iterative的排列写法,如果面试被问到需要掌握,注意这里一定要排序nums,因为用temp[-1] < nums[i]来找index
def subset3(self,res,nums):
stack = []
stack.append([])
while stack:
temp = stack.pop()[:]
res.append(temp)
for i in range(len(nums)):
if not temp or temp[-1] < nums[i]:
#相当于没有用temp[-1]到 第i-1个数字
subset = temp[:]
temp.append(nums[i])
stack.append(subset)
return res
遍历:这里用了一个preorder traversal,同时维护了一个pointer,指向最大的node
def traversal(self, root):
res = None # 这个res就是那个容器,记录了最大的节点
self.helper(root, res)
return res
def helper(self, root, res):
if not root:
return
if res and root.val > res.val:
res = root
self.helper(root.left, res)
self.helper(root.right, res)
分治:函数本身就返回了这个最大的节点
def divideConcur(self, root):
if not root:
return root
left = divideConcur(self, root.left)
right = divideConcur(self, root.right)
return self.maxNode(root, left, right) # maxNode返回三个节点,value最大的node
二分法:sqrt(x)
当需用从O(n)或者O(n^2) 优化到O(logn), O(nlogn)时,一般会考虑二分或者二分的思路。二分的思路一般都比较容易想到,但是难点是写二分的时候很容易写出bug,我自己总结的模板是这样的:(以sqrtx这道题为例)
def sqrt(self, x):
def guess(num):
if num * num < x:
return -1
elif num * num == x:
return 0
else:
return 1
left, right = 0, sys.maxint
while left < right - 1:
mid = left + (right - left) / 2
g = guess(mid)
if g == 0:
return mid
elif g < 0:
left = mid
else:
right = mid
if guess(right) <= 0:
return right
else:
return left
这个模板几个点:
1. 有一个guess函数。再简单的情况下不需要这个函数,直接在while循环中计算就可以了,但是如果有比较复杂的二分题目,最好还是写一个guess函数,这样可读性更高;
2. while循环终止的条件是 left < right - 1,这样在终止循环的时候答案可能在mid,left和right三个值中出现,如果mid,就会直接返回;如果left或者right,那么会在跳出循环之后再看;
先看right还是先看left,取决于要求,比如找最大值,那就先看right;如果是找最小值,那就先看left。
while q:
size = len(q)
for i in range(size):
temp = q.pop(0)
ans.append(temp)
for n in temp.neighbors:
if n not in visited:
q.append(n)
visited[n] = True
return ans
与之前不同是每次便利把同一层的node全部便利,这里用到了queue的FIFO特性。注意在for循环的时候一定要先得到q当前的size再loop,因为后面会把新node加入到q,q的size是一直变化的。