leetcode经典题目(9)--栈、队列与哈希表

1. 用栈实现队列(NO.232)

题目描述:使用栈实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
解题思路:是用两个栈,一个用于入队操作,一个用于出队操作。一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        stack<int> st1;
        stack<int> st2;
    }    
    /** Push element x to the back of queue. */
    void push(int x) {
        st1.push(x);
    }    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if (st2.empty()){
            while (!st1.empty()){
                st2.push(st1.top());
                st1.pop();
            }
        }
        int res = st2.top();
        st2.pop();
        return res;
    }
    
    /** Get the front element. */
    int peek() {
        if (st2.empty()){
            while (!st1.empty()){
                st2.push(st1.top());
                st1.pop();
            }
        }
        int res = st2.top();
        return res;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return st1.empty() && st2.empty();
    }
private:
    stack<int> st1;
    stack<int> st2;
};
2. 用队列实现栈(NO.225)

题目描述:使用队列实现栈的下列操作:
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
解题思路:出栈:将非空队列中的除队尾元素外的所有元素转移至另一个队列中,然后将最后一个元素出队;入栈:将元素压入到非空队列的队尾。

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
        queue<int> qu1;
        queue<int> qu2;
    }   
    /** Push element x onto stack. */
    void push(int x) {
        if (qu1.empty())
            qu2.push(x);
        else
            qu1.push(x);
    }    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int res;
        if (qu1.empty()){
            while (qu2.size() > 1){
                qu1.push(qu2.front());
                qu2.pop();
            }
            res = qu2.front();
            qu2.pop();
        }
        else if (qu2.empty()){
            while (qu1.size() > 1){
                qu2.push(qu1.front());
                qu1.pop();
            }
            res = qu1.front();
            qu1.pop();
        }
        return res;
    }    
    /** Get the top element. */
    int top() {
        int res;
        if (qu1.empty()){
            while (qu2.size() > 1){
                qu1.push(qu2.front());
                qu2.pop();
            }
            res = qu2.front();
            qu1.push(res);
            qu2.pop();
        }
        else if (qu2.empty()){
            while (qu1.size() > 1){
                qu2.push(qu1.front());
                qu1.pop();
            }
            res = qu1.front();
            qu2.push(res);
            qu1.pop();
        }
        return res;
    }  
    /** Returns whether the stack is empty. */
    bool empty() {
        return qu1.empty() && qu2.empty();
    }
private:
    queue<int> qu1;
    queue<int> qu2;
};
3. 最小值栈(NO.155)

题目描述:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
解题思路:使用一个栈minValue记录数据栈的最小值,数据栈添加或者删除元素时,minValue栈也做相应的操作,使用变量min记录栈的最小值。

class MinStack {
private:
    stack<int> data;
    stack<int> minValue;
    int min = 0x7FFFFFFF;
public:
    /** initialize your data structure here. */
    MinStack() {
    }    
    void push(int x) {
        data.push(x);
        min = min < x ? min : x;
        minValue.push(min);      
    }  
    void pop() {
        data.pop();
        minValue.pop();  
        min = minValue.empty() ? 0x7FFFFFFF : minValue.top();     
    }
    int top() {
        return data.top();       
    }
    int getMin() {
        return min;       
    }
};
4. 用栈实现括号匹配(NO.20)

题目描述:给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。注意空字符串可被认为是有效字符串。
解题思路:创建一个栈。遍历字符串,如果遇到的是左括号,则将其压入栈中,如果遇到的是右括号,分以下几种情况:(1)栈为空,肯定不匹配,返回false;(2)栈非空,且该右括号也栈顶的左括号匹配,则将栈顶元素弹出,继续遍历;(3)栈非空,但该右括号也栈顶左括号不匹配,则字符串无效,返回false。

class Solution {
public:
    bool isValid(string s) {
        stack<char> st;
        for (int i = 0; i < s.size(); i++){
            if (s[i] == '(' || s[i] == '{' || s[i] == '[')
                st.push(s[i]);
            else{
                if (st.empty())
                    return false;
                 else if ((s[i] == ')' && st.top() == '(') || (s[i] == ']' && st.top() == '[') ||                        (s[i] == '}' && st.top() == '{'))
                    st.pop();
                else
                    return false;
            }
        }
        return st.empty();       
    }
};
5. 数组中元素与下一个比它大的元素之间的距离(NO.739)

题目描述:请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
解题思路一:从后往前遍历,便不用一个一个的比较,只考虑一个递增的子列,从而找到比当前值大的值的位置。最后一个元素对应的结果为0。要求出第i天对应的结果,只需要知道第i+1天对应的结果就可以:(1)若T[i] < T[i+1],那么res[i]=1;(2)若T[i] > T[i+1]:若res[i+1]=0,那么res[i]=0;若res[i+1]!=0,那就比较T[i]和T[i+1+res[i+1]](即将第i天的温度与比第i+1天大的那天的温度进行比较)

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

