我在这里阅读这篇社论:https://www.geeksforgeeks.org/given-an-array-arr-find-the-maximum-j-i-such-that-arrj-arri/,但我无法理解O(n)解决方案的工作原理。描述它的段落似乎与代码矛盾。我已经遍历了一个示例数组,并手动确保这似乎可行,但对我来说却一点也不直观。
对解决编程难题有更丰富经验的人愿意解释它的工作原理和原因,或解释它的问题吗?
谢谢。
(下面是上面链接的文字:)
给定一个数组arr [],找到最大j – i,使得arr [j]> arr [i] 给定数组arr [],找到最大j – i,使得arr [j]> arr [i]。
示例:
Input: {34, 8, 10, 3, 2, 80, 30, 33, 1}
Output: 6 (j = 7, i = 1)
Input: {9, 2, 3, 4, 5, 6, 7, 8, 18, 0}
Output: 8 ( j = 8, i = 0)
要解决此问题,我们需要获得arr []的两个最佳索引:左索引i和右索引j。对于元素arr [i],如果arr [i]左侧的元素小于arr [i],则无需为左索引考虑arr [i]。类似地,如果arr [j]的右侧有一个更大的元素,那么对于正确的索引,我们不需要考虑这个j。因此,我们构造了两个辅助数组LMin []和RMax [],使得LMin [i]在包含arr [i]的arr [i]的左侧保留最小的元素,而RMax [j]在arr [i]的右侧保留最大的元素arr [j]包括arr [j]。构建完这两个辅助数组后,我们从左到右遍历这两个数组。在遍历LMin []和RMa []时,如果我们看到LMin [i]大于RMax [j],则必须向前移动LMin [](或执行i ++),因为LMin [i]左侧的所有元素都是大于或等于LMin [i]。否则,我们必须继续在RMax [j]中寻找更大的j – i值。
答案 0 :(得分:2)
有效。代码作者只是采用了一个令人困惑的快捷方式。
正如社论所指出的,给定索引i1 < i2
与arr[i1] ≤ arr[i2]
,没有必要考虑i = i2
。我们总是可以通过设置i = i1
来做得更好,因为对于所有j
,
j - i1 > j - i2
和arr[j] > arr[i2]
,则arr[i2] ≥ arr[i1]
表示arr[j] > arr[i1]
的事实。类似地,在给定索引j1 < j2
和arr[j1] ≤ arr[j2]
的情况下,没有必要考虑使用j = j1
。
让我们检查第一个样本输入并消除所有这些次优的候选对象。
34 8 10 3 2 80 30 33 1
34 8 3 2 1 // candidate values of arr[i]
80 33 1 // candidate values of arr[j]
观察到两个子序列都减少。这是上述条件成为候选人的直接结果。
搜索最佳的i
和j
现在涉及编程竞赛陈词滥调。让我将可能性组织成表格。 请注意,该算法不会显式构造此表。只是视觉辅助。
80 33 1
-------------
34 √
8 √ √
3 √ √
2 √ √
1 √ √
复选标记(√
)表示arr[i] < arr[j]
。下降意味着增加i
并减少arr[i]
。向左移动意味着减少j
并增加arr[j]
。因此,无论哪里有复选标记,下方或左侧的所有正方形或某些组合也都具有复选标记。另一方面,给定一个带有选中标记的正方形在另一个带有选中标记的正方形的下方/左侧,则后一个正方形一定是更好的解决方案,因为i
较小或j
较大或两者。因此,我们对复选标记和无复选标记之间的边界非常感兴趣,因为这是最佳解决方案所在。
跟踪边界的算法很简单。从左上角的正方形开始。如果当前正方形上有一个选中标记,请向右走。否则,下去。希望您能了解此过程如何在时间O(#rows + #columns)
内访问每个列中的第一个对勾标记。这是另一个可能的表。
33 8 7 3
---------------
34
8 √
3 √ √ √
2 √ √ √ √
1 √ √ √ √
要执行该实现,请注意,我们正在执行相同的搜索,但是重复了一些行/列以填充非候选者留下的空白空间,从而避免了麻烦索引之间的对应关系。基本上是相同的想法。
答案 1 :(得分:0)
这是单调函数的魔力,并且是通过可视化问题的解决方案空间以及这些值如何相互对齐而获得的洞察力。让我们在链接到的页面中绘制一个示例; x轴上的数组索引,y轴上的LMin和RMax:
{34, 8,10, 3, 2,80,30,33, 1}
0 1 2 3 4 5 6 7 8
80 r r r r r r
.
34 l
33 r r
. ^
30
.
10
.
8 l l
. ^
3 l
2 l l l l
1 lr
0 1 2 3 4 5 6 7 8
r
值不是(不一定)与数组索引关联的值;相反,它表示我们可以向右扩展一个间隔多远,从而确保右侧的r
不会更大(这意味着我们可能会错过更大的间隔)。同样,l
表示我们处于最低的左侧值,并且由于我们首先探索沿r
的移动,因此可以保证不会错过更早的{{1} }进行搜索的任何间隔。显然,我们最多沿所有l
和所有r
进行从左到右的迭代,所以l
。