javaScript 结构算法刷题 链表

一些容易忘记的知识点

  • 链表的存储方式
    数组在内存中是连续分布,但是链表不是
    链表是通过指针域的指针 链接在内存中的各个节点
    所以链表的节点在内存中不是连续分布,而是散乱分布在内存中的某地址上,分配机制取决于系统的内存管理

移除链表元素

leetcode 203
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

var removeElements = function(head, val) {
    // 虚拟节点
    const ret = new ListNode(0,head)
    let cur = ret

    while(cur.next){
        if(cur.next.val === val){
            cur.next = cur.next.next
            continue
        }
        cur = cur.next
    }
    return ret.next
};

链表设计

具体代码直接就抄了

class LinkNode {
    constructor(val, next) {
        this.val = val;
        this.next = next;
    }
}

/**
 * Initialize your data structure here.
 * 单链表 储存头尾节点 和 节点数量
 */
var MyLinkedList = function() {
    this._size = 0;
    this._tail = null;
    this._head = null;
};

/**
 * 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.getNode = function(index) {
    if(index < 0 || index >= this._size) return null;
    // 创建虚拟头节点
    let cur = new LinkNode(0, this._head);
    // 0 -> head
    while(index-- >= 0) {
        cur = cur.next;
    }
    return cur;
};
MyLinkedList.prototype.get = function(index) {
    if(index < 0 || index >= this._size) return -1;
    // 获取当前节点
    return this.getNode(index).val;
};

/**
 * 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 node = new LinkNode(val, this._head);
    this._head = node;
    this._size++;
    if(!this._tail) {
        this._tail = node;
    }
};

/**
 * 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 node = new LinkNode(val, null);
    this._size++;
    if(this._tail) {
        this._tail.next = node;
        this._tail = node;
        return;
    }
    this._tail = node;
    this._head = node;
};

/**
 * 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._size) return;
    if(index <= 0) {
        this.addAtHead(val);
        return;
    }
    if(index === this._size) {
        this.addAtTail(val);
        return;
    }
    // 获取目标节点的上一个的节点
    const node = this.getNode(index - 1);
    node.next = new LinkNode(val, node.next);
    this._size++;
};

/**
 * 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._size) return;
    if(index === 0) {
        this._head = this._head.next;
        // 如果删除的这个节点同时是尾节点,要处理尾节点
        if(index === this._size - 1){
            this._tail = this._head
        }
        this._size--;
        return;
    }
    // 获取目标节点的上一个的节点
    const node = this.getNode(index - 1);    
    node.next = node.next.next;
    // 处理尾节点
    if(index === this._size - 1) {
        this._tail = node;
    }
    this._size--;
};

反转链表

leetcode 206
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

// 双指针
var reverseList = function(head) {
    if(!head || !head.next) return head
    let tmp = null, pre = null, cur = head
    while(cur){
        temp = cur.next
        cur.next = pre
        pre = cur
        cur = temp
    }
    return pre
};
// 递归
var reverse = function(pre,head){
    if(!head) return pre
    const tmp = head.next
    head.next = pre
    pre = head
    return reverse(pre,tmp)
}
var reverseList = function(head) {
    return reverse(null,head)
};

递归感觉能更好理解一点,牢记链表结构val和next组成,next!!!!!指向下一个节点,也可理解为指向下一个对象

两两节点交换

leetcode24
请添加图片描述
左1是没换,右一是换的步骤,按照1.23.写出来,防止变量丢失,所以按照1,2,3反过来写程序

var swapPairs = function(head) {
    let ret = new ListNode(0,head), temp = ret
    // 循环条件直接考虑末端节点
    while(temp.next != null  && temp.next.next != null){
        let cur = temp.next.next
        let pre = temp.next
        pre.next = cur.next
        cur.next = pre
        temp.next = cur 
        temp = pre
    }
    return ret.next
};

删除链表倒数第n个节点

leetcode19

搞个双指针,fast根据倒数第n个,先跑n个距离,然后slow和fast同时往后走,当fast指向null时,slow就是倒数第n个节点

var removeNthFromEnd = function(head, n) {
    let ret = new ListNode(0,head)
    let slow = fast = ret
    while(n--) fast = fast.next
    while(fast.next != null) {
        fast = fast.next
        slow = slow.next
    }
    slow.next = slow.next.next
    return ret.next
};

链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

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

在这里插入图片描述

 var getListLen = function(head) {
     let len = 0, cur = head
     while(cur){
         len++
         cur = cur.next
     }
     return len
 }
var getIntersectionNode = function(headA, headB) {
    let curA = headA, curB = headB
    let lenA = getListLen(headA)
    let lenB = getListLen(headB)

    if(lenA < lenB){
        let temp = curA
        curA = curB
        curB = temp
        let lentemp = lenA
        lenA = lenB
        lenB = lentemp
    }
    let i = lenA - lenB
    while(i-- > 0){
        curA = curA.next
    }
    while(curA && curA !== curB){
        curA = curA.next
        curB = curB.next
    }
    return curA
};

环形链表

leetcode 142
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
在这里插入图片描述
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点

var detectCycle = function(head) {
    if(!head || !head.next) return null
    let slow = head, fast = head
    while(fast.next != null && fast.next.next != null){
        fast = fast.next.next
        slow = slow.next
        if(fast == slow){
            let index1 = fast
            let index2 = head
            while(index1 != index2){
                index1 = index1.next
                index2 = index2.next
            }
            return index1
        }
    }
    return null
};

tips
说一个比较难想象的点,快慢指针相遇后的while怎么实现找到入口,很简单特值法,只转1圈就快慢相遇,公式推导里面就有个结论是 : 从head出发到入口的距离 等于 快慢指针相遇点到入口的距离

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值