解题思路二:使用一个栈存储尚未找到较大值的下标。遍历数组,如果当前数字大于栈顶数字,则可求得栈顶数字与比其大的值的距离,然后将栈顶元素弹出,继续比较栈中下一个元素。如果当前数字小于栈顶元素,则将其入栈。可以发现栈中元素是递减的。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        vector<int> res(T.size(),0);
        stack<int> st;
        for (int i = 0; i < T.size(); i++){
            while (!st.empty() && T[i] > T[st.top()]){
                res[st.top()] = i - st.top();
                st.pop();
            }
            st.push(i);
        }
        return res;
    }
};
6. 循环数组中比当前元素大的下一个元素(NO.503)

题目描述:给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
解题思路:与上一题相似,只不过是循环数组,且找的是元素值而不是位置。令i的取值为0到2n,取其对应于循环数组中的值与栈顶元素比较,如果大于,弹出栈顶元素,如果小于且i小于n,入栈。

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n,-1);
        stack<int> st;
        for (int i = 0; i < n * 2; i++){
            int num = nums[i % n];
            while (!st.empty() && num > nums[st.top()]){
                res[st.top()] = num;
                st.pop();
            }
            if (i < n)
                st.push(i);
        }
        return res;
    }
};
7. 最长和谐子序列(NO.594)

题目描述:和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1。现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度。
输入: [1,3,2,2,5,2,3,7]; 输出: 5; 原因: 最长的和谐数组是:[3,2,2,2,3].
解题思路:使用一个哈希表,记录每个元素出现的次数,求相邻元素出现次数的和。这里使用unordered_map创建哈希表。

class Solution {
public:
    int findLHS(vector<int>& nums) {
        unordered_map<int,int> mymap;
        int res = 0;
        for (int num : nums){
            mymap[num]++;
            if (mymap[num-1] > 0)
                res = max(res,mymap[num-1]+mymap[num]);
            if (mymap[num+1] > 0)
                res = max(res,mymap[num+1]+mymap[num]);
        }
        return res;
    }
};
8. 最长连续序列(NO.128)

题目描述:给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 O(n)。
输入: [100, 4, 200, 1, 3, 2];输出: 4;解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
解题思路一:使用动态规划,令dp[i]表示以第i个元素结尾的连续序列长度。首先对数组排序,遍历数组,如果nums[i]=nums[i-1],则dp[i]=dp[i-1];如果nums[i]=nums[i-1]+1,则dp[i]=dp[i-1]+1,否则,dp[i]=1.但是时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn).

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1)
            return n;
        sort(nums.begin(),nums.end());
        vector<int> dp(n,1);
        int max = 1;
        for (int i = 1; i < n; i++){
            if (nums[i] == nums[i-1])
                dp[i] = dp[i-1];
            else if (nums[i] == nums[i-1] + 1)
                dp[i] = dp[i-1] + 1;
            if (dp[i] > max)
                max = dp[i];
        }
        return max;
    }
};

解题思路二:题目要求 O(n) 复杂度。
用哈希表存储每个端点值对应连续区间的长度。遍历数组:
(1)若数已在哈希表中:跳过不做处理
(2)若是新数加入:判断其左右相邻数是否在哈希表中,如果在,计算当前数的区间长度curLength,并更新最大长度和区间两边端点的长度值。

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_map<int,int> mymap;
        int maxLength = 0;
        for (int num : nums){
            if (mymap.find(num) == mymap.end()){//新数
                int curLength = 0;
                if (mymap.find(num-1) == mymap.end() && mymap.find(num+1) == mymap.end())
                    curLength = 1;
                else if (mymap.find(num-1) == mymap.end()){//右相邻数在哈希表中
                    curLength = mymap[num+1] + 1;
                    mymap[num+mymap[num+1]] = curLength;//更新右区间端点的长度值
                }
                else if (mymap.find(num+1) == mymap.end()){//左相邻数在哈希表中
                    curLength = mymap[num-1] + 1;
                    mymap[num-mymap[num-1]] = curLength;//更新左区间端点的长度值
                }
                else{//左右相邻数都在哈希表中
                    curLength = mymap[num-1] + mymap[num+1] + 1;
                    mymap[num-mymap[num-1]] = curLength;
                    mymap[num+mymap[num+1]] = curLength;
                }
                mymap[num] = curLength;
                if (curLength > maxLength)
                    maxLength = curLength;
            }
        }
        return maxLength;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值