Day1-链表

90 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

写在前面

很少会在公共平台记录,因为总是怕“错”,怕暴露弱点,不过现在发现,其实也没什么,因为自己又没有“流量”,哈哈哈。。欢迎偶然看到的朋友留言指正。
所以呢,开始多写文章,多总结,总结的过程可以加深印象,而写好的文章也方便自己检索。
现在开始刷算法,看看可以坚持多少天!Fighting!

链表和数组基本概念

数组的随机访问(查):
根据数组下标来找到某个元素叫随机访问,因为数组是有序的,无论长度是一百还是一万,想找到某个元素都是等价的,跟长度无关。所以查找时间复杂度是O(1)。
数组的增删改:
比如插入某个元素,那么该位置后的数据都要改变index,所以复杂度是O(n)

链表都是指向关系:
链表的随机访问:
1=>2=>3=>4=>5
需要一个一个的向下传,找到某个值的位置,所以是O(n)
而增删的话,比如2和3之间增加一个10,直接改变2的指向即可,所以是O(1)

适用情况:
有序数据的存储,对随机访问有要求时,要优先使用数组,如任务队列
对删除插入需求多,随机访问少,则适合用链表
数组+链表可以拼接组成其他的数据结构

如何手写一个链表结构

写了几遍就发现,这个在理解含义的基础上,背一下吧。。就固定这么写

// 链表的构成就是 值+指针
class NodeList {
    constructor(val) {
        this.val = val
        this.next = null
    }
}

class LinkNodeList {
    constructor() {
        this.head = null
    }
    append(val) {
        let node = new NodeList(val)
        let p = this.head
        if (this.head) {
            // 找到链表最后一个节点,把这个节点.next赋值为node
            while(p.next) {
                p = p.next
            }
            p.next = node
            console.log(this.head)
        } else {
            // 头节点是null时候,链表是空的,把第一个node值赋值给head
            this.head = node
        }
    }
}

let linkList = new LinkNodeList()

linkList.append(1)
linkList.append(2)
linkList.append(3)
linkList.append(4)
linkList.append(5)

打印结果

image.png

力扣203-移除链表元素

image.png

普通方法-采用递归

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

哨兵方法

/**
 * @param {ListNode} head
 * @param {number} val
 * @return {ListNode}
 */
var removeElements = function(head, val) {
    // 定义一个哨兵元素:哨兵=>1=>2=>3
    // 来减少对于head为空时候的判断
    let ele = {
        next: head
    }
    let p = ele
    while(p.next) {
        if (p.next.val === val) {
            // 多跳一步
            p.next = p.next.next
        } else {
            p = p.next
        }
    }
    return ele.next
};

调试

刚开始刷,很多地方不理解,但是又没有办法直接在力扣上console,所以自己写了一个链表的类。
采用普通方法-递归的调试:

class NodeList {
    constructor(val) {
        this.val = val
        this.next = null
    }
}

class LinkNodeList {
    constructor() {
        this.head = null
    }
    append(val) {
        let node = new NodeList(val)
        let p = this.head
        if (this.head) {
            while(p.next) {
                p = p.next
            }
            p.next = node
        } else {
            this.head = node
        }
        return this.head
    }
}

let linkList = new LinkNodeList()

linkList.append(1)
linkList.append(2)
linkList.append(6)
linkList.append(4)

var removeElements = function(head, val) {
    console.log('head-s', head)
    if (head === null) {
        return head
    }
    head.next = removeElements(head.next, val)
    console.log('head-e',head)
    return head.val === val ? head.next : head
};

console.log(removeElements(linkList.append(5),6))

打印结果:

image.png

错误写法

var removeElements = function(head, val) {
    let p = head;
    if (head === null) {
        return head
    }
    while(p.next) {
        if (p.next.val === val) {
            p.next = p.next.next
            console.log(p)
        }
        else {
            p = p.next
        }
    }
    return head
};

用例3不通过,重复元素会返回一个元素值,修改方法?

力扣141-环形链表

image.png

常规解法

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    let cache = new Set()
    while(head) {
        if (cache.has(head)) {
            return true
        } else {
            cache.add(head)
        }
        head = head.next
    }
    return false
};

双指针法

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    // 双指针法
    let fast = head
    let slow = head
    while (fast && fast.next) {
        fast = fast.next.next
        slow = slow.next
        if (fast == slow) {
            return true
        }
    }
    return false
};

参考:github.com/course-dash…