【数据结构与算法】程序员面试金典 4.1-4.12

面试题 04.01. 节点间通路

class Solution {
public:
    bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
        vector<vector<int>> vec(n);
        vector<bool> visit(n,false);
        for(int i=0; i<graph.size(); ++i){
            vec[graph[i][0]].push_back(graph[i][1]);
        }
        // return dfs(vec, visit, start, target);
        return bfs(vec, visit, start, target);
    }

    bool dfs(vector<vector<int>>& vec, vector<bool>& visit, int start, int target){
        if(start == target){
            return true;
        }
        visit[start] == true;
        for(auto it : vec[start]){
            if(dfs(vec, visit, it, target)){
                return true;
            }
        }
        visit[start] == false;
        return false;
    }

    bool bfs(vector<vector<int>>& vec, vector<bool>& visit, int start, int target){
        queue<int> q;
        q.push(start); // 把起始点加入队列 
        while(!q.empty()){
            int now = q.front();
            if(now == target){
                return true;
            }
            visit[now] = true;
            for(auto it : vec[now]){
                if(visit[it] == false){
                    q.push(it);
                }
            }
            q.pop();            
        }
        return false;
    }
};

面试题 04.02. 最小高度树
跑出来和测试用例结果不同,其实没有错误,点提交可以AC,因为结果并不唯一。

