让我们做个简单的观察:如果我们有两个元素a[i]和a[j],其中i < j且a[i] < a[j],那么我们可以确定j不会成为解的第一个元素(他可能成为第二个,但那是另外一回事),因为i是更好的替代者。
这告诉我们,如果我们从a的元素中贪心地构建一个递减序列,左半部分的答案肯定来自于那里。
例如,对于:12 3 61 23 51 2,贪婪的递减序列如下所示:
12 -> 12 3 -> 我们忽略61,因为它比3差-> 我们忽略23,因为它比3差-> 我们忽略51,因为它比3差-> 12 3 2。
因此,答案左侧将包含12 3或2。
现在,在随机情况下,它的长度为O(log N),因此您可以针对每个元素进行二进制搜索,作为答案的右侧,这将得到O(N log log N),这很不错,如果您在字符串的右侧应用相同的逻辑,则在随机情况下,您可以获得O(log^2 N + N(从读取)),这是O(N)。 但是,在非随机情况下,我们也可以做到O(N)。
假设我们有这个递减序列。我们从字符串的右侧开始,做以下操作,只要我们可以将递减序列的最后一个与当前数字配对:
1)如果通过取递减序列的最后一个和当前的数字找到更好的解,则更新答案
2)即使我们更新了答案,或者没有更新答案,我们也会弹出递减序列的最后一个元素,因为我们是它的完美匹配(任何其他匹配都在左侧,并且会给出具有更小j-i的答案)
3)重复,直到我们可以配对这两个对象
示例代码:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int N; cin >> N;
vector<int> A(N + 1);
for (int i = 1; i <= N; ++i)
cin >> A[i];
vector<int> decreasing;
pair<int, int> answer;
decreasing.push_back(1);
for (int i = 1; i <= N; ++i)
if (A[i] < A[decreasing.back()])
decreasing.push_back(i);
for (int i = N; i > 0; --i) {
while (decreasing.size() and A[decreasing.back()] < A[i]) {
pair<int, int> current_pair(decreasing.back(), i);
if (current_pair.second - current_pair.first > answer.second - answer.first)
answer = current_pair;
decreasing.pop_back();
}
}
cout << "Best pair found: (" << answer.first << ", " << answer.second << ") with values (" << A[answer.first] << ", " << A[answer.second] << ")\n";
}
稍后编辑:
我看到您举了一个例子:我从1开始索引,以使它更清晰,并打印(i,j)而不是(j,i)。您可以根据需要进行修改。
lg N
еӣ еӯҗзҡ„з®—жі•дёҺи§ЈеҶіж–№жЎҲжңүд»Җд№Ҳе…ізі»пјҹиҜҘж•°з»„жҳҜжңӘжҺ’еәҸзҡ„гҖӮй—®йўҳиҰҒжұӮеңЁе…¶дёӯжүҫеҲ°дёӨдёӘе…ғзҙ пјҢе®ғ们д№Ӣй—ҙзҡ„и·қзҰ»жңҖиҝңпјҢ并满足дёҖдёӘдёҚзӯүејҸгҖӮ - Happy Green Kid Naps