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 模式(特别的单调栈)