剑指Offer66题之19-24

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

第19题:顺时针打印矩阵

题目

输入一个矩阵,按照从外向里顺时针的顺序依次打印出每一个数字。

解析

根据当前索引位置,采用不同的移动方式

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int> ret;
        // 一圈一圈的循环
        for (int x = 0, y = 0, up = 0, down = matrix.size() - 1, left = 0, right = matrix[0].size() - 1, f = 0; 
             left <= right && up <= down; ++y, ++x, ++left) {
             // 先向右移动
            for (; left <= right && up <= down && y <= right; ret.push_back(matrix[x][y++]));
            // 向下移动,注意up增加
            for (++x, --y, ++up; left <= right && up <= down && x <= down; ret.push_back(matrix[x++][y]));
            // 向左移动
            for (--y, --x, --right; left <= right && up <= down && y >= left; ret.push_back(matrix[x][y--]));
            // 向上移动
            for (--x, ++y, --down; left <= right && up <= down && x >= up; ret.push_back(matrix[x--][y]));
        }
        return ret;
    }
};

第20题:包含min函数的栈

题目

定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

解析

这题要用可持久化的数据结构,也就是说当从栈中弹出元素时,要在 O ( 1 ) O(1) 的时间复杂度内得到最小值。那么只能空间换时间了;
设置一个数据栈,一个辅助栈,辅助栈中存储的是每一步的最小值,当前状态的最小值就是辅助栈的栈顶元素,即
把元素压入数据栈时,比较辅助栈栈顶元素和压入的元素的大小,如果压入的元素比栈顶元素小,那么就把压入的元素压入辅助栈;如果压入的元素比栈顶元素大,那么就把栈顶元素再次压入辅助栈;
当从数据栈中弹出元素时,同时也要从辅助栈中弹出元素。
这样就完成了可持久化。

class Solution {
public:
   stack<int> minStack, st;
   void push(int value) {
       st.push(value);
       minStack.push(minStack.empty() || minStack.top() > value ? value : minStack.top());
   }
   void pop() {
       st.pop();
       minStack.pop();
   }
   int top() {
       return st.top();
   }
   int min() {
       return minStack.top();
   }
};

第21题:栈的压入、弹出序列

题目

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

解析

题目中的示例:(push 1,push 2, push 3, push 4, pop 4, push 5,pop 5, pop3, pop2 ,pop2, pop1)。
利用栈的先入后出这个性质,我们来模拟元素进栈就可以解决这个问题,具体做法如下:
根据进栈序列依次进栈;
进栈的过程中,判断栈顶元素是否和出栈序列当前元素相同,如果相同,那么就出栈,出栈序列指向下一个,重复这个过程,直到不相同为止;
当所有元素都入栈后,判断栈是否为空,如果为空,那么出栈序列就是合法的。

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int> st;
        for (int i = 0, j = 0; i < (int)pushV.size(); i++)
        	// 先push一个元素;判断条件;弹出,出栈序列后移
            for (st.push(pushV[i]); !st.empty() && j < (int)popV.size() && st.top() == popV[j]; st.pop(), ++j);
        return st.empty();
    }
};

第22题:从上往下打印二叉树

题目

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

解析

二叉树的层序遍历,利用一个队列就可以实现了,具体点说就是BFS

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/

class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int> ret;
        queue<struct TreeNode *> que;
        que.push(root);
        while (!que.empty()) {
        	// now:队列中的第一个元素, 最早进入的元素
            auto now = que.front();
            // 
            que.pop();
            if (now == nullptr)
                continue;
            ret.push_back(now->val);
            que.push(now->left);
            que.push(now->right);
        }
        return ret;
    }
}

第23题:二叉搜索树的后序遍历序列

题目

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解析

递归方法。根据二叉搜索树的特点,即 left < root < right

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
        return sequence.size() == 0 ? false : judge(sequence, 0, sequence.size());
    }

    bool judge(vector<int> &sequence, int l, int r)
    {
        if (l == r)
            return true;
        int mid = l, last = 0;
        // 判断 left < root ( root = sequence [r-1])
        for (; mid < r - 1 && sequence[mid] < sequence[r - 1]; ++mid);
        // 判断 right > root
        for (last = mid; last < r - 1 && sequence[last] > sequence[r - 1]; ++last);
        return last == r - 1 && judge(sequence, l, mid) && judge(sequence, mid, r - 1);
    }
};

备注

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值*; 它的左、右子树也分别为二叉排序树。

第24题:二叉树中和为某一值的路径

题目:

输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

解析

递归方法,深度优先搜索DFS (Depth First Search)

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int> > ret;
        vector<int> path;
        dfs(ret, root, expectNumber, path, 0, 0);
        return ret;
    }

    void dfs(vector<vector<int> > &ret, TreeNode* root,int expectNumber, vector<int> &path, int len, int sum)
    {
    	// path为路径,len为路径长度,sum为路径之和
    	// 空节点,返回
        if (root == nullptr)
            return ;
        // 存入当前节点数值
        if (len == path.size())
            path.push_back(root->val);
        else
            path[len] = root->val;
        // 当遍历完一个路径,且路径之和满足条件,保存路径
        if (sum + root->val == expectNumber && root->left == nullptr && root->right == nullptr) {
            vector<int> arr(len + 1);
            for (int i = 0; i < len + 1; arr[i] = path[i], ++i);
            ret.push_back(arr);
            return ;
        }
        // 左右子树的递归调用
        dfs(ret, root->left, expectNumber, path, len + 1, sum + root->val);
        dfs(ret, root->right, expectNumber, path, len + 1, sum + root->val);
    }
};

参考:剑指Offer66题之每日6题 - 第四天

猜你喜欢

转载自blog.csdn.net/muyiyushan/article/details/88430872