栈--力扣

二叉树中序遍历

给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]

		   1
		    \
		     2
		    /
		   3
	
	输出: [1,3,2]

##代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

// 中序遍历 先遍历左子树,根节点,右子数
// 如果是递归做法则递归遍历左子树,访问根节点,递归遍历右子数
// 非递归过程:先访问 最左子树绩点 在访问其父节点 在访问其兄弟
// while循环条件 中序遍历需先判断当前结点是否存在,若存在把该节点放入栈中,再将当前节点设置为节点的做孩子
// 若不存在则取栈顶元素为CUR,当且仅当栈顶元素也为空,循环结束


// c++] 非递归,都是套路。
// 注:为每一种算法,以及基本步骤取名,是记忆算法的捷径。学过象棋的朋友都知道,学象棋,先学基本杀招,象棋中的每种基本杀法都有固定的名字,比如双马饮泉,马后炮、闷宫、二鬼拍门之类的。不取名字,临时想出来的,可能每次写的步骤都不一样,导致你实现起来速度慢。同样算法你也可以这样学习,每一种经典算法,取一个自己熟悉的“杀法”名称,以助你快速杀题。

// 先入栈,在访问
// 中序遍历,左臂入栈法,
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
     
        vector<int> res;
        stack<TreeNode *> path;
        while(root){
            path.push(root);
            root=root->left;
        }
        while(!path.empty()){
            auto node = path.top();
            path.pop();
            res.push_back(node->val);
            //每 pop 一个节点,将其右子数做*左臂入站*操作。
            node = node ->right;
            while(node){
                path.push(node);
                    node =node->left;
            }
        }
        
        return res;
    }
};

二叉树前序遍历

给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]

   1
    \
     2
    /
   3 

输出: [1,2,3]

##代码

最简单的非递归遍历,前面方法的加强版

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        stack<TreeNode *> path;
        TreeNode * cur=root;
        while(!path.empty() || cur)
        {
            if(cur!=NULL ){
                res.push_back(cur->val);
                path.push(cur);
                cur=cur->left;
                         }
            else{
                cur =path.top();
                path.pop();
                cur = cur -> right;
            
                        }
        }
       return res; 
    }
};

##题目:简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

##代码:

class Solution {
    // 按"/"分割,去除空白和'.', 遇到".."把前面的一个和".."都删除。最后如果是空,   //就返回"/", c++代码如下:
public:
    
    string simplifyPath(string path) {
     istringstream is(path); //从String对象中读取字符
     vector<string> parts;
     string temp;
     while (getline(is ,temp,'/')){//is输入流,把读入的字符串存到temp中
         //遇到/就停止
         if(!temp.empty())
             parts.push_back(temp);
         }
         auto it = parts.begin();//用于代替冗长复杂、变量使用范围专一的变量声明。
         while(it != parts.end()){
             
             if(*it == ".")
                 it = parts.erase(it);
             else if (*it == ".."){
                 int count =0;
                 if(it != parts.begin()){
                     it--;
                     it = parts.erase(it);
                 }
                 it = parts.erase(it);
             }
             else {
                 it++;
             }
             
         }
         if(parts.empty())
             return "/";
         string re;
         for (auto each :parts){
             re+="/";
             re+=each;
         }
         return re;
     
    }
};

新知识总结

此题思路:

按“/”分割,如果非空就压入vector中,双“//”中间一定是空的,不需要区分斜杠的树目
开始处理vector,如果遇到“.”删除,遇到"…",删除两个
遇到其他的正常操作
把无冗杂操作的vector拼接成一个string,及时简化的路径

遇到的新知识:

istringstream is(path); //从String对象中读取字符

getline(is ,temp,’/’)//is输入流,把读入的字符串存到temp中遇到"/"就停止

auto it = parts.begin();//用于代替冗长复杂、变量使用范围专一的变量声明。

删除操作:

 if(*it == ".")
             it = parts.erase(it);

拼接操作:

	 string re;
     for (auto each :parts){
         re+="/";
         re+=each;
     }

##逆波兰式表达式求值

根据逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: [“2”, “1”, “+”, “3”, “*”]
输出: 9
解释: ((2 + 1) * 3) = 9

##代码

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        //遇到字符串就预算然后在压入
        int A ,B,C;
        vector<int> ans;
        auto it = tokens.begin();
        while(it != tokens.end()){
            if(* it == "+"){
                it++;
                A =ans.back();
                ans.pop_back();
                B= ans.back();
                 ans.pop_back();
                C= A + B;
               ans.push_back(C);
               
            }
            else if(* it == "-"){
                it++;
                A =ans.back();
                ans.pop_back();
                B= ans.back();
                 ans.pop_back();
                C= B - A;
                ans.push_back(C);
            }
            else if(* it == "*"){
                 it++;
                A =ans.back();
                ans.pop_back();
                B= ans.back();
                 ans.pop_back();
                C= A * B;
                ans.push_back(C);
            }
            else if(* it == "/"){
                 it++;
                A =ans.back();
                ans.pop_back();
                B= ans.back();
                 ans.pop_back();
                C= B / A;
                ans.push_back(C);
              
            }
            else{
                ans.push_back(stoi(*it));
                it++;
            }
        }
        return ans.back();
            
        
    }
};

二叉树的锯齿形层次遍历

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回锯齿形层次遍历如下:

[
  [3],
  [20,9],
  [15,7]
]

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
      //先层次遍历,在奇数行reverse翻转一下就行了
        vector<vector<int>> ans;
        if(!root) {
            return ans;
        }
        
        stack<TreeNode*> node;
        node.push(root);
             int Ce=0;
        while(!node.empty()){
            vector<int> t;
            vector<TreeNode *> level;
            while(!node.empty()){
                level.push_back(node.top());
                
                node.pop();
                
            }
            for(auto i:level){
                t.push_back(i->val);
                if(Ce%2==0){
                    if(i->left) node.push(i->left);
                    if(i->right) node.push(i->right);
                }
                if(Ce%2==1){
                    if(i->right){
                        
                    node.push(i->right);
                    
                    }
                    if(i->left) {
                    node.push(i->left);
                    
                    }
                    
                }                       
        }                    
           Ce++;  
           ans.push_back(t); 
        }
        return ans;
    }
};

代码2

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ans;
	    if (!root) return ans;
        vector<TreeNode*> d;
        d.push_back(root);
        while(!d.empty()){
            vector<int> t;
            vector<TreeNode*> node(d.begin(),d.end());
            d.clear();
            for(auto i :node){
                t.push_back(i->val);
                if(i->left) d.push_back(i->left);
                if(i->right) d.push_back(i->right);
            }
            ans.push_back(t);
        }
        
    //以上是层次遍历
        for(auto i=1;i<ans.size();i = i+2){
            reverse(ans[i].begin(),ans[i].end());
        }
    //奇数序号用reverse翻转
        return ans;
    }
};

每日温度

根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高,请输入 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。

#代码

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
      /**
 * 根据题意,从最后一天推到第一天,这样会简单很多。因为最后一天显然不会再有升高的可能,结果直接为0。
 * 再看倒数第二天的温度,如果比倒数第一天低,那么答案显然为1,如果比倒数第一天高,又因为倒数第一天
 * 对应的结果为0,即表示之后不会再升高,所以倒数第二天的结果也应该为0。
 * 自此我们容易观察出规律,要求出第i天对应的结果,只需要知道第i+1天对应的结果就可以:
 * - 若T[i] < T[i+1],那么res[i]=1;
 * - 若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天大的那天的温度进行比较)
 */
        stack<int> s;
        vector<int> res(T.size(),0);//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;
    }
};

##验证二叉树的前序序列化

序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。

     _9_
    /   \
   3     2
  / \   / \
 4   1  #  6
/ \ / \   / \
# # # #   # #

例如,上面的二叉树可以被序列化为字符串 “9,3,4,#,#,1,#,#,2,#,6,#,#”,其中 # 代表一个空节点。
给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。
每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 ‘#’ 。
你可以认为输入格式总是有效的,例如它永远不会包含两个连续的逗号,比如 “1,3” 。

代码

class Solution {
public:
    bool isValidSerialization(string preorder) {
        //二叉树的叶子节点的数目必须是根节点数+1;
        //入度和初度必须相等即可
        //根节点入度为0,出度为2,其他非叶子节点入度为1出度为2,叶子节点入度为一出度为零
        //入度减一,出度加一,先给度数赋值为1,即可把根节点看作是非叶子节点了
        int n=1;
        string str;
        istringstream is(preorder);
        while(getline(is,str,','))
        {
            --n;
            if(n<0) return false;
            if(str != "#") n+=2;
        }
        return n==0;
        
        
    }
};

下一个更大的元素II

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。

##单调递减栈解法220ms

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        //小技巧:增大一倍数组,不用考虑循环
        vector<int>doubleNums;
        stack<int> st;
        for(int num : nums){
            doubleNums.push_back(num);
        }
        for(int num:nums){
            doubleNums.push_back(num);
        }
        
        int sz = nums.size();
        vector<int> res(sz,-1);//sz在运行时才有正确值,所以这两个定义放在函数内部
        for(int i=0; i<2*sz ; ++i){
            while(!st.empty() && nums[st.top()]<doubleNums[i]){
               res[st.top()]=doubleNums[i];
               st.pop();
            }
            if(i<sz) st.push(i);//只需要原nums中的数字所处位置的【下标】进栈
        //因为res的长度必须是sz,超过sz的部分我们只是为了给之前栈中的数字找较大值,所以不能压入栈

        }
        return res;
    }

};

暴力代码904ms

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int size=nums.size();
        vector<int> result(size,-1);
        for(int i=0;i<nums.size();i++){
            int k=i+1;
            while(k<nums.size()+i){
                if(nums[k%nums.size()]>nums[i]){
                    result[i]=nums[k%nums.size()];
                        break;
                }
                k++;
            }
            //if(k==(nums.size()+1)) result.push_back(-1);
        }
        return result;
        
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值