求最小數 * 區間和最大值

來源:字節跳動編程題
大意:找出一個數組中區間最小數*區間和的最大值java

思路 & 代碼 思路:每一個數均可以成爲區間最小數,那麼當它成爲最小數時,使所在區間儘量大則乘積更大,而後取全部乘積最大值便可。計算區間時,咱們能夠分爲左右區間來計算,爲避免重複計算區間範圍,計算左區間時,能夠維護一個單調遞增棧(不小於當前值的自動構成左區間一員),右區間同理。

時間:O(n),空間:O(n)編程

import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * 〈一句話功能簡述〉<br> 
 * 〈區間最大值:https://www.nowcoder.com/questionTerminal/3f4867e9cbe54403ac5df55b8e678df9〉
 *
 * @author Administrator
 * @create 2020/12/5
 * @since 1.0.0
 */
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        Deque<Integer> stack = new LinkedList<>(); // 單調遞增棧(記錄下標)
        int n = in.nextInt();
        int[] num = new int[n+1];
        int[] prefix = new int[n+1];
        Node[] goal = new Node[n+1];
        for(int i = 1; i <= n; i++) {
            goal[i] = new Node(); // 對象初始化必須 new
        }
        for(int i = 1; i <= n; i++) {
            num[i] = in.nextInt();
            prefix[i] = prefix[i-1] + num[i];
            // 注意:由於最終的結果是對相應乘積求和而非取最大值,這裏的出棧比較和下面的比較兩處只能取一處等號
            // eg: [1 2 2 2 1]
            while(!stack.isEmpty() && num[stack.peek()] >= num[i]) stack.pop();
            goal[i].start = stack.isEmpty() ? 0 : stack.peek(); // 棧空應該賦予 0 而非 i-1
            stack.push(i);
        }
        stack.clear();
        for(int i = n; i >= 1; i--) {
            while(!stack.isEmpty() && num[stack.peek()] > num[i]) stack.pop();
            goal[i].end = stack.isEmpty() ? n : stack.peek()-1; // 棧空時賦予 n 而非 i
            stack.push(i);
        }
        long ans = 0;
        for(int i = 1; i <= n; i++) ans = Math.max(ans, (long)(prefix[goal[i].end]- prefix[goal[i].start])*(long)num[i]);
        System.out.print(ans);
    }
}

class Node {
    int start;
    int end;
    Node() {}
}
相關文章
相關標籤/搜索