leetcode 503.下一个更大元素Ⅱ
报错代码:
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
stack<int>st;
vector<int>result(nums.size(),-1);
st.push(0);
for(int i=1;i<nums.size()*2;i++){
if(nums[i%nums.size()]<=nums[st.top()]){
st.push(i%nums.size());
}
else{
while(nums[i%nums.size()]>nums[st.top()]&&!st.empty()){
result[st.top()]=nums[i%nums.size()];
st.pop();
}
st.push(i%nums.size());
}
}
return result;
}
};
错误信息的意思是:运行时发生了一种未定义行为(Undefined Behavior)。具体来说,它在尝试对一个非对齐的地址(即不是4字节对齐的地址)进行整数的引用绑定,而这个操作是未定义的。该错误通常发生在空指针解引用,数组越界等情况。
这个错误出现在while循环这一句:
while(nums[i%nums.size()]>nums[st.top()]&&!st.empty())
while 循环如果这么写,那么,在检查栈是否为空之前,就已经尝试从栈顶取值,这是有问题的。当栈为空时,这将会导致未定义行为。
非空操作的判定必须写在前面,才能防止栈顶已经为空的时候出现未定义行为的操作!
修改为:
while(!st.empty()&&nums[i%nums.size()]>nums[st.top()])
在C++中,逻辑AND操作符(&&
)和逻辑OR操作符(||
)都具有"短路"特性。
对于逻辑AND操作符,如果左边的操作数为假,那么不论右边的操作数是什么,整个表达式的结果都是假,因此不需要再计算右边的操作数。对于逻辑OR操作符,如果左边的操作数为真,那么不论右边的操作数是什么,整个表达式的结果都是真,因此不需要再计算右边的操作数。
因此,写单调栈的while循环,while条件里面包括了非空检查的时候,检查栈是否为空的语句必须放在前面,确定非空之后再尝试从栈顶取值!如果栈已经为空,那么!st.empty()
的结果为假,右边的nums[i%nums.size()] > nums[st.top()]
就不会被执行,从而避免对空栈进行操作的未定义行为。