A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.
Design an algorithm to insert a new node to a complete binary tree keeping it complete after the insertion.
Implement the CBTInserter class:
CBTInserter(TreeNode root) Initializes the data structure with the root of the complete binary tree.
int insert(int v) Inserts a TreeNode into the tree with value Node.val == val so that the tree remains complete, and returns the value of the parent of the inserted TreeNode.
TreeNode get_root() Returns the root node of the tree.
The number of nodes in the tree will be in the range [1, 1000].
0 <= Node.val <= 5000
root is a complete binary tree.
0 <= val <= 5000
At most 104 calls will be made to insert and get_root.
Solutions
Solution 1: BFS
Thinking
Insertion into a complete binary tree always fills the leftmost vacancy. Searching from the root every time repeats work on already-full nodes. After a BFS stores nodes in an array, heap indexing applies: the parent of a new node is at \((sz-1)//2\). Insert and get_root are then constant time.
We can use an array \(\textit{tree}\) to store all nodes of the complete binary tree. During initialization, we use a queue \(q\) to perform level-order traversal of the given tree and store all nodes into the array \(\textit{tree}\).
When inserting a node, we can find the parent node \(p\) of the new node through the array \(\textit{tree}\). Then we create a new node \(\textit{node}\), insert it into the array \(\textit{tree}\), and make \(\textit{node}\) as the left child or right child of \(p\). Finally, we return the value of \(p\).
When getting the root node, we directly return the first element of the array \(\textit{tree}\).
In terms of time complexity, it takes \(O(n)\) time for initialization, and the time complexity for inserting a node and getting the root node are both \(O(1)\). The space complexity is \(O(n)\), where \(n\) is the number of nodes in the tree.
# Definition for a binary tree node.# class TreeNode:# def __init__(self, val=0, left=None, right=None):# self.val = val# self.left = left# self.right = rightclassCBTInserter:def__init__(self,root:Optional[TreeNode]):self.tree=[]q=deque([root])whileq:for_inrange(len(q)):node=q.popleft()self.tree.append(node)ifnode.left:q.append(node.left)ifnode.right:q.append(node.right)definsert(self,val:int)->int:p=self.tree[(len(self.tree)-1)//2]node=TreeNode(val)self.tree.append(node)ifp.leftisNone:p.left=nodeelse:p.right=nodereturnp.valdefget_root(self)->Optional[TreeNode]:returnself.tree[0]# Your CBTInserter object will be instantiated and called as such:# obj = CBTInserter(root)# param_1 = obj.insert(val)# param_2 = obj.get_root()
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */typeCBTInserterstruct{tree[]*TreeNode}funcConstructor(root*TreeNode)CBTInserter{q:=[]*TreeNode{root}tree:=[]*TreeNode{}forlen(q)>0{fori:=len(q);i>0;i--{node:=q[0]q=q[1:]tree=append(tree,node)ifnode.Left!=nil{q=append(q,node.Left)}ifnode.Right!=nil{q=append(q,node.Right)}}}returnCBTInserter{tree}}func(this*CBTInserter)Insert(valint)int{p:=this.tree[(len(this.tree)-1)/2]node:=&TreeNode{val,nil,nil}this.tree=append(this.tree,node)ifp.Left==nil{p.Left=node}else{p.Right=node}returnp.Val}func(this*CBTInserter)Get_root()*TreeNode{returnthis.tree[0]}/** * Your CBTInserter object will be instantiated and called as such: * obj := Constructor(root); * param_1 := obj.Insert(val); * param_2 := obj.Get_root(); */