/**
 * 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:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return dfs(nums, 0, nums.size()-1);
    }
    TreeNode* dfs(vector<int>& nums, int left, int right){
        if(left > right){
            return NULL;
        }
        int mid = (left + right) >> 1;
        TreeNode* ptr = new TreeNode(nums[mid]);
        ptr->left = dfs(nums, left, mid-1);
        ptr->right = dfs(nums, mid+1, right);
        return ptr;
    }
};

面试题 04.03. 特定深度节点链表

参考模板:https://www.cnblogs.com/cell-coder/p/12344619.html

模板描述:

void 按层数层序遍历(根节点){
    初始化队列,临时变量;
    将根节点放入队列中;
    while(队列不为空){
        获取队列长度size;
        while(size不为0){
            取出队首结点;
            if(队首结点的左孩子不为NULL) 将队首结点的左孩子放进队列;
            if(队首结点的右孩子不为NULL) 将队首结点的右孩子放进队列;
            弹出队首结点;
            完成一个结点的遍历,size--;
        }
    }
}


模板代码:

struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
void BFS(TreeNode* root){
    int size=0;
    TreeNode *temp;
	queue<TreeNode*> que;
    que.push(root);
    while(!que.empty()){
        size=que.size();
        while(size--){
            temp=que.front();
            que.pop();
            if(temp->left!=NULL) que.push(temp->left);
            if(temp->right!=NULL) que.push(temp->right);
        }
    }
}

解题参考:https://www.cnblogs.com/cell-coder/p/12344685.html
双100%

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<ListNode*> listOfDepth(TreeNode* tree) {
        int size = 0;
        TreeNode * temp;
        queue<TreeNode*> q;
        q.push(tree);

        vector<ListNode*> res;
        
        while(!q.empty()){
            size = q.size();
            ListNode* head = new ListNode(-1); // 值不重要,重要的是个伪头节点
            ListNode* p = head;
            while(size--){
                temp = q.front();
                if(temp->left){q.push(temp->left);}
                if(temp->right){q.push(temp->right);}
                q.pop();
                p->next = new ListNode(temp->val);
                p = p->next;
            } 
            res.push_back(head->next);
        }
        return res;
    }
};

面试题 04.04. 检查平衡性
方法1:定义getHeight函数,只是为了获得一个节点的最大深度

/**
 * 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:
    bool isBalanced(TreeNode* root) {
        if(root == NULL){
            return true;
        }
        if(abs(getHeight(root->left) - getHeight(root->right)) > 1){
            return false;
        }
        return isBalanced(root->left) && isBalanced(root->right);
    }
    int getHeight(TreeNode* root){
        if(root == NULL){
            return 0;
        }
        return max(getHeight(root->left),getHeight(root->right))+1;
    }
};

方法二:定义一个dfs函数,同时完成深度计算和合法性检查

/**
 * 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:
    bool isBalanced(TreeNode* root) {
        return dfs(root) != -1;
    }

    int dfs(TreeNode* root) {
        if (root == NULL) return 0;

        int left = dfs(root->left);
        if (left == -1) return -1;

        int right = dfs(root->right);
        if (right == -1 || abs(left - right) > 1) return -1;

        return max(left, right) + 1;
    }
};

面试题 04.05. 合法二叉搜索树

/**
 * 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:
    bool isValidBST(TreeNode* root) {
        if(root == NULL){
            return true;
        }
        vector<int> ans;
        dfs(ans, root);
        for(int i=1; i<ans.size(); ++i){
            if(ans[i-1] >= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
                return false;
            }
        }
        return true;
    }

    void dfs(vector<int>& ans, TreeNode* root){
        if(root == NULL){
            return;
        }
        dfs(ans, root->left);
        visit(ans, root);
        dfs(ans,root->right);
    }

    void visit(vector<int>& ans, TreeNode* root){
        ans.push_back(root->val);
    }
};

注意:

for(int i=1; i<ans.size(); ++i){
	if(ans[i-1] >= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
        return false;
    }
}

与下列写法相同,注意边界条件:

for(int i=0; i<ans.size()-1; ++i){
	if(ans[i+1] <= ans[i]){// 因为输入[1,1],应输出false,所以这里得加=
        return false;
    }
}

面试题 04.06. 后继者

方法1:BST + 递归 (BST是二叉搜索树)
20% 100%
如果结点 p 的值大于等于 root 的值,说明 p 的后继结点在 root 右子树中,那么就递归到右子树中查找。
如果结点 p 的值小于 root 的值,说明 p 在 root 左子树中,而它的后继结点有两种可能,要么也在左子树中,要么就是 root:
如果左子树中找到了后继结点,那就直接返回答案。
如果左子树中没有找到后继结点,那就说明 p 的右儿子为空,那么 root 就是它的后继结点。

/**
 * 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:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if(root == NULL || p == NULL){
            return NULL;
        }
        if(p->val >= root->val){
            return inorderSuccessor(root->right, p);
        }
        
        TreeNode* left = inorderSuccessor(root->left, p);
        return ((left == NULL)? root : left);
    }
};

方法2:BST+非递归
如果 p 有右儿子,那么它的后继结点就是右子树的最左边的儿子。
如果 p 没有右儿子,那么它的后继结点就是,沿着 p 往上到 root 的路径中,第一个左儿子在路径上的结点。因为这个结点的左子树中 p 是最右边的结点,是最大的,所以它就是 p 的后继结点。因为是二叉搜索树,我们就可以从根结点开始往 p 走,根据结点值的大小决定走的方向。

/**
 * 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:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if(root == NULL || p == NULL){
            return NULL;
        }

        if(p->right){
            p = p->right; // 右子树
            while(p->left){ // 找到右子树的最左节点
                p = p->left;
            }
            return p;
        }

        TreeNode* res = NULL;
        while(root != p){
            if(root->val < p->val){
                root = root->right;
            }else{
                res = root;
                root = root->left;
            }
        }
        return res;
    }
};

拓展:
一般树+递归
那如果是一般的二叉树,中序遍历就不满足单调递增了,这时候我们就只能找出中序遍历的结点顺序,然后才能得到 p 的后继结点。

所以我们直接采用递归来做中序遍历就行了,中序遍历结果保存下来,最后取 p 的下一个结点。

/**
 * 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:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        vector<TreeNode*> res;
        inorder(root, res);
        res.push_back(NULL);
        for(int i=0; i<res.size()-1;++i){
            if(res[i] == p){
                return res[i+1];
            }
        }
        return NULL;
    }

    void inorder(TreeNode* root, vector<TreeNode*>& res){
        if(root->left){
            inorder(root->left,res);
        }
        
        res.push_back(root);

        if(root->right){
            inorder(root->right, res);
        }
    }
};

一般树+非递归
当然还可以采用栈来做中序遍历,这样就是非递归了。同样结果保存下来,最后取 p 的下一个结点。

/**
 * 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:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
       vector<TreeNode*> res;
       stack<TreeNode*> st;
       while(!st.empty() || root){
           while(root){
               st.push(root);
               root = root->left;
           }
           root = st.top();
           st.pop();
           res.push_back(root);
           root = root->right;
       }
       res.push_back(NULL);
       for(int i=0; i<res.size()-1; ++i){
           if(res[i] == p){
               return res[i+1];
           }
       }
       return NULL;
    }
};

LeetCode上没有4.07

面试题 04.08. 首个共同祖先
递归代码的执行过程,有空的时候看:https://leetcode-cn.com/problems/diameter-of-binary-tree/solution/shi-pin-jie-shi-di-gui-dai-ma-de-yun-xing-guo-chen/

/**
 * 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:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL || root == p || root == q){
            return root;
        }

        TreeNode * left = lowestCommonAncestor(root->left, p, q);
        TreeNode * right = lowestCommonAncestor(root->right, p, q);

        if(left && right){
            return root;
        }
        return left ? left : right;
    }
};

面试题 04.09. 二叉搜索树序列
题目等级:困难

很牛的一个解法:https://blog.csdn.net/zjulyx1993/article/details/106127257
原版:

/**
 * 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>> BSTSequences(TreeNode *root) {
        vector<vector<int>> res;
        if (!root) {
            res.push_back({});
            return res;
        }
 
        function<void(TreeNode *, vector<TreeNode *>, vector<int>)> findPath =
                [&](TreeNode *curNode, vector<TreeNode *> nextValidNodes, vector<int> path) {
                    if (curNode->left) {
                        nextValidNodes.push_back(curNode->left);
                    }
                    if (curNode->right) {
                        nextValidNodes.push_back(curNode->right);
                    }
                    if (nextValidNodes.empty()) {
                        res.push_back(path);
                        return;
                    }
 
                    int size = nextValidNodes.size();
                    for (int i = 0; i < size; ++i) {
                        swap(nextValidNodes[i], nextValidNodes[size - 1]);
                        vector<TreeNode *> newq(&nextValidNodes[0], &nextValidNodes[size - 1]);
                        swap(nextValidNodes[i], nextValidNodes[size - 1]);
                        path.push_back(nextValidNodes[i]->val);
                        findPath(nextValidNodes[i], newq, path);
                        path.pop_back();
                    }
                };
 
        findPath(root, {}, {root->val});
 
        return res;
    }
};

热心网友翻版:

/**
 * 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>> ans;
    vector<vector<int>> BSTSequences(TreeNode* root) {
        if(root == NULL) return {{}};

        queue<TreeNode*> que;

        vector<int> path;

        path.push_back(root->val);

        core(root,que,path);

        return ans;
    }

    void core(TreeNode* root,queue<TreeNode*> que,vector<int> &path){
        if(!root) return;

        if(root->left) que.push(root->left);
        if(root->right) que.push(root->right);

        if(que.empty()){
            ans.push_back(path);
            return;
        }

        int n=que.size();
        while(n--){
            TreeNode* cur=que.front();que.pop();
            path.push_back(cur->val);
            core(cur,que,path);
            que.push(cur);
            path.pop_back();
        }
    }
};

普通解法:https://blog.csdn.net/qq_21201267/article/details/105422633

/**
 * 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 {
	vector<vector<int>> ans;
	vector<int> temp;
	deque<TreeNode*> q;
public:
    vector<vector<int>> BSTSequences(TreeNode* root) {
    	if(!root)
    		return {{}};
    	q.push_back(root);
    	dfs();
    	return ans;
    }

    void dfs()
    {
    	if(q.empty())
    	{
    		ans.push_back(temp);
    		return;
    	}
    	int size = q.size();
    	while(size--)//这层有几个人
    	{
    		TreeNode *tp = q.front();
    		q.pop_front();	//队列,第一个人出队
    		temp.push_back(tp->val);
    		int children = 0;
    		if(tp->left)//把下层加入队列
    		{
    			q.push_back(tp->left);
    			children++;
    		}
    		if(tp->right)
    		{
    			q.push_back(tp->right);
    			children++;
    		}
    		dfs();
    		while(children--)
    			q.pop_back();//把下层的删除
    		q.push_back(tp);//第一个人去队尾
    		temp.pop_back();
    	}
    }
};

面试题 04.10. 检查子树

/**
 * 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:
    bool checkSubTree(TreeNode* t1, TreeNode* t2) {
        if(t2 == NULL){
            return true;
        }
        if(t1 == NULL){
            return false;
        }
        if(t1->val != t2->val){
            return checkSubTree(t1->left, t2)|| checkSubTree(t1->right, t2);
        }
        return checkSubTree(t1->left, t2->left) && checkSubTree(t1->right, t2->right);
    }
};

面试题 04.11. 随机节点
这题LeetCode上没有

面试题 04.12. 求和路径
方法一:暴力递归:DFS递归

/**
 * 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:
    int res = 0;
    int pathSum(TreeNode* root, int sum) {
        if(root == NULL){
            return 0;
        }
        dfs(root, sum);
        pathSum(root->left, sum);
        pathSum(root->right, sum);
        return res;
    }
    void dfs(TreeNode* root, int sum){
        if(root == NULL){
            return;
        }
        int cursum = 0 ;
        cursum += root->val;
        if(cursum == sum){
            res++;
        }
        dfs(root->left, sum-cursum);
        dfs(root->right,sum-cursum);
    }
};

方法二:前缀和。就是到达当前元素的路径上,之前所有元素的和。
参考1:https://www.cnblogs.com/yonezu/p/13324770.html
参考2:https://leetcode-cn.com/problems/paths-with-sum-lcci/solution/qian-zhui-he-de-ying-yong-di-gui-hui-su-by-shi-huo/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值