一、 143 重排链表
问题描述
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解题思路
1、快慢指针+拆分
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
var reorderList = function(head) {
if(head.next===null){return head;}
let l1=head;
let halfnode=head;
let fullnode=head;
//找到中间节点
while(fullnode.next&&fullnode.next.next){
halfnode=halfnode.next;
fullnode=fullnode.next.next;
}
//断开列表并翻转后半部分链表
let fast=halfnode.next;
let slow=new ListNode(null);
halfnode.next=null;
while(fast){
let next=fast.next;
fast.next=slow;
slow=fast;
fast=next;
}
//将翻转后的链表插入前半部分链表中
while(l1&&slow.next){
let nextnode1=l1.next;
l1.next=slow;
let nextnode2=slow.next;
slow.next=nextnode1;
l1=nextnode1;
slow=nextnode2;
}
return head;
};
二、 116 填充每个节点的下一个右侧节点指针
问题描述
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
解题思路
递归
基本思路:使用递归的算法,计算出每个节点对应左右子节点的next,当前节点为root,root.left.next为当前节点的右节点,root.right.next为当前节点的next节点的左节点。
var connect=function(root){
if(root==null||root.left==null) return root;
root.left.next=root.right;
root.right.next=root.next==null?null:root.next.left;
root.left=connect(root.left);
root.right=connect(root.right);
return root;
};
三、 117 填充每个节点的下一个右侧节点指针II
问题描述
给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
解题思路
1、层序遍历
利用队列先入先出的特点。在层序遍历时,上一个节点的next指向当前节点即可。
/**
* @param {Node} root
* @return {Node}
*/
var connect = function(root) {
if(root=null) return root;
//队列
let queue=[root];
while(queue.length){
let size=queue.length;
let pre;
while(size){
let cur=queue.shift();
//链表当前层节点接入next指针
if(pre) pre.next=cur;
pre=cur;
//装入下一层节点
if(cur.left) queue.push(cur.left;
if(cur.right)
queue.push(cur.right);
size--;
}
}
return root;
};
2、不使用额外空间复杂度的解题思路
在上一层为下一层建立Next指针;当遍历到某层节点时,该层节点的next指针已经建立,所以不需要队列,只需要找到下一层最左边的节点,就可以从该节点开始,向遍历链表一样遍历该层所有节点。
var connect=function(root){
//上一个节点
let last;
//下一层从左至右第一个节点,即下一层最左边节点
let nextstart;
const handle=(p)=>{
//上一个节点的next指向当前节点
if(last!=null) last.next=p;
//下一层中最左边节点为空,则将下一个节点指向当前节点,先记录起来方便下一层循环使用
if(nextstart==null) nextstart=p;
last=p;
};
if(root==null) return null;
let start=root;
while(start!=null){
last=null;
nextstart=null;
for(let p=start;p!=null;p=p.next){
//先处理左节点再处理右节点,处理完之后下一层的next指针已经建立好了
if(p.left) handle(p.left);
if(p.rigth) handle(p.right);
}
//进入下一层
start=nextstart;
}
return root;
};