剑指 第4章 解决面试题的思路

二叉树的镜像

题目:操作给定的二叉树,将其变换为源二叉树的镜像。

思路:先序遍历,交换非叶子节点的左右子节点。

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if (pRoot == nullptr) return;
        if (pRoot->left == nullptr && pRoot->right == nullptr) return;
        else {
            TreeNode *temp = pRoot->left;
            pRoot->left = pRoot->right;
            pRoot->right = temp;
        }
        if (pRoot->left) Mirror(pRoot->left);
        if (pRoot->right) Mirror(pRoot->right);
    }
};

顺时针打印矩阵

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 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.
思路:视作按圈打印,每打印一圈需要四个步骤,依次分析每个步骤的发生条件。

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        int rows = matrix.size(), cols = matrix[0].size();
        int start = 0;
        vector<int> res;
        while(rows > start * 2 && cols > start * 2){
            int endX = cols - 1 - start, endY = rows - 1 - start;
            // left -> right
            for(int i = start; i <= endX; i++) res.push_back(matrix[start][i]);
            // up -> down
            if(start < endY)
                for(int i = start + 1; i<= endY; i++) res.push_back(matrix[i][endX]);
            // right -> left
            if(start < endX && start < endY)
                for(int i = endX - 1; i>= start; i--) res.push_back(matrix[endY][i]);
            // down -> up
            if(start< endY-1 && start < endX)
                for(int i = endY-1; i>=start+1;i--) res.push_back(matrix[i][start]);
            start++;
        }
        return res;
    }
};

包含min函数的栈

题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路:用两个普通的栈结构来实现,一个栈记录数据,另一个栈用来维护最小值。

class Solution {
public:
    void push(int value) {
        sdata.push(value);
        if(smin.empty()) smin.push(value);
        else if(smin.top()>value) smin.push(value);
        else smin.push(smin.top());
    }
    void pop() {
        sdata.pop();
        smin.pop();
    }
    int top() {
        return sdata.top();
    }
    int min() {
        return smin.top();
    }
private:
    stack<int> sdata;
    stack<int> smin;
};

栈的压入、弹出序列

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

从上到下打印二叉树

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

思路:

/*
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> res;
        if(root == nullptr) return res;
        deque<TreeNode*> nodeque;
        nodeque.push_back(root);
        while(!nodeque.empty()){
            res.push_back(nodeque.front()->val);
            if(nodeque.front()->left != nullptr) nodeque.push_back(nodeque.front()->left);
            if(nodeque.front()->right != nullptr) nodeque.push_back(nodeque.front()->right);
            nodeque.pop_front();
        }
        return res;
    }
};

二叉搜索树的后序遍历序列

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

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.size() == 0) return false;
        int i = 0;
        int root = sequence[sequence.size() - 1];
        for(; i < sequence.size() - 1; ++i){
            if(sequence[i] > root) break;
        }
        int j = i;
        for(; j < sequence.size() - 1; ++j){
            if(sequence[j] < root) return false;
        }
        vector<int> left_tree, right_tree;
        for(int m = 0; m < i; ++m){
            left_tree.push_back(sequence[m]);
        }
        for(int m = i; m < sequence.size() - 1; ++m){
            right_tree.push_back(sequence[m]);
        }
        bool left = true, right = true;
        if(i>0) left = VerifySquenceOfBST(left_tree);
        if(i<sequence.size() - 1) right = VerifySquenceOfBST(right_tree);
        return left && right;
    }
};

二叉树中和为某一值的路径

题目:输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
思路:DFS

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
    vector<vector<int>> allRes;
    vector<int> tmp;
    void dfsFind(TreeNode* node, int left){
        tmp.push_back(node->val);
        if(left - node->val == 0 && !node->left && !node->right)
            allRes.push_back(tmp);
        else{
            if(node->left) dfsFind(node->left, left - node->val);
            if(node->right) dfsFind(node->right, left - node->val);
        }
        tmp.pop_back();
    }
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        if(root) dfsFind(root, expectNumber);
        return allRes;
    }
};

复杂链表的复制

题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:三个步骤:1、在原链表的每个节点后面插入复制得到的兄弟节点,2、设置所有兄弟节点的特殊指针,3、将此链表拆开,拆成原链表和复制后的链表。

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead){
        if(pHead == nullptr) return nullptr;
        RandomListNode* pNode = pHead;
        while(pNode){
            RandomListNode* pCloned = new RandomListNode(pNode->label);
            pCloned->next = pNode->next;
            pNode->next = pCloned;
            pNode = pCloned->next;
        }
        pNode = pHead;
        while(pNode){
            RandomListNode* pCloned = pNode->next;
            if(pNode->random) pCloned->random = pNode->random->next;
            pNode = pCloned->next;
        }
        RandomListNode* pNode1 = pHead;
        RandomListNode* pClonedHead = pHead->next;
        RandomListNode* pNode2 = pClonedHead;
        while(pNode1){
            pNode1->next = pNode2->next;
            pNode1 = pNode1->next;
            if(pNode1 == nullptr) break;
            pNode2->next = pNode1->next;
            pNode2 = pNode2->next;
        }
        return pClonedHead;
    }
};

二叉搜索树与双向链表

题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
    void ConvertHelper(TreeNode* pNode, TreeNode* &pLastNodeInList){
        if(pNode == nullptr) return;
        if(pNode->left) ConvertHelper(pNode->left, pLastNodeInList);
        pNode->left = pLastNodeInList;
        if(pLastNodeInList) pLastNodeInList->right = pNode;
        pLastNodeInList = pNode;
        if(pNode->right) ConvertHelper(pNode->right, pLastNodeInList);
    }
public:
    TreeNode* Convert(TreeNode* pRootOfTree){
        if(pRootOfTree == nullptr) return nullptr;
        TreeNode* pLastNodeInList = nullptr;
        ConvertHelper(pRootOfTree, pLastNodeInList);
        // pRootOfTree: 待处理的树
        // pLastNodeInList: 双向链表的结尾元素
        TreeNode* ans = pLastNodeInList;
        while(ans && ans->left)
            ans = ans->left;
        return ans;
    }
};
发布了36 篇原创文章 · 获赞 51 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/xzy_thu/article/details/81915228