算法刷题——链表

581 阅读5分钟

24 两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.

链接:leetcode-cn.com/problems/sw…

解题思路1(迭代)

用三个指针分别指向前一个,要交换的第一个,要交换的第二个,进行相应交换之后继续向后遍历,如果是偶数个节点first会先到Null,如果是奇数个节点second会先到null。 这里要专门处理一下前两个节点(也可以设置一个哑元节点)

/**
 * 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 {ListNode}
 */
var swapPairs = function(head) {
    
    if(head === null || head.next === null)//判断为空或者只有一个节点的情况
        return head;
    
    let pre = null;//第一个节点的前一个
    let first = head;//要交换的第一个节点
    let second = first.next;//要交换的第二个节点

    while(second != null){
        if(pre === null){//处理链表表头
            first.next = second.next;
            second.next  = first;
            head = second; 
        }else{
            pre.next = second;
            first.next = second.next;
            second.next = first;
        }
        first = first.next;
        if(first === null)//只有偶数个节点
            break;
        pre = second.next;
        second = first.next;//second===null说明有奇数个节点
    }
    return head;
};

解题思路2(递归)

递归方法就是把链表所有节点都分为两组,那么递归的功能就是返回交换后的第一个节点,所以在递归里面就可以只解决内部两个节点的交换问题。

/**
 * 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 {ListNode}
 */
var swapPairs = function(head) {
    
    if(head === null || head.next === null)//判断为空或者只有一个节点的情况为递归出口
        return head;
    let after = head.next;
    head.next = swapPairs(after.next);//下一组交换节点返回的交换后的第一个
    after.next = head;
    return after;//返回这两个中的交换后的第一个
};

203 移除链表元素

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

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

leetcode-cn.com/problems/re…

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} val
 * @return {ListNode}
 */
var removeElements = function(head, val) {
    let  dummy = new ListNode(0,head);//设立一个哑元节点
    let  pre = dummy;
    while(pre.next != null){
        let cur = pre.next;
        if(cur.val === val)
            pre.next = cur.next;
        else
            pre = pre.next;
    }
    return dummy.next;
};

2 两数相加

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

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
输入:l1 = [0], l2 = [0]
输出:[0]
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

链接:leetcode-cn.com/problems/ad…

解题思路

用变量res表示进位,把对应的数相加,然后加上进位进行计算。这里要注意的是如果两个链表长度不等,那么还要继续计算剩下链表的部分;如果最后进位不为0,那么还要多加一个节点存储进位。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    let res = 0;//表示进位
    let pre = new ListNode(0,null);
    let newhead = pre;
    while(l1 || l2 || res){//在最后res不为0时也要继续加一个节点
        let a = !l1 ? 0 : l1.val;
        let b = !l2 ? 0 : l2.val;
        let sum = a + b + res;
        res = Math.floor(sum/10);//计算进位
        sum = sum - res * 10;
        let cur = new ListNode(sum,null);//生成结果节点
        pre.next = cur;
        pre = pre.next;
        l1 = l1? l1.next : null;
        l2 = l2? l2.next : null;
    }
    return newhead.next;
};

19删除链表的倒数第N个节点

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

示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n  保证是有效的。

链接:leetcode-cn.com/problems/re…

思路解析

使用快慢指针,快指针先和慢指针隔开n的距离,之后一起遍历,当快指针到末尾的时候,慢指针正好指向被删除的节点。(这里还是用了一个bre指针指向被删节点的前一个节点,方便删除时使用)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    let dummy = new ListNode(0,head);
    let bre = dummy;//被删节点的前一个结点
    let cur = head;//被删节点
    let pre = head;//先行节点
    while(--n)
        pre = pre.next;
    while(pre.next){
        pre = pre.next;
        cur = cur.next;
        bre = bre.next;
    }
    bre.next = cur.next;
    return dummy.next;

};

206 反转链表

反转一个单链表。

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

链接:leetcode-cn.com/problems/re…

解题思路

/**
 * 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 {ListNode}
 */
var reverseList = function(head) {
    let pre = null;
    let cur = head;
    while(cur != null){
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
};

92.反转链表 II

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

解题思路

部分反转需要记录四个位置,分别是m-1,m,n,n+1,这样才可以在反转完[m,n]之后和其余的节点正常连接。 反转部分借用上一题的代码,稍微更改一下返回值。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} m
 * @param {number} n
 * @return {ListNode}
 */
var reverseBetween = function(head, m, n) {
    let sliceStart = null;//m位置
    let sliceEnd = null;//n位置
    let pre = null;//m的前一个位置
    let tail = null;//n的后一个位置
    let count = 1;
    let cur = head;
    while(count <= n){
        if(count === m-1){
            pre = cur;
        }
        if(count === m){
            sliceStart = cur;
        }
        if(count === n){
            sliceEnd = cur;
        }
        cur = cur.next;
        count++;
    }
    tail = sliceEnd.next;
    sliceEnd.next = null;
    [sliceStart,sliceEnd] = reverseList(sliceStart);
    if(pre){
        pre.next = sliceStart;
    }else{
        head = sliceStart;
    }
    sliceEnd.next = tail;
    return head;
};

var reverseList = function(head) {
    let pre = null;
    let cur = head;
    while(cur != null){
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return [pre,head];
};