簡體   English   中英

二和 Leetcode 解釋、Hashmap、Javascript

[英]Two-sum Leetcode explanation, Hashmap, Javascript

我只是想知道誰能一步一步解釋這個解決方案的算法。 我不知道 hashmap 是如何工作的。 你能不能給出一個使用哈希圖的基本例子來讓我理解這個算法。 謝謝!

var twoSum = function(nums, target) {
  let hash = {};

  for(let i = 0; i < nums.length; i++) {
    const n = nums[i];
    if(hash[target - n] !== undefined) {
      return [hash[target - n], i];
    }
    hash[n] = i;
  }
  return [];
}

您的代碼采用一組數字和一個目標數字/總和。 然后它返回數組中兩個數字的索引,這些數字相加為目標數字/總和。

考慮一個數字數組,例如[1, 2, 3]和目標5 您的任務是在此數組中找到與5相加的兩個數字。 解決這個問題的一種方法是循環遍歷數組中的每個數字並問自己“是否有一個數字(我已經在我的數組中看到過)可以添加到當前數字中以獲得我的target總和?”。

好吧,如果我們遍歷[1, 2, 3]的示例數組,我們首先從索引 0 開始,編號為1 目前,我們已經看到沒有數字可以加1來獲得目標5因為我們還沒有遍歷任何數字。

所以,到目前為止,我們遇到了數字1 ,它位於索引0 這作為{'1': 0}存儲在哈希映射(即對象)中。 其中鍵是數字,值 ( 0 ) 是看到它的索引。 該對象的目的是存儲我們看到的數字以及它們出現的索引。

接下來,循環繼續到索引 1,當前編號為2 我們現在可以問自己這個問題:是否有一個我已經在數組中看到的數字,我可以將它添加到我當前的數字2以獲得目標總和5 可以通過執行target-currentNumber獲得添加到當前數字以到達目標所需的數量。 在這種情況下,我們當前在2 ,因此我們需要添加3以獲得目標總和 5。使用 hashmap/object,我們可以檢查是否已經看到數字3 為此,我們可以嘗試通過執行obj[target-currentNumber]訪問對象3鍵。 目前,我們的對象只有'1'鍵,所以當我們嘗試訪問3鍵時,你會得到undefined 這意味着我們還沒有看到數字3 ,所以,截至目前,沒有任何東西可以添加到2來獲得我們的target總和。

所以現在我們的對象/哈希圖看起來像{'1': 0, '2': 1} ,因為我們已經看到了索引0處的數字1 ,我們已經看到了索引1處的數字2

最后,我們到達數組中索引 2 處的最后一個數字。數組的索引 2 保存數字3 現在,我們再問自己一個問題:是否有一個我們已經看到的數字可以與3 (我們當前的數字)相加得到target總和? 我們需要添加到3以獲得目標數字5數字是2 (通過執行target-currentNumber )。 我們現在可以檢查我們的對象,看看我們是否已經在數組中看到了數字2 為此,我們可以使用obj[target-currentNumber]來獲取鍵2存儲的值,該鍵存儲索引 1。這意味着數組中確實存在數字2 ,因此我們可以將其添加到3中達到我們的目標。 由於值在對象中,我們現在可以返回我們的發現。 那是所見號碼發生位置的索引,以及當前號碼的索引。

通常,該對象用於跟蹤數組中所有先前看到的數字,並保留看到該數字的索引值。

