1、链表相关的算法

108 阅读3分钟

链表

初始链表结构

class Node {
  constructor(value) {
    this.value = value
    this.next = null
  }
}

let head = new Node(1)

数组实现


let data = new Array(10)
let next = new Array(10)

function add(index, nextIndex, val) {
  next[index] = nextIndex
  data[nextIndex] = val
}

add(3, 5, 1)
add(5, 9, 2)
add(9, 0, 10)


链表结构为 3 --> 5 --> 91     2     10

应用场景图

1、操作系统内的动态内存分配 --- 链表

2、LRU缓存淘汰算法




leetcode实战解题

题 141、 环形链表(链表判环)

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

解题思路: 一个快走(走两步)一个慢走(走一步) 若相遇则有环,为null则无环

var hasCycle = function (head) {
    let p = head
    if (!p) {
        return false
    }
    let q = p.next
    if (!q) {
        return false
    }
    while (p && q) {
        if (p === q) {
            break
        }
        p = p.next
        q = q.next && q.next.next
    }
    return (p === q) && p !== null
};
题 142、 环形链表(找到入环的第一个节点)

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

解题思路: 一个快走(走两步)一个慢走(走一步),找到相遇节点。 然后有一个节点从头开始走,另一个节点从相遇点走到再次相遇点,则是入环节点。

var detectCycle = function (head) {
    if (!head) {
        return head
    }
    let hasCycle = false
    let p = head, q = head
    while (q.next && q.next.next) {
        p = p.next
        q = q.next.next
        if (p === q) {
            hasCycle = true
            break
        }
    }
    let newp = head
    if (hasCycle) {
        while (newp != q) {
            newp = newp.next
            q = q.next
        }
        return newp
    } else {
        return null
    }
};
题 202、 快乐数

解题思路: 一个快走(走两步,求2步快乐数)一个慢走(求1步快乐数),若相遇则无限。

题 206、 反转链表

解题思路: 1.定义新节点初始为null, 做循环不断将链表的节点指向新链表

2.递归

var reverseList = function (head) {
    if (!head || !head.next) {
        return head
    }
    let tail = head.next
    let p = reverseList(head.next)
    head.next = tail.next
    tail.next = head
    return p
};
题 92、 反转链表(区间反转)
var reverseBetween = function (head, left, right) {
    if (!head || !head.next) {
        return head
    }
    if (left > right) {
        return head
    }
    let nh = new ListNode()
    nh.next = head
    let h = nh
    let ctn = right - left + 1
    while (--left) {
        h = h.next
    }
    let p = reverseN(h.next, ctn)
    h.next = p
    return nh.next

};

// 区间反转
var reverseN = function (head, n) {
    if (n === 1) {
        return head
    }
    let tail = head.next
    let p = reverseN(head.next, n - 1)
    head.next = tail.next
    tail.next = head
    return p
}
题 25、 k个一组反转链表(区间反转)
var reverseN = function (head, n) {
    if (n === 1) {
        return head
    }
    let tail = head.next
    let p = reverseN(head.next, n - 1)
    head.next = tail.next
    tail.next = head
    return p
}
题 61、 旋转链表

记录尾节点,走k位,然后断开

题 91、 删除链表倒数第n个节点

先建个虚拟节点p,p走n步得到q,做循环当pq一起走,q为空的时候停下来。此时处理p

题 83、删除链表中的重复节点

判断下一个是否相等,持续性删除后面节点,不等的话,p向后走一步

题 82、出现过重复的值都删掉

先建虚拟头节点, 比较下个节点和下下个节点,相等去找到不同的节点,然后链接

var deleteDuplicates = function (head) {
    if (!head) {
        return head
    }
    let ret = new ListNode()
    ret.next = head
    let p = ret
    let q = head.next
    while (p.next) {
        if (hasRepet(p.next)) {
            p.next = getNext(p.next)
        } else {
            p = p.next
        }
    }
    return ret.next

};

function hasRepet(head) {
    if (!head) {
        return false
    }
    if (head.next && head.next.val === head.val) {
        return true
    }
    return false
}

function getNext(p) {
    if (!p) {
        return p
    }
    let q = p.next
    while (q && q.val === p.val) {
        q = q.next
    }
    return q
}