1.栈类型问题(leetcode)

个人总结,可读性有点差,各位只需要把这些都题自己去做做进行。

1-leetcode-232-用栈实现队列

思路:每次进栈的时候将栈顶,通过辅助栈转换成队头。只需要在push的时候操作。

class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int> stk1;
    stack<int> stk2;
    MyQueue() {
        //队列是先进先出,用两个栈,每次出队的时候先腾空其他的所有
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        stk1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if (!stk1.empty()){
            int n = stk1.size()-1;   //需要移动的数量
            for (int i = 0; i < n; i++){
                int temp = stk1.top();
                stk2.push(temp);
                stk1.pop();
            }
            int res = stk1.top();
            stk1.pop();
            while (!stk2.empty()){
                int temp = stk2.top();
                stk2.pop();
                stk1.push(temp);
            }
            return res;
        }
        return -1;
    }
    
    /** Get the front element. */
    int peek() {
        if (!stk1.empty()){
            int n = stk1.size()-1;   //需要移动的数量
            for (int i = 0; i < n; i++){
                int temp = stk1.top();
                stk2.push(temp);
                stk1.pop();
            }
            int peek = stk1.top();
            stk1.pop();
            stk2.push(peek);
            while (!stk2.empty()){
                int temp = stk2.top();
                stk2.pop();
                stk1.push(temp);
            }
            return peek;
        }
        return -1;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return stk1.empty();
    }
};

2-leetcode-225. 用队列实现栈

思路,push栈的时候,通过两个队列,将新进的栈顶元素放到队头

class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> qu1;
    queue<int> help;
    MyStack() {
        //栈是后进先出,两个队列实现,在压栈的时候实现每次取出来压到队头做栈顶
        // 两个队列,让队头作栈顶
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        while (!qu1.empty()){
            int top = qu1.front();
            qu1.pop();
            help.push(top);
        }
        qu1.push(x);
        while (!help.empty()){
            int top = help.front();
            qu1.push(top);
            help.pop();
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int p = qu1.front();
        qu1.pop();
        return p;
    }
    
    /** Get the top element. */
    int top() {
        return qu1.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return qu1.empty();
    }
};


3-leetcode-155-最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

思路,构建一个辅助栈,保存当前位置的最小值
构建的时候要初始化一个最小值

class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> min_stk;
    stack<int> data_stk;
    MinStack() {
        min_stk.push(INT_MAX);    // 这里一定不能忘了
    }
    
    void push(int x) {
        int now_min = min_stk.top();
        if (x < now_min){
            min_stk.push(x);
        }
        else {
            min_stk.push(now_min);
        }
        data_stk.push(x);
    }
    
    void pop() {
        if (!data_stk.empty()){
            data_stk.pop();
            min_stk.pop();
        }
    }
    
    int top() {
        if (!data_stk.empty()){
            return data_stk.top(); 
        }
        return -1;
    }
    
    int getMin() {
        if (!data_stk.empty()){
            return min_stk.top(); 
        }
        return -1;
    }
};


4括号相关题目
1-leetcode-20. 有效的括号(√写的没这个好)

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

思路:将最新的左括号存入栈中,如果遍历到右括号,判断和栈顶的左括号是否匹配

  • 如果栈是空的 且收到了 } ] ) 就是错的
  • 如果结束了栈还不是空的,说明错了
class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        if (s == "") return true;
        for (auto & x : s){
            if (x == '(' || x == '[' || x == '{'){
                //压栈
                stk.push(x);
            }
            else {
                //对比并出栈
                if (stk.empty()) return false;
                char top = stk.top();
                stk.pop();
                bool one = (top == '(' && x == ')');
                bool two = (top == '[' && x == ']');
                bool three = (top == '{' && x == '}');
                if ((one || two || three) != true){
                    return false;
                }
            }
        }
        return stk.empty();
    }
};

2-leetcode-22-括号的生成(×)

错误原因:回溯的条件不是if else 而是,如果left > 0就可以一直选( 进行填充

if (left > 0){           //如果 (的个数  大于 )的个数,进行 '('的递归
    helpfunc(left-1, right, path + '(');
}
if (left < right) {
    helpfunc(left, right-1, path + ')');
}

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

类似于一个全排列问题但是又限制料件

  • 右括号必须在左括号之后使用
  • 类似于一个不记录的回溯,通过return回溯
class Solution {
public:
    string path;
    vector<string> res;
    vector<string> generateParenthesis(int n) {
        //递归实现,本来是自由组合,多了个什么条件让你想一想
        int left_count = n;
        int right_count = n;
        dfs(path, left_count, right_count, 2 * n);

        return res;
    }

    void dfs(string path, int left, int right){
        // 终止条件,如果这个存储的结果等于2n可以保存
        if (path.size() == size && left == 0 && right == 0){
            res.push_back(path);
            return;
        }

        if (left > 0){
            dfs(path + '(', left-1, right);
        }
        if (left < right){    //左括号的可用次数必须比右括号少
            dfs(path + ')', left, right-1);
        }
    }
};

3-leetcode-32-最长有小括号(×)

给定只包含 ‘(’ ')'的字符串,求可以组成的有效括号字符长度有多少

思路:
利用一个栈去存储左括号,当遇见右括号的时候就出栈,并用当前的下标索引减去当前栈顶的下标索引,这样可以得到以此结尾的能组成的长度。

为了保证 (()))不会出现问题,也就是说栈底必须存储)来告诉括号,之前的和他不能在生成额配对了,在这里(索引)停止。

