在牛客网刷剑指offer

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jxust_tj/article/details/51932679

重建二叉树

题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

分析:

前序遍历序列的第一个数字是根节点,在中序遍历序列中找到这个数字的位置,那么中序遍历序列中在这个数字左边的序列是左子树结点,右边的是右子树结点。而在前序遍历序列中从第二个数字开始有一段连续的序列是左子树结点,长度与在中序遍历中的一样。既然知道了左、右子树的前、中序遍历,那么通过递归实现即可,函数返回根节点。

code:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;	
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
		if(pre.size() <= 0) return NULL;
        TreeNode* T = new TreeNode(pre[0]);
        vector<int> prel, prer, inl, inr;
        int index = 0;
        for(int i=0; i<in.size(); i++) {
            if(in[i] == pre[0]) {
                index = i; break;
            }
        }
        for(int i=0; i<in.size(); i++) if(in[i] != pre[0]) {
            if(i < index) inl.push_back(in[i]);
            else inr.push_back(in[i]);
        }
        for(int i=1; i<pre.size(); i++) {
            if(i <= index) prel.push_back(pre[i]);
            else prer.push_back(pre[i]);
        }
        T->left = reConstructBinaryTree(prel,inl);
        T->right = reConstructBinaryTree(prer,inr);
        return T;
    }
};

用两个栈实现队列

题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

解析

push操作:将数字放进stack1里,pop操作:弹出stack2.top元素即可,假如stack2为空,操作之前应将stack1所有元素内容放到stack2中。

扫描二维码关注公众号,回复: 4345861 查看本文章
class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if(stack2.empty()) {
            while(!stack1.empty()) {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int value = stack2.top();
        stack2.pop();
        return value;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

旋转数组的最小数字

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解析:

这个二分挺好的,我写错了好多次,要千万注意二分的条件以及不同的情况下这个条件是否成立。

code:

class Solution {
public:
    int minNumberInRotateArray(vector<int> v) {
        int l = 0, r = v.size()-1, mid; 
        while(l < r) {
            mid = (l+r)/2;
            if(v[mid] > v[r]) l = mid+1; //这里一开始我写的是if(v[l] < v[mid])。当最小值在顶端时出错
            else r = mid;
        }
        return v[l];
    }
};

树的子结构

题目描述:
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

解析:

直接遍历递归,时间复杂度为O(n*m)。有人说将它们先序遍历变成字符串,然后看b是否是a的子串,用kmp算法可达到时间复杂度为O(n+m)。但我觉得这样不行。举个例子:A是一个深度为2的二叉树,共3个结点,父结点值为1,左儿子结点值为2,右儿子结点值为3。B也是一个深度为2的二叉树,共2个结点,父结点值为1,右儿子结点为3。B是A的子树,但A的前序遍历为{1,2,3},而B的前序遍历为{1,3},后面的根本不是前面的子串,故不成立。不知道此题是否有更好的解法,还请各位大牛告知。

code:

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
    bool isSame(TreeNode* p1, TreeNode* p2) {
        if(p2 == NULL) return true; //P2为空表示子树这条线路已经走完了
        if(p1 == NULL) return false; //当子树的这条线路还没走完你A树的却走完了肯定不行
        if(p1->val == p2->val) {
            if(isSame(p1->left,p2->left) && isSame(p1->right,p2->right)) {
                return true;
            }
        }
        return false;
    }
public:
    bool HasSubtree(TreeNode* p1, TreeNode* p2)
    {
        if(p1 == NULL || p2 == NULL) return false;
		if(isSame(p1,p2) || HasSubtree(p1->left,p2) || HasSubtree(p1->right,p2)) return true;
        return false;
    }
};

顺时针打印矩阵

题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 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.

分析

分四个方向走,走到不能走的地方90度转弯,遍历过的位置进行标记。其实用dfs挺好写的。

code:

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
		vector<int> v;
        int x = 0, y = 0, t = 0, n = matrix.size(), m = matrix[0].size();
        while(t < n*m) {
            while(t < n*m && y < m && matrix[x][y] != -1) {v.push_back(matrix[x][y]); matrix[x][y++] = -1; t++;} y--, x++;
            while(t < n*m && x < n && matrix[x][y] != -1) {v.push_back(matrix[x][y]); matrix[x++][y] = -1; t++;} x--, y--;
            while(t < n*m && y >= 0 && matrix[x][y] != -1) {v.push_back(matrix[x][y]); matrix[x][y--] = -1; t++;} y++, x--;
            while(t < n*m && x >= 0 && matrix[x][y] != -1) {v.push_back(matrix[x][y]); matrix[x--][y] = -1; t++;} x++, y++;
        }
        return v;
    }
};

栈的压入、弹出序列

题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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) {
        stack<int> s1;
        int index = 0;
        for(int i=0; i<pushV.size(); i++) {
            s1.push(pushV[i]);
            while(!s1.empty() && s1.top() == popV[index]) {
                s1.pop(); index++;
            }
        }
        return s1.empty();
    }
};


猜你喜欢

转载自blog.csdn.net/jxust_tj/article/details/51932679