数据结构与算法【进阶】
贪心算法
在对问题求解时,总市做出当前看来时最好的选择。
- 不从整体最优上考虑
- 局部最优解
找零问题
假设商店老板需要找零n元钱,钱币的面额:100元、50元、20元、5元、1元,如何找零使得所有钱币数量最少?
t = [100,50,20,5,1] def change(t,n): m = [0 for _ in range(len(t))] for i,money in enumerate(t): m[i] = n // money n = n % money return m,n
背包问题
一个小偷在某个商店发现右n个商品,第i个商品价值vi元,重wi千克。他希望拿走的价值尽量高,但他的背包子最多只能容纳W千克的东西。他应该拿走哪些商品?
0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次。(商品为金条)
分数背包:对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)
goods = [(60,10),(100,20),(120,30)] #(价格,重量) goods.sort(key=lambda x:x[0]/x[1],reverse=True) def fractional_backpack(goods,w): m = [0 for _ in range(len(goods))] for i,(price,weight) in enumerate(goods): if w >= weight: m[i]=1 w -= weight else: m[i] = w / weight w = 0 break return m
拼接最大数字问题
有n个非负整数,将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?
from functools import cmp_to_key li = [32,94,238,1286,6,71] def xy_cmp(x,y): if x+y < y+x: return 1 elif x+y > y+x: return -1 else: return 0 def number_join(li): li = list(map(str,li)) li.sort(key=cmp_to_key(xy_cmp)) return "".join(li)
活动选择问题
假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能共一个活动使用
每个活动都有一个开始时间si和结束时间fi,表示活动在[si,fi)区间占用场地
问:安排哪些活动能够使该场地举办的活动的个数最多?
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
si | 1 | 3 | 0 | 5 | 3 | 5 | 6 | 8 | 8 | 2 | 12 |
fi | 4 | 5 | 6 | 7 | 9 | 9 | 10 | 11 | 12 | 14 | 16 |
贪心结论:最先结束的活动一定是最优解的一部分
activities = [(1,4),(3,5),(8,6),(5,7),(3,9),(6,10),(8,11),(8,12),(2,14),(12,16)] # 保证活动是按结束时间排号序的 activities.sort(key=lambda x:x[1]) def activity_slection(a): res = [a[0]] for i in range(1,len(a)): if a[i][0]>=res[-1][1]: # 当前活动的开始时间小于等于最后一个入选活动的结束时间 # 不冲突 res.append(a[i]) return res
动态规划
- 最优子结构(递推式)
- 重复子问题,将重复的子问题存起来
斐波那契数列
-
Fn=Fn-1+Fn-2
-
递归求解第n项
def fib(n): if n == 1 or n == 2: return 1 else: return fib(n-1)+fib(n-2) ''' 为什么递归效率低? 因为有重复计算 f(5)=f(4)-f(3) f(4)=f(3)-f(2) ''' # 此处循环方法使用的动态规划思想 def fib_no_rec(n): f = [0,1,1] if n > 2: for i in range(n-2): num = f[-1]+f[-2] f.append(num) return f[n]
钢条切割问题
某公司出售钢条,出售价格与钢条长度之间的关系如下表:
长度i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
价格pi | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 |
问题:现有一段长度为n的钢条和上面的价格表,求切割钢条方案,使得总收益最大
思考:长度为n的钢条的不同切割方案有几种
p = [0,1,5,8,9,10,17,17,20,24,30] # 递归方法 def cut_rod_recurision_1(p,n): if n==0: return 0 else: res = p[n] for i in range(1,n): res = max(res,cut_rod_recurision_1(p,i)+cut_rod_recurision_1(p,n-i)) return res # 自顶向下实现 def cut_rod_recurision_2(p,n): if n == 0: return 0 else: res = 0 for i in range(1,n+1): res = max(res,p[i]+cut_rod_recurision_2(p,n-i)) return res
# 自底向上实现 def cur_rod_dp(p,n): r = [0] for i in range(1,n+1): q = 0 for j in range(1,i+1): q = max(q,p[j]+r[i-j]) r.append(q) return r[n] # 最优解+最优切割方案 def cur_rod_extend(p,n): r = [0] s = [0] for i in range(1,n+1): res_r = 0 # 价格的最大值 res_s = 0 # 价格最大值对应方案的左边不切割部分的长度 for j in range(1,i+1): if p[j] + r[i-j] > res_r: res_r = p[j]+r[i-j] res_s = j r.append(res_r) s.append(res_s) return r[n],s def cut_rod_solution(p,n): r,s = cur_rod_extend(p,n) ans = [] while n > 0: ans.append(s[n]) n -= s[n] return ans
时间复杂度O(n²)
最长公共子序列
# 动态规划法 def lcs_length(x,y): m = len(x) n = len(y) c = [[0 for _ in range(n+1)] for _ in range(m+1)] for i in range(1,m+1): for j in range(1,n+1): if x[i-1] == y[j-1]: # i j 位置上的字符匹配的时候,来自于左上方+1 c[i][j] = c[i-1][j-1]+1 else: c[i][j] = max(c[i-1][j],c[i][j-1]) return c[m][n] # 回溯法 def lcs(x,y): m = len(x) n = len(y) c = [[0 for _ in range(n+1)] for _ in range(m+1)] b = [[0 for _ in range(n+1)] for _ in range(m+1)] for i in range(1,m+1): for j in range(1,n+1): if x[i-1] == y[j-1]: # i j 位置上的字符匹配的时候,来自于左上方+1 c[i][j] = c[i-1][j-1]+1 b[i][j] = 1 elif c[i-1][j] > c[i][j-1]: # 来自上方 c[i][j] = c[i-1][j] b[i][j] = 2 else: # 来自左方 c[i][j] = c[i][j-1] b[i][j] = 3 return c[m][n],b def lcs_trackback(x,y): c,b = lcs(x,y) i = len(x) j = len(y) res = [] while i>0 and j>0: if b[i][j] == 1: # 来自左上方 res.append(x[i-1]) i -= 1 j -= 1 elif b[i][j] == 2: # 来自上方 i -= 1 else: j -= 1 return "".join(reversed(res))
欧几里得算法
最大公约数
gcd(a,b) = gcd(b,a mod b)
def gcd(a,b): if b == 0: return a else: return gcd(b,a % b) def gcd2(a,b): while b>0: r = a % b a = b b = r return a
实现分数计算
class Fraction: def __init__(self,a,b): self.a=a self.b=b x = self.gcd(a,b) self.a /= x self.b /= x def gcd(a,b): while b > 0: r = a % b a = b b = r return a def __str__(self): retunr "%d%d" %(%self.a,self.b) def zxgs(a,b): # 最小公倍数 x = self.gcd(a,b) return a*b/x def __add__(self,other): a = self.a b = self.b c = other.a d = other.b fenmu = self.zxgs(b,d) fenzi = a * fenmu / b + c * fenmu / d return Fraction(fenzi,fenmu)
RSA算法
现代密码系统:加密算法是公开的,密钥是秘密的
- 对称加密
- 非对称加密
过程
本文作者:注入灵魂
本文链接:https://www.cnblogs.com/totopian/p/16022286.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步