为了防止()) 这里栈先插入一个-1

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> stk;
        int res = 0;
        stk.push(-1);    // basecase ())
        for (int i = 0; i < s.size(); i++){
            if (s[i] == '('){
                stk.push(i);
            }
            else {
                stk.pop();
                if (!stk.empty()){  
                    // 不为空就记录和更新最大值
                    int a = stk.top();
                    res = max(res, i - a);
                }else {
                    //为空说明当前结尾的括号最多到这个 ) 处,记录这里的下标表示终止
                    stk.push(i);
                }
            }
        }
        return res;
    }
};

4-leetcode-678有效的括号字符串(√)

给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:

任何左括号 ( 必须有相应的右括号 )。
任何右括号 ) 必须有相应的左括号 ( 。
左括号 ( 必须在对应的右括号之前 )。

  • 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。
    一个空字符串也被视为有效字符串。

思路:比较取巧,建立两个栈

  • 存储左括号
  • 存储星号
  • )优先和左括号和星号判断

最后在判断左括号是否能够与将星号转换出来的 ) 进行配对

  • 左括号的下标必须小于 * 的下标
  • 结尾左括号的个数必须为0
class Solution {
public:
    bool checkValidString(string s) {
        stack<char> left;
        stack<char> star;
        for (int i = 0; i < s.size(); i++){
            if (s[i] == '('){
                left.push(i);
            }
            else if (s[i] == '*'){
                star.push(i);
            }
            else if (s[i] == ')'){
                if (!left.empty()){
                    left.pop();
                }
                else if(!star.empty()){
                    star.pop();
                }
                else {
                    return false;
                }
            }
        }
        //判断星号是不是可以
        while(!left.empty() && !star.empty()){
            if (left.top() > star.top()){
                return false;
            }
            star.pop();
            left.pop();
        }
        return left.empty();

    }
};

5-leetcode-636-函数的独占时间(×)

错误原因

可以直接按照括号操作来做,但是res要减去之前别的进程消耗的duration。“括号”的存储用pair,同时记录id和起始时间。

题目:
给出一个非抢占单线程CPU的 n 个函数运行日志,找到函数的独占时间。

每个函数都有一个唯一的 Id,从 0 到 n-1,函数可能会递归调用或者被其他函数调用。

日志是具有以下格式的字符串:function_id:start_or_end:timestamp。例如:“0:start:0” 表示函数 0 从 0 时刻开始运行。“0🔚0” 表示函数 0 在 0 时刻结束。

函数的独占时间定义是在该方法中花费的时间,调用其他函数花费的时间不算该函数的独占时间。你需要根据函数的 Id 有序地返回每个函数的独占时间。

思路:利用栈,因为是单线程,最先结束的一定是之前刚刚开始的,相当于一个括号问题。

  • 所以如果遇到start就存入栈中,当遇到一个end时,对应的start一定是上栈顶对应的任务,可以计算出这个时间。出栈。
  • 当计算完成一个duration时, 此时的新栈顶是没有占用当前的这段duration,这时,需要减去duration,因为在收到自己结束的命令时刻时,中间别的程序占用的都需要减去。
class Solution {
public:
    vector<int> exclusiveTime(int n, vector<string>& logs) {
        stack<pair<int, int>> st;
        vector<int> res(n, 0);
        for (auto & s: logs){
            int pos1 = s.find(':');
            //cout << s_last << endl;
            int pos2 = s.find(':', pos1+1);
            int id = stoi(s.substr(0, pos1));
            int time = stoi(s.substr(pos2+1));
            string state = s.substr(pos1+1, pos2-pos1-1);
            cout << id << ' ' << time << ' ' << state <<endl;
            if (state == "start"){
                //压栈
                st.push(make_pair(id, time));
            }
            else {
                //如果这个时间点有结束的,肯定是栈顶的程序id结束的,可以直接计算出当前id的执行时间
                //但是当前时间节点下 总共运行到时间点time,但是又duration多的时间是别人执行的,需要减去
                int duration = time - st.top().second+1;
                st.pop();
                res[id] += duration;
                if (!st.empty()){
                    res[st.top().first] -= duration;
                }
            }
        }
        return res;
    }
};

另外这里需要再重视一下sting对应的一些库函数。

1 int pos1 = string.find(‘x’) //找到x第一次出现的下标

2 int pos2 = string.find(‘x’, po1+1); //找到x第二次出现的下标

3 string in = string.substr(pos1, pos2 - pos1 - 1);
// 找到x x 中间的字符串

4 int a = stoi(“123”); a == 123
// string to int = stoi;

6-leetcode-739-数组中元素与下一个比它大的元素距离(√单调栈)

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

思路:单调栈,将一个降序,比当前元素小的存入栈中,这样就不会遗漏,栈顶永远是当前的最小元素,当遇到比最小元素大的时候,取出来逐一比较,将其放置在res

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        // 题目本身的意思是找到第一个比当前数值大的数的下标,并存入数组中
        //建立一个栈来存储,如果这个数没有大于任何一个数,那么就将他存入栈中
        vector<int> res(T.size(),0);
        stack<int> stk;
        for (int i = 0; i < T.size(); i++){
            while (!stk.empty() && T[i] > T[stk.top()]){
                int index = stk.top();
                res[index] = i - index;
                stk.pop();
            }
            stk.push(i);
        }
        return res;
    }
};

7-1-leetcode-下一个更大元素 I(√)

给定两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

思路:先用一个单调栈存储nums2中的每个小标对应的大的数据,在输入hash表,方便nums1的查找

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        //先用一个单调栈来存储
        //找到nums2中比他大的第一个数
        stack<int> stk;
        vector<int> res(nums2.size(), -1);
        for (int i = 0; i < nums2.size(); i++){
            int num = nums2[i];
            while (!stk.empty() && nums2[i] > nums2[stk.top()]){
                res[stk.top()] = nums2[i];
                stk.pop();
            }
            stk.push(i);
        }
        unordered_map<int, int> my_map;
        for (int i = 0; i < nums2.size(); i++){
            my_map[nums2[i]] = res[i];
        }
        vector<int> res2;
        for (int i = 0; i < nums1.size(); i++){
            res2.push_back(my_map.at(nums1[i]));
        }
        return res2;
    }
};

7-2-leetcode-503-循环数组中比当前元素大的下一个元素(×)

错误原因:

  • 如何处理循环数组下标的遍历? i % n
  • 如果找到了一圈以后就不再压栈

和上一题不一样的是这是一个循环数组,循环数组遍历的方式不一样。而且如果之前更新过了,就不需要再更新了,只需要取出来就行。

两种方法处理循环队列:

  • 如果这个结果已经被更新了,就不再更新
  • 如果i > n 说明已经不需要将新遍历的递减数组存入栈中
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        //找到一个比当前值大的数,将这个数本身存入结果中
        // 因为是循环,所以我们需要两次循环才行。
        stack<int> stk;
        int n = nums.size() ;
        vector<int> res(nums.size(), -1);
        for (int i = 0; i < n * 2; i++){
            //当前的值
            int num = nums[i % n];
            while (!stk.empty() && num > nums[stk.top()]){
                int index = stk.top();
                stk.pop();
                res[index] = num;
            }
            if (i < n){
                stk.push(i);
            }
            //stk.push(i%n);
        }
        return res;
    }
};

7-3-556下一个更大元素 III

给定一个32位正整数 n,你需要找到最小的32位整数,其与 n 中存在的位数完全相同,并且其值大于n。如果不存在这样的32位整数,则返回-1

1121 -> 1211

34765 -> 35467

思路:从后向前先找到不是递增的第一个点,index;
总这个index向后搜索,找到比他大的数里头最小的一个数。最后进行reverse

class Solution {
public:
    int nextGreaterElement(int n) {
        vector<int> nums;
        while (n != 0){
            nums.push_back((n % 10));
            n /= 10;
        }
        reverse(nums.begin(),nums.end());
        // 获得字符串
        int index = -1;
        for (int i = nums.size()-1; i >= 1; i--){
            //  12321
            if (nums[i-1] < nums[i]){
                index = i-1;
                break;
            }
        }
        if (index == -1){
            return -1;
        }
        // 找到比他大的数里  最小的数
        int per = nums.size()-1;
        for (int i = index+1; i < nums.size(); i++){
            if (nums[i] <= nums[index]){
                break;
            }
            per = i;
        }
        swap(nums, per, index);
        //翻转index 之后的数
        int res = str_reserve(nums, index);
        return res;
    }

    int str_reserve(vector<int> nums, int start){
        long long  res = 0;
        for (int i = 0; i <= start; i++){
            res = res * 10 + nums[i];
        }
        for (int i = nums.size()-1; i > start; i--){
            res = res * 10 + nums[i];
        }
        if (res > INT_MAX) return -1;
        return res;
    }


    void swap(vector<int> &str, int i, int j){
        int temp = str[j];
        str[j] = str[i];
        str[i] = temp;
    }

};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值