关键:寻找重复子问题
递归
#python
def recursion(level, param1,param2,...):
#recursion terminator
if level > MAX_LEVEL:
process_result
return
#process logic in current level
process(level, data...)
#drill down
self.recursion(level + 1,p1,...)
#reverse the current level status if needed
//java
public void recur(int level, int param){
//terminator
if(level > MAX_LEVEL){
//process result
return;
}
//process current logic
process(level,param);
//drill down
recur(level:level+1,newParam);
//restore current status
分治
divide&conquer
#分治代码模板
def divide_conquer(problem,param1,param2,...):
#recursion terminator
if problem is None:
print_result
return
#prepare data
data = prepare_data(problem)
wubproblems = split_problem(problem,data)
#conquer subproblems
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult2=self.divide_conquer(subproblems[1],p1,...)
subresult3=self.divide_conquer(subproblems[2],p1,...)
...
#process and generate the final result
result = process_result(subresult1,subresult2,subresult3...)
#revert thr current level states
回溯
Backtracking
思想是试错
回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
• 找到一个可能存在的正确的答案;
• 在尝试了所有可能的分步方法后宣告该问题没有答案。
在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。
DFS BFS
结点
#python
class TreeNode:
def __init__(self,val):
sef.val = val
self.left,self.right = None,None
//java
public class TreeNode{
public int val;
public TreeNode left,right;
public TreeNode(int val){
this.val = val;
this.left = null;
this.right = null;
}
}
dfs递归
visited = set()
def dfs(node,visited):
if node in visited:#terminator
#already visited
return
visited.add(node)
#process current node here
for next_node in node.children():
if not next_node in visited:
dfs(next_node,visited)
dfs非递归
def DFS(self,tree):
if tree.root id None:
return []
visited,stack=[],[tree,root]
while stack:
node = stack.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
stack.push(nodes)
bfs代码
def bfs(graph ,start,end):
queue =[]
queue.append([start])
visited.add(start)
while queue:
node = queue.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
queue.push(nodes)
贪心算法
Greedy
问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。
每一步选择重都采取在当前状态下最好的选择。
贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
动态规划 和 递归或者分治 没有根本上的区别(关键看有无最优的子结构)
拥有共性:找到重复子问题
差异性:最优子结构、中途可以淘汰次优解
二分查找
目标函数单调
存在上下界(bounded)
能够通过索引访问(index accessible)
left ,right = 0,len(array)-1
while left <= right:
mid = (left +right)/2
if array[mid] == target:
#find the target!!
break or return result
elif array[mid]<target:
left = mid+1
else:
right = mid -1
动态规划
状态转移方程(DP方程)
关键点:
-
最优子结构 opt[n] = best_of(opt[n-1], opt[n-2], …)
-
储存中间状态:opt[i]
-
递推公式(状态转移方程或者 DP 方程)
Fib: opt[i] = opt[n-1] + opt[n-2]
二维路径:opt[i,j] = opt[i+1][j] + opt[i][j+1] (且判断a[i,j]是否空地)