2021-11-06每日刷题打卡
力扣——每日一题
268. 丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
示例 1:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
简单粗暴,先把nums用sort快速排序一遍,然后找nums[i]!=i的那个下标,就是缺失的数,return i 即可。
class Solution {
public:
int missingNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
int n=nums.size();
for(int i=0;i<n;i++)
{
if(nums[i]!=i)
{
return i;
}
}
return n;
}
};
力扣——二叉树
449. 序列化和反序列化二叉搜索树
序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。
设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。
编码的字符串应尽可能紧凑。
示例 1:
输入:root = [2,1,3]
输出:[2,1,3]
我这里采用前序遍历的方法(本来想用层序的,但这样字符串可能要有点长,而且后序我不喜欢所以用前序)。
前序转字符串的方式就是递归,每次先判断当前节点是否为空,如果为空就往字符串上加一个标志性的字符来说明这是空结点,我这里用的是N(NULL),如果不为空,就把当前节点的val值转为字符串加在字符串上,然后再把该节点的左右子节点送去递归,注意每个节点的val值之间要用特殊的字符隔开,我用的是“,”。等递归完后所有的字符串都合在一起了,直接return即可。
字符串转换成二叉树的方式也是递归(递归真是个好东西),我们用自己写的dfs函数来完成递归,一共三个参数,字符串data,节点root和索引下标i(i和节点要以引用方式传递)。一开始i先为0在之后的递归里逐渐增加,每次先判断data[i]是否为“N",如果是说明这里的节点应该为空,把当前节点指向空后直接结束程序,注意要把i+=2(跳过”,“)。如果不为N,那就先遍历字符串,当遇到”,“时结束遍历,再把遍历过的字符串转换成数字,这就是节点的val值,把值赋给root,然后送root的左右子节点去递归。当递归结束后我们得到的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 Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(!root)return "N";
return to_string(root->val)+","+serialize(root->left)+","+serialize(root->right);
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
TreeNode *root;
int i=0;
dfs(data,i,root);
return root;
}
void dfs(string data,int& i,TreeNode*& root)
{
if(data[i]=='N')
{
i+=2;
root=NULL;
return;
}
string str;
for(int j=i;j<data.size();j++)
{
if(data[j]==',')
{
j++;
i=j;
break;
}
str+=data[j];
}
root =new TreeNode(get_num(str));
dfs(data,i,root->left);
dfs(data,i,root->right);
}
int get_num(string str)
{
int num=0;
for(int i=0;i<str.size();i++)
{
num=num*10+(str[i]-'0');
}
return num;
}
};
// Your Codec object will be instantiated and called as such:
// Codec* ser = new Codec();
// Codec* deser = new Codec();
// string tree = ser->serialize(root);
// TreeNode* ans = deser->deserialize(tree);
// return ans;
1028. 从先序遍历还原二叉树
我们从二叉树的根节点 root 开始进行深度优先搜索。
在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。
如果节点只有一个子节点,那么保证该子节点为左子节点。
给出遍历输出 S,还原树并返回其根节点 root。
示例 1:
输入:“1-2–3--4-5–6--7”
输出:[1,2,5,3,4,6,7]
这里我们采用递归的方法来写(问了大佬大佬写的用栈迭代更简单但我想不出来所以只能用递归),我们用dfs来实现递归,dfs有四个参数,一个是树的结点root,一个是字符串traversal,一个是深度u(u和i初始都为0),一个是遍历字符串的索引i。(索引和结点要以引用方式传递)每次开头先计算一下字符串的‘-’数,遍历字符串然后计算,当遇到不是‘-’的字符时判断一下‘-’数是否小于深度u,如果小于那么就直接return结束程序,如果不小于那就让i继承当前遍历的下标,然后结束这一次的遍历,然后在进行一次遍历,把遍历到的字符都变成数字,当遇到‘-’字符时结束遍历,把转变的数字赋给root,然后再把root的左右子结点送去递归,注意u要+1。最后所有递归结束后root就是字符串转换后的二叉树。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(string traversal, TreeNode*& root, int& i, int u)
{
int child_u = 0;
for (int j = i; j < traversal.size(); j++)
{
if (traversal[j] != '-')
{
if (child_u < u)
{
return;
}
else
i = j;
break;
}
child_u++;
}
int num=0;;
for (int j = i; j < traversal.size(); j++)
{
if (traversal[j] == '-')
{
i = j;
break;
}
num=num*10+(traversal[j]-'0');
}
root = new TreeNode(num);
dfs(traversal, root->left, i, u + 1);
dfs(traversal, root->right, i, u + 1);
}
TreeNode* recoverFromPreorder(string traversal) {
TreeNode* root;
int i = 0, deep = 0;
dfs(traversal, root, i, deep);
return root;
}
};
919. 完全二叉树插入器和剑指 Offer II 043. 往完全二叉树添加节点
完全二叉树是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。
设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作:
CBTInserter(TreeNode root) 使用头节点为 root 的给定树初始化该数据结构;
CBTInserter.insert(int v) 向树中插入一个新节点,节点类型为 TreeNode,值为 v 。使树保持完全二叉树的状态,并返回插入的新节点的父节点的值;
CBTInserter.get_root() 将返回树的头节点。
示例 1:
输入:inputs = [“CBTInserter”,“insert”,“get_root”], inputs = [[[1]],[2],[]]
输出:[null,1,[1,2]]
第一次在力扣写实现题!真不容易啊呜呜呜!
记得先在类里写个成员变量的二叉树,公有权限或私有权限都行(一开始忘了成员变量郁闷的要死)。
构造函数(要求实现功能是用传入的二叉树来初始化成员变量的二叉树):用dfs递归的方式来初始化,每次把成员变量的二叉树的值和root的val一样,然后判断root是否有左右子节点,如果有就把成员变量的左右子节点和root的左右子节点分别传入下一次的递归里,当所有递归结束后得到的就是和root一样的二叉树了。
插入函数(往二叉树插入一个新的节点):用层序遍历来遍历成员变量的二叉树,去找第一个没有左右子节点或者只有左节点没有右节点的那一个父节点随便创建一个新的节点,用传入的val值来初始化它,再把这个节点连在父节点的左节点或右节点上,最后返回这个父节点的val值。
返回函数:直接返回成员变量的二叉树即可,非常简单。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class CBTInserter {
private:TreeNode* root;
public:
CBTInserter(TreeNode* root) {
dfs(root,this->root);
}
void dfs(TreeNode* root,TreeNode *&p)
{
p=new TreeNode(root->val);
if(root->left)dfs(root->left,p->left);
if(root->right)dfs(root->right,p->right);
}
int insert(int val) {
queue<TreeNode*>que;
que.push(this->root);
TreeNode *q;
q=new TreeNode(val);
while(que.size())
{
int len=que.size();
for(int i=0;i<len;i++)
{
if(que.front()->left&&que.front()->right)
{
que.push(que.front()->left);
que.push(que.front()->right);
}
else if(que.front()->left&&!que.front()->right)
{
que.front()->right=q;
return que.front()->val;
}
else if(!que.front()->left&&!que.front()->right)
{
que.front()->left=q;
return que.front()->val;
}
que.pop();
}
}
return {};
}
TreeNode* get_root() {
return this->root;
}
};
/**
* Your CBTInserter object will be instantiated and called as such:
* CBTInserter* obj = new CBTInserter(root);
* int param_1 = obj->insert(val);
* TreeNode* param_2 = obj->get_root();
*/