這是運行代碼的示例。 它返回[1, 2] ,因為索引12處的數字可以加在一起得到5的目標總和:

 const twoSum = function(nums, target) { const hash = {}; // Stores seen numbers: {seenNumber: indexItOccurred} for (let i = 0; i < nums.length; i++) { // loop through all numbers const n = nums[i]; // grab the current number `n`. if (hash[target - n] !== undefined) { // check if the number we need to add to `n` to reach our target has been seen: return [hash[target - n], i]; // grab the index of the seen number, and the index of the current number } hash[n] = i; // update our hash to include the. number we just saw along with its index. } return []; // If no numbers add up to equal the `target`, we can return an empty array } console.log(twoSum([1, 2, 3], 5)); // [1, 2]

像這樣的解決方案可能看起來過度設計。 您可能想知道為什么您不能只查看數組中的一個數字,然后查看所有其他數字,看看您是否遇到加起來等於target 像這樣的解決方案可以很好地工作,但是,它的效率不是很高。 如果您的數組中有N 個數字,在最壞的情況下(沒有兩個數字加起來等於您的target ),您需要遍歷所有這些N 個數字 - 這意味着您將進行N次迭代。 但是,對於每次查看單數的迭代,您都需要使用內部循環查看其他數字。 這意味着對於外循環的每次迭代,您將對內循環進行N次迭代。 這將導致您執行 N*N 或 N 2工作(O(N 2 ) 工作)。 與這種方法不同的是,本答案前半部分描述的解決方案只需要對整個數組進行N次迭代。 使用對象,我們可以在常數(O(1))時間內找到對象中是否有數字,這意味着上述算法的總工作量僅為O(N)。

有關對象如何工作的更多信息,您可以在此處閱讀有關括號表示法和其他屬性訪問器方法的信息


編輯:正如您要求的對象/哈希圖的進一步示例/用法,這里有一些示例。

對象的一些簡單用例是存儲鍵值對。 為了真正簡化它,您可以將對象/哈希圖視為一個數組,但是,您可以擁有“命名”索引而不是索引(即數字)。 例如,您可以有一個如下所示的數組:

//                 0      1   2   3
const person = ["James", "A", 18, 3];

上面,我們有一個 person 數組,其中包含有關person信息。 在索引0我們有這個人的名字,在索引1我們有姓氏的首字母,在索引2我們有這個人的年齡,在索引3我們有這個人的家庭成員數量。 這種表示單個人的方式不是很友好,因為您必須記住每個索引包含哪些信息。 猜測並不總是那么容易,特別是如果他們持有數字。 因此,相反,我們可以使用一個對象來表示一個人。 這基本上允許我們命名我們的索引(這些命名的索引被稱為)。 所以使用上面的數組,我們可以做類似的事情來將我們的person表示為一個對象:

const person = {
  name: "James",
  surname_initial: "A",
  age: 18,
  familyMembers: 3
}

現在要訪問name保存的數據,您可以使用括號表示法( person["name"]給出 "James")或點表示法( person.name也給出 "James")來獲取"James"的值。 這樣做可以讓您清楚地定義每條數據是什么。

對象的好處是它們只能保留唯一的鍵。 如果您嘗試設置一個key ,例如person["age"] = 30 ,那么您將更新age鍵以使其值為30 它不會創建名稱為age 2 個,而是將鍵age的值更新為新值30 因此,對象可以很好地處理諸如分組或查找唯一值之類的事情。

對象的另一個用例可能是保持數組中項目頻率的計數。 例如,如果您有數組['a', 'b', 'a', 'a', 'b', 'c'] ,並且要求您找出有多少個'a' , 'b' s 和'c'出現在數組中,您可以為此使用一個對象。 主要思想是遍歷數組並檢查對象以查看當前項是否已經是對象中的鍵。 如果是,那么您可以增加它持有的計數器,如果它不在您的對象中,您可以將新鍵設置為當前項目,並將值設置為1 ,以表明到目前為止您只看到該項目之一。 這可以像這樣實現:

 const arr = ['a', 'b', 'a', 'a', 'b', 'c']; const freq = {}; for(let i = 0; i < arr.length; i++) { const currentItem = arr[i]; if(freq[currentItem]) { // if currentItem is a key in the freq object freq[currentItem] = freq[currentItem] + 1; // update the currentItems counter value to be incremented } else { // if the currentItem is not a key in the freq object freq[currentItem] = 1; // set a new key to be the value of `currentItem`, and initialize its counter to `1`. } } console.log(freq); // Output the freq object to see frequency.

function twoSum(numbers, target) {
  for (let i = 0; i < numbers.length; i++) {
  for (let j = i + 1; j < numbers.length; j++) {
    if (numbers[i] + numbers[j] === target) {
      return [numbers.indexOf(numbers[i]), numbers.lastIndexOf(numbers[j])];
    }
  }
}
}

const nums = [1,5,9];

const twoSum = (nums, target) => {// O(n)

let map = {}; //O(n)
for (let i = 0 ; i < nums.length ; i++){
    var value = nums[i];
    var complementPair = target - value;

    if (map[complementPair] !== undefined){
        return [map[complementPair],i];
    }
    map[value] = i;

}

}

console.log(twoSum(array1, 10));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM