給定一個單鏈表,其中的元素按升序排序,將其轉換爲高度平衡的二叉搜索樹。
本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。
示例:
給定的有序鏈表: [-10, -3, 0, 5, 9],
一個可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面這個高度平衡二叉搜索樹:
0
/ \
-3 9
/ /
-10 5
class Solution {//方法一:二分 斷開鏈表 得考慮delete 麻煩
public:
TreeNode* sortedListToBST(ListNode* head) {
if(!head)return nullptr;
if(!head->next)return new TreeNode(head->val);
ListNode *mid=head,*end=head,*temp=nullptr;
while(end&&end->next){
temp=mid;
mid=mid->next;
end=end->next->next;
}
TreeNode *res=new TreeNode(mid->val);
if(temp){
temp->next=nullptr;
res->left=sortedListToBST(head);
}
else
res->left=nullptr;
temp=mid->next;
delete mid;
res->right=sortedListToBST(temp);
return res;
}
};
class Solution {方法二:不斷開鏈表
public:
TreeNode* sortedListToBST(ListNode* head) {
if(!head)return nullptr;
return BuildTree(head,nullptr);
}
TreeNode* BuildTree(ListNode* head,ListNode* tail){
if(head==tail)return nullptr;
if(head->next==tail)return new TreeNode(head->val);
ListNode *mid=head,*end=head;
do{
mid=mid->next;
end=end->next->next;
}while(end!=tail&&end->next!=tail);
TreeNode *res=new TreeNode(mid->val);
res->left=BuildTree(head,mid);
res->right=BuildTree(mid->next,tail);
return res;
}
};
②快慢指針:
1)mid偏右:
a.slow=head;fast=head; do{}while(fast&&fast->next);
b.slow=head;fast=head->next; while(fast&&fast->next){};
2)mid偏左:
a.slow=head;fast=head; while(fast&&fast->next){};
b.slow=head;fast=head->next; do{}while(fast&&fast->next);
class Solution {//方法二變形:鏈表存數組
vector<int>nums;
public:
TreeNode* sortedListToBST(ListNode* head) {
if(!head)return nullptr;
while(head)
nums.push_back(head->val),head=head->next;
return BuildTree(0,nums.size()-1);
}
TreeNode* BuildTree(int start,int end){
if(start>end)return nullptr;
if(start==end)return new TreeNode(nums[start]);
int mid=start+((end-start)>>1);
TreeNode *res=new TreeNode(nums[mid]);
res->left=BuildTree(start,mid-1);
res->right=BuildTree(mid+1,end);
return res;
}
};
給定一個完美二叉樹,其所有葉子節點都在同一層,每個父節點都有兩個子節點。二叉樹定義如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指針,讓這個指針指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指針設置爲 NULL。
初始狀態下,所有 next 指針都被設置爲 NULL。
示例:
輸入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}
輸出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}
解釋:給定二叉樹如圖 A 所示,你的函數應該填充它的每個 next 指針,以指向其下一個右側節點,如圖 B 所示。
class Solution {
public:
Node* connect(Node* root) {
if(!root)return root;
helper(root,root->left);
//root->next=nullptr;
helper(root,root->right);
return root;
}
void helper(Node* parent,Node* cur){//遞歸 中序遍歷
if(!cur)return;
helper(cur,cur->left);
if(parent->left==cur)cur->next=parent->right;
else if(parent->next)cur->next=parent->next->left;
helper(cur,cur->right);
}
};
class Solution {
public:
Node* connect(Node* root) {
if(!root)return root;
Node *LevelOrderLeft=root;
while(LevelOrderLeft->left){//層序遍歷:next代替隊列實現常數級額外空間
Node *LevelOrderHead=LevelOrderLeft;
while(LevelOrderHead){
LevelOrderHead->left->next=LevelOrderHead->right;
if(LevelOrderHead->next)
LevelOrderHead->right->next=LevelOrderHead->next->left;
LevelOrderHead=LevelOrderHead->next;
}
LevelOrderLeft=LevelOrderLeft->left;
}
return root;
}
};
給定一個二叉樹
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指針,讓這個指針指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指針設置爲 NULL。
初始狀態下,所有 next 指針都被設置爲 NULL。
進階:
你只能使用常量級額外空間。
使用遞歸解題也符合要求,本題中遞歸程序佔用的棧空間不算做額外的空間複雜度。
示例:
輸入:root = [1,2,3,4,5,null,7]
輸出:[1,#,2,3,#,4,5,7,#]
解釋:給定二叉樹如圖 A 所示,你的函數應該填充它的每個 next 指針,以指向其下一個右側節點,如圖 B 所示。
提示:
樹中的節點數小於 6000
-100 <= node.val <= 100
class Solution {
public:
Node* connect(Node* root) {
if(!root)return root;
Node *LevelOrderLeft=root;//層序遍歷每一層的第一個元素:無子/有一子/有二子
while(LevelOrderLeft){
Node *LevelOrderHead=LevelOrderLeft;
while(LevelOrderHead&&!LevelOrderHead->left&&!LevelOrderHead->right)LevelOrderHead=LevelOrderHead->next;//尋找每一層的第一個有效元素:至少有一子
if(!LevelOrderHead)break;
Node *nextLevel=nullptr,*pre=nullptr;
//nextLevel層序遍歷下一層的第一個元素
//pre表示每一層的有效元素的前一個有效元素的最後一子,初始化爲第一個有效元素的最後一子
if(LevelOrderHead->left&&LevelOrderHead->right){//有效元素有二子
nextLevel=LevelOrderHead->left;
LevelOrderHead->left->next=LevelOrderHead->right;
pre=LevelOrderHead->right;
}
else if(LevelOrderHead->left){//有效元素只有左子
nextLevel=LevelOrderHead->left;
pre=LevelOrderHead->left;
}
else{//有效元素只有右子
nextLevel=LevelOrderHead->right;
pre=LevelOrderHead->right;
}
for(LevelOrderHead=LevelOrderHead->next;LevelOrderHead;LevelOrderHead=LevelOrderHead->next){//遍歷每一層元素
if(!LevelOrderHead->left&&!LevelOrderHead->right)continue;//過濾得到有效元素
//對有效元素進行next拼接:有二子/有左子/有右子
if(LevelOrderHead->left&&LevelOrderHead->right){
pre->next=LevelOrderHead->left;
LevelOrderHead->left->next=LevelOrderHead->right;
pre=LevelOrderHead->right;
}
else if(LevelOrderHead->left){
pre->next=LevelOrderHead->left;
pre=LevelOrderHead->left;
}
else{
pre->next=LevelOrderHead->right;
pre=LevelOrderHead->right;
}
}
LevelOrderLeft=nextLevel;
}
return root;
}
};
/*思路
在當前層時,把下一層第一個節點用nextLevel記錄下來,然後遍歷當前層的時候,把下面一層串起來,當前層遍歷完,通過nextLevel可以開始下一層的遍歷(同樣重複上述, 將nextLevel記錄下下層第一個節點,然後遍歷該層, 並把下面一層串起來)
*/
class Solution {
public:
Node* connect(Node* root) {
if(!root)return root;
Node *curLevel=root,*nextLevel=new Node(0);//下一層的僞頭節點
while(curLevel){
Node *nextLevelEnd=nextLevel;
while(curLevel){
if(curLevel->left){
nextLevelEnd->next=curLevel->left;
nextLevelEnd=nextLevelEnd->next;
}
if(curLevel->right){
nextLevelEnd->next=curLevel->right;
nextLevelEnd=nextLevelEnd->next;
}
curLevel=curLevel->next;
}
if(nextLevel==nextLevelEnd)break;
curLevel=nextLevel->next;
}
return root;
}
};