顺时针打印矩阵+栈的压入、弹出序列+树的层序遍历(非递归)+二叉树中和为某一值的路径+数组中只出现一次的数字

题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
见:剑指offer第128页

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        int row=matrix.size();
        int col=matrix[0].size();
        vector<int> result;
        if(row==0||col==0) return result;
        int start=0;//每一圈左上角的数的横纵坐标相等,均为start
        while(col>start*2&&row>start*2){
            int endX=col-1-start; //第start圈的最后一列的坐标  终止列号
            int endY=row-1-start; //第start圈的最后一行的坐标  终止行号
            for(int i=start;i<=endX;i++) result.push_back(matrix[start][i]);  //第一行总是存在的
            if(start<endY){//只有当至少还有两行时,才需要执行从上到下的遍历  起始行号小于终止行号
                for(int i=start+1;i<=endY;i++) result.push_back(matrix[i][endX]); 
            }
            if(start<endX&&start<endY){ //只有当至少还有两行两列时,才需要执行从右到左的遍历  起始行号小于终止行号且起始列号小于终止列号
                for(int i=endX-1;i>=start;i--) result.push_back(matrix[endY][i]);
            }
            if(start<endX&&start<endY-1){ //只有当至少有三行两列时,才需要执行从下到上的遍历  起始行号比终止行号小2且起始列号小于终止列号
                for(int i=endY-1;i>=start+1;i--) result.push_back(matrix[i][start]);
            }
            start++;//圈数+1
        }
        return result;
    }    
};

题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if(pushV.size()!=popV.size()) return false;
        if(pushV.size()==0) return true;
        stack<int> s;
        int index=0;  //popV的索引
        int index2=0; //pushV的索引
        while(index<popV.size()&&index2<pushV.size()){
            while(index2<pushV.size()&&(s.empty()||s.top()!=popV.at(index))){//当栈为空或者栈顶元素不是下一个待弹出的元素,就将下一个元素入栈
                s.push(pushV.at(index2));
                index2++;
            }
            while(index<popV.size()&&s.top()==popV.at(index)){//当栈顶元素是待弹出元素,就将其弹出
                s.pop();
                index++;
            }
        }
        if(s.empty()) return true;//若待压入序列已经全部压入,但是并没有被全部弹出,此时栈非空
        return false;
    }
};

题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

//思路1:使用两个vector,每一层占用一个,轮流使用
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int> result;
        if(root==NULL) return result;
        vector<TreeNode*> v1;
        vector<TreeNode*> v2;
        v1.push_back(root);//先将根节点加入v1
        while(v1.size()!=0||v2.size()!=0){
            if(v1.size()!=0){//遍历v1中的节点,打印其值,并将各自的左右子节点加入v2
                for(int i=0;i<v1.size();i++){
                    result.push_back(v1[i]->val);
                    if(v1[i]->left!=NULL) v2.push_back(v1[i]->left);
                    if(v1[i]->right!=NULL) v2.push_back(v1[i]->right);                    
                }
                v1.clear();//遍历完之后清除v1
            }
            if(v2.size()!=0){//遍历v2中的节点,打印其值,并将各自的左右子节点加入v1
                for(int i=0;i<v2.size();i++){
                    result.push_back(v2[i]->val);
                    if(v2[i]->left!=NULL) v1.push_back(v2[i]->left);
                    if(v2[i]->right!=NULL) v1.push_back(v2[i]->right);                   
                }
                 v2.clear();//遍历完之后清除v2
            }
        }
        return result;

    }
};
//思路2:使用队列,每次从队列中取出一个节点,然后将其左右节点入队
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int> result;
        if(root==NULL) return result;
        queue<TreeNode* > q;
        q.push(root);
        while(!q.empty()){
            TreeNode* node=q.front();
            q.pop();
            result.push_back(node->val);
            if(node->left!=NULL) q.push(node->left);
            if(node->right!=NULL) q.push(node->right);
        }
        return result;

    }
};

题目描述
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
思路:递归,使用vector记录路径,使用先序遍历的方式访问节点,将节点添加到路径上,并累加该节点的值,如果该节点为叶子节点且路径中节点值之和等于给定值,则该路径符合要求,存储路径,然后递归回到其父节点。注意在退出之前要在路径上删除当前节点并减去当前节点的值。

class Solution {
public:
    vector<vector<int>> result;
    void find(TreeNode* root,int expectNumber,vector<int> path,int currentNumber){
        currentNumber+=root->val;  //当前的和
        path.push_back(root->val); //把当前节点加入路径中
        bool isleaf=(root->left==NULL&&root->right==NULL); //判断是不是叶子节点
        if(currentNumber==expectNumber&&isleaf){ //如果是叶子节点且当前和等于给定的数           
            result.push_back(path);
        }
        if(root->left!=NULL) find(root->left,expectNumber,path,currentNumber); //如果不是叶子节点,则递归遍历子树
        if(root->right!=NULL) find(root->right,expectNumber,path,currentNumber);
        path.pop_back();  //先序遍历,回到父节点之前将当前节点从路径中删除

    }
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {        
        if(root==NULL) return result;
        vector<int> path;
        find(root,expectNumber,path,0);
        return result;
    }
};

题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路:两个相同的数字的异或为0,先将所有数字进行异或,结果其实是两个不同的数字异或的结果,然后找到这两个数字异或后为1的数位,以此位将所有数字分为两组,则这两个数字必定出现在不同的组内,问题就转化成了找一组数据中只出现一次的一个数字的问题,只需要将两组数字分别进行异或,结果就是这两个数字。

class Solution {
public:
    int find(vector<int> v){
        int res=0;
        for(int i=0;i<v.size();i++){
            res=res^v[i];
        }
        return res;
    }
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.size()<2) return ;
        int r=0; //注意,异或前初始化为0,0和任意数的异或结果为该数本身
        for(int i=0;i<data.size();i++){
            r=r^data[i];//所有数字进行异或
        }
        int index=0;
        while(r){
            if(r&1) break;//找到异或后为1的数位
            else{
                index++;
                r=r>>1;
            }
        }
        int temp=1<<index;
        vector<int> v1;
        vector<int> v2;
        for(int i=0;i<data.size();i++){//以为1 的位维基准,将所有数据划分为两组
            if(data[i]&temp) v1.push_back(data[i]);
            else v2.push_back(data[i]);
        }
        *num1=find(v1);//转化成在一组数据中找只出现一次的数
        *num2=find(v2);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值