当我们谈论算法我们在谈论什么:由疫情核酸检测想到的分治算法(Divide-and-Conquer)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_159
北京的疫情一波未平一波又起,由此看来,战“疫”将是一场旷日持久的战争,绝不能掉以轻心、轻易言胜。病毒随时都会死灰复燃,以生命为代价换来的经验教训值得我们每一个人久久深思。笔者所在的小区也开始组织居民批量进行核酸检测,本以为会是一幅摩肩接踵,水泄不通的场景,却出人意料的井然有序、有层有次,效率非常高。原来检疫部门采取了一种特别的策略:每五个人用一组试剂盒,进行快筛,分分钟搞定了几百人的社区检测。
这里解释一下病毒核酸检测的原理,检测人员提取小区居民的鼻腔拭子或者咽拭子(就是用一根棉签在咽喉处或者鼻腔深处刮取一些分泌物),然后将该棉签放入试剂盒,以病毒独特的基因序列检测靶标,通过PCR扩增,使我们选择的这段靶标DNA序列指数级增加,每一个扩增出来的DNA序列,都可与我们预先加入的一段荧光标记探针结合,产生荧光信号,扩增出来的靶基因越多,累计的荧光信号就越强。说白了就是试剂盒荧光反映变色越强烈,说明病毒体量和活性越强。
而五人一组共用一个试剂盒测试,如果结果呈阳性,再对其中四个人分别测试即可。 由于绝大部分人都是健康的,所以这样可以提高五倍的检测量,从而检测更多的人,很明显这次检疫使用到了类似归并的“分治法”来解决问题,提高效率。
分治法,即“分而治之”,出自清·俞樾《群经平议·周官二》“巫马下士二人医四人”:“凡邦之有疾病者,疕疡者造焉,则使医分而治之,是亦不自医也。” 其核心思想是:将一个难以直接解决的大问题,分拆成一些规模较小的相同问题,随后各个击破,分而治之。可以理解为:如果原问题可以分割成n个子问题,1<n<=原问题,且这些子问题均可解并且利用这些子问题的解求出原问题的解,那么分治方法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归算法提供了遍历。反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归的使用。所以分治与递归经常同时应用在算法解决方案中。
核酸检测正好契合分治算法的使用场景:该问题的规模只要缩小到一定的规模就可以容易的解决。该问题可以分解为若干个规模较小的相同问题(检测是否阳性)。
而我们在技术面试中,可以利用分治算法解决的经典问题如下:
归并排序
def merge_sort(lst):
# 从递归中返回长度为1的序列
if len(lst) <= 1:
return lst
middle = len(lst) / 2
# 1.分解:通过不断递归,将原始序列拆分成 n 个小序列
left = merge_sort(lst[:middle])
right = merge_sort(lst[middle:])
# 进行排序与合并
return merge(left, right)
def merge(left, right):
i, j = 0, 0
result = []
# 2.解决:比较传入的两个子序列,对两个子序列进行排序
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
# 3.合并:将排好序的子序列合并
result.extend(left[i:])
result.extend(right[j:])
return result
快速排序
def quickSort(listx):
if len(listx)<=1:
return listx
pivot = listx[len(listx)//2] #取列表中中间的元素为被比较数pivot
listl = [x for x in listx if x < pivot] #<pivot的放在一个列表
listm = [x for x in listx if x ==pivot] #=pivot的放在一个列表
listr = [x for x in listx if x > pivot] #>pivot的放在一个列表
left = quickSort(listl) #递归进行该函数
right = quickSort(listr) #递归进行该函数
return left + listm + right #整合
print(quickSort([9,3, 6, 8, 9, 19, 1, 5])) #[1, 3, 5, 6, 8, 9, 9, 19]
折半查找
def binary_search(lis, key):
low = 0
high = len(lis) - 1
time = 0
while low < high:
time += 1
mid = int((low + high) / 2)
if key < lis[mid]:
high = mid - 1
elif key > lis[mid]:
low = mid + 1
else:
# 打印折半的次数
print("times: %s" % time)
return mid
print("times: %s" % time)
return False
二叉树的最大深度问题
class Solution(object):
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
left = self.maxDepth(root.left) + 1
right = self.maxDepth(root.right) + 1
return left if left > right else right
计算x 的 n 次幂问题
class Solution(object):
def myPow(self, x, n):
"""
:type x: float
:type n: int
:rtype: float
"""
if not n:
return 1
if n < 0:
return 1 / self.myPow(x, -n)
if n % 2:
return (x * self.myPow(x, n - 1))
return self.myPow(x * x, int(n / 2))
当然了,分治算法也并非无懈可击,回到核酸检测的场景,这种做法在最乐观情况下,的的确确是提升了五倍的效率,但是在最不乐观情况下,反而会增大工作量。如果在检测这些人中一个感染的患者都没有,那就是最乐观情况,5人一组检查一遍就OK了;如果这群人全部(正确来讲是在分组后的每一组中都有至少一个)感染人员,这种极端恶劣的情况下会导致至少增加分组数量的工作量,所以根本问题又变成了在假设一定感染率的情况下,如何确定多少个样本一组检测比较好。考虑的因素可能包括,检测效率,费用,有阳性的时候快速定位等。实际监测的时候,还可以不同地区不同的检测策略,监测策略也可以根据检测结果调整。
结语:算法其实在生活中无处不在,很多同学出去面试时往往惧怕做算法题,其实算法也不过就是一种解决问题的方法,目的也仅仅是为了提高效率,如果在生活中多观察、多思考,也许会对算法能力的提升有一定的帮助。
原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_159
当我们谈论算法我们在谈论什么:由疫情核酸检测想到的分治算法(Divide-and-Conquer)的更多相关文章
- 分治算法——Karastsuba算法
分治(Divide and Conquer)算法:问题能够分解为子问题,每一个问题是能够独立的解决的,从子问题的解能够构建原问题. Divide:中间分.随机分.奇偶分等,将问题分解成独立的子问题 C ...
- Union-Find 检测无向图有无环路算法
不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...
- 算法(第4版)-1.5 案例研究:union-find算法
问题→ 动态连通性:当程序从输入中读取了整数对p q时,如果已知的所有整数对都不能说明p和q是相连的,那么则将这一对整数写入到输出中.如果已知的数据可以说明p和q 是相连的,那么程序应该忽略p q这对 ...
- 从两个平方算法到分治算法-java
先来看看问题的来源,假设有这么一个数组: 1 2 -5 4 -2 3 -3 4 -15 我们要求出其中连续字数组的和的最大值 例如这么可以很明显看出 4+ –2 + 3 + –3 + 4 = 6 所有 ...
- [算法]检测空间三角形相交算法(Devillers & Guigue算法)
#pragma once //GYDevillersTriangle.h /* 快速检测空间三角形相交算法的代码实现(Devillers & Guigue算法) 博客原地址:http://bl ...
- 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点
平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...
- [算法]分治算法(Divide and Conquer)
转载请注明:http://www.cnblogs.com/StartoverX/p/4575744.html 分治算法 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是 ...
- 分治算法求乘方a^b 取余p(divide and conquer)
传统的计算方法为循环n个a相乘.时间复杂度为O(n). 如用分治算法,效率可提升至O(lgn). 结合recursive有 double pow(int a, int n){ ) ; ) return ...
- UVA 10245 The Closest Pair Problem 最近点问题 分治算法
题意,给出n个点的坐标,找出两点间最近的距离,如果小于10000就输出INFINITY. 纯暴力是会超时的,所以得另辟蹊径,用分治算法. 递归思路将点按坐标排序后,分成两块处理,最近的距离不是在两块中 ...
随机推荐
- 767. Reorganize String - LeetCode
Question 767. Reorganize String Solution 题目大意: 给一个字符串,将字符按如下规则排序,相邻两个字符一同,如果相同返回空串否则返回排序后的串. 思路: 首先找 ...
- 151-模型-Power BI&Power Pivot模型DAX函数使用量分析
151-模型-Power BI&Power Pivot模型DAX函数使用量分析 1.背景 我们在 Power BI 或者 Power Pivot 项目中会写很多的 DAX 表达式.在最后项目交 ...
- Proxmox 5.4使用vgpu_unlock,为GTX1060开启vGPU支持
本文介绍如何为GTX1060显卡开启vGPU功能.消费级显卡不支持nvidia GRID vGPU功能.在2021年初,疫情激发了黑客的创作热情,给出了一个vgpu_unlock的补丁,可以让消费级显 ...
- 关于我学git这档子事(2)
将本地main分支push到远程dev分支(不同名分支间的push) 远程dev分支还未创建 (在push同时创建远程dev分支,并将本地main分支内容上传) git push -u --set-u ...
- pip下载更改为清华镜像
step1: + 在user(用户)下新建一文件夹再在该文件夹下新建pip.ini文件 + 例如:user/pip/pip.ini + tips:如果未打开在查看里的隐藏扩展名记得打开 step2: ...
- 向sqlserver 数据库插入emoji 表情包
1.emoji 属于特殊字符 所以我们必须使用utf-8 的编码格式进行保存 不过好在sqlserver 默认支持utf-8 2.将需要存储emoji的字段必须设置为nvarchar 类型 因为v ...
- 二叉树遍历在Unity中的实现
前言:今天放一天,想到要放国庆假了就心烦气躁,躺床上又焦虑,回想起面试官的一副扑克脸,马上跳起来看了看数据结构. 今天复习了二叉树,包括一些基本概念和特性,当看到二叉树遍历的章节时,马上联想到了Uni ...
- 论文解读(GraphDA)《Data Augmentation for Deep Graph Learning: A Survey》
论文信息 论文标题:Data Augmentation for Deep Graph Learning: A Survey论文作者:Kaize Ding, Zhe Xu, Hanghang Tong, ...
- Java常用类-包装类
包装类 Java中的基本类型功能简单,不具备对象的特性,为了使基本类型具备对象的特性,所以出现了包装类,就可以像操作对象一样操作基本类型数据;包装类不是为了取代基本数据类型,而是在数据类型需要使用 ...
- 论文解读(USIB)《Towards Explanation for Unsupervised Graph-Level Representation Learning》
论文信息 论文标题:Towards Explanation for Unsupervised Graph-Level Representation Learning论文作者:Qinghua Zheng ...