503. Next Greater Element II

503. Next Greater Element II

第一次解法

暴力遍历整个数组,时间复杂度 O(N²) 每个元素都从头开始找并记录比它大的元素的下标,在元素左边的时候总是更新,在元素右边的时候只要找到一个符合要求的就 break 找下一个,找不到则设为 -1

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> res;
        for(int i=0;i<nums.size();++i) {
            int idx = -2;
            for(int j=0;j<nums.size();++j) {
                if (nums[j]>nums[i]) {
                    if (j < i && idx < 0) {
                        idx = j;
                    } else if (j > i) {
                        idx = j;
                        break;
                    }
                }
            }
            
            if (idx < 0)
                res.push_back(-1);
            else
                res.push_back(nums[idx]);
        }
        return res;
    }
};

最优解,使用栈

时间复杂度:O(N) 空间复杂度:O(N)

#define MAX_NUMS 10000

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> res(nums.size(), -1);
        bitset<MAX_NUMS> bs;
        stack<int> s;
        
	// 优先右边开始找
        for(int j=nums.size()-1;j>=0;--j) {
	// 从右向左扫描,一定保证栈顶指向元素是最大的,那么就越可能是下一个大的元素
            while (!s.empty() && nums[s.top()] <= nums[j]) s.pop();

            if (!s.empty()) {
                res[j] = nums[s.top()];
		// 标记第一遍已找到的元素
                bs[j] = 1;
            }
            
            s.push(j);
        }
        
	// 没找到的刚好可以利用之前的栈已经存好的从左到右大的元素继续找
        for(int j=nums.size()-1;j>0;--j) {
	   // 只找那些没找到的
            if (bs[j] == 0) {
                while(!s.empty() && nums[j] >= nums[s.top()]) s.pop();
                
                if (!s.empty()) res[j] = nums[s.top()];
            }
        }
        
        return res;
    }
};

以分段的思想来看待整个数组的话,环形查找就是把数组拆分 A….B元素….C 变成了 B元素 ….C A… 刚好从右向左扫一遍就能节省计算量

收获

在原先时间复杂度最优解的情况下自己进一步优化了空间,使用紧凑的bitset位图来标记找到的元素

#stack