代码随想录 11.18 || 单调栈 LeetCode 739.每日温度、496.下一个更大的元素Ⅰ

单调栈

        单调栈,即栈中存储的元素值单调递增 or 递减,通常用于在一维数组中寻找任意位置元素的右边或者左边第一个更 大 / 小 元素的位置。在遍历过程中,使用单调栈记录遍历过的元素,栈中存放的是元素的下标,而并非元素本身。

739.每日温度

     给定一个整数数组 temperatures,表示每天的温度,返回一个数组 answer,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。计算一维数组 temperatures 中每一个元素与右边第一个最大的元素的距离。

       使用单调栈存储遍历过元素的下标,在遍历过程中可分为三种情况:当前访问元素大于、小于和等于栈顶元素,对应着不同的处理。

        当前访问元素 temperatures[i] > st.top(),说明我们找到了对应 st.top() 为下表的元素右边第一个最大值,temperatures[i]。根据题意要求,结果集中存储的是右边第一个更大元素到该元素的距离,因此 result[st.top()] = i - st.top(),并将栈顶元素出栈。注意,当前访问的元素,可能比栈不止一个元素都大,即它可能是多个元素的右边第一个最大的元素,所以需要使用一个循环进行遍历。直至不符合要求或者栈空,然后将当前元素压栈。从上述操作可以看出,栈顶元素为即将要加入结果集的元素的下标,当前访问的元素为可能符合要求的元素。

        当前访问元素 temperatures[i] < st.top(),说明当前元素不符合要求,直接将当前元素压栈,相等情况同理。

class Solution {
public:
    vector dailyTemperatures(vector &T) {
        int len = T.size();
        auto result = vector (len, 0);

        stack st; 
        st.push(0);

        for (int i = 1; i < len; ++i) {
            if (T[i] <= T[st.top()]) st.push(i);
            else {
                while (!st.empty() && T[i] > T[st.top()]) {
                    result[st.top()] = i - st.top();
                    st.pop();
                }
                st.push(i);
            }
        }

        return result;
    }
};

         下面是精简过后的代码。

class Solution {
public:
    vector dailyTemperatures(vector &T) {
        int len = T.size();

        vector result(len, 0);
        stack st;
        
        for (int i = 0; i < len; ++i) {
            while (!st.empty() && T[i] > T[st.top()]) {
                result[st.top()] = i - st.top();
                st.pop();
            }
            st.push(i);
        }

        return result;
    }
};

496.下一个更大的元素Ⅰ

    题干过于复杂,不在此赘述。本题为单调栈经典题目,设有一些变化。数组 nums1 是 nums2 的子集,寻找 num1 中的元素,在 nums2 中右边第一个更大的元素。

        首先是暴力解法,居然通过了,嵌套三个循环,第一个循环用于在 nums1 中挑选元素,第二个循环用于在 nums2 中寻找给定元素的位置,第三个循环用于返回给定元素右起第一个更大的值。在实现上是三层嵌套循环,但是本质上为两层嵌套循环,第三层循环只执行了一次。

class Solution {
public:
    vector nextGreaterElement(vector &nums1, vector &nums2) {
        int len1 = nums1.size(), len2 = nums2.size();

        vector result(len1, -1);

        for (int i = 0; i < len1; ++i) {
            for (int j = 0; j < len2; ++j) {
                if (nums2[j] != nums1[i]) continue;
                for (int k = j + 1; k < len2; ++k) {
                    if (nums2[k] > nums1[i]) {
                        result[i] = nums2[k];
                        break;
                    }
                }
                break;
            }
        }
        
        return result;
    }
};

        单调栈解法,nums1 是 nums2 的子集,那么只要找到 nums2 中所有元素右边第一个更大的元素的值,然后判断该元素在不在 nums1 中,如果在将这个更大的值添加进结果集即可。问题转化为单调栈 + 哈希映射的使用。下面的代码可以如 739.每日温度 进行精简。

class Solution {
public:
    vector nextGreaterElement(vector &nums1, vector &nums2) {
        int len1 = nums1.size(), len2 = nums2.size();
        
        vector result(len1, -1);
        if (len1 == 0) return result;

        unordered_map umap;
        for (int i = 0; i < len1; ++i) umap[nums1[i]] = i;

        stack st;
        st.push(0);

        for (int i = 1; i < len2; ++i) {
            if (nums2[i] < nums2[st.top()]) st.push(i);
            else if (nums2[i] == nums2[st.top()]) st.push(i);
            else {
                while (!st.empty() && nums2[i] > nums2[st.top()]) {
                    if (umap.count(nums2[st.top()]) > 0) {
                        int index = umap[nums2[st.top()]];
                        result[index] = nums2[i];
                    }
                    st.pop();
                }
                st.push(i);
            }
        }

        return result;
    }
};

你可能感兴趣的:(算法,数据结构)