LC6227.下一个更大元素 IV(双单调栈||set||线段树)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LC6227.下一个更大元素 IV(双单调栈||set||线段树)相关的知识,希望对你有一定的参考价值。

LC6227.下一个更大元素 IV(双单调栈||set||线段树)

1.双单调栈

class Solution 
public:
    vector<int> secondGreaterElement(vector<int>& nums) 
        int n = nums.size();
        stack<int> s1, s2;
        vector<int> res(n, -1);
        for(int i=0; i<n; ++i)
            while(!s2.empty() && nums[s2.top()]<nums[i])
                int t = s2.top();
                s2.pop();
                res[t] = nums[i];
            
            stack<int> tmp;
            while(!s1.empty() && nums[s1.top()]<nums[i])
                int t = s1.top();
                s1.pop();
                tmp.push(t);
            
            while(!tmp.empty())
                s2.push(tmp.top());
                tmp.pop();
            
            s1.push(i);
        
        return res;
    
;

2.set

先将数组按照val降序,val相等 id升序。

然后维护一个id的set。

按顺序遍历数组(用二维存val和id)。因为之前的val都是大于等于此时的val的,如果等于也不影响因为id<当前id。我们在set里查找id大于当前的,然后调用下next 迭代器 就可以求出答案了。

class Solution 
public:
    vector<int> secondGreaterElement(vector<int>& nums) 
        int n = nums.size();
        
        // 将所有下标按 nums[i] 降序为第一关键字,i 升序为第二关键字排序
        typedef pair<int, int> pii;
        vector<pii> vec;
        for (int i = 0; i < n; i++) vec.push_back(pii(-nums[i], i));
        sort(vec.begin(), vec.end());

        vector<int> ans(n);
        set<int> st;
        // 按排序后的顺序枚举下标
        for (int i = 0; i < n; i++) 
            // 找到有序列表里比 i 大的第二个数
            auto it = st.upper_bound(vec[i].second);
            if (it != st.end() && next(it) != st.end()) ans[vec[i].second] = nums[*next(it)];
            else ans[vec[i].second] = -1;
            // 将当前下标加入有序列表
            st.insert(vec[i].second);
        
        return ans;
    
;

3.线段树

先单调栈预处理每个位置的下一个元素,然后就是在 [ p o s + 1 , n ] [pos+1,n] [pos+1,n]上查找大于 v a l val val的第一个下标,这个可以线段树分治做,维护每个区间的最值。若左区间满足直接返回,否则往右子区间找。

参考

class node 
    l: number = 0;
    r: number = 0;
    val: number = 0;
    constructor(_l: number = 0, _r: number = 0) 
        this.l = _l, this.r = _r;
    

class SegTree 
    private segs: node[];
    constructor(n: number) 
        this.segs = new Array<node>(n * 4);
        this.build(1, 1, n);
    
    build(u: number, l: number, r: number): void 
        this.segs[u] = new node(l, r);
        if (l === r) return;
        let mid = l + r >> 1;
        this.build(u << 1, l, mid);
        this.build(u << 1 | 1, mid + 1, r);
    
    pushup(u: number): void 
        this.segs[u].val = Math.max(this.segs[u << 1].val, this.segs[u << 1 | 1].val);
    
    update(u: number, x: number, v: number): void 
        if (this.segs[u].l === x && this.segs[u].r === x) 
            this.segs[u].val = v;
            return;
        
        let mid = this.segs[u].l + this.segs[u].r >> 1;
        if (x <= mid) this.update(u << 1, x, v);
        else this.update(u << 1 | 1, x, v);
        this.pushup(u);
    
    // 返回[l, r]区间中从左向右第一个大于d的位置,不存在返回-1
    query(u: number, l: number, r: number, d: number): number 
        if (this.segs[u].l === l && this.segs[u].r === r) 
            if (this.segs[u].val <= d) return -1;
            else 
                if (this.segs[u].l == this.segs[u].r) return this.segs[u].l;
                let mid = this.segs[u].l + this.segs[u].r >> 1;
                if (this.segs[u << 1].val > d) return this.query(u << 1, l, mid, d);
                else return this.query(u << 1 | 1, mid + 1, r, d);
            
         else 
            let mid = this.segs[u].l + this.segs[u].r >> 1;
            if (r <= mid) return this.query(u * 2, l, r, d);
            else if (l > mid) return this.query(u << 1 | 1, l, r, d);
            else 
                let pos = this.query(u << 1, l, mid, d);
                if(pos == -1) pos = this.query(u << 1 | 1, mid + 1, r, d);
                return pos;
            
        
    

function secondGreaterElement(nums: number[]): number[] 
    const n = nums.length;
    const r = new Array(n).fill(-1); // 单调栈求出每个数右边离它最近比他大的数
    const stk = new Array();
    for (let i = n - 1; i >= 0; i -- ) 
        while (stk.length && nums[i] >= nums[stk[stk.length - 1]]) stk.pop();
        if (stk.length) r[i] = stk[stk.length - 1];
        stk.push(i);
    

    const tr = new SegTree(n);
    const res = new Array();

    for (let i = n - 1; i >= 0; i -- ) 
        if (r[i] === -1 || r[i] == n - 1) res.push(-1); // 当前元素后没有比它大的元素 或 比它大的元素在最后
        else 
            let pos = r[i] + 2;
            let q = tr.query(1, pos, n, nums[i]);
            res.push(q === -1 ? -1 : nums[q - 1]);
        
        tr.update(1, i + 1, nums[i]);
    

    return res.reverse();
;

以上是关于LC6227.下一个更大元素 IV(双单调栈||set||线段树)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题(161)~下一个更大元素 I哈希+单调栈

LeetCode 516. 最长回文子序列(区间dp) / 36. 有效的数独/73. 矩阵置零/496. 下一个更大元素 I / 456. 132 模式(特别的单调栈)

503. 下一个更大元素 II

496. 下一个更大元素 I

[H单调栈] lc5196. 队列中可以看到的人数(单调栈+双周赛57_4)

[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)