名企高频笔试题目(3)

[待更]

二叉树根节点到叶子节点的所有路径的数字之和

题目描述

给定一个仅包含数字 0−9 的二叉树,每一条从根节点到叶子节点的路径都可以用一个数字表示。
例如根节点到叶子节点的一条路径是1→2→3,那么这条路径就用123 来代替。
找出根节点到叶子节点的所有路径表示的数字之和
例如:

img

这颗二叉树一共有两条路径,
根节点到叶子节点的路径 1→2 用数字12 代替
根节点到叶子节点的路径1→3 用数字13 代替
所以答案为12+13=25

示例1

输入
{1,0}
输出
10

示例2

输入
{1,#,9}
输出
19

深搜版:

class Solution {
public:
    int sumNumbers(TreeNode* root) {
        int path = 0,sum = 0;
        dfs(root, path, sum);
        return sum;
    }
    void dfs(TreeNode* root, int path,int& sum) {
        if(root){
            path = path * 10 + root->val;
            if(!root->left && !root->right)  sum += path;  //达到叶子节点
            if(root->left)  dfs(root->left,path,sum);  //往左子树
            if(root->right)  dfs(root->right,path,sum);  //往右子树
            path /= 10;  //返回上级节点前,从当前路径中删除此节点。
        }
    }
};

递归版:

class Solution {
public:
    int sumNumbers(TreeNode *root) {
       return dfs(root,0);
    }
    int dfs(TreeNode *root, int sum)
        {
        if(!root)  return 0;
        if(!root->left && !root->right)  return sum * 10 + root->val;
        return dfs(root->left,sum * 10 + root->val) + dfs(root->right,sum * 10 + root->val);
    }
};

二叉搜索树与双向链表

题目描述

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

分析:需要结果有序,使用中序遍历,修改当前指针会影响中序遍历,所以需要一个变量来保存上一个节点。

    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if (pRootOfTree == nullptr)  return nullptr;
        TreeNode* pre = nullptr;
        inOrder(pRootOfTree, pre);
        while (pRootOfTree->left)  //定位到排序后的首节点
            pRootOfTree = pRootOfTree->left;
        return pRootOfTree;
    }
    void inOrder(TreeNode* cur, TreeNode*& pre) {
        if (cur == nullptr)  return;
        inOrder(cur->left, pre);
        cur->left = pre;
        if (pre)  pre->right = cur;
        pre = cur;
        inOrder(cur->right, pre);
    }

判断一棵二叉树是否为搜索二叉树和完全二叉树

题目描述

给定一棵二叉树,已经其中没有重复值的节点,请判断该二叉树是否为搜索二叉树和完全二叉树。

示例1

输入
{2,1,3}
输出
[true,true]

分析:

中序遍历有序说明是搜索二叉树,层次遍历检查是否满足完全二叉树的性质。

class Solution {
public:
    vector<bool> judgeIt(TreeNode* root) {
        // write code here
        vector<bool> res{true,true};
        if (!root)  return res;
        inOrder(root);
        for(int i = 1;i<midSeq.size();++i)  //检查是否升序序列
            if (midSeq[i] < midSeq[i - 1]) {
                res[0] = false;
                break;
            }
        res[1] = isComplete(root);
        return res;
    }
    void inOrder(TreeNode* root) {  //中序遍历
        if (root == nullptr)  return;
        inOrder(root->left);
        midSeq.emplace_back(root->val);
        inOrder(root->right);
    }
    bool isComplete(TreeNode* root) {
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty())  //层序遍历
        {
            int len = q.size();
            for (int i = 0; i < len; ++i) {
                TreeNode* temp = q.front();
                if (temp->left && temp->right) {  //左右孩子都有
                    q.push(temp->left);
                    q.push(temp->right);
                    q.pop();
                }
                else if (temp->right)  return false;  //只有右孩子
                else{  //只有左孩子,或者叶子节点
                    if(temp->left)  q.push(temp->left);
                    q.pop();
                    while (!q.empty()){  //其后须全是叶子节点
                        if (q.front()->left || q.front()->right)  return false;
                        q.pop();
                    }
                    return true;
                }
            }
        }
    }
private:
    vector<int> midSeq;//中序遍历序列
};

加起来为目标值的组合

题目描述

给出一组候选数 C 和一个目标数 T,找出候选数中起来和等于T 的所有组合。
C 中的每个数字在一个组合中只能使用一次。

注意:

  • 题目中所有的数字(包括目标数 T )都是正整数
  • 组合中的数字 (a1, a2, … , ak) 要按非递增排序 (a1 <= a2 <= … <= ak).
  • 结果中不能包含重复的组合

例如:给定的候选数集是[10,1,2,7,6,1,5],目标数是8

解集是:

[1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]

分析:经典回溯法。不断搜索尝试符合条件的解,当和大于target时沿路径回到回溯点。

void dfs(vector<int>& num, int cur, vector<vector<int>>& res, vector<int>& path, int index) {
    if (cur == 0) {  //符合条件,各项的和为target
        res.push_back(path);
        return;
    }
    for (int i = index; i < num.size(); ++i) {
        if (num[i] > cur)  break;  //若加此项,各项之和将大于target
        if (i > index && num[i] == num[i - 1]) continue;  //若“跳过”某个元素则i>index,这一步很关键,去重
        path.push_back(num[i]);
        dfs(num, cur - num[i], res, path, i + 1);
        path.pop_back();  //还原现场
    }
}
vector<vector<int> > combinationSum2(vector<int>& num, int target) {
    sort(num.begin(), num.end());
    vector<vector<int>> res;
    vector<int> path;
    dfs(num, target, res, path, 0);
    return res;
}

缺失数字

题目描述

从0,1,2,...,n这n+1个数中选择n个数,找出这n个数中缺失的那个数,要求O(n)尽可能小。

示例1

输入
[0,1,2,3,4,5,7]
输出
6

分析:尽可能小的O(n),采用二分查找法。最终迭代结束是条件a[mid] == mid的状态发生了变化(从真到假或从假到真)。

int solve(int* a, int aLen) {
    // write code here
    int l = 0;
    int r = aLen - 1;
    while (l < r) {
        int mid = (l + r) / 2;
        if (a[mid] == mid)  l = mid + 1;
        else  r = mid - 1;
    }
    return l == a[l] ? l + 1 : l;  //l == a[l]则缺失在右,否则缺失在左
  }
};

找到搜索二叉树中两个错误的节点

题目描述

一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请按升序输出这两个错误节点的值。(每个节点的值各不相同)

示例1

输入
{1,2,3}
输出
[1,2]

分析:题目指明了两个错误节点,可利用中序遍历(升序序列)来定位这两个值。

class Solution {
public:
	vector<int> findError(TreeNode* root) {
		// write code here
		inOrder(root);
		int l, r;
		vector<int> res;
		for (r = vec.size() - 1; r > 1; --r)
			if (vec[r] < vec[r - 1]) {  //从右到左找异常(较小)
				res.emplace_back(vec[r]);
				break;
			}
		for (l = 0; l < vec.size() - 1; ++l)
			if (vec[l] > vec[l + 1]) {  //从左到右找异常(较大)
				res.emplace_back(vec[l]);
				break;
			}
		return res;
	}
	void inOrder(TreeNode* root) {  //中序遍历
		if (!root)  return;
		inOrder(root->left);
		vec.emplace_back(root->val);
		inOrder(root->right);
	}
private:
	vector<int> vec;  //中序序列
};
posted @ 2020-09-22 11:29  kite97  阅读(297)  评论(0编辑  收藏  举报