【问题标题】:Find the pair (i,j) such that i<j and and (a[i] + a[j]) is maximum找到对 (i,j) 使得 i<j 并且 (a[i] + a[j]) 最大
【发布时间】:2020-01-11 04:44:04
【问题描述】:

给定一个未排序的数组 – arr 找到一对 arr[i] 和 arr[j] 使得 arr[i] &lt; arr[j] &amp; i&lt;j(arr[i] + arr[j]) 是最大值。

预期时间复杂度 - O(n)

对于数组a = {4, 1, 3, 2, 5, 3}

pair is (4, 5).

这是我尝试过的代码..

void findPair(int[] a){  
        int n = a.length;
        int max = a[0];
        int secondMax = Integer.MIN_VALUE;

        for(int i=1; i<n; i++){
            if(a[i]>max){
                secondMax = max;
                max = a[i];
            }
        }
        if(secondMax == Integer.MIN_VALUE){
            System.out.println("-1 -1");
        }
        else{
            System.out.println(secondMax+" "+max);
        }
}

【问题讨论】:

  • 谢谢。仍然存在:如果没有解决方案,我们返回什么,如[4,3,2,1]

标签: java arrays algorithm


【解决方案1】:

这是一个使用堆栈的解决方案。这个想法是堆栈始终包含一个降序,这样对于您查看的每个数字,它都可以与堆栈中低于它的最大数字配对。

在使用时弹出数字是安全的,因为例如如果你有一个 6 并且堆栈的顶部是 3,则无需保留 3,以防它可以与更大的数字配对;如果以后有 7,您将等待将其与 6 而不是 3 配对。

public void solution(int[] arr) {
    Stack<Integer> stack = new Stack<>();
    int bestX = -1, bestY = -1, bestSum = -1;

    for(int y : arr) {
        while(!stack.isEmpty() && stack.peek() < y) {
            int x = stack.pop();
            if(x + y > bestSum) { bestX = x; bestY = y; bestSum = x + y; }
        }
        stack.push(y);
    }

    System.out.println(bestX + " " + bestY);
}

尽管嵌套循环,时间复杂度是O(n),因为内层循环总是从栈中弹出,每个元素只被压入一次,所以只能被弹出一次。

【讨论】:

    【解决方案2】:

    我对你的问题想了很多,我想我找到了一个可以接受的解决方案。

    您应该从数组末尾(右侧)开始将数组拆分为子数组。以迭代方式构建子数组。您从最右边的数字开始,然后将 他之前低于他的所有数字添加到子数组中。当您到达一个大于/等于子数组中最右边数字的数字时,迭代将转到下一个子数组。

    例子:

    您的数组是:{1,7,3,4,5,4,6,2}

    输出应该是:(5,6)

    拆分应该是:

    {{1, 7}, {3, 4, 5, 4, 6}, {2}}

      <--(3)     <--(2) <--(1)
    

    您从值为 2 的最后一个索引开始。他前面的数字是 6,所以这是第一个子数组的结尾。接下来从 6 开始,直到 7 之前的所有数字都小于 6,因此您将它们添加到该子数组中。最后一个子数组以 7 开头并加 1。请参阅箭头以进行说明。

    接下来,在每个子数组中检查从左到右的哪个数字最大,并将其标记为可能与最右边的数字配对。

    在我们的示例中,它将是:(1,7), (5,6)。

    只有两个选项,因为 {2} 只有 1 个变量。在最右边为 6 的子数组中,最大数为 5,在最右边为 7 的子数组中,1 是唯一的其他数字,因此它也是最大值。

    如果没有找到对,则返回“没有找到可能的对”。

    最后,校验和并返回最大的对:(5,6)

    1+7 = 8 &lt; 5+6 = 11

    为什么是O(n)

    • 您扫描阵列一次以进行拆分:O(n)
    • 每个大小为d 的子数组扫描最大值:O(d)
    • 所有子阵列扫描的总和:O(n)

    总计:O(n)

    我不擅长 Java,所以我的代码可以用 Python 编写,而且转换应该很容易(因为 Python 很简单!)。如果你想要 Python 代码,请告诉我,我会为你写一些。另外,我可以解释更多为什么这个算法有效(如果没有完全理解)。

    【讨论】:

    • 这是 O(n) 解决方案,这肯定会奏效。我会写java代码。感谢您告知方法。
    • 谢谢。此外,您实际上不必“构建”子数组。您可以只扫描也低于最右边数字的最大数字。
    【解决方案3】:

    免责声明:解决方案是 O(n^2),而不是 OP 要求的 O(n)

    如何使用 2 个嵌套循环:

    • i0a.length
    • ji+1a.length

    这确保i&lt;j 然后有一个 if 来确保a[i]&lt;a[j] 并找到最大值

    int currentMax = -1;
    int foundI = -1;
    int foundJ = -1;
    for(int i=0; i<a.length; i++) {
        for(int j=i+1; j<a.length; j++) {
            if(a[i] < a[j] && a[i] + a[j] > currentMax) {
                currentMax = a[i] + a[j];
                foundI = i;
                foundJ = j;
            }
        }
    }
    

    输出:

    System.out.println("i:" + foundI);
    System.out.println("j:" + foundJ);
    System.out.println("a[i]:" + a[foundI]);
    System.out.println("a[j]:" + a[foundJ]);
    System.out.println("sum:" + currentMax);
    

    i:0
    j:4
    a[i]:4
    a[j]:5
    sum:9
    

    【讨论】:

    • 谢谢,但我需要 O(n) 解决方案。
    • 这个解决方案是 O(n^2),因为它遍历所有索引对,其中 i &lt; j
    • @kaya3 好的,谢谢,我将在答案顶部添加免责声明,因为它仍然对找到此线程的人有用
    猜你喜欢
    • 2021-04-09
    • 1970-01-01
    • 2019-04-19
    • 2017-09-10
    • 2012-10-20
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多