【问题标题】:Better Solution for Finding out Maximums for Consecutive Array Subsequences找出连续数组子序列的最大值的更好解决方案
【发布时间】:2014-09-06 21:51:42
【问题描述】:

假设,给定一个整数数组 A,我想用 A 找出另一个 COUNT 数组。

例如,int A[] = {34, 10, 15, 14, 30, 27, 21, 32, 50}

对于上面的例子,COUNT[] 应该是:{0, 0, 1, 0, 3, 0, 0, 6, 8}

这里,COUNT[i]对应A[i],COUNT[i]表示A中小于A[i]的连续先前元素个数。

例如,A[1] = 10, COUNT[1] = 0,因为 A 中没有小于 A[1] 的前一个元素。

A[7] = 32, COUNT[7] = 6,因为 32 大于前 6 个连续元素(例如,10、15、14、30、27、21)。

我们可以为这个问题提供 O(n) 的解决方案吗?

编辑:

根据@user1990169 的算法, 我在 Java 中实现它如下,但它没有给出预期的输出,因为算法不计算堆栈上不存在的那些索引(在早期迭代中已经弹出)。

public static void main(String[] args) throws Exception {

    Stack<Integer> stack = new Stack<Integer>();

    // int a[] = new int[] { 53, 2, 7, 5, 15, 12, 10, 38, 72 };
    int a[] = new int[] { 34, 10, 15, 14, 30, 27, 21, 32, 50 };

    int N = a.length;

    int[] count = new int[N];

    int tos = 0;
    int poppedElemIdx = 0;
    int popCount = 0;

    boolean counted = false;

    stack.clear();

    for (int i = 0; i < N; i++) {

        popCount = 0;
        counted = false;
        while (!stack.isEmpty()) {

            tos = stack.peek();

            if (a[tos] > a[i]) {

                stack.push(i);
                count[i] = count[poppedElemIdx] + popCount;
                counted = true;
                break;

            }

            poppedElemIdx = stack.pop();
            popCount++;
            // popCount += (count[poppedElemIdx] + 1);

        }

        if (counted) {
            continue;
        }

        stack.push(i);
        count[i] = popCount;

    }

    // Print count array
    for (int i = 0; i < N; i++) {
        System.out.print(count[i] + " ");
    }

}

【问题讨论】:

    标签: arrays algorithm data-structures


    【解决方案1】:

    O(N) 空间和 O(N) 时间复杂度算法。

    从左到右遍历数组。维护一个外部元素堆栈。

    A[0] = 34, push 34 onto stack. Count[0] = 0.  
    A[1] = 10,  
    Now keep popping out from stack till either it is empty 
    or you encounter a number greater than the current element (10). 
    Here 34 is > 10, hence we push 10 onto stack and make Count[1] = 0.  
    
    A[2] = 15.  
    So we pop out 10 from the stack, push 15 onto stack,  
    and make Count[2] = Count[ last popped out index ] + Number of indices popped out  
                      = 0 + 1 = 1.  
    A[3] = 14.
    So we push 14 onto stack and make Count[3] = 0.
    A[4] = 30.
    So we pop out 14 and 15 from the array, push 30 onto the array 
    and make Count[4] = Count[ index of 15 ] + Number of indices popped out(2) 
                      = 1 + 2 = 3.
    

    这样做直到到达数组的末尾。

    由于每个项目只被压入一次并从堆栈中弹出一次,因此时间复杂度为 O(2*N) = O(N)。

    编辑:按照建议,将索引存储在堆栈中会更好,而不是值。

    【讨论】:

    • +1 非常好的解决方案。您可以在堆栈中推送索引而不是值。我也理解你所说的Count[ last popped out index ] + Number of indices popped out 的意思,但对其他读者来说,更多细节会有所帮助。
    • @IvayloStrandjev 谢谢。详细阐述了我的算法,使其更清晰。
    • 非常感谢,@user1990169。你刚刚解决了股票利润最大化问题(在不知不觉中):D
    • @user1990169,您提到的算法中似乎存在一些错误,或者我没有正确理解它,您能告诉我我的代码有什么问题吗(请参阅问题的编辑部分)?
    • @user1990169,在逻辑上进行了一些小的更改后,代码工作正常。再次感谢!
    【解决方案2】:

    对原始算法进行小幅修改后的工作程序:

    public static void main(String[] args) throws Exception {
    
        Stack<Integer> stack = new Stack<Integer>();
    
        int a[] = new int[] { 53, 2, 7, 5, 15, 12, 10, 38, 72 };
        // int a[] = new int[] { 34, 10, 15, 14, 30, 27, 21, 32, 50 };
    
        int N = a.length;
    
        int[] count = new int[N];
    
        int tos = 0;
        int poppedElemIdx = 0;
        int popCount = 0;
    
        boolean counted = false;
    
        stack.clear();
    
        for (int i = 0; i < N; i++) {
    
            popCount = 0;
            counted = false;
            while (!stack.isEmpty()) {
    
                tos = stack.peek();
    
                if (a[tos] > a[i]) {
    
                    stack.push(i);
                    count[i] = popCount;
                    counted = true;
                    break;
    
                }
    
                poppedElemIdx = stack.pop();
                popCount += (count[poppedElemIdx] + 1);
    
            }
    
            if (counted) {
                continue;
            }
    
            stack.push(i);
            count[i] = popCount;
    
        }
    
        // Print count array
        for (int i = 0; i < N; i++) {
            System.out.print(count[i] + " ");
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-23
      • 2014-07-20
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 2022-12-20
      • 2016-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多