503. Next Greater Element II Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, output -1 for this number. Example 1: Input: [1,2,1] Output: [2,-1,2] Explanation: The first 1's next greater number is 2; The number 2 can't find next greater number; The second 1's next greater number needs to search circularly, which is also 2.

//题意:从数组中从左到右找到比sum[i]大的值

public static int[] nextGreaterElements(int[] nums) {
    int []a =new int[nums.length];
    int k = 0, status;

    for (int i = 0; i < nums.length-1; i++) {
        status = 0;
//          第一遍for,筛选sum[i]后的值
        for (int j = i+1; j < nums.length; j++) 
        if(nums[j] > nums[i]) {
            status = 1;
            a[k++] = nums[j];
            break;
        }
//          第二遍,筛选sum[i]前的值
        for (int j = 0; j < i && status==0; j++) 
            if(nums[j] > nums[i]) {
                status = 1;
                a[k++] = nums[j];
                break;
            }

//          如果都找不到,那就是-1
        if(status == 0)
            a[k++] = -1;
    } 
    status = 0;
//        对最后的一个数进行处理
    for (int i = 0; i < nums.length-1; i++) 
        if(nums[i] > nums[nums.length-1]) {
            status = 1;
            a[k++] = nums[i];
            break;
        }
    if (status == 0 && nums.length != 0) 
        a[k++] = -1;

    return a;   
}

代码不够简洁,我使用System.arraycopy(),构造doublenums[] 包含两个nums数据,这样就不需要回头来判断数组前面的值了

public int[] nextGreaterElements(int[] nums) {
    int []a =new int[nums.length];
    int []doublenums = new int[2*nums.length];
    System.arraycopy(nums, 0, doublenums, 0, nums.length);
    System.arraycopy(nums, 0, doublenums, nums.length, nums.length);

    int k = 0, status;
    for (int i = 0; i < nums.length; i++) {
        status = 0;
        for (int j = i+1; j < doublenums.length; j++) 
            if(doublenums[j] > nums[i]) {
                status = 1;
                a[k++] = doublenums[j];
                break;
            }
        if(status == 0)
            a[k++] = -1;
    }

    return a;   
}

上面效率不高,空间和时间都是O(n^2),而且调用System.arraycopy也会耗费一些时间, 让我们来优化下,可以用数学表达式 j%nums.length 来代替doublenums的作用

public int[] nextGreaterElements(int[] nums) {
    int []a =new int[nums.length];

    int k = 0, status;
    for (int i = 0; i < nums.length; i++) {
        status = 0;
        for (int j = i+1; j < 2*nums.length; j++) 
            if(nums[j%nums.length] > nums[i] && j%nums.length != i ) {
                status = 1;
                a[k++] = nums[j%nums.length];
                break;
            }
        if(status == 0)
            a[k++] = -1;
    }

    return a;   
}

上面效率没提高多少,只是少用了一个空间,让我们使用stack来提高效率 思路: 构建栈stack,nums从 i = 2*nums.length-1(倒着来,也是难想到的顺着来就不行了) 开始循环进行如下动作进栈: (1):进栈前判断nums[i]是否大于stack.peek(),没有的话, 将其Next Greater Element 设置为stack.peek(),然后入栈; (2):大于的话,则stack.pop(),直到不大于或者为空。 将其Next Greater Element 设置为stack.peek(),空着设置为-1,然后入栈;

public static int[] nextGreaterElements(int[] nums) {
    int []a =new int[nums.length];
    Stack<Integer> stack = new Stack<>();
    for (int i = 2*nums.length-1; i > 0; i--) {
        if(stack.isEmpty()) {
            stack.push(nums[i%nums.length]);
            a[i%nums.length] = -1;
            continue;
        }
        if(nums[i%nums.length] < stack.peek()) {
            a[i%nums.length] = stack.peek();
            stack.push(nums[i%nums.length]);
        }
        if(nums[i%nums.length] >= stack.peek()) {
            while(!stack.isEmpty() && nums[i%nums.length] >= stack.peek())
                stack.pop();
            if(stack.isEmpty())
                a[i%nums.length] = -1;
            else 
                a[i%nums.length] = stack.peek();

            stack.push(nums[i%nums.length]);

        }
    }

    return a;   
}

思路很好,但是实现过程太多if语句。效率太低,继续改进 将三种情况整合, 当!stack.isEmpty() && nums[i%nums.length时,只执行stack.pop(); 其他两种变成一个a>b?a:b表达式; 最后都执行 stack.push(nums[i%nums.length]);

public static int[] nextGreaterElements(int[] nums) {
    int []a =new int[nums.length];
    Stack<Integer> stack = new Stack<>();
    for (int i = 2*nums.length-1; i >=0; i--) {
         while(!stack.isEmpty() && nums[i%nums.length] >= stack.peek())
             stack.pop();
         a[i%nums.length]=  stack.isEmpty()? -1:stack.peek();
         stack.push(nums[i%nums.length]);
    }

    return a;   
}