【JavaScript算法】-链表合辑07:重排链表、填充每个节点的下一个右侧节点指针、填充每个节点的下一个右侧节点指针II

一、 143 重排链表

问题描述

给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
【JavaScript算法】-链表合辑07:重排链表、填充每个节点的下一个右侧节点指针、填充每个节点的下一个右侧节点指针II_第1张图片

解题思路

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。
【JavaScript算法】-链表合辑07:重排链表、填充每个节点的下一个右侧节点指针、填充每个节点的下一个右侧节点指针II_第2张图片

解题思路

递归

基本思路:使用递归的算法,计算出每个节点对应左右子节点的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。
【JavaScript算法】-链表合辑07:重排链表、填充每个节点的下一个右侧节点指针、填充每个节点的下一个右侧节点指针II_第3张图片

解题思路

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;
};

你可能感兴趣的:(#,Leetcode刷题,链表,javascript,算法)