数据结构--链表篇

240 阅读10分钟

链表定义:用一组任意存储的单元来存储线性表的数据元素。一个对象存储着本身的值和下一个元素的地址。
特点:查询慢-需要遍历才能查询到元素; 插入快-插入元素只需断开连接重新赋值; 下面是我自己准备的一些链表训练题,  从简单到复杂阶梯式上升.

链表设计

设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能: 

  •  get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  •  addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  •  addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  •  addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  •  deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

来源: leetcode-cn.com/problems/de…

/**
 * Initialize your data structure here.
 */
var MyLinkedList = function() {
    this.head = null;
    this.tail = null;
    this.length = 0;
};

/**
 * Get the value of the index-th node in the linked list. If the index is invalid, return -1\. 
 * @param {number} index
 * @return {number}
 */
MyLinkedList.prototype.get = function(index) {
    if(index >= 0 && index < this.length) {
        let i = 0;
        let cur = this.head;
        while(i < index) {
            cur = cur.next;
            i++
        }
        return cur.val;
    } else {
        return -1
    }
};

/**
 * Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtHead = function(val) {
    const lastHead = this.head;
    const node = new ListNode(val);
    this.head = node;
    this.head.next = lastHead;
    if(!this.tail){
        this.tail = node;
        this.tail.next = null
    }
    this.length++;
};

/**
 * Append a node of value val to the last element of the linked list. 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtTail = function(val) {
    const lastTail = this.tail;
    const node = new ListNode(val);
    this.tail = node;
    if(lastTail) {
        lastTail.next = this.tail;
    }
    if(!this.head) {
        this.head = node;
        this.head.next = null;
    }
    this.length++;
};

/**
 * Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. 
 * @param {number} index 
 * @param {number} val
 * @return {void}
 */
MyLinkedList.prototype.addAtIndex = function(index, val) {
    if(index === this.length) {
        this.addAtTail(val)
    } else if(index <= 0) {
        this.addAtHead(val)
    } else if(index > 0 && index < this.length) {
        let i = 0;
        let prev = this.head;
        while(i < index - 1) {
            prev = prev.next;
            i++
        }
        const node = new ListNode(val);
        node.next = prev.next;
        prev.next = node;
        this.length++;
    }
};

/**
 * Delete the index-th node in the linked list, if the index is valid. 
 * @param {number} index
 * @return {void}
 */
MyLinkedList.prototype.deleteAtIndex = function(index) {
    if(index > 0 && index < this.length) {
        let i = 0, prev = null, cur = this.head;
        while(i < index) {
            prev = cur;
            cur = cur.next;
            i++
        }
        prev.next = cur.next;
        if(index === this.length - 1) {
            this.tail = prev;
        }
        this.length--;
    } else if(index === 0) {
        this.head = this.head.next;
        this.length--;
    }
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * var obj = new MyLinkedList()
 * var param_1 = obj.get(index)
 * obj.addAtHead(val)
 * obj.addAtTail(val)
 * obj.addAtIndex(index,val)
 * obj.deleteAtIndex(index)
 */

反转链表

反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例: 

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

来源: leetcode-cn.com/problems/fa…

迭代实现

// 通过前驱结点及后继结点的概念, 使用遍历:
// 当前结点的next指向它的前驱结点
// 之前的前驱结点变成当前结点
// 当前结点变成原结点的后继结点
// 如果为null, 完成遍历
var reverseList = function(head) {
    let pre = null, cur = head;
    while(cur) {
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
};

递归实现

var reverseList = function(head) {
    if(!head || !head.next) return head;
    let p = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return p;
};

反转链表 II

反转从位置m到n的链表。请使用一趟扫描完成反转。(1 ≤m≤n≤ 链表长度)

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

来源: leetcode-cn.com/problems/re…

var reverseBetween = function(head, m, n) {
    let count = n - m;
    let dummy = { next: head }, p = dummy;
    let pre, cur, start, tail;
    for (let i = 0; i < m - 1; i++) {
        p = p.next;
    }
    let front = p;
    pre = tail = p.next;
    cur = pre.next;
    for(let i = 0; i < count; i++) {
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    front.next = pre;
    tail.next = cur;
    return dummy.next;
};

两个一组反转链表

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

输入: 1->2->3->4
输出: 2->1->4->3

来源: leetcode-cn.com/problems/sw…

var swapPairs = function(head) {
    if(!head || !head.next) return head;
    let dummyHead = { next: head };
    let node1, node2, p = dummyHead;
    while((node1 = p.next) && (node2 = p.next.next)) {
        node1.next = node2.next;
        node2.next = node1;
        p.next = node2;
        p = node1;
    }
    return dummyHead.next;
};

K个一组反转链表

给你一个链表,每k个节点一组进行翻转,请你返回翻转后的链表。

给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5

来源: leetcode-cn.com/problems/re…

// 采用栈解
var reverseKGroup = function(head, k) {
    stack = [], dummy = { next: null };
    let pre = dummy;
    while(true) {
        let count = 0, tmp = head;
        while(tmp && count < k) {
            stack.push(tmp);
            tmp = tmp.next;
            count++;
        }
        if(count != k){
            pre = pre.next;
            break;
        }
        while(stack.length > 0){
            pre.next = stack.pop();
            pre = pre.next;
        }
        pre.next = tmp;
        head = tmp;
    }
    return dummy.next;
};

旋转链表

给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

来源: leetcode-cn.com/problems/ro…

var rotateRight = function(head, k) {
    let dummy = { next: head };
    let count = 0, L = dummy, R = dummy, tmp = dummy, modK;
    while(tmp.next) {
        tmp = tmp.next;
        count++;
    }
    if(count === 0) return null;
    modK = k % count;
    while(modK--) {
        R = R.next;
    }
    while(R.next) {
        R = R.next;
        L = L.next;
    }
    R.next = dummy.next;
    dummy.next = L.next;
    L.next = null;
    return dummy.next;
};

合并链表

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

来源: leetcode-cn.com/problems/me…

var mergeTwoLists = function(l1, l2) {
    if(!l1) return l2;
    if(!l2) return l1;
    let dummy = { next: null };
    let p = dummy, p1 = l1, p2 = l2;
    while(p1 && p2) {
        if(p1.val > p2.val) {
            p.next = p2;
            p = p.next;
            p2 = p2.next;
        } else {
            p.next = p1;
            p = p.next;
            p1 = p1.next;
        }
    }
    if(p1) p.next = p1;
    else p.next = p2;
    return dummy.next;
};

合并K个排序链表

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

来源: leetcode-cn.com/problems/me…

实现一: 数组实现

var mergeKLists = function(lists) {
    let len = lists.length;
    if(len == 0) return null;
    if(len == 1) return lists[0];
    let arr = [];
    for (let i = 0; i < len; i++) {
        let tmp = lists[i];
        while(tmp){
            arr.push(tmp.val);
            tmp = tmp.next;
        }
    }
    arr.sort((a, b) => {
        return a-b
    })
    let dummy = { next: null };
    let cur = dummy;
    for (let i = 0; i < arr.length; i++) {
        let node = new ListNode(arr[i]);
        cur.next = node;
        cur = cur.next;
    }
    return dummy.next;
};

实现二: 分治合并

var mergeKLists = function(lists) {
    let mergeTwoList = (l1, l2) => {
        let dummy = { next: null };
        let current = dummy;
        while(l1 && l2) {
            if(l1.val < l2.val) {
                current.next = l1;
                current = current.next;
                l1 = l1.next;
            } else {
                current.next = l2;
                current = current.next;
                l2 = l2.next;
            }
        }
        if(l1 === null){
            current.next = l2;
        } else {
            current.next = l1;
        }
        return dummy.next;
    }

    if(lists.length === 0) return null;
    if(lists.length === 1) return lists[0];
    if(lists.length === 2) return mergeTwoList(lists[0], lists[1]);
    const mid = lists.length >> 1;
    const l1 = [];
    for(let i = 0; i < mid; i++) {
        l1[i] = lists[i]
    }
    const l2 = [];
    for(let i = mid, j = 0; i < lists.length; i++, j++) {
        l2[j] = lists[i]
    }
    return mergeTwoList(mergeKLists(l1), mergeKLists(l2))
};

快慢指针

删除链表的倒数第N个结点

给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点。

输入:1->2->3->4->5, n=2
输出:1->2->3->5

来源:leetcode-cn.com/problems/re…

快慢指针实现:

var removeNthFromEnd = function(head, n) {
    let dummy = { next: head };
    let fast = dummy, low = dummy;
    while(n) {
        fast = fast.next;
        n--;
    }
    while(fast.next){
        low = low.next;
        fast = fast.next;
    }
    low.next = low.next.next;
    return dummy.next;
}

倒数第K个结点

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

输入:1->2->3->4->5, k=2
输出:4

来源: leetcode-cn.com/problems/kt…

var kthToLast = function(head, k) {
    let left = head, right = head;
    for (let i = 0; i < k; i++) {
        right = right.next;
    }
    while(right) {
        left = left.next;
        right = right.next;
    }
    return left.val;
};

环形链表

给定一个链表,判断链表中是否形成环。

来源: leetcode-cn.com/problems/li…

var hasCycle = function(head) {
    if(!head || !head.next) return false;
    let slow = head;
    let fast = head.next;
    while(fast && fast.next) {
        if(slow === fast) return true;
        slow = slow.next;
        fast = fast.next.next;
    }
    return false;
};

环形链表  II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

来源: leetcode-cn.com/problems/li…

var detectCycle = function(head) {
    while(head && head.next) {
        if(head.flag) {
            return head;
        } else {
            head.flag = 1;
            head = head.next
        }
    }  
    return  null;  
};

链表的中间节点

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

来源: leetcode-cn.com/problems/mi…

var middleNode = function(head) {
    let slow = head, fast = head;
    while(fast && fast.next) {
        slow = slow.next;
        fast = fast.next;
        fast = fast.next;
    }
    return slow;
};

重排链表

给定一个单链表 L:L0→L1→…→Ln-1→Ln , 将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→… 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。  

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

来源: leetcode-cn.com/problems/re…

var reorderList = function(head) {
    let dummy = { next: head }, slow = dummy, fast = dummy;
    while(fast && fast.next) {
        slow = slow.next;
        fast = fast.next;
        fast = fast.next;
    }
    let right = slow.next;
    slow.next = null;
    let left = dummy.next;
    right = reverseList(right);
    while(left && right) {
        let lNext = left.next;
        let rNext = right.next;
        right.next = left.next;
        left.next = right;
        left = lNext;
        right = rNext;
    }
    return dummy.next;
};

function reverseList(list) {
    let pre = null, cur = list;
    while(cur) {
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}

删除链表元素

删除排序链表中的重复元素

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

输入: 1->1->2->3->3
输出: 1->2->3

来源: leetcode-cn.com/problems/re…

var deleteDuplicates = function(head) {
    let cur = head;
    while(cur && cur.next) {
        if(cur.val === cur.next.val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return head;
};

删除排序链表中的重复元素 II

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。

输入: 1->2->3->3->4->4->5
输出: 1->2->5

来源: leetcode-cn.com/problems/re…

var deleteDuplicates = function(head) {
    if(!head) return null;
    let dummy = { next: head };
    let p = head;
    let pre = dummy;
    while(p && p.next) {
        if(p.val === p.next.val) {
            let val = p.val;
            while(p && p.val === val) {
                p = p.next;
            }
            pre.next = p;
        } else {
            pre = p;
            p = p.next;
        }
    }
    return dummy.next;
};

移除排序链表元素

删除链表中等于给定值val的所有节点。

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

来源: leetcode-cn.com/problems/re…

var removeElements = function(head, val) {
    let dummy = { next: head };
    let pre = dummy;
    while(pre && pre.next) {
        if(pre.next.val === val) {
            pre.next = pre.next.next;
        } else {
            pre = pre.next;
        }
    }
    return dummy.next;
};

从链表中删去总和值为零的连续节点

给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。 删除完毕后,请你返回最终结果链表的头节点。 

输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。

来源: leetcode-cn.com/problems/re…

var removeZeroSumSublists = function(head) {
    let dummy = { next: head };
    let pre = dummy;
    while(pre) {
        let cur = pre.next;
        let sum = 0;
        while(cur) {
            sum += cur.val;
            cur = cur.next;
            if(sum === 0) {
                pre.next = cur;
                break;
            }
        }
        if(!cur) pre = pre.next;
    }
    return dummy.next;
};

链表求和

两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

来源: leetcode-cn.com/problems/ad…

var addTwoNumbers = function(l1, l2) {
    let dummy = { next: null };
    let tmp = dummy, sum, n = 0;
    while(l1 || l2) {
        const n1 = l1 ? l1.val : 0;
        const n2 = l2 ? l2.val : 0;
        sum = n1 + n2 + n;
        tmp.next = new ListNode(sum % 10);
        tmp = tmp.next;
        n = parseInt(sum / 10)
        if(l1) l1 = l1.next;
        if(l2) l2 = l2.next;
    }
    if(n > 0) tmp.next = new ListNode(n);
    return dummy.next;
};

两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7

来源: leetcode-cn.com/problems/ad…

var addTwoNumbers = function(l1, l2) {
    let stack1  = [], stack2 = [];
    while(l1) {
        stack1.push(l1.val);
        l1 = l1.next;
    }
    while(l2) {
        stack2.push(l2.val);
        l2 = l2.next;
    }
    let dummy = null, sum = 0, n = 0;
    while(stack1.length > 0 || stack2.length > 0 || n != 0) {
        let n1 = stack1.length ? stack1.pop() : 0;
        let n2 = stack2.length ? stack2.pop() : 0;
        sum = n1 + n2 + n;
        let node = new ListNode(sum % 10);
        n = parseInt(sum / 10);
        node.next = dummy;
        dummy = node;
    }
    return dummy;
};

其他

回文链表

请判断一个链表是否为回文链表

输入: 1->2
输出: false

来源: leetcode-cn.com/problems/pa…

var isPalindrome = function(head) {
    let num = [];
    while(head) {
        num.push(head.val);
        head = head.next;
    }
    while(num.length > 1) {
        if(num.pop() !== num.shift()) {
            return false;
        }
    }
    return true;
};

链表中的下一个更大节点

输入:[2,1,5]
输出:[5,5,0]

输入:[1,7,5,1,9,2,5,1]
输出:[7,9,9,9,0,5,0,0]

来源: leetcode-cn.com/problems/ne…

栈实现:

var nextLargerNodes = function(head) {
    let arr = [], valArr = [], stack = [];
    let i = 0, value;
    while(head) {
        value = head.val;
        valArr[i] = value;
        while(stack.length > 0 && value > valArr[stack[stack.length - 1]]) {
            arr[stack.pop()] = value;
        }
        stack.push(i);
        i++;
        head = head.next;
    }
    let res = new Array(i).fill(0);
    for (let j = 0; j < i; j++) {
        if(arr[j]) {
            res[j] = arr[j]
        }
    }
    return res;
};

奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL

来源: leetcode-cn.com/problems/od…

var oddEvenList = function(head) {
    if(!head || !head.next) return head;
    const dummyHead1 = { next: head };
    const dummyHead2 = { next: head.next };
    let odd = dummyHead1.next, even = dummyHead2.next;
    while(odd && odd.next && even && even.next) {
        const oddNext = odd.next.next;
        const evenNext = even.next.next;
        odd.next = oddNext;
        even.next = evenNext;
        odd = oddNext;
        even = evenNext;
    }
    odd.next = dummyHead2.next;
    return dummyHead1.next;
};

分隔链表

给定一个链表和一个特定值x,对链表进行分隔,使得所有小于x的节点都在大于或等于x的节点之前。你应当保留两个分区中每个节点的初始相对位置。

输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5

来源: leetcode-cn.com/problems/pa…

var partition = function(head, x) {
    let small = dummySmall = new ListNode(0);
    let great = dummyGreat = new ListNode(0);
    while(head) {
        if(head.val < x) {
            small.next = head;
            small = small.next;
        } else {
            great.next = head;
            great = great.next;
        }
        head = head.next;
    }
    small.next = dummyGreat.next;
    great.next = null;
    return dummySmall.next;
};

分隔链表

给定一个头结点为 root 的链表, 编写一个函数以将链表分隔为 k 个连续的部分。 每部分的长度应该尽可能的相等: 任意两部分的长度差距不能超过 1,也就是说可能有些部分为 null。 这k个部分应该按照在链表中出现的顺序进行输出,并且排在前面的部分的长度应该大于或等于后面的长度。 返回一个符合上述规则的链表的列表。  

举例: 1->2->3->4, k = 5 // 5 结果 [ [1], [2], [3], [4], null ]

来源: leetcode-cn.com/problems/sp…

var splitListToParts = function(root, k) {
    let len = getlength(root);
    let node = [], tmp;
    if(k >= len) {
        let cur = root;
        let index = 0;
        while(cur) {
            tmp = cur;
            node[index++] = cur;
            cur = cur.next;
            tmp.next = null;
        }
        while(k > len) {
            tmp = null;
            node[index++] = tmp;
            k--
        }
    } else {
        let t = Math.floor(len / k);
        let mod = len % k;
        let cur = root;
        for (let i = 0; i < k; i++) {
            let sign = t;
            node[i] = cur;
            while(cur != null && sign > 1) {
                cur = cur.next;
                sign--;
            }
            if(mod > 0) {
                cur = cur.next;
                tmp = cur;
                cur = cur.next;
                tmp.next = null;
                mod--;
            } else {
                tmp = cur;
                cur = cur.next;
                tmp.next = null;
            }
        }
    }
    return node;
};
function getlength(head) {
    let cur = head, count = 0;
    while(cur) {
        cur = cur.next;
        count++;
    }
    return count;
}

对链表进行插入排序

插入排序算法: 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。 重复直到所有输入数据插入完为止。  

来源: leetcode-cn.com/problems/in…

var insertionSortList = function(head) {
    if(!head) return null;
    let dummy = { next: head };
    while(head && head.next) {
        if(head.val <= head.next.val) {
            head = head.next;
            continue;
        }
        pre = dummy;
        while(pre.next.val < head.next.val) {
            pre = pre.next;
        }
        cur = head.next;
        head.next = cur.next;
        cur.next = pre.next;
        pre.next = cur;
    }
    return dummy.next;
};

有序链表转换二叉搜索树

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

来源: leetcode-cn.com/problems/co…

var sortedListToBST = function(head) {
    let makeTree = (head, tail) => {
        if(head === tail) return null;
        let p1 = head, p2 = head;
        while(p2 !== tail) {
            p2 = p2.next;
            if(p2 !== tail){
                p1 = p1.next;
                p2 = p2.next;
            }
        }
        var treeNode = new TreeNode(p1.val);
        treeNode.left = makeTree(head, p1);
        treeNode.right = makeTree(p1.next, tail);
        return treeNode;
    }
    return makeTree(head, null);
};

相交链表

编写一个程序,找到两个单链表相交的起始节点。

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A[4,1,8,4,5],链表 B[5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

来源: leetcode-cn.com/problems/in…

var getIntersectionNode = function(headA, headB) {
    let a = headA, b = headB;
    while(a !== b) {
        if(a === null) {
            a = headB;
        } else {
            a = a.next;
        }
        if(b === null) {
            b = headA;
        } else {
            b = b.next;
        }
    }
    return a;
};

从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

输入:head = [1,3,2]
输出:[2,3,1]

来源: leetcode-cn.com/problems/co…

var reversePrint = function(head) {
    let stack = [], cur = head, arr = [];
    while(cur) {
        stack.push(cur.val);
        cur = cur.next;
    }
    while(stack.length) {
        arr.push(stack.pop())
    }
    return arr;
};