代码随想录 | Day 58 - LeetCode 739. 每日温度、LeetCode 496. 下一个更大元素 I

        动态规划部分终于结束,今天是倒数第3天,开始单调栈部分。之前没有接触过单调栈,自己直接做没有想出这种方法。单调栈的主要应用场景是“一维数组中,寻找某个元素左/右边比它大/小的第一个元素”。需要注意栈中只需要存储下标,就可以通过所给的数组找到对应元素的值。还有无论哪种情况,都要记得在最后把当前元素也放入栈。最后,在结果像第2题一样要求是非有序且为子集时,可以借助map。


        第1题(LeetCode 739. 每日温度)自己没想出来O(n)的方法,看了题解的单调栈解法。核心思路是创建并维护一个数值上单调递减(因为这道题要求下一个更大的温度)的栈,符合规则就放入栈;不符合的话则需要弹出所有比当前数值小的元素,并同时对弹出元素对应位置的结果赋值(结果就是当前元素下标与被弹出元素下标的差值),最后再将当前元素放入栈。为实现这一目的,理论上既需要知道每个元素的值,又需要知道其下标,似乎需要将两者都放入栈中。但如果知道下标,通过temperatures可以直接获取温度值,所以栈中只需要存储下标即可。需要注意,最开始栈是空的,需要手动放入第0个元素或者在循环中对此做特殊处理。

        这样的做法会使得右边没有更大数字的元素永远无法进行res的赋值,而题目要求这些元素的结果均设置为0,所以可以在初始化时就将所有结果设置为0。

class Solution {
public:
    vector dailyTemperatures(vector& temperatures) {
        vector res(temperatures.size(), 0);
        stack st;
        st.push(0);
        for (int i = 0; i < temperatures.size(); ++i) {
            if (temperatures[i] <= temperatures[st.top()]) {
                st.push(i);
            }
            else {
                while (!st.empty() && temperatures[i] > temperatures[st.top()]) {
                    res[st.top()] = i - st.top();
                    st.pop();
                }
                st.push(i);
            }
        }
        return res;
    }
};

        第2题(496. 下一个更大元素 I)与上一题的第1个不同在于最终要返回的结果是子集而不是全部,且该子集中数字相对于原集合是乱序的。这样一来如果完全照搬上一题的方法,时间复杂度就会因为统计结果而变成O(n²)。

        解决办法是用nums1作为键来创建一个map,值用来保存结果。得到正确结果后,再将其按照nums1的顺序转换为vector返回。在遍历nums2计算结果、弹出栈的过程中,只有某个元素在map的键中时才将其结果放入map。

        另外由于(1)结果是用map保存的;(2)最终要返回的结果不再是位置的差值,而是比当前元素大的第1个元素本身;(3)题目说明nums2中元素均不重复,所以这一题不再需要记录下标了,可以只记录数值。

        初始化方面,这道题需要改为初始化map,并全部初始化为-1。

class Solution {
public:
    vector nextGreaterElement(vector& nums1, vector& nums2) {
        unordered_map map;
        for (int i = 0; i < nums1.size(); ++i) {
            map[nums1[i]] = -1;
        }
        stack st;
        st.push(nums2[0]);
        for (int i = 0; i < nums2.size(); ++i) {
            if (nums2[i] <= st.top()) {
                st.push(nums2[i]);
            }
            else {
                while (!st.empty() && nums2[i] > st.top()) {
                    if (map.find(st.top()) != map.end()) {
                        map[st.top()] = nums2[i];
                    }
                    st.pop();
                }
                st.push(nums2[i]);
            }
        }
        vector res(nums1.size());
        for (int i = 0; i < nums1.size(); ++i) {
            res[i] = map[nums1[i]];
        }
        return res;
    }
};

        判断当前元素是否在map中存在,既可以像上面一样使用map.find(),也可以通过判断map.count()的结果是否为0来判断。

你可能感兴趣的:(代码随想录,leetcode,算法,数据结构,c++)