鏈表和數(shù)組

數(shù)組

  • 數(shù)組是一種順序存儲(chǔ)結(jié)構(gòu),它需要一個(gè)連續(xù)的內(nèi)存空間來(lái)存放數(shù)據(jù)。
  • 數(shù)組隨機(jī)訪問(wèn)一個(gè)元素時(shí),可以通過(guò)下標(biāo)直接訪問(wèn)任意元素,因?yàn)閿?shù)組是連續(xù)存儲(chǔ)的,所以就可以通過(guò)偏移量快速計(jì)算出元素的地址,因此數(shù)組訪問(wèn)元素的復(fù)雜度是O(1)。
  • 數(shù)組插入和刪除需要移動(dòng)大量其他元素, 因?yàn)樗麄兪琼樞虼鎯?chǔ)的, 所以當(dāng)插入或刪除的時(shí)候,都需要給它的到來(lái)騰位置,所以復(fù)雜度是O(n)。

鏈表

  • 鏈表是一種鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),它不需要連續(xù)的內(nèi)存空間,而是通過(guò)指針將一系列零散的內(nèi)存空間串聯(lián)起來(lái)。
  • 鏈表隨機(jī)訪問(wèn)一個(gè)元素時(shí),我們需要從節(jié)點(diǎn)開(kāi)始順序遍歷整個(gè)鏈表,直到找個(gè)目標(biāo)元素,因?yàn)樗欠沁B續(xù)存儲(chǔ)的,找的當(dāng)前元素必須找到上一個(gè)元素,找到上一個(gè)元素必須又找到更上一級(jí)的元素,以此類(lèi)推。 因此鏈表隨機(jī)訪問(wèn)元素的復(fù)雜度是O(n)。
  • 鏈表插入和刪除元素只需要修改相鄰節(jié)點(diǎn)足以,所以復(fù)雜度是O(1)。

使用JS實(shí)現(xiàn)一個(gè)鏈表

  • 首先鏈表我們知道的它是按照順序,上一個(gè)指向下一個(gè)的,所以我們需要有個(gè)類(lèi)來(lái)生成鏈表的數(shù)據(jù)結(jié)構(gòu)。
class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}
  • 然后開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)單的鏈表,append和print方法。當(dāng)我們第一次append的時(shí)候,這時(shí)候head是沒(méi)有值的,所以我們需要生成一個(gè)head,然后到后面添加的時(shí)候,我們需要淺拷貝一個(gè)head,然后while循環(huán),找到這個(gè)鏈表的最后一個(gè)節(jié)點(diǎn),把當(dāng)前的值賦值給最后一個(gè)節(jié)點(diǎn)的next。
class LinkNodeList {
  constructor() {
    this.head = null;
  }

  append(val) {
    const newNode = new Node(val);
    if (!this.head) {
      this.head = newNode;
      return;
    }

    let current = this.head;
    //找到鏈表最后一個(gè)節(jié)點(diǎn)
    while (current.next) {
      current = current.next;
    }

    //給最后一個(gè)節(jié)點(diǎn)的next賦值
    current.next = newNode;
  }

  print() {
    let current = this.head;
    let ret = '';
    if (!this.head) {
      console.log('No data');
      return;
    }
    while (current) {
      ret += `${current.val} -> `;
      current = current.next;
    }
    console.log(ret);
  }
}

const linkList = new LinkNodeList();

linkList.append(1);
linkList.append(2);
linkList.append(3);
linkList.append(4);
linkList.print();

203. 移除鏈表元素

image.png

這里有一個(gè)新的概念,哨兵元素,就在鏈表的頭,設(shè)置一個(gè)哨兵,它是肯定存在的。然后使用while循環(huán),如果next值等于這個(gè)val,那么就指向下下個(gè)。

var removeElements = function (head, val) {
    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
}; 

141. 環(huán)形鏈表

image.png

這個(gè)題就有兩個(gè)思路

  • 我們每次將值存在集合中,當(dāng)集合中存在重復(fù)的時(shí)候,就return true,否則就往里面添加。
  • 快慢指針,如果是環(huán)形,兩者終能相遇。
var hasCycle = function (head) {
    // const cache = new Set()
    // while (head) {
    //     if (cache.has(head)) {
    //         return true;
    //     } else {
    //         cache.add(head)
    //     }
    //     head = head.next
    // }
    // return false

    let slow = head
    let fast = head
    while (fast && fast.next) {
        fast = fast.next.next
        slow = slow.next
        if(slow === fast) return true
    }
    return false
};

146. LRU 緩存

首先我們需要知道LRU緩存是什么,LRU 是 Least Recently Used(最近最少使用)的縮寫(xiě),是一種常用的緩存淘汰策略。當(dāng)我們經(jīng)常使用的我們會(huì)放在最前面,然后當(dāng)超過(guò)最大緩存數(shù)的時(shí)候,我們會(huì)淘汰最不常使用的,也就是最后一項(xiàng)數(shù)據(jù)。

我們?cè)贘S中,我們可以使用到Map的數(shù)據(jù)結(jié)構(gòu),因?yàn)檫@個(gè)Map,當(dāng)我們set的時(shí)候,他是存儲(chǔ)到末尾的,所以我們可以跟我們上述介紹的概念反過(guò)來(lái)。

當(dāng)我們get讀取緩存的時(shí)候,如果我們緩存有值,那么我們就delete當(dāng)前key,然后重新set。這樣就保證我們最近使用的值在末尾。
當(dāng)我們put存值的時(shí)候,如果有值,我們同樣需要?jiǎng)h除當(dāng)前key,然后重新set, 當(dāng)我們需要Put一個(gè)新的值,但是大于緩存數(shù)的時(shí)候,我們就可以淘汰Map數(shù)據(jù)結(jié)構(gòu)的第一個(gè)值(this.cache.keys().next().value),然后再set新的值

/**
 * @param {number} capacity
 */
var LRUCache = function (capacity) {
    this.cache = new Map()
    this.max = capacity
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function (key) {
    if (this.cache.has(key)) {
        const tmp = this.cache.get(key)
        this.cache.delete(key)
        this.cache.set(key,tmp)
        return tmp
    }
    return -1
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function (key, value) {
    if (this.cache.has(key)) {
        this.cache.delete(key)
    } else if (this.cache.size >= this.max) {
        this.cache.delete(this.cache.keys().next().value)
    }
    this.cache.set(key, value)
};


/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 遍歷速度 雖然遍歷數(shù)組和鏈表的時(shí)間復(fù)雜度都是O(n),但是在實(shí)際中數(shù)組的速度要比鏈表快,這是為什么呢? 數(shù)組...
    cxq要努力閱讀 695評(píng)論 0 0
  • 鏈表 鏈表是線性表的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),是用一組任意的存儲(chǔ)單元來(lái)存儲(chǔ)數(shù)據(jù),存儲(chǔ)單元不一定是連續(xù)的。數(shù)據(jù)元素隨機(jī)存儲(chǔ),并通...
    小李不木閱讀 902評(píng)論 0 0
  • 二者都屬于一種數(shù)據(jù)結(jié)構(gòu) 從邏輯結(jié)構(gòu)來(lái)看 1. 數(shù)組必須事先定義固定的長(zhǎng)度(元素個(gè)數(shù)),不能適應(yīng)數(shù)據(jù)動(dòng)態(tài)地增減的情況...
    Lee堅(jiān)武閱讀 1,278評(píng)論 0 50
  • 數(shù)組和列表很相似,都是有序的元素集合。他們之間的特點(diǎn)列在了下面: 數(shù)組 array 數(shù)組在內(nèi)存中,數(shù)組是一塊連續(xù)的...
    無(wú)敵的肉包閱讀 348評(píng)論 0 1
  • 數(shù)組和鏈表的優(yōu)缺點(diǎn) 數(shù)組的所有元素在內(nèi)存地址中必須是在一起的,不能分開(kāi)。如果需要插入元素,那就要數(shù)組中的所有值全部...
    meto風(fēng)閱讀 83評(píng)論 0 0

友情鏈接更多精彩內(nèi)容