掘金刷题-最大乘积问题 | 豆包MarsCode AI刷题

31 阅读3分钟

问题描述

对于一个有 N 个元素的数组,包含如下的元素 a1, a2, ..., an,我们定义了两个函数:

  • L(i) = j 需要满足的条件如下:

    • j < i
    • a[j] > a[i]
    • 如果找不到 j 的话,那么 L(i) = 0;如果有多个 j 的话,选择离 i 最近的那一个
  • R(i) = k 需要满足的条件如下:

    • k > i
    • a[k] > a[i]
    • 如果找不到 k 的话,那么 R(i) = 0;如果有多个 k 的话,选择离 i 最近的那一个

最后,我们定义 MAX(i) = L(i) * R(i),我们需要找到 MAX(i) 的最大值,其中 1 <= i <= N。

输入格式

总共有两行,第一行是数组长度 N,第二个是空格分割的所有数组的内容。

输出格式

输出 MAX(i) 的最大值。

输入样例

5
5 4 3 4 5

输出样例

8

解释说明

  • L(1) = 0,所以 MAX(1) = 0
  • L(2) = 1, R(2) = 5,所以 MAX(2) = 1 * 5 = 5
  • L(3) = 2, R(3) = 4,所以 MAX(3) = 2 * 4 = 8
  • L(4) = 1, R(4) = 5,所以 MAX(4) = 1 * 5 = 5
  • R(5) = 0,所以 MAX(5) = 0

数据范围

  • 1<=𝑁<=1051<=N<=105
  • 1<=𝑎[𝑖]<=1091<=a[i]<=109

思路

这个题要求的L函数存放的是数组中第i个元素的左侧离它最近且大于它的值,而R函数同理,是右侧最近且大于的数。由此可以想到栈中后进先出的特性,当栈顶元素大于a[i]时,就可以把栈顶元素的索引存入l中,否则,弹出栈顶元素,判断下一个元素(当栈不为空)。

案例图解

image.png 图中只展示了L函数的存入过程,但是R函数的存入过程与L是差不多的。

AC代码

import java.util.*;
public class Main {
    public static int solution(int n, int[] array) {
        // Edit your code here
        //定义两个数组存放离元素最近且大于元素的索引
        int[] left=new int[n];
        int[] right=new int[n];
        Stack<Integer> stk=new Stack<>();
        for(int i=0;i<n;i++){
            while(!stk.isEmpty()&&array[stk.peek()]<=array[i]){
                stk.pop();
            }
            left[i]=stk.isEmpty()?0:stk.peek()+1;
            stk.push(i);
        }
        stk.clear();
        for(int i=n-1;i>=0;i--){
            while(!stk.isEmpty()&&array[stk.peek()]<=array[i]){
                stk.pop();
            }
            right[i]=stk.isEmpty()?0:stk.peek()+1;
            stk.push(i);
        }
        int max=0;
        for(int i=0;i<n;i++){
        max=Math.max(max,left[i]*right[i]);
        }
        return max;
    }

    public static void main(String[] args) {
        // Add your test cases here

        System.out.println(solution(5, new int[]{5, 4, 3, 4, 5}) == 8);
    }
}

核心代码的要点:

  • 循环比较栈顶元素的值。
  • 当栈为空时,L或R数组存入0。
  • 判断和存入结束后,栈中压入元素。

总结

题目的重点就是利用栈来实现对元素的撤销操作,在满足题目要求的情况下将不满足条件的元素撤销,实现了循环遍历数组做不到的操作。

学习心得

这道题十分清晰的展现了使用栈来解决问题的过程,从这道题目中我更深刻的体会到栈对于操作的销毁的方便性(题目中将不合格的栈顶元素弹出),虽然这道题的难度不高,但是对于栈的理解却是很有帮助的。