【JavaScript算法】-链表合辑09:203 移出链表元素、237 删除链表中的节点、146 LRU缓存

一、203 移除链表元素

问题描述

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
在这里插入图片描述

解题思路

双指针

a、设置虚拟节点dmy并进行初始化使其next指向head;
b、初始化双指针cur=head,pre=dmy;
c、判断cur.val是否等于目标值val,相等则令pre.next=cur.next,删除当前节点;
d、否则pre指针向后移动;
e、直到cur移动到链表末尾,最后返回dmy.next。

var removeElements = function(head, val) {
    if(head==null) return null;
    let dmy=new ListNode(0,head);
    let cur=head;
    let pre=dmy;
    while(cur){
        if(cur.val==val){
            pre.next=cur.next;
        }else{
            pre=pre.next;
        }
        cur=cur.next;
    }
    return dmy.next;
};
递归

递归调用函数removeElements,传入head.next和 val,如果当前元素值是val,则返回下一个元素,否则直接返回当前元素。

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

二、237 删除链表中的节点

有一个单链表的 head,我们想删除它其中的一个节点 node。

给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。
链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。
删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

  • 给定节点的值不应该存在于链表中。
  • 链表中的节点数应该减少 1。
  • node 前面的所有值顺序相同。
  • node 后面的所有值顺序相同。
    自定义测试:
  • 对于输入,你应该提供整个链表 head
  • 要给出的节点 node。node 不应该是链表的最后一个节点,而应该是链表中的一个实际节点。
  • 我们将构建链表,并将节点传递给你的函数。
  • 输出将是调用你函数后的整个链表。
    在这里插入图片描述

解题思路

狸猫换太子

实话实说,看官解之前以为是什么新套路,看到官解那一刻我傻了。

var deleteNode=function(node){
	node.val=node.next.val;
	node.next=node.next.next;
}

三、146 LRU缓存

问题描述

请你设计并实现一个满足LRU(最近最少使用)缓存约束的数据结构。
实现LRUCache类:

  • LRUCache(int capacity)以正整数作为容量capacity初始化LRU缓存
  • int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回-1
  • void put(int key,int value)如果关键字key已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组key-value。如果插入操作导致关键字数量超过capacity,则应该逐出最久未使用的关键字
    函数get和put必须以O(1)的平均时间复杂度运行。
    在这里插入图片描述

解题思路

1、链表+哈希

题意分析
get()和put()的时间复杂度需要是O(1),显然不能使用数组(数组删除或者添加元素的时间复杂度是O(N),因为需要挪动其他元素),所以考虑使用链表,这样删除和添加元素的时间复杂度是O(1),但是找到这个需要删除的节点需要O(N),所以还需要一个哈希表来记录节点的位置。
下面给出伪代码:

function put(key,value){
	if(key存在){
		更新key的value;
		将该key节点移到链表头部; //方便快速找到最近最久未使用的节点
	}else{
		if(缓存满了){
			删除最后一个节点;
			删除其在哈希表中的映射;
		}
		新建一个节点;
		在哈希表中增加映射;
		把该节点加入链表头部;
	}
}

function get(key){
	if(key存在){
		返回节点值;
		将该节点移动到链表头部;
	}else{
		返回-1;
	}
}

完整代码

class DoubleLinkedListNode {

    constructor(key, value) {

        this.key = key

        this.value = value

        this.prev = null

        this.next = null

    }

}



class LRUCache {

    constructor(capacity) {

        this.capacity = capacity

        this.usedSpace = 0

        // Mappings of key->node.

        this.hashmap = {}

        this.dummyHead = new DoubleLinkedListNode(null, null)

        this.dummyTail = new DoubleLinkedListNode(null, null)

        this.dummyHead.next = this.dummyTail

        this.dummyTail.prev = this.dummyHead

    }



    _isFull() {

        return this.usedSpace === this.capacity

    }



    _removeNode(node) {

        node.prev.next = node.next

        node.next.prev = node.prev

        node.prev = null

        node.next = null

        return node

    }



    _addToHead(node) {

        const head = this.dummyHead.next

        node.next = head

        head.prev = node

        node.prev = this.dummyHead

        this.dummyHead.next = node

    }



    get(key) {

        if (key in this.hashmap) {

            const node = this.hashmap[key]

            this._addToHead(this._removeNode(node))

            return node.value

        }

        else {

            return -1

        }

    }



    put(key, value) {

        if (key in this.hashmap) {

            // If key exists, update the corresponding node and move it to the head.

            const node = this.hashmap[key]

            node.value = value

            this._addToHead(this._removeNode(node))

        }

        else {

        // If it's a new key.

            if (this._isFull()) {

                // If the cache is full, remove the tail node.

                const node = this.dummyTail.prev

                delete this.hashmap[node.key]

                this._removeNode(node)

                this.usedSpace--

            }

            // Create a new node and add it to the head.

            const node = new DoubleLinkedListNode(key, value)

            this.hashmap[key] = node

            this._addToHead(node)

            this.usedSpace++

        }

    }

}
2、map
a. LRU 缓存策略举例:
	i. 假设缓存大小为 4,依次打开了 gitlab、力扣、微信、QQ,缓存链表为 QQ -> 微信 -> 力扣 -> gitlab;
	ii. 若此时切换到了「微信」,则缓存链表更新为  微信 -> QQ -> 力扣 -> gitlab;
	iii. 若此时打开了腾讯会议,因为缓存已经满 4 个 ,所以要进行缓存淘汰机制,删除链表的最后一位 「gitlab」,则缓存链表更新为 腾讯会议 -> 微信 -> QQ -> 力扣;
b. 本题用的是 map 迭代器,map 实现了 iterator,next 模拟链表的下一个指针,为了方便操作,这里将 map 第一个元素作为链表的最后一个元素;
let cache = new Map();
cache.set('a', 1);
cache.set('b', 2);
cache.set('c', 3);

cache.keys(); // MapIterator {'a', 'b', 'c'}
cache.keys().next().value; // a
// Vue3的keeplive组件就是使用了这种LRU管理组件的缓存
var LRUCache=function(capacity){
	this.map=new Map();
	this.capacity=capacity;
}

LRUCache.prototype.get=function(key){
	if(this.map.has(hey)){
		let value=this.map.get(key);
		//重新set,相当于更新到map最后
		this.map.delete(key);
		this.map.set(key,value);
		return value;
	}
	return -1;
}

LRUCache.prototype.put=function(key.value){
	//存在,就删除再赋值
	if(this.map.has(key)){
		this.map.delete(key);
	}
	this.map.set(key,value);

	//判断是否超出容量,进入淘汰机制
	if(this.map.size>this.capacity){
		this.map.delete(this.map.keys().next().value);
}

	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值