Meet in the middle

Meet in the Middle算法精讲
本文介绍了一种称为Meet in the Middle(MITM)的算法思想,它通过分割问题并利用额外空间来提高解决问题的效率。文章详细探讨了MITM在4和问题、双向搜索、2DES加密破解、离散对数问题中的应用,并提供了实现代码示例。

译文转自

原文:

Meet in the middle(有时候也叫作split and merge)是一种用以获取足够高效解决方案的灵巧的思想。和分治思想非常类似,它将问题分割成两个部分,然后试着合并这两个子问题的结果。好处在于通过使用一点额外的空间,你可以解决两倍规模的原来可以解决的问题。

       在我们继续之前,我必须要指出,附加问题是这篇文章中最好的部分。现在,我们来看这个技巧的一些应用。


4和问题(流行的面试问题)
       给定一个整数数组A,问数组中是否存在4个数,使得这4个数的和是0(同一个元素可以被多次使用)。例如:数组A = [2, 3, 1, 0, -4, -1],一种可能的方案是3 + 1 + 0 - 4 = 0 或 0 + 0 + 0 + 0 = 0。

       朴素的算法是判断所有可能的4个数的组合,这种方案需要计算O(N^4)次。

       一个些微改进的算法是暴力搜索所有的可能的n^3个3个数的组合,并且用hash表来判断-(a+b+c)是否在原始的数组中。这个算法的复杂度是O(n^3) 

       到目前为止,你可能想知道meet in the middle在这里要怎么应用,最关键的洞察来自于改写a + b + c + d = 0 成 a + b = -(c + d)。现在我们可以存储n^2个a+b的和在一个hash表S中,然后可以枚举所有可能c和d的n^2种组合并且判断S中是否包括-(c+d)。


       代码看起来这样:

[python]  view plain  copy
  1. def 4sum(A):  
  2.   sums = {}  
  3.   for a in A:  
  4.     for b in A:  
  5.       sums[a + b] = (a, b)  
  6.   
  7.   for c in A:  
  8.     for d in A:  
  9.       if -(c + d) in sums:  
  10.         print (sums[-(c + d)][0], sums[-(c + d)][1], c, d)  
  11.         return  
  12.   
  13.   print "No solution."   

 

       这个算法的时间复杂度和空间复杂度都是O(n^2),这个问题没有已知的更快的算法。

 

双向搜索


       在一个很大的图中找到两个点的最短路径,比如说Facebook的朋友关系图(友谊图)。

 

       宽度优先搜索算法是这个问题的标准方法。假设这两个节点之间之间的距离是k,并且网络中点的平均度数是p,那么BFS算法需要扩展O(p^k)个节点。


       一个更好的方案是同时从两个节点开始搜索,并且看什么时候这两个搜索的边界相遇。这个可以将需要扩展的节点降低到O(p^(k/2))。这个方案在寻路问题表现很好,包括明确的图以及游戏中遇到的不明确的图。

 
破解2DES加密

       DES是一种使用56bit密钥的加密标准。今天计算机可以使用暴力搜索的方法来破解加密。一种简单的使得加密算法更安全的方法是应用两次加密,使用两个不同的密钥。这种方法容易受到Diffile-Hellman发明的中间者攻击。3DES工作的原理是通过用2个密钥对明文进行3次加密。


       我们来看看为什么2DES是容易受到攻击的。假设Ek是密钥为k的加密函数,Dk是密钥为k的解密函数。2DES算法使用两个密钥k和K,Ek(EK(p)) = s是一个加密过程,并且DK(Dk(s)) = p是一个解密。

       Diffie-Hellman的中间相遇攻击用空间换取时间来找到这两个密钥。对于p,尝试所有可能的密钥可以取得对应的多个Ek(p)的集合。同样地,对于s可以用所有可能的密钥来解密,取得所有可能Dk(s)的集合。如果我们能够在这两个集合中找到匹配的一对,也就是说Eki(p) = Dkj(s),那么密钥就是ki和kj。

       

       朴素的暴力算法需要2^56*2^56次迭代来遍历所有可能的k1和k2的值,而这个算法使用2^56*56的空间来存储所有的Eki(p),并且2^56个操作来找到匹配。

       这个是相当多的空间和相当多的计算时间。但对于一个足够大的公司或者国家,它就变得非常可能的范畴。

       2001的国际奥赛的问题DOUBLE要求破解24密钥长度的2DES就是非常可行的。

 

离散对数算法


       给定一个素数n和p,q两个数,0 <= p,q <= n-1,找到k使得p^k = q(mod n)。

       朴素的算法是遍历所有可能的k的值,复杂度为O(n)。

       baby-step, giant-step算法使用了MITM,更高效地解决了这个问题。

       记k = i[sqrt(n)] + j,i <= sqrt(n)且j <= sqrt(n)。替换等式中的k,我们有p^(i*[sqrt(n)] + j) = q(mod n),然后两边同除以p^j有:p^(i*sqrt(n)) = q*p^(-j) (mod n)

       在这个时候,我们可以暴力搜索等式两边并且找到一个碰撞。

       这个算法需要O(sqrt(n))的空间和O(sqrt(n))的时间

 

警告

       与分治不同,MITM不能用于递归,因为子问题和原问题没有相同的结构。双向搜索在很多时候可以用其他的启发式搜索算法来代替。

 

附加问题

1.朋友的朋友(面试问题)

       给定社交网络中的两个名字,设计一个有效的方法,判断其中一个是否是另外一个的朋友的朋友


2.6度空间(6度间隔/6度分割)

       给定社交网络中的两个名字,设计一个有效的方法,判断这两个人是否最多相隔6个朋友


3.等分
       给定一个40个实数的集合A,判断是否有方法将集合A分成两个子集,使得两个子集的元素和相同。(提示:复杂度O(2^(n/2)) 

4.最小点覆盖
       给定一个有n(n <= 30)个节点的图,找到一个最小的点集,使得图中的每一条边至少有一个顶点在这个点集中。(提示:复杂度O(3^(n/2))

5.正方形栅栏
       给定一个数组L,代表n个木板的长度。请回答是否存在一种方法,使用所有的木板构成一个正方形栅栏且不损坏也不重叠。(提示:复杂度O(4^n/2))

6.8拼图
       8拼图是在一个有8个板子和1个空位置的3*3拼板上滑动的游戏,在每一步你只能移动一个与空的位置正交相邻的板子到空的位置上。游戏开始时板子和空位置随机配置,目标是用最少的移动将拼版移动成指定的配置。找到一个有效的算法来解决(提示:每一个位置最多31次移动可解决)。下图我们让可以看到解决8拼图的一系列的移动。

       

7. 4-反转问题

       给定两个相同长度的字符串S和T。请指出是否能够从S得到T,使用4种子串翻转操作。(提示:复杂度O(n^5))








------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.双向BFS,深度为1,第一遍记录起点能走到的所有点,第二遍找终点是否能到这些点

2.也是双向BFS,深度到3,

3.实数范围很大,如果数很小可以用背包,想到数大可不可以把包的体积离散化,后来想想数很大时,重复的部分应该很少,所以不可行

暴搜O(2^n),  没想到别的好方法。。。。看了原文下面的评论

设所有数总和为sum,把这些数按个数分两半,然后O(2^(n/2)) 搜出这一半所有的组合并记录(hash)假设为A,然后在对另一半进行O(2^(n/2))搜索,得到值B,如果找到A=sum/2-B,说明就是可以等分的

正确性,因为把原来这些数分成S1,S2两个等大部分(不等大也是可以的,不过等大时速度最优),而符合要求的和为sum/2的那些数,肯定一部分属于S1一部分属于S2



<think>好的,我现在需要回答用户关于折半搜索(Binary Search)与meet in the middle算法的结合或比较的问题,以及它们的原理和应用。首先,我得先理解这两个概念各自是什么,然后看看它们之间的关系和区别。 用户提供的引用中有提到折半搜索和meet in the middle,但看起来有些地方可能混淆了这两个术语。比如引用[1]提到折半搜索是Binary Search,而引用[2]到[5]则把折半搜索和meet in the middle视为同一技术。这里可能存在术语上的差异,需要仔细区分。 首先,Binary Search(折半搜索/二分搜索)通常指的是在有序数组中查找目标值的方法,每次将搜索范围减半,时间复杂度O(log n)。而Meet in the Middle(中间相遇)是一种分治策略,将问题分成两部分分别求解,再合并结果,常用于处理复杂度指数级的问题,比如某些暴力搜索问题。 用户的问题可能集中在两者是否有关联,或者如何结合使用。需要明确的是,虽然两者都有“分治”的思想,但应用场景不同。Binary Search用于查找,而Meet in the Middle用于优化搜索过程,特别是在处理较大规模的问题时,例如拆分搜索空间以减少时间复杂度。 接下来,根据提供的引用,引用[2]到[5]详细描述了Meet in the Middle的应用,比如将整个搜索过程分成两部分,分别处理后合并结果,以降低时间复杂度。例如,当直接暴力搜索的复杂度是O(2^n)时,拆分成两部分后复杂度变为O(2^(n/2)),再加上合并步骤,如排序后使用二分查找或双指针,总体复杂度会大大降低。 需要指出的是,可能用户提到的“折半搜索”在这里实际上指的是Meet in the Middle,而不是传统的Binary Search。因此,在回答时需要澄清术语,避免混淆。比如,中文里“折半搜索”可能被用来翻译两者,但实际是不同的算法。 接下来,整理技术原理和应用: 1. **技术原理**: - **Binary Search**:适用于有序数据,每次比较中间元素,缩小搜索范围。 - **Meet in the Middle**:将问题分解为两个子问题,分别求解所有可能的子集或状态,再合并结果。通常用于优化指数级算法,比如子集和问题、旅行商问题(TSP)的部分情况等。 2. **结合或比较**: - **区别**:Binary Search是查找算法,Meet in the Middle是分治策略,用于优化搜索。 - **结合点**:在Meet in the Middle的合并阶段,可能会使用Binary Search来高效查找符合条件的解,例如在合并两个子集的结果时,对其中一个排序后,用Binary Search快速定位。 3. **应用场景**: - Meet in the Middle常用于解决NP难问题,当问题规模较大但可以分割时,例如某些组合优化问题。 - Binary Search则用于查找、确定边界条件等,如旋转数组中的最小值、数值范围的快速定位。 需要引用用户提供的资料中的例子,比如引用[4]提到的世界冰球锦标赛题目,将n场比赛分成两半,分别搜索可能的花费组合,然后合并时用Binary Search找到符合条件的组合数。这说明在Meet in the Middle的合并阶段,Binary Search被用作工具。 另外,引用[5]提到将46次方的问题拆分成两个23次方,复杂度降低,这也是Meet in the Middle的典型应用,而合并时可能需要排序和Binary Search,这展示了二者的结合。 总结回答结构: 1. 澄清术语:区分Binary Search和Meet in the Middle2. 原理分述:分别解释两者的工作原理。 3. 比较与结合:指出差异及可能的结合点(如合并阶段使用Binary Search)。 4. 应用实例:举例如子集和问题、竞赛题目中的具体应用。 5. 相关问题:生成相关问题供用户进一步学习。 需要确保回答中正确使用LaTeX格式,如时间复杂度写成$O(2^{n/2})$,并引用提供的参考资料中的例子,如引用[4][5]中的案例。 最后,生成的相关问题应围绕原理、应用、优化等方面,帮助用户深入理解。</think>### 折半搜索与Meet in the Middle的技术原理及应用解析 #### 一、术语澄清与基本原理 1. **折半搜索(Binary Search)** 折半搜索是一种基于**有序数组**的查找算法,通过不断缩小搜索范围至原区间的一半来定位目标值。其时间复杂度为$O(\log n)$,例如在有序数组中查找元素$x$时,每次比较中间值以决定向左或向右继续搜索[^1]。 2. **Meet in the Middle(中间相遇算法)** 这是一种分治策略,将原问题拆分为两个独立的子问题,分别求解所有可能的子状态,最后合并结果。其核心目标是**降低指数级复杂度**,例如将$O(2^n)$优化为$O(2^{n/2})$,并通过合并策略(如二分或双指针)统计最终答案[^2][^5]。 #### 二、技术原理对比与结合 | **维度** | **折半搜索(Binary Search)** | **Meet in the Middle** | |------------------|------------------------------|---------------------------------------| | **目标** | 快速定位目标值 | 优化暴力搜索,处理大规模组合问题 | | **输入要求** | 数据必须有序 | 无特殊要求,适用于可分治的问题 | | **时间复杂度** | $O(\log n)$ | $O(2^{n/2} \cdot n)$(合并步骤主导) | | **结合点** | 在Meet in the Middle的合并阶段,利用Binary Search快速筛选有效解[^4] | — | #### 三、Meet in the Middle的核心步骤 1. **拆分问题** 将原问题划分为两个规模相近的子问题,例如将$n$个元素的集合分为前$n/2$和后$n/2$个。 2. **独立搜索** 对每个子集进行暴力搜索,生成所有可能的状态(如子集和),分别存入数组$a$和$b$。 3. **合并结果** - 对数组$b$排序,使其有序化。 - 遍历数组$a$中的每个元素$a_i$,在$b$中使用**Binary Search**找到满足条件(如$a_i + b_j \leq m$)的元素数量[^4]。 **示例**:在“世界冰球锦标赛”问题中,需统计总花费不超过$m$的所有观赛组合。将$n$场比赛分为两半,分别生成所有可能的子集和,合并时通过Binary Search统计有效组合数[^3][^4]。 #### 四、应用场景 1. **子集和问题** 给定集合$S$和目标值$m$,寻找所有子集的和等于$m$。直接暴力搜索复杂度为$O(2^n)$,使用Meet in the Middle可优化至$O(n \cdot 2^{n/2})$[^5]。 2. **密码学中的碰撞攻击** 通过拆分密钥空间,分别计算前一半和后一半的可能值,再寻找匹配结果。 3. **旅行商问题(TSP)** 对于节点数$n$较大的情况,将路径分为两段,分别计算最短路径后合并。 #### 五、优化与局限性 - **优势**:将指数级复杂度降为平方根级别,例如$O(2^{46}) \rightarrow O(2^{23})$。 - **局限性**:合并阶段需额外时间(如排序、二分),且空间占用较高(需存储所有子状态)。 ```python # Meet in the Middle示例:统计子集和小于等于m的组合数 def meet_in_middle(arr, m): def dfs(sub_arr, results, idx, current_sum): if idx == len(sub_arr): results.append(current_sum) return dfs(sub_arr, results, idx + 1, current_sum) # 不选当前元素 dfs(sub_arr, results, idx + 1, current_sum + sub_arr[idx]) # 选当前元素 mid = len(arr) // 2 left, right = arr[:mid], arr[mid:] sum_a, sum_b = [], [] dfs(left, sum_a, 0, 0) dfs(right, sum_b, 0, 0) sum_b.sort() count = 0 for s in sum_a: target = m - s # 使用Binary Search找到sum_b中<=target的元素数量 count += bisect_right(sum_b, target) return count ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值