原文转载自「刘悦的技术博客」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)的更多相关文章

  1. 分治算法——Karastsuba算法

    分治(Divide and Conquer)算法:问题能够分解为子问题,每一个问题是能够独立的解决的,从子问题的解能够构建原问题. Divide:中间分.随机分.奇偶分等,将问题分解成独立的子问题 C ...

  2. Union-Find 检测无向图有无环路算法

    不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...

  3. 算法(第4版)-1.5 案例研究:union-find算法

    问题→ 动态连通性:当程序从输入中读取了整数对p q时,如果已知的所有整数对都不能说明p和q是相连的,那么则将这一对整数写入到输出中.如果已知的数据可以说明p和q 是相连的,那么程序应该忽略p q这对 ...

  4. 从两个平方算法到分治算法-java

    先来看看问题的来源,假设有这么一个数组: 1 2 -5 4 -2 3 -3 4 -15 我们要求出其中连续字数组的和的最大值 例如这么可以很明显看出 4+ –2 + 3 + –3 + 4 = 6 所有 ...

  5. [算法]检测空间三角形相交算法(Devillers & Guigue算法)

    #pragma once //GYDevillersTriangle.h /* 快速检测空间三角形相交算法的代码实现(Devillers & Guigue算法) 博客原地址:http://bl ...

  6. 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

    平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...

  7. [算法]分治算法(Divide and Conquer)

    转载请注明:http://www.cnblogs.com/StartoverX/p/4575744.html 分治算法 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是 ...

  8. 分治算法求乘方a^b 取余p(divide and conquer)

    传统的计算方法为循环n个a相乘.时间复杂度为O(n). 如用分治算法,效率可提升至O(lgn). 结合recursive有 double pow(int a, int n){ ) ; ) return ...

  9. UVA 10245 The Closest Pair Problem 最近点问题 分治算法

    题意,给出n个点的坐标,找出两点间最近的距离,如果小于10000就输出INFINITY. 纯暴力是会超时的,所以得另辟蹊径,用分治算法. 递归思路将点按坐标排序后,分成两块处理,最近的距离不是在两块中 ...

随机推荐

  1. Python的.gitignore模板

    参考:https://github.com/github/gitignore Python的.gitignore模板,记录一下方便查询 # Byte-compiled / optimized / DL ...

  2. QC快速充电

    QC快充 一.高通QC快充的介绍 二.识别充电类型的芯片介绍 三.QC充电曲线 四.如何在log中看QC充电类型 五.QC3识别错误 六.波形图 一.高通QC快充的介绍 高通QC快充技术,又称Quic ...

  3. React简单教程-4.1-hook

    前言 虽然我们简单感受了一下 useState 的用法,但我想你还是对 React 里的 hook 迷迷糊糊的.本文我们将明确下 React 的概念. HOOK 前生今世 在我示例中,写的 React ...

  4. CabloyJS究竟是一款什么样的框架

    CabloyJS是什么样的框架 CabloyJS 是一款自带工作流引擎的 Node.js 全栈框架,一款面向开发者的低代码开发平台,更是一款兼具低代码的开箱即用和专业代码的灵活定制的 PAAS 平台 ...

  5. 2020.10.17【普及组】模拟赛C组 总结

    总结 这次比赛 120 分,老师说上 200 是不容易的,但我觉得这不是我真的水平 改题情况 T1 题目大意:有 N 个小朋友,每个小朋友有 \(B_i\) 个朋友,问从中随机选 3 人使得 3 人关 ...

  6. windiws下安装Composer

    1.先下载Composer-Setup.exe,下载地址:下载Composer .会自动搜索php.exe的安装路径,如果没有,就手动找到php路径下的php.exe. 2.在PHP目录下,打开php ...

  7. Ribbon的ServerStats引起内存泄露问题总结

    问题描述 服务运行一段时间之后,出现页面卡顿加载慢的问题,使用top命令查看了服务器的使用情况,发现CPU飙高,接着查看了该进程中每个线程的占用情况,发现导致CPU高的线程是JVM垃圾回收的线程,然后 ...

  8. DAST 黑盒漏洞扫描器 第四篇:扫描性能

    0X01 前言 大多数安全产品的大致框架 提高性能的目的是消费跟得上生产,不至于堆积,留有余力应对突增的流量,可以从以下几个方面考虑 流量:减少无效流量 规则:减少规则冗余请求 生产者:减少无效扫描任 ...

  9. 实现领域驱动设计 - 使用ABP框架 - 存储库

    存储库 Repository 是一个类似于集合的接口,领域层和应用程序层使用它来访问数据持久性系统(数据库),以读写业务对象(通常是聚合) 常见的存储库原则是: 在领域层定义一个存储库接口(因为它被用 ...

  10. JavaScript与Node.js一起打造一款聊天App

    聊天是我们人与人交流最直接的方式,互联网的加入使我们交流更加便捷.我们手机上的微信.QQ是我们手机必不可少的应用软件.那么,我们是否可以做一款聊天应用呢? 之前我自己闲着没事,研究过一些技术,做了一款 ...