名企高频笔试题目(3)
[待更]
二叉树根节点到叶子节点的所有路径的数字之和
题目描述
给定一个仅包含数字 0−9 的二叉树,每一条从根节点到叶子节点的路径都可以用一个数字表示。
例如根节点到叶子节点的一条路径是1→2→3,那么这条路径就用123 来代替。
找出根节点到叶子节点的所有路径表示的数字之和
例如:
这颗二叉树一共有两条路径,
根节点到叶子节点的路径 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; //中序序列
};