二分查找
- 二分查找比简单查找快
- 算法运行时间以增速度量大O表示法,不以秒为时间单位
- O(log n)比O(n)快
# 二分查找
def midsearch(data,target):
low=0
high=len(data)-1
while low<=high: #这里是<=因为要运行到范围只有一个元素的时候
mid=int((low+high)/2)
if target==data[mid]:
return True
if target<data[mid]:
high=mid-1
else:
low=mid+1
return False
data=[1,2,4,5,7,9]
target1=11
target2=9
print(midsearch(data,target1))
print(midsearch(data,target2))
数组和链表
- 数组和链表的区别:数组地址是连续的,链表不连续
数组 | 链表 | |
---|---|---|
读取 | O(1) | O(n) |
插入删除 | O(n) | O(1) |
- 同一数组中,数据类型需要保持一致
递归
- 一般来说,循环可以获得更好的性能,而递归(调用栈消耗内存和影响性能)更好理解
- 基线递归,加入基线条件,避免无限调用
分治法
分治法:
- 找出简单的基线条件
- 确定如何缩小问题的规模,使其符合基线条件
欧几里得算法:求最大公约数
def GCD(a,b):
print("GCD:",a,b)
if a%b==0:
return b
else:
return GCD(b,a%b)
print(GCD(72,27))
快速排序
# 非原地
def quicksort(array):
if len(array)<2:
return array
else:
pivot=array[0]
less=[i for i in array[1:] if i<=pivot]
greater=[i for i in array[1:] if i>pivot]
return quicksort(less)+[pivot]+quicksort(greater)
# 原地
def quicksort(array, l, r):
if l < r:
q = partition(array, l, r)
quick_sort(array, l, q - 1)
quick_sort(array, q + 1, r)
def partition(array, l, r):
privot = array[r]
i = l
for j in range(l, r):
if array[j] <= privot:
array[i], array[j] = array[j], array[i]
i+=1
array[i], array[r] = array[r], array[i]
return i
归并排序
def merger_sort(L):
if len(L)<=1:
return L
mid=int(len(L)/2)
left=merger_sort(L[:mid])
right=merger_sort(L[mid:])
return merge(left,right)
def merge(left,right):
l,r=0,0
res=[]
while l<len(left) and r<len(right):
if left[l]<right[r]:
res.append(left[l])
l+=1
else:
res.append(right[r])
r+=1
res+=list(left[l:])
res+=list(right[r:])
return res
散列表
- 平均查询修改的时间都是O(1),但是最糟情况下的时间是O(n)
- 一般经验来说,一旦装填因子大于0.7就要调整散列表的长度
- Python中简单使用{}来创建一个散列表
广度优先搜索
图
- 图由节点和边组成
- 相连的节点互为邻居
- 可以通过散列表来建立图
- 树是一种特殊的图,没有向后的边
广度优先搜索
- 从根节点出发,先遍历完每个邻居,再去遍历邻居的邻居(不包含已经访问过的节点)
- 可以通过队列(FIFO)实现
- 栈是(LIFO)
狄克斯特拉算法
- 狄克斯特拉算法可以用于求有向无环图最短路径问题(不包含负权边)
- 当包含负权边时,使用贝尔曼-福德算法
贪心算法
- 贪心算法,每步都采取最优的做法
- 贪心算法,不一定能取得最优解,但是能取得近优解
- NP完全问题,无法在多项式时间内快速解决的问题
动态规划
- 动态规划可以帮助在给定的约束条件下寻找到最优解
- 解决一个问题的过程可以分解为解决子问题的情况下,就可以用动态规划解决
- 典型的动态规划问题如背包问题
01背包
# bag 6
# a(3,10)
# b(1,3)
# c(2,9)
# d(2,5)
# e(1,6)
def solve2(vlist,wlist,totalWeight):
totalLength=len(vlist)
resArr = [0]*(totalWeight+1)
for i in range(1,totalLength):
for j in range(totalWeight,0,-1):
if wlist[i] <= j:
resArr[j] = max(resArr[j],resArr[j-wlist[i]]+vlist[i])
print(resArr)
return resArr[-1]
v = [0,10,3,9,5,6]
w = [0,3,1,2,2,1]
weight = 6
result = solve2(v,w,weight)
print(result)
完全背包
只是内循环顺序不同
# bag 6
# a(3,10)
# b(1,3)
# c(2,9)
# d(2,5)
# e(1,6)
def solve2(vlist,wlist,totalWeight):
totalLength=len(vlist)
resArr = [0]*(totalWeight+1)
for i in range(1,totalLength):
for j in range(1,totalWeight+1):
if wlist[i] <= j:
resArr[j] = max(resArr[j],resArr[j-wlist[i]]+vlist[i])
print(resArr)
return resArr[-1]
v = [0,10,3,9,5,6]
w = [0,3,1,2,2,1]
weight = 6
result = solve2(v,w,weight)
print(result)
多重背包
而已转化为0 1把背包解决
最长公共子序列 子串
两个个注意的地方:
- 创建二维数组的大小为m*n
- 最长公共子序列的大小位于右下角
# 最长公共子序列
def comp_sequence(str1,str2):
m=len(str1)
n=len(str2)
w=[[0]*(n) for i in range(m)]
#辅助记录结果0表示斜向上,-1表示向上,1表示向左
c=[[0]*(n) for i in range(m)]
for i in range(0,m):
for j in range(0,n):
if str1[i]==str2[j]:
w[i][j]=w[i-1][j-1]+1
elif w[i-1][j]>w[i][j-1]:
w[i][j]=w[i-1][j]
c[i][j]=-1
else:
w[i][j]=w[i][j-1]
c[i][j]=1
# 回溯最长子序列
subs=""
i=m-1
j=n-1
while i>=0 and j>=0:
if c[i][j]==0:
subs=str1[i]+subs
i-=1
j-=1
elif c[i][j]==-1:
i-=1
else:
j-=1
print(w[-1][-1],subs)
# 最长公共子串
def comp_string(str1,str2):
m=len(str1)
n=len(str2)
w=[[0]*(n) for i in range(m)]
lmax=0
subs=""
for i in range(0,m):
for j in range(0,n):
if str1[i]==str2[j]:
w[i][j]=w[i-1][j-1]+1
else:
w[i][j]=0
#记录更新子串
if w[i][j]>lmax:
lmax=w[i][j]
subs=str1[i+1-lmax:i+1]
print(lmax,subs)
str1="foitksh"
str2="fitqsh"
comp_sequence(str1,str2)
comp_string(str1,str2)
总结来说,如果解决问题可以通过解决子问题(画网格),那么这个问题就很适合用动态规划解决。
K最近邻算法
特征提取>>度量距离>>分类或回归
后面高阶内容单独再写吧,嗯,可以开始刷题了呢~~~