[5月算法笔记]-链表月

191 阅读3分钟

链表

哑节点与迭代法的常规方式(链表的遍历方式)

在链表中,所谓的迭代法多用于像当前节点与下一节点要进行比较判断,所以我们才进行一个方法的迭代。

迭代法常规模版

    function iteration(listNums){
        const dummy = new ListNode(0)
        dummy.next = listNums
        //定义tmp对链表进行操作
        let tmp = dummy
        
        while(结束条件){
            if(curr 与 next进行比较判断){
                ...options
                // tmp.next = tmp.next.next
            }else{
                tmp = tmp.next
            }
        }
        return dummy

力扣203.移除链表元素

image.png

递归法

链表的定义具有递归的性质,因此链表题目常可以用递归的方法求解。这道题要求删除链表中所有节点值等于特定值的节点,可以用递归实现。

对于给定的链表,首先对除了头节点 head 以外的节点进行删除操作,然后判断 head 的节点值是否等于给定的val。如果 head 的节点值等于val,则 head 需要被删除,因此删除操作后的头节点为head.next;如果 head 的节点值不等于 val,则 head 保留,因此删除操作后的头节点还是 head。上述过程是一个递归的过程。

/**
 * 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) {
    if(!head) return head
    head.next = removeElements(head.next,val)
    return head.val == val ? head.next : head
};

迭代法

利用哑(脏)节点对next进行迭代

/**
 * 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) {
    const dummy = new ListNode(0,head)
    let temp = dummy

    while(temp.next){
        if(temp.next.val == val){
            temp.next = temp.next.next
        }else {
            temp = temp.next
        }
    }

    return dummy.next   
};

力扣21.合并两个有序链表

image.png

递归法

var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

迭代法

var mergeTwoLists = function(l1, l2) {
    let ans = new ListNode(0)
    let tmp =ans

    while(l1 != null && l2 !=null){
        if(l1.val>=l2.val){
            tmp.next = l2
            l2 = l2.next
        }else{
            tmp.next = l1
            l1 = l1.next
        }
        tmp = tmp.next
    }

    tmp.next =l1 == null ? l2 : l1

    return ans.next
};

力扣83.删除排序链表中的重复元素

image.png

var deleteDuplicates = function(head) {
    var cur = head;
    //判断头节点和下一节点必须同时存在要不就没有必要了
    while(cur && cur.next) {
        if(cur.val == cur.next.val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return head;
};

力扣面试题 02.01. 移除重复节点

image.png

 //哑节点 + hash表的方式
var removeDuplicateNodes = function(head) {
    const directory = {}
    const flag = new ListNode(0)
    flag.next = head
    let tmp = flag

    while(tmp.next){
        let val = tmp.next.val
        if(!directory[val]){
            directory[val] = true
            tmp = tmp.next
        }else{
            tmp.next = tmp.next.next
        }
    }

    return flag.next
};

双指针/快慢指针法

206.反转链表

image.png

    var reverseList = function(head){
        let prev = null
        let cur = head
        while(cur){
            let next = cur.next
            next = prev
            prev = cur
            cur = next
        }
        return prev
    }

剑指 Offer 22. 链表中倒数第k个节点

image.png

  var reverseList = function(head) {
      let curr = head
      let prev = null

      while(curr){
          let next = curr.next
          curr.next = prev
          prev = curr
          curr = next
      }
      return prev
};

876. 链表的中间结点

image.png

数组思想

链表的缺点在于不能像数组结构一样存在索引值,所以我们可以引入数组的思想解决一些问题,下面是借鉴的数组思想(leetcode不能通过,因为只会返回当前节点的val值)

var middleNode = function(head) {
    const ans = []

    while(head){
        ans.push(head.val)
        head = head.next
    }
    let mid = parseInt(ans.length / 2)
    console.log(ans[mid])

    return ans[mid]
};

快慢指针

利用快慢指针可以解决很多问题,只需快指针每次2步,慢指针每次2步即可。

var middleNode = function(head) {
    let slow = head
    let fast = head

    while(fast && fast.next){
        slow = slow.next
        fast = fast.next.next
    }

    return slow
};