496. Next Greater Element I + 503. Next Greater Element II + 556. Next Greater Element III

时间:2022-11-04 12:14:18

▶ 给定一个数组与它的一个子列,对于数组中的一个元素,定义它右边第一个比他大的元素称为他的后继,求所给子列的后继构成的数组

▶ 第 496 题,规定数组最后一个元素即数组最大元素的后继均为 -1

● 自己的版本,12 ms,最快的解法算法与之相同

 class Solution
{
public:
vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums)
{
const int m = findNums.size(), n = nums.size();
int i, j;
unordered_map<int, int> table;
vector<int> output;
for (i = ; i < n; table[nums[i]] = i, i++);
for (i = ; i < m; i++)
{
if (findNums[i] == nums[n - ])
{
output.push_back(-);
continue;
}
for (j = table[findNums[i]] + ; j < n && nums[j] < findNums[i]; j++);
if (j == n)
output.push_back(-);
else
output.push_back(nums[j]);
}
return output;
}
};

▶ 第 503 题,数组换成环状,只有数组最大元素的后继为 -1

● 自己的代码,124 ms,添加一个标记 mark 的线性搜索方法

 class Solution
{
public:
vector<int> nextGreaterElements(vector<int>& nums)
{
const int n = nums.size();
int i, mark;
vector<int> output(n, -);
for (mark = ; mark < n - && nums[mark] <= nums[n - ]; mark++);
if (mark < n - ) // 找到了某个位置,标记上,若 mark == n - 1,说明 nums[n - 1] 就是最大的
output[n - ] = nums[mark];
for (i = n - ; i >= ; i--)
{
if (nums[i] < nums[i + ])
{
output[i] = nums[i + ];
mark = i + ;
}
else
{
for (; mark != i && nums[mark] <= nums[i]; mark = (mark + ) % n);
if (mark != i)
output[i] = nums[mark];
}
}
return output;
}
};

● 大佬的代码,111 ms

 class Solution
{
public:
vector<int> nextGreaterElements(vector<int>& nums)
{
const int n = nums.size();
int i, num, ind;
stack<int> st; // 栈维护 num 的单调递减的子列的下标,遇到较大的当前值的时候出栈,出到元素值大于当前值为止
vector<int> result(n, -);
for (i = ; i < * n; i++)// 扫描两趟,确保末尾的元素找到后继
{
for (num = nums[i % n]; !st.empty() && num > nums[st.top()]; ind = st.top(), st.pop(), result[ind] = num);
// 若 num 较大,则把栈中的较小元素都指向 num
st.push(i % n); // 空栈,或者剩余部分的值大于当前值,将当前值压栈
}
return result;
}
};

● 大佬的代码,103 ms,两步走战略

 class Solution
{
public:
vector<int> nextGreaterElements(vector<int> nums)
{
const int n = nums.size();
if(n==)
return vector<int>();
vector<int> res(n);
int i, maxValue, index, real;
for (maxValue = nums[], i = index = ; i < n; i++)// 第一轮,将两种情况的第 k 元素进行标记:
{ // ① nums[ k ] < nums[ k + 1 ]
if (nums[i] > maxValue) // ② nums[ k ] >= nums[ k + 1 ] ... nums[ k + m ] 且 nums[ k ] < nums[ k + m ]
{ // 注意第一轮结束时 index 等于数组最大元素的下标
res[i - ] = i;
res[index] = i;
maxValue = nums[i];
index = i;
}
}
for (res[index] = -, i = index - ; i > index - n; i--)// 将数组最大元素的输出值置 -1,从最大元素开始向左遍历数组
{
real = (i + n) % n;
if (res[real] != )
continue;
res[real] = (real == n - ? : real + );// 让该元素的输出值初始化为它右边那个元素
for (; res[real] != - && nums[real] >= nums[res[real]]; res[real] = res[res[real]]);// 寻找该元素的真实输出值
}
for (i = ; i < n; i++)// 将下标置换回元素的值
{
if (res[i] != -)
res[i] = nums[res[i]];
}
return res;
}
};

● 其他方法,枚举,时间复杂度 O(n2)