难以思考分而治之的方法

Posted

技术标签:

【中文标题】难以思考分而治之的方法【英文标题】:Difficulty in thinking a divide and conquer approach 【发布时间】:2021-09-14 17:02:38 【问题描述】:

我是自学算法。众所周知,分而治之是算法设计范式之一。我研究了mergeSort、QuickSort、Karatsuba Multiplication,将数组的反转计数作为这种特定设计模式的示例。虽然听起来很简单,将问题划分为子问题,递归地解决每个子问题,并合并每个子问题的结果,但我发现很难形成如何将这种逻辑应用于新问题的想法。据我了解,所有上述规范示例都提出了一个非常聪明的技巧来解决问题。例如,我正在尝试解决以下问题:

给定一个由 n 个数字组成的序列,使得两个连续数字之间的差是恒定的,以对数时间找出缺失的项。

Example: [5, 7, 9, 11, 15] 
Answer: 13

首先,我想到了可以使用分而治之的方法来解决它的想法,因为天真的方法需要 O(n) 时间。根据我对分而治之的理解,我是这样处理的: 原问题可以分为两个独立的子问题。我可以递归地搜索两个子问题中的缺失项。所以,我先分问题。

leftArray = [5,7,9]
rightArray = [11, 15]

现在它说,我需要递归地解决子问题,直到它变得微不足道。在这种情况下,子问题的大小变为 1。如果只有一个元素,则缺少 0 个元素。现在合并结果。但我不知道该怎么做或它会如何解决我原来的问题。

当然,我在这里遗漏了一些重要的东西。我的问题是如何解决这种分而治之的问题。我应该想出一个像 mergeSort 或 QuickSort 这样的技巧吗?我越是看到这类问题的解决方案,感觉我是在记住解决方法,而不是理解,每个问题的解决方法都不一样。任何关于解决分而治之的心态的帮助或建议将不胜感激。我已经尝试了很长时间来发展我的算法技能,但我几乎没有进步。提前致谢。

【问题讨论】:

【参考方案1】:

你有正确的方法。唯一缺少的部分是一种 O(1) 的方式来决定要丢弃哪一边。

首先,注意你的问题中的数字必须是有序的,否则你不能做得比 O(n) 更好。还需要至少三个数字,否则你不会弄清楚“步骤”。

有了这种理解,您可以通过检查前三个项来确定 O(1) 时间内的“步长”,并查看连续项之间的区别。有两种可能的结果:

两者的区别是相同的,并且 一个差异是另一个差异的两倍。

案例 2 很幸运地为您提供了一个解决方案,因此从现在开始我们将只考虑第一个案例。有了步骤,您可以通过减去端点并将结果与​​间隔数乘以步骤进行比较来确定范围中是否存在间隙。如果您得出相同的结果,则该范围没有缺失项,并且可以丢弃。当两半都可以丢弃时,间隙就在它们之间。

【讨论】:

关于订购的要点 - 没有一些已知的订单,有必要全部检查一下 非常感谢@Sergey Kalinichenko。我正在尝试了解您提供的方法。那么,这是否发生在解决方案的分而治之或合并步骤中?我的意思是在快速排序中,我们在除法步骤中完成主要工作,然后递归,在合并排序中,它发生在递归之后的合并步骤中。抱歉,我可能听起来很愚蠢,但我正在尝试建立一个心理模型来解决这些类型的问题。 @AshequlHaque 由于解决方案是 O(log n),因此没有“工作”需要完成各个部分。这就是这个问题与 mergeSort 不同的原因。你需要做的就是分裂,因为“征服”是自动发生的,而且是免费的。这将类似于二分搜索算法,它不断划分区间直到找到解决方案,因为划分区间是“有效负载”工作。 再次感谢先生。 @SergeyKalinichenko 如果你有时间,最后一个问题。当您看到这些类型的问题时,首先想到要解决的问题是什么? @MarkRansom 这将扼杀 O(log N) 要求。【参考方案2】:

正如 @Sergey Kalinichenko 指出的那样,这假设传入的集合是有序的


但是,如果您确定输入是有序的(在这种情况下很可能),请观察第 n 个位置的值是 start + jumpsize * index;这使您可以平分以找到它移动的位置

示例:[5, 7, 9, 11, 15] 答案:13

start    = 5
jumpsize = 2
检查中点:5 * 2 * 2 -> 9 这是有效的,因此移位必须在 中点之后 递归

您可以通过检查前 3 个值来找到 jumpsize

a, b, c = (language-dependent retrieval)
gap1 = b - a
gap2 = c - b
if gap1 != gap2:
    if (value at 4th index) - c == gap1:
        missing value is b + gap1  # 2nd gap doesn't match
    else:
        missing value is a + gap2  # 1st gap doesn't match

bisect remaining values

【讨论】:

该问题并未指明jumpsize 是已知的。 确实如此;但是,您可以通过检查前 3 个值来了解它(如果它们不平衡,则检查第 4 个值的确切位置) 谢谢@ti7,您能大致了解一下您是如何处理它的吗?我应该想出一个公式并递归应用它吗? @MarkRansom 我添加了一个关于如何检测大小的代码示例! @AshequlHaque 是的,您知道结果在哪一半,只要您发现不匹配,您只需要新中点的索引和大小就知道它是previous value + size

以上是关于难以思考分而治之的方法的主要内容,如果未能解决你的问题,请参考以下文章

Elastic Search | 记一次Kibana执行ES-DSL脚本实战思考过程

Elastic Search | 记一次Kibana执行ES-DSL脚本实战思考过程

Elastic Search | 记一次Kibana执行ES-DSL脚本实战思考过程

关于递归排序和快速排序的衍生思考

#私藏项目实操分享# Java代码优化-请求合并与分而治之

算法复习_分治算法之二分搜索棋盘覆盖快速排序