视频笔记
(1)算法与数据结构:
任务的安排,不要先入先出。采用优先队列
加密货币,区块链。
必要条: 算法与数据及结构。
算法和数据结构是有用和有趣的。
任务的安排,不要先入先出。采用优先队列
加密货币,区块链。
必要条: 算法与数据及结构。
算法和数据结构是有用和有趣的。
Binary Tree 链表和数结合区块链。
(2)如何事半功倍的学习算法
《outliers》
chunk it up 切碎成知识点
Deliberate practicing 刻意练习
Feedback 反馈
(2)如何事半功倍的学习算法
《outliers》
chunk it up 切碎成知识点
Deliberate practicing 刻意练习
Feedback 反馈
星际争霸: 控兵 运营
Sorting Link_list list spanning tree
Tree_Graph Stack Hashing
Abstrack_data_type{
Tree_Graph Stack Hashing
Abstrack_data_type{
stack{Vector};
Queue{Linked List,
Priority Queue{
Heap
}
};
Queue{Linked List,
Priority Queue{
Heap
}
};
SetP{Hash Set,
Tree Set
}
Map{
Tree Set
}
Map{
Hash Map,
Tree Map
}
Tree Map
}
}
Data struct Aglum
刻意练习:
Feedback 反馈:
主动反馈,
被动反馈。算法和面试题。
Feedback 反馈:
主动反馈,
被动反馈。算法和面试题。
(03)如何计算算法的复杂度
Algorithm
时间复杂度,空间复杂度。
Big O notation
O(1): 常数级
O(N): for循环
O(N^2):for嵌套
O(log(n)): for(int i=0;i<n;i = i*2)
O(k^N): for(int i=0; i<math.pow(2,n);i++)
O(n!):for(int i=0; i<=factorial(n);i++)
累加: 从O(n)---->O(1);
def fib(n):
if n==0 or n==1:
return n
return fib(n-1)+fib(n-2)
常见的算法:
Big O notation
O(1): 常数级
O(N): for循环
O(N^2):for嵌套
O(log(n)): for(int i=0;i<n;i = i*2)
O(k^N): for(int i=0; i<math.pow(2,n);i++)
O(n!):for(int i=0; i<=factorial(n);i++)
累加: 从O(n)---->O(1);
def fib(n):
if n==0 or n==1:
return n
return fib(n-1)+fib(n-2)
常见的算法:
(4):通过leetCode来进行算法题目练习
坚持,刻意练习
https://leetcode.com/problemset/all/
array[2,7,11,15] target = 9
return index
/*
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
return 一个对象
*/
class Solution:
def twoSum(self,nums,target): #nums is array
hash_map = dict() #定义一个map
for i, x in enumerate(nums): #枚举
if target - x in hash_map: #查找是否存在
return [i,hash_map[tatget-x]] #如果存在则把两个都返回
hash_map[x]=i #不存在则放入map
https://leetcode.com/problemset/all/
array[2,7,11,15] target = 9
return index
/*
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
return 一个对象
*/
class Solution:
def twoSum(self,nums,target): #nums is array
hash_map = dict() #定义一个map
for i, x in enumerate(nums): #枚举
if target - x in hash_map: #查找是否存在
return [i,hash_map[tatget-x]] #如果存在则把两个都返回
hash_map[x]=i #不存在则放入map
(5)理论讲解
数组插入:时间复杂度O(N)
链表:插入删除O(1) 查找O(N)
[head] [data,next] [data,next]
链表:插入删除O(1) 查找O(N)
[head] [data,next] [data,next]
反转链表:
def reverseList(self,head):
cur,prev = head, None
while cur:
cur.next,prev,cur = prev,cur,cur.next
return prev
cur,prev = head, None
while cur:
cur.next,prev,cur = prev,cur,cur.next
return prev
节点反转:
def swapPairs(self,head):
pre, pre.next = self,head
while pre.next and pre.next.next:
a = pre.next
b = a.next
prev.next, b.next, a.next = b,a,b.next
pre = a
pre, pre.next = self,head
while pre.next and pre.next.next:
a = pre.next
b = a.next
prev.next, b.next, a.next = b,a,b.next
pre = a
return self.next
判断是否有环:
def hanCycle(self,head):
fast = slow = head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return False
判断是否有环:
def hanCycle(self,head):
fast = slow = head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return False
07 堆栈和队列
消息队列的
www.bigocheatsheet.com
08 判断括号是否有效:
08 判断括号是否有效:
string 大众小括号是否匹配
def isValid(self,s):
stack = []
paren_map = {')':'(',']':'[','}':'{'}
for c in s:
if c not in paren_map: # 返回的是key 是左括号入栈
stact.append(c)
elif not stack of paren_map[c] !=stack.pop():
return False
return not stack #如果不为空
def isValid(self,s):
stack = []
paren_map = {')':'(',']':'[','}':'{'}
for c in s:
if c not in paren_map: # 返回的是key 是左括号入栈
stact.append(c)
elif not stack of paren_map[c] !=stack.pop():
return False
return not stack #如果不为空
public boolean isValid(String s)
{
int lenght;
do{
lenght = s.length();
s = s.replace("()","").replace("{}","").replace("[]","");
{
int lenght;
do{
lenght = s.length();
s = s.replace("()","").replace("{}","").replace("[]","");
}while(lenght != s.length())
return s.lenght() == 0
}
10 优先队列
10 优先队列
用堆实现,二叉搜索树 Mini Heap
11 返回数据流中的第k大的元素
12 返回滑动窗口中最大的值
13 映射和集合
HashMap HashSet TreeMap TreeSet
12 返回滑动窗口中最大的值
13 映射和集合
HashMap HashSet TreeMap TreeSet
Hash Function
108+105+101+115 = 429 429%30 = 9
Hash 碰撞: 拉链法
Hash 碰撞: 拉链法
list_x = [1,2,3,4]
map_x = {
'jack': 100,
'张三':80,
'selina':90
}
map_x = {
'jack': 100,
'张三':80,
'selina':90
}
set_x = {}O(1)的时间复杂度
Hash 的时间复杂度 O(1)
python:
dict hashMap
std::unorderedmap
std::map
python:
dict hashMap
std::unorderedmap
std::map
14:有效的字母异位
1 排序 --》对比 时间复杂度: log(n)
2 使用map 字母计数 时间复杂度: O(N)
1 排序 --》对比 时间复杂度: log(n)
2 使用map 字母计数 时间复杂度: O(N)
Valid Anagram
def isAnagram3(self,s,t):
return sorted(s) == sorted(t)
def isAnagram3(self,s,t):
return sorted(s) == sorted(t)
def isAnagram1(self,s,t):
dict1, dict2 = {},{}
for item in s:
dict[item] = dict.get(item,0)+1
for item in t:
#default -- 如果指定键的值不存在时,返回该默认值值。
dict[item] = dict.get(item,0)+1
return dict == dict
dict1, dict2 = {},{}
for item in s:
dict[item] = dict.get(item,0)+1
for item in t:
#default -- 如果指定键的值不存在时,返回该默认值值。
dict[item] = dict.get(item,0)+1
return dict == dict
def isAnagram2(self,s,t):
dict1 , dict2 = [0]*26, [0]*26 #创建一个数组
for item in s:
dict[ord(item)-ord('a')] +=1
for item in t:
dict[ord(item)-ord('a')] +=1
return dict1 == dict2
16 查找数组中三个数的求和为一个定值
1 暴力: a,b,c,-->3*Loop
2 map set
3 !Loop sorted find
1 暴力: a,b,c,-->3*Loop
2 map set
3 !Loop sorted find
def threeSum(self,nums):
if len(nums) < 3: #数组长度
return []
nums.sort() #排序
res = set() #集合
for i,v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]: 去重
continue
d = {} 空的字典
for x in nums[i+1:]:
if x not in d:
d[-v-x] = 1
else:
res.add((v,-v-x,x))
return map(list,res)
if len(nums) < 3: #数组长度
return []
nums.sort() #排序
res = set() #集合
for i,v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]: 去重
continue
d = {} 空的字典
for x in nums[i+1:]:
if x not in d:
d[-v-x] = 1
else:
res.add((v,-v-x,x))
return map(list,res)
def threeSum(self,nums):
res = []
nums.sort()
for i in xrange(len(nums)-2):
if i> 0 and num[i] == nums[i-1]
continue
if i> 0 and num[i] == nums[i-1]
continue
l,r = i+1,len(nums)-1
while l<r:
s = nums[i]+ nums[l]+ nums[r]
if s < 0: l += 1
else s > 0: r -=1
else:
res.appendd((nums[i],nums[l],nums[r]))
while l < r and nums[l] == nums[l+1]: 去重处理
l+=1
while l < r and nums[r] == nums[r-1]:
r -= 1
l +=1 ;r -=1
while l<r:
s = nums[i]+ nums[l]+ nums[r]
if s < 0: l += 1
else s > 0: r -=1
else:
res.appendd((nums[i],nums[l],nums[r]))
while l < r and nums[l] == nums[l+1]: 去重处理
l+=1
while l < r and nums[r] == nums[r-1]:
r -= 1
l +=1 ;r -=1
return res
Binary Tree
root sub-tree left-tree
分层打印二叉树
Graph:
binary search Tree
18 判断是否是二叉排序树: 时间复杂度
1中序遍历 后 升序 左 根 右
2 recursion: validate
中序变量 左根右
def isValidBST(self,root): 判断是否是二叉树
inorder = self.inorder(root)
return inorder = list(sorted(set(inorder)))
def inorder(self,root):
if root is None:
return
return self.inorder(root.letf) + [root.val] + self.inorder(root.right) 返回的序列 低效
分层打印二叉树
Graph:
binary search Tree
18 判断是否是二叉排序树: 时间复杂度
1中序遍历 后 升序 左 根 右
2 recursion: validate
中序变量 左根右
def isValidBST(self,root): 判断是否是二叉树
inorder = self.inorder(root)
return inorder = list(sorted(set(inorder)))
def inorder(self,root):
if root is None:
return
return self.inorder(root.letf) + [root.val] + self.inorder(root.right) 返回的序列 低效
中序遍历: 不需要全部罗列,只需要保存当前节点
def isValidBST(self, root):
self.prev = None;
return self.helper(root)
def helper(self, root):
if root is None:
return True
if not self.helper(root.left):
return False
if self.prev and self.prev.val >= root.val:
return False
self.prev = root
return self.helper(root.right)
public boolean isValid(TreeNode root,integer min,Integer max)
{
if (root == null) return true;
if (min !=null && root.val <= min) return false;
if (max != null && root.val >= max) return false;
return isValid(root.left,mix,root.val)&&
isValid(root.right,root.val,max);
isValid(root.right,root.val,max);
}
19 二叉树二叉树搜索
1 查找公共祖先: 寻找路径path封装两个节点
找到q记下路径 找到p记下了路径 找到公共系节点
2 Recursion _findPorq(root,p,q) 时间复杂度 O(N)
if root == q or root ==p
findPorq(root.left,p,q)
findPorq(root.right,p,q)
找到q记下路径 找到p记下了路径 找到公共系节点
2 Recursion _findPorq(root,p,q) 时间复杂度 O(N)
if root == q or root ==p
findPorq(root.left,p,q)
findPorq(root.right,p,q)
TreeNode lowestCommonAncestor(TreeNode root, TreeNode p,TreeNode q)
{
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
如果左边也包含 右边也包含 当前节点就是公共节点
return left == null ? right : right == null ? left : root;
TreeNode right = lowestCommonAncestor(root.right,p,q);
如果左边也包含 右边也包含 当前节点就是公共节点
return left == null ? right : right == null ? left : root;
}
二叉搜索树 左边的小于 root 右边的大于root
def lowestCommonAncestor(self, root, p,q):
if p.val < root.val > q.val:
return self.lowestCommonAncestor(root.left,p,q)
if p.val > root.val < q.val:
return self.lowestCommonAnccestor(root.right,p,q)
return root
循环方法
def lowestCommonAncestor(self,root,p,q):
while root:
if p.val < root.val > q.val:
root = root.left
elif p.val > root.val < q.val:
root = root.right
else:
return root
二叉搜索树 左边的小于 root 右边的大于root
def lowestCommonAncestor(self, root, p,q):
if p.val < root.val > q.val:
return self.lowestCommonAncestor(root.left,p,q)
if p.val > root.val < q.val:
return self.lowestCommonAnccestor(root.right,p,q)
return root
循环方法
def lowestCommonAncestor(self,root,p,q):
while root:
if p.val < root.val > q.val:
root = root.left
elif p.val > root.val < q.val:
root = root.right
else:
return root
20 二叉树的遍历:
Pre_order 根左右
def preorder(self,root):
if root:
self.traverse_path.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
In_order 左根右
def inorder(self,root):
if root:
self.inorder(root.left)
self.traverse_path.append(root.val)
self.inorder(root.right)
Post_order 左右根
def postorder(self,root):
if root:
self.postorder(root.left)
self.postorder(root.right)
self.traverse_path.append(root.val)
实用度小
实用度高的广度和深度
Pre_order 根左右
def preorder(self,root):
if root:
self.traverse_path.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
In_order 左根右
def inorder(self,root):
if root:
self.inorder(root.left)
self.traverse_path.append(root.val)
self.inorder(root.right)
Post_order 左右根
def postorder(self,root):
if root:
self.postorder(root.left)
self.postorder(root.right)
self.traverse_path.append(root.val)
实用度小
实用度高的广度和深度
21 递归&分治
是一种循环。自己调用自己。死循环,死递归
盗梦空间
一层--》二层--三层--四层(中止)--三层--二层--一层
n!
def Factorial(n):
if n<=1: 终止条件
return 1
return n*Factorial(n-1)
是一种循环。自己调用自己。死循环,死递归
盗梦空间
一层--》二层--三层--四层(中止)--三层--二层--一层
n!
def Factorial(n):
if n<=1: 终止条件
return 1
return n*Factorial(n-1)
开始判断层级,
def recursion(level,param1,param2,...):
终止条件
if level > MAX_LEVEL: 到达层次限制 返回
print_result
return
业务逻辑
process_data(level,data...) 做自己要做的事
调用下一层
self.recursion(level+1,p1,..)
收尾工作
reverse_state(level)
def recursion(level,param1,param2,...):
终止条件
if level > MAX_LEVEL: 到达层次限制 返回
print_result
return
业务逻辑
process_data(level,data...) 做自己要做的事
调用下一层
self.recursion(level+1,p1,..)
收尾工作
reverse_state(level)
fib
def fib(n):
if n==0 or n==1:
return n
return fib(n-1)+f(n-2)
def fib(n):
if n==0 or n==1:
return n
return fib(n-1)+f(n-2)
分治: Divde& Conquer
动态规划,子问题记忆
动态规划,子问题记忆
def divide_conquer(problem,param1,param2,..)
if problem is None:
print_result
reutrn
data = prepare_data(problem)
subproblems = split_problem(problem,data)
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult1 = self.divide_conquer(subproblems[0],p1,...)
...
result = process_result(subresult1,subresult1,subresult1)
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult1 = self.divide_conquer(subproblems[0],p1,...)
...
result = process_result(subresult1,subresult1,subresult1)
Pow(x,n)
1调用库函数 0(1)
2暴力;O(N)
3分治 O(log(n))
2暴力;O(N)
3分治 O(log(n))
def myPow(self,x,n):
if not m:
return 1
if n<0:
return 1/self.myPow(x,-n)
if n%2:
reutrn x*self.myPow(x,n-1)
return self.myPow(x*x,n/2)
if not m:
return 1
if n<0:
return 1/self.myPow(x,-n)
if n%2:
reutrn x*self.myPow(x,n-1)
return self.myPow(x*x,n/2)
非递归
def myPow(self,x,n):
if n<0:
x = 1/x
n = -n
pow = 1 用于结果返回
while n:
if n&1:
pow * = x
x *= x
n >>=1 等于n除以2
return pow
def myPow(self,x,n):
if n<0:
x = 1/x
n = -n
pow = 1 用于结果返回
while n:
if n&1:
pow * = x
x *= x
n >>=1 等于n除以2
return pow
23找出的数组的元素的出现的次数大于 2分之长度的element
1 暴力循环:两层循环 count(x) 复杂度O(N平方)
2Map {x(key):count(值)} 时间复杂度O(N)
空间O(N)
3sort 时间复杂度O(NlogN)
4分治 数组一分为二,左边寻找 右边查找
return count(left) > count(right) ? left : right
时间复杂度O(NlogN)
1 暴力循环:两层循环 count(x) 复杂度O(N平方)
2Map {x(key):count(值)} 时间复杂度O(N)
空间O(N)
3sort 时间复杂度O(NlogN)
4分治 数组一分为二,左边寻找 右边查找
return count(left) > count(right) ? left : right
时间复杂度O(NlogN)
24贪心算法
在当前看来最好选择
算价值36的面额的纸币
问题能过分成子问题来解决。最优子结构。
贪心算法,对每个子问题的解决方案都做出选择,不能回退。 动态规划则会保存以前的运算结果。并根据以前的结果对当前进行选择。有回退功能。
在当前看来最好选择
算价值36的面额的纸币
问题能过分成子问题来解决。最优子结构。
贪心算法,对每个子问题的解决方案都做出选择,不能回退。 动态规划则会保存以前的运算结果。并根据以前的结果对当前进行选择。有回退功能。
25买卖股票问题
搜索贪心算法
最多持有1股 买卖无数次
1 搜索DFS 时间复杂度O(N)
2 贪心法每日买卖O(n)
3 DP时间复杂度O(n)
26 广度优先搜索
寻找特定的节点。在二叉树中怎么查找value == 100
计算机查找: 内存扫荡,整个数据的扫荡
一层一层访问。地毯式搜索。将一层一层的加入队列。
搜索贪心算法
最多持有1股 买卖无数次
1 搜索DFS 时间复杂度O(N)
2 贪心法每日买卖O(n)
3 DP时间复杂度O(n)
26 广度优先搜索
寻找特定的节点。在二叉树中怎么查找value == 100
计算机查找: 内存扫荡,整个数据的扫荡
一层一层访问。地毯式搜索。将一层一层的加入队列。
def BFS(graph,start,end):
queue = [] 数组
queue = [] 数组
queue.append([start])
visited.add(start) 任何被访问的加入集合
visited.add(start) 任何被访问的加入集合
while queue:
node = queue.pop()
visited.add(node) 标记已经被访问过
node = queue.pop()
visited.add(node) 标记已经被访问过
process(node)
找后继节点,没有没有被问过 访问
nodes = generate_related_nodes(node)
queue.push(nodes)
找后继节点,没有没有被问过 访问
nodes = generate_related_nodes(node)
queue.push(nodes)
27 深度优先搜索
为什么要深度搜索?计算机一根经一查到底。
为什么要深度搜索?计算机一根经一查到底。
visited = set() 保存访问过的节点
def dfs(node,visited):
visited.add(node)
...
for next_node in node.children:
if not next_node in visited:
dfs(next_node,visited)
def dfs(node,visited):
visited.add(node)
...
for next_node in node.children:
if not next_node in visited:
dfs(next_node,visited)
def DFS(self,tree):
if tree.root is Node:
return []
visited,stackt = [],[tree.root]
if tree.root is Node:
return []
visited,stackt = [],[tree.root]
while stack:
#访问节点
node = stack.pop()
添加到访问集
visited.add(node)
#访问节点
node = stack.pop()
添加到访问集
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
stack.push(nodes)
nodes = generate_related_nodes(node)
stack.push(nodes)
28 对二叉树按层输出节点:
1 BFS 广度优先 判断属于那一层
循环 时间复杂度O(N)
2 DFS 数组,记住深度。
1 BFS 广度优先 判断属于那一层
循环 时间复杂度O(N)
2 DFS 数组,记住深度。
class Solution(object):
def levelOrder(self,root):
if not root: return []
result = []
queue = collections.deque() 双端队列
把根节点加入
queue.append(root)
def levelOrder(self,root):
if not root: return []
result = []
queue = collections.deque() 双端队列
把根节点加入
queue.append(root)
#visited = set(root)
while queue:
取出层的长度
level_size = len(queue)
current_level = []
for _ in rang(level_size):
#取出当前层中队列中的节点
node = queue.popleft()
取出当前层中节点的值
current_level.append(node.val)
把节点的下一层放入队列
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(current_level)
取出层的长度
level_size = len(queue)
current_level = []
for _ in rang(level_size):
#取出当前层中队列中的节点
node = queue.popleft()
取出当前层中节点的值
current_level.append(node.val)
把节点的下一层放入队列
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
result.append(current_level)
return result
深度优先
class Solution(object):
def levelOrder(self,root): 获得根节点
if not root: return []
self.result = [] 返回集
self._dfs(root,0) 调用函数
return self.result
参数: 节点 深度
私有函数
def _dfs(self,node,level):
if not node: return
结果比当前行还要小
if len(self.result) < level+1:
self.result.append([])
一维为层 二维为值
self.result[level].append(node.val)
深度优先
class Solution(object):
def levelOrder(self,root): 获得根节点
if not root: return []
self.result = [] 返回集
self._dfs(root,0) 调用函数
return self.result
参数: 节点 深度
私有函数
def _dfs(self,node,level):
if not node: return
结果比当前行还要小
if len(self.result) < level+1:
self.result.append([])
一维为层 二维为值
self.result[level].append(node.val)
self._dfs(node.left,level+1)
self._dfs(node.right,level=1)
self._dfs(node.right,level=1)
29 二叉树最大最小的深度:
2 BFS 按层扫荡 判断是否是叶子接待你
3 退进,记住max ,min 时间复杂度o(n)
找最大深度;
class Solution:
def maxDepth(self,root):
if not root: return 0
1 自己本身深度的一层
return 1+max(self.maxDepth(root.left),self.maxDepth(root.right))
def maxDepth(self,root):
if not root: return 0
1 自己本身深度的一层
return 1+max(self.maxDepth(root.left),self.maxDepth(root.right))
class Solution{
public:
int minDepth(TreeNode* root)
{
if(!root) return 0;
if(!root->left) return 1+minDepth(root->left);
if(!root-right) return 1+minDepth(root->right)
分治
int leftMinDepth = minDepth(root->left);
int rightMinDepth = minDepth(root->right);
返回当前层的最小深度
int result = 1 + min(leftMinDepth,rightMinDepth);
return result;
}
public:
int minDepth(TreeNode* root)
{
if(!root) return 0;
if(!root->left) return 1+minDepth(root->left);
if(!root-right) return 1+minDepth(root->right)
分治
int leftMinDepth = minDepth(root->left);
int rightMinDepth = minDepth(root->right);
返回当前层的最小深度
int result = 1 + min(leftMinDepth,rightMinDepth);
return result;
}
}
java
public class Solution{
public int minDepth(TreeNode root){
if (root == NULL) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
左右的较小者加1
return (left ==0 || right ==0) ? left + right +1 : Math.min(left,right)+1;
public class Solution{
public int minDepth(TreeNode root){
if (root == NULL) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
左右的较小者加1
return (left ==0 || right ==0) ? left + right +1 : Math.min(left,right)+1;
}
}
30 生成括号:
给定一个n , 输出所有匹配的括号
1 数学归纳法
2 递归搜索,字符串的长度为2 * n
把所有的可能配皮全部罗列出来,去除不合法的
3 1 局部不合法减枝,不再递归
2 leftused, rightused O(2的n次方)
class Solution(object);
def generationParenthesis(self,n):
self.list = []
self._gen(0,0,n," ")
return self.list
左边的括号已经用了多少个
def _gen(self,left,right,n,reslet):
终止条件 括号的数量是否已经用完了
if left == n and right ==n:
self.list.append(result)
return
if left < n:
self._gen(left + 1,right, n,result+"(")
if left > right and right < n:
self._gen(left,right+1,n,result +")")
def generationParenthesis(self,n):
self.list = []
self._gen(0,0,n," ")
return self.list
左边的括号已经用了多少个
def _gen(self,left,right,n,reslet):
终止条件 括号的数量是否已经用完了
if left == n and right ==n:
self.list.append(result)
return
if left < n:
self._gen(left + 1,right, n,result+"(")
if left > right and right < n:
self._gen(left,right+1,n,result +")")
31 剪枝
32 N-queues
DFS 搜索
枚举列,第一层放置位置,判断能不能方
1 暴力
2 剪枝 数组row[i],col[j] 把行和列标志为1
pie[i+j] = 1
na[i-j] = 1
DFS 搜索
枚举列,第一层放置位置,判断能不能方
1 暴力
2 剪枝 数组row[i],col[j] 把行和列标志为1
pie[i+j] = 1
na[i-j] = 1
遍历level 判断当前层是否有i,j是否满足
遍历下一层
遍历下一层
def solveNQueue(self,n):
f
if n<1 return []
结果集
self.result = []
self.cols = set();self.pie = set();self.na = set()
self.DFS(n,0,[])
return self.result
def DFS(self,n,row,cur_state):
终止条件
if row >=n:
把结果放入结果集
self.result.append(cur_state)
return
for col in rang(n):
列被之前占用
if col in self.cols or row + col in self.pie or row -col in self.na:
continue
把皇后放入这个位置
没有占用把这一行放入结果集
self.cols.add(col)
self.pie.add(row+col)
self.na.add(row-col)
f
if n<1 return []
结果集
self.result = []
self.cols = set();self.pie = set();self.na = set()
self.DFS(n,0,[])
return self.result
def DFS(self,n,row,cur_state):
终止条件
if row >=n:
把结果放入结果集
self.result.append(cur_state)
return
for col in rang(n):
列被之前占用
if col in self.cols or row + col in self.pie or row -col in self.na:
continue
把皇后放入这个位置
没有占用把这一行放入结果集
self.cols.add(col)
self.pie.add(row+col)
self.na.add(row-col)
self.DFS(n,row+1,cur_state+[col])
清空现场
self.cols.remove(col)
self.pie.remove(row+col)
self.na.remove(row-col)
def _geerate_result(self,n):
board = []
for res in self.result:
for i in res:
board.append(.*i+'Q'+'.'*(n-i))
return [board[i: i+n] for i in range(0,len(board),n)]
清空现场
self.cols.remove(col)
self.pie.remove(row+col)
self.na.remove(row-col)
def _geerate_result(self,n):
board = []
for res in self.result:
for i in res:
board.append(.*i+'Q'+'.'*(n-i))
return [board[i: i+n] for i in range(0,len(board),n)]
range(start, stop[, step])
参数说明:
start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
参数说明:
start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
def so(self,n):
def df(queue,xy_dif,xy_sum):
p = len(queue)
if p == n:
result.append(queue)
return None
for q in range(n):
if q not in queue and p-q not in xy_dif and p+q not in xy_sum:
df(queue+[q],xy_dif+[p-q],xy_sum+[p+q])
result = []
df([],[],[])
生成二维数组
print ([["."*i+"Q"+"."*(n-i-1) for i in sol] for sol in result])
def df(queue,xy_dif,xy_sum):
p = len(queue)
if p == n:
result.append(queue)
return None
for q in range(n):
if q not in queue and p-q not in xy_dif and p+q not in xy_sum:
df(queue+[q],xy_dif+[p-q],xy_sum+[p+q])
result = []
df([],[],[])
生成二维数组
print ([["."*i+"Q"+"."*(n-i-1) for i in sol] for sol in result])
public void solveSudoku(char[][] board)
{
if (board == null || board.lenght ==0) return ;
solve(board);
{
if (board == null || board.lenght ==0) return ;
solve(board);
}
public blooean solve(char [][] board)
{
for (int i = 0; i < board.length;i++) for (int j < board[0].length; j++){
if (board[i][j] == "."){
for (char c = '1'; c <= '9'; c++){
if (isvalid(board,i,j,c)){
board[i][j] = c;
递归调用
if (solve(board))
return true
else
不然 还原
board[i][j] = '.';
}end 判断合法
}end 枚举可以放入的字符
1-9 都不能放入 返回
return false;
} end 判断是否为空格
}
{
for (int i = 0; i < board.length;i++) for (int j < board[0].length; j++){
if (board[i][j] == "."){
for (char c = '1'; c <= '9'; c++){
if (isvalid(board,i,j,c)){
board[i][j] = c;
递归调用
if (solve(board))
return true
else
不然 还原
board[i][j] = '.';
}end 判断合法
}end 枚举可以放入的字符
1-9 都不能放入 返回
return false;
} end 判断是否为空格
}
return true
}
// 判断是否有重复的
private boolean isValid(char[][] board, int row, int col, char c){
// 9*9的方格
for(int i = 0;i < 9; i++)
{
if(board[i][col] != '.' && board[i][col] ==c) return false; // check row
if(board[row][i]!= '.' && board[row][i]== c) return false; check column
if(board[3*(row/3) + i /3][3* (col/3)+i%3] !='.' && board[3*(row/3) + i /3][3* (col/3)+i%3] == c) return false; //check 3*3
// 判断是否有重复的
private boolean isValid(char[][] board, int row, int col, char c){
// 9*9的方格
for(int i = 0;i < 9; i++)
{
if(board[i][col] != '.' && board[i][col] ==c) return false; // check row
if(board[row][i]!= '.' && board[row][i]== c) return false; check column
if(board[3*(row/3) + i /3][3* (col/3)+i%3] !='.' && board[3*(row/3) + i /3][3* (col/3)+i%3] == c) return false; //check 3*3
}
return true;
}
return true;
}
34 二分查找 时间复杂度log(n)
left, right = 0,len(array)-1
while left <= right:
mid = (left + right)/2
if array[mid] == target:
brear or return result
elif array[mid] < target :
left = mid + 1
else :
right = mid -1
35 开平方
target = 5
1 二分法查找
2 牛顿迭代法
double squrt(int x, double flag){
if(x == 0||x == 1) return x;
int l = 1, r = x, res;
while (l <=r){
int m = (l+r)/2
if (m == x/m){
return m;
if(x == 0||x == 1) return x;
int l = 1, r = x, res;
while (l <=r){
int m = (l+r)/2
if (m == x/m){
return m;
}else if (m > x /m) 更新右边界
{
r = m-1;
{
r = m-1;
}else{ 更新左边界
l = m+1;
res = m; 跳出循环后的返回
}
}
l = m+1;
res = m; 跳出循环后的返回
}
}
return res;
}
}
牛顿迭代法:
class Solution(object):
def mySqurt(self,x):
r = x
while r*r > x:
r = (r+ x/r) /2
return r
class Solution(object):
def mySqurt(self,x):
r = x
while r*r > x:
r = (r+ x/r) /2
return r
36 字典树
trie数据结构,最大限度查询
空间换时间的办法。
根节点不包含字符, 路径上对应的字符组成的
字节不相同。
trie数据结构,最大限度查询
空间换时间的办法。
根节点不包含字符, 路径上对应的字符组成的
字节不相同。
static final int ALPHTABLET_SIZE = 256
static class TrieNode{
//有一个孩子节点数组
TrieNode[] children = new TrieNode[ALPHTABLET_SIZE];
// 是不是字符
boolean isEndOfword = false;
TriNode(){
isEndOFWord = false; //不是字符
for (int i =0;i < ALPHTABLET_SIZE; i++)
{
static class TrieNode{
//有一个孩子节点数组
TrieNode[] children = new TrieNode[ALPHTABLET_SIZE];
// 是不是字符
boolean isEndOfword = false;
TriNode(){
isEndOFWord = false; //不是字符
for (int i =0;i < ALPHTABLET_SIZE; i++)
{
children[i] = NULL; 初始化孩子节点
}
}
}
}
public class Solution{
Set<string> res = new HashSet<string>();
public List<string> findWords(char[][] board,String[] words){
创建一个字典树
Trie trie = new Trie();
把要匹配的字母添加到字典树中
for (String word: words)
{
trie.insert(word);
}
字母表的维度和长度
int m = board.lenght();
int n = board[0].length();
字母表的维度和长度
int m = board.lenght();
int n = board[0].length();
boolenn[][] visited = new boolean[m][n];
for (int i = 0; i < m;i++)
for (int j = 0;j < n;j++){
dfs(board,visited,"",i,j,trie);
}
for (int i = 0; i < m;i++)
for (int j = 0;j < n;j++){
dfs(board,visited,"",i,j,trie);
}
}
return new ArrayList<string>(res)
return new ArrayList<string>(res)
}
public void dfs(char[][] board,boolean[][] visited,String str, int x,int y, Trie tire){
if(x < 0 || x >= board.length || y < 0 || y>=board[0].lendgth) return ;
如果被访问过
if (visited[x][y]) return ;
str +=board[x][y];
是不是前缀
if(!trie.startWith(str)) return;
if(trie.seach(str)){
res.add(str);
}
改变访问标志
visited[x][y] = true;
递归遍历左边
dfs(board,visited,str,x-1,y,trie);
递归调用右边
dfs(board,visited,str,x+1,y,trie);
递归调用下边
dfs(board,visited,str,x,y-1,trie);
递归调用上边
dfs(board,visited,str,x,y+1,trie);
visited[x][y] = false;
}
if(x < 0 || x >= board.length || y < 0 || y>=board[0].lendgth) return ;
如果被访问过
if (visited[x][y]) return ;
str +=board[x][y];
是不是前缀
if(!trie.startWith(str)) return;
if(trie.seach(str)){
res.add(str);
}
改变访问标志
visited[x][y] = true;
递归遍历左边
dfs(board,visited,str,x-1,y,trie);
递归调用右边
dfs(board,visited,str,x+1,y,trie);
递归调用下边
dfs(board,visited,str,x,y-1,trie);
递归调用上边
dfs(board,visited,str,x,y+1,trie);
visited[x][y] = false;
}
字典树
class TrieNode:
def __init__(self):
// type of list
self.children = [None] * ALPHTABLET_SIZE
self.isEndofWord = False
方向数组
dx = [-1,1,0,0]
dy = [0,0,-1,1]
END_OF_WORD = "#"
class TrieNode:
def __init__(self):
// type of list
self.children = [None] * ALPHTABLET_SIZE
self.isEndofWord = False
方向数组
dx = [-1,1,0,0]
dy = [0,0,-1,1]
END_OF_WORD = "#"
class Solution(object):
参数判断
def findWords(self, board, words):
if not board or not board[0]: return []
if not words: return []
装载结果
self.result = set()
Python中通过Key访问字典,当Key不存在时,会引发‘KeyError’异常。为了避免这种情况的发生,可以使用collections类中的defaultdict()方法来为字典提供默认值。
空的字典
字典树的节点
root = collections.defaultdict();
把
for word in words:
node = root
for char in word:
node = node.setdefault(char,collection.defaultdict())
node[END_OF_WORD]=END_OF_WORD
字母表的大小
self.m self.n = len(board),len(board[0])
参数判断
def findWords(self, board, words):
if not board or not board[0]: return []
if not words: return []
装载结果
self.result = set()
Python中通过Key访问字典,当Key不存在时,会引发‘KeyError’异常。为了避免这种情况的发生,可以使用collections类中的defaultdict()方法来为字典提供默认值。
空的字典
字典树的节点
root = collections.defaultdict();
把
for word in words:
node = root
for char in word:
node = node.setdefault(char,collection.defaultdict())
node[END_OF_WORD]=END_OF_WORD
字母表的大小
self.m self.n = len(board),len(board[0])
for i in xrange(self.m):
for j in xrange(self.n):
是否是前缀
if board[i][j] in root:
self._dfs(board,i,j,"",root)
def _dfs(self,board,i,j,cur_word,cur_dict)
现在单词
cur_word +=board[i][j]
字典树的层
cur_dict = cur_dict[board[i][j]]
是不是已经找到单词
if END_OF_WORD in cur_dict:
self.result.add(cur_word)
标记是否被访问过
tmp, board[i][j] = board[i][j], '@'
xrange() 函数用法与 range 完全相同,所不同的是生成的不是一个数组,而是一个生成器。
for k in xrang(4):
x,y = i + dx[k],j+dy[k]
if 0 <=x<self.m and 0 <=y<=self.n \
and board[x][y]!='@' and board[x][y] \
in cur_dict:
self._dfs(board,x,y,cur_word,cur_dict)
恢复
board[i][j] = tmp
for j in xrange(self.n):
是否是前缀
if board[i][j] in root:
self._dfs(board,i,j,"",root)
def _dfs(self,board,i,j,cur_word,cur_dict)
现在单词
cur_word +=board[i][j]
字典树的层
cur_dict = cur_dict[board[i][j]]
是不是已经找到单词
if END_OF_WORD in cur_dict:
self.result.add(cur_word)
标记是否被访问过
tmp, board[i][j] = board[i][j], '@'
xrange() 函数用法与 range 完全相同,所不同的是生成的不是一个数组,而是一个生成器。
for k in xrang(4):
x,y = i + dx[k],j+dy[k]
if 0 <=x<self.m and 0 <=y<=self.n \
and board[x][y]!='@' and board[x][y] \
in cur_dict:
self._dfs(board,x,y,cur_word,cur_dict)
恢复
board[i][j] = tmp
class Trie(object):
def __init__(self):
self.root = {}
self.end_of_word = "#"
def __init__(self):
self.root = {}
self.end_of_word = "#"
def insert(self,word):
node = self.root
for char in word:
node = node.serdefault(char,{})
node[self.end_of_word] = self.end_of_word
node = self.root
for char in word:
node = node.serdefault(char,{})
node[self.end_of_word] = self.end_of_word
def search(self,word):
node = self.root
for char in word:
if char not in node:
return false
node = node[char]
return self.end_of_word in node
node = self.root
for char in word:
if char not in node:
return false
node = node[char]
return self.end_of_word in node
def startsWith(self,prefix):
node = self.root
for char in prefix:
if char not in node:
return false
node = node[char]
return True
字典树
class TrieNode{
public char val
public boolean isword;
定义一个数组 每个节点都有26个孩子节点
public TrieNode[] children = new TrieNode[26]
public TrieNode() {}
有参构造
TrieNode(char c){
TrieNode node = new TrieNode();
node.val = c
node = self.root
for char in prefix:
if char not in node:
return false
node = node[char]
return True
字典树
class TrieNode{
public char val
public boolean isword;
定义一个数组 每个节点都有26个孩子节点
public TrieNode[] children = new TrieNode[26]
public TrieNode() {}
有参构造
TrieNode(char c){
TrieNode node = new TrieNode();
node.val = c
}
}
public class Trie{
private TrieNode root
public Trie(){
根节点
root = new TriedNode();
root.val = "";
private TrieNode root
public Trie(){
根节点
root = new TriedNode();
root.val = "";
}
public void insert(String word){
TrieNode ws = root;
for(int i=0;i< word.length();i++)
{
char c = word.charAt(i);
当c 不存在 创建一个新的
if(ws.children[c-'a'] == null){
ws.children[c-'a'] = new TriedNode(c);
}
ws = ws.children[c-'a'];
}
ws.isWord = true;
}
public boolean search(String word){
TrieNode ws = root;
//查找是否存在
for(int i = 0;i< word.length;i++){
char c = word.charAt(i);
if(ws.children[c-'a'] == null) return false;
ws = ws.children[c-'a'];
public boolean search(String word){
TrieNode ws = root;
//查找是否存在
for(int i = 0;i< word.length;i++){
char c = word.charAt(i);
if(ws.children[c-'a'] == null) return false;
ws = ws.children[c-'a'];
}
return ws.isword;
}
public boolean startWitch(String prefix)
{
TrieNode ws = root;
for (int i =0;i< prefix.length();i++){
char c = prefix.charAt(i);
if (ws.children[c-'a'] == null) return false;
ws = ws.children[c-'a'];
}
return true;
}
return ws.isword;
}
public boolean startWitch(String prefix)
{
TrieNode ws = root;
for (int i =0;i< prefix.length();i++){
char c = prefix.charAt(i);
if (ws.children[c-'a'] == null) return false;
ws = ws.children[c-'a'];
}
return true;
}
}
39 位运算
对二进制操作。
& | ^ ~
判断奇偶 X &1 == 1 or ==0
最低为清零: x = x &(x-1)
40 统计bit1的个数
1) x% 2 if ==1 count ++
x = x>>1 时间复杂度 O(n)
2) x = x&(x-1)
while(x!=0){
count ++;
x = x&(x-1)
}
& | ^ ~
判断奇偶 X &1 == 1 or ==0
最低为清零: x = x &(x-1)
40 统计bit1的个数
1) x% 2 if ==1 count ++
x = x>>1 时间复杂度 O(n)
2) x = x&(x-1)
while(x!=0){
count ++;
x = x&(x-1)
}
def hammingweight(self,n):
rst = 0
mask = 1
for i in range(32):
if n & mask:
rst +=1
mask = mask >>1
return rst
rst = 0
mask = 1
for i in range(32):
if n & mask:
rst +=1
mask = mask >>1
return rst
int hamingWeith(uint32_t n){
int rst = 0;
for(;n; n&=n-1)
++rst;
return rst;
int rst = 0;
for(;n; n&=n-1)
++rst;
return rst;
}
41 2的幂次方
1) 循环模2
2)位运算 x!=0 && x(x-1) ==0
1) for i=0 ==>n count.bit(i)
2)for (int i=0; i<n;i++)
count[i] = count[i&(i-1)]+1
2)for (int i=0; i<n;i++)
count[i] = count[i&(i-1)]+1
bool isPowerOfTwo(int n){
return n>0 && !(n&(n-1))
}
def isPowerOfTwo(self,n):
return n>0 and not (n&(n-1))
}
def isPowerOfTwo(self,n):
return n>0 and not (n&(n-1))
vector<int> countBits(int num){
定义要给数组大小位 nums+1 初始值为0
vector<int> bits(nums+1,0);
for (int i =1; i<=nums; i++){
地推
bits[i] += bits[i&(i-1)] +1;
}
return bits;
}
定义要给数组大小位 nums+1 初始值为0
vector<int> bits(nums+1,0);
for (int i =1; i<=nums; i++){
地推
bits[i] += bits[i&(i-1)] +1;
}
return bits;
}