【前端來刷LeetCode】兩數之和與兩數相加

大部分玩前端的小夥伴,在算法上都相對要薄弱些,畢竟調樣式、調兼容就夠掉頭髮的了,哪還有多餘的頭髮再去折騰。javascript

確實在前端中須要使用到算法的地方是比較少,但若要往高級方向發展,算法的基本功就很是重要啦。對了,算法在面試中但是必考項啊,因此爲了指望薪資,頭髮仍是得作下犧牲呀。前端

有些小夥伴認爲,刷了那些奇奇怪怪的算法題,可在工做中不多能直接派上用場,嗯,沒錯,因此學算法是件高延遲知足的事情。那麼學算法,到底收穫什麼呢?我以爲經過練習算法,培養咱們解決問題的潛意識才是最重要的。java

學習算法,最直接有效的就是刷題,刷題有不少渠道,我比較推薦 LeetCode,它有國內和國外版,很是方便。如今網上有不少大牛都分享各自刷題的解法,但百讀不如一練嘛,因此我也開個【來刷LeetCode】系列,由淺入深,分享個人解法和思路,由於個人解法確定不是最棒的,因此還會在加上我以爲優秀的解法。node

嗶嗶了這麼多,咱們如今開擼。代碼略多,建議你們先點個贊(我就是來騙讚的~)面試

兩數之和

兩數之和,題目描述以下:算法

給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。 你能夠假設每種輸入只會對應一個答案。可是,你不能重複利用這個數組中一樣的元素。數組

示例:數據結構

給定 nums = [2, 7, 11, 15], target = 9
由於 nums[0] + nums[1] = 2 + 7 = 9
因此返回 [0, 1]函數

個人思路

這題,最暴力的解法就是逐個循環查找,但時間複雜度是 n*n ,太暴力的不適合咱們。 能夠這麼看,在遍歷第一個值得時候,保留這個值與target的差,而後在下次遍歷中,看看是否是與保留的差值相同,若是相同,那麼就能夠找到咱們想要的結果了。畫個簡單的表格以下:學習

序號 當前值 差值
0 2 7
1 7 2

這樣一來,就須要記錄差值,散列表這一數據結構就排上用場了,來看看百科關於散列表的介紹:

散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它經過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫作散列函數,存放記錄的數組叫作散列表。 給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數後若能獲得包含該關鍵字的記錄在表中的地址,則稱表M爲哈希(Hash)表,函數f(key)爲哈希(Hash) 函數。

而js中的對象就是基於哈希表結構,因此咱們構造一個js對象便可,value是當前遍歷到的值,key是其與目標值的差。

這是個人解法以下:

/** * @param {number[]} nums * @param {number} target * @return {number[]} */
var twoSum = function (nums, target) {
    let map = {};
    let result = []
    for (let index = 0;index <= nums.length;index++) {
        const val = nums[index];
        if (map[val] !== undefined) {
            result.push(map[val], index);
            break;
        }
        const a = target - val;
        map[a] = index
    }
    return result;
};

// nums = [2, 6, 3, 15], target = 9
// twoSum(nums,target)
複製代碼

兩數相加

兩數之和,題目描述以下:

給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,而且它們的每一個節點只能存儲 一位 數字。

若是,咱們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。

您能夠假設除了數字 0 以外,這兩個數都不會以 0 開頭。

示例:

輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
緣由:342 + 465 = 807

個人思路

看到這題,個人第一想法就是把鏈表的每一個節點的值合併成一個整形,而後在相加,最後在轉換成鏈表,思路很是簡單暴力。可等我寫完,測試用例一跑,結果以下

error
緣由是 JavaScript 中Number的精度是16位,超過了就會出現精讀丟失,看來直接轉換而後相加的方式不行啊,不要緊,那就用數組模擬大數相加。完整的步驟以下

  1. 將多個 ListNode 結構變成二維數組
  2. 把二維數組中的每個下標對應的元素相加,從下標 0 開始相加,滿十進一位,算是模擬大數相加的一種簡單方式,最後輸出的是一維數組
  3. 把一維數組轉換成 ListNode 結構

個人解法以下

/** * 將多個ListNode結構變成二維數組,在計算該二維數組各個節點的和 * 如傳入的兩個ListNode對象 {val:2,next:{val:3,next:null}} {val:4,next:{val:5,next:null}} * 轉成以下二維數組 [ [2,3], [4,5] ], 計算兩數組和 ,返回 [6,8] * @param {...any} list */
function addListNode(...list) {
    const valList = list.map((node) => {
        const list = [];
        while (node) {
            list.push(Number(node.val));
            node = node.next;
        }
        return list;
    })
    return arraySum(valList);
}
/** * 計算數組的和 * @param {*} list */
function arraySum(list) {
    return list.reduce((result, item) => {
        return arrayItemSum(result, item);
    }, [])
}

/** * 計算傳入的數組的和 * @param {Array} a * @param {Array} b */
function arrayItemSum(a, b) {
    let logArray = a;
    let sortArray = b;
    if (b.length > a.length) {
        logArray = b;
        sortArray = a;
    }
    let addOne = 0; //滿十進一
    const result = logArray.reduce((result, val, index) => {
        const sum = (result[index] || 0) + val + addOne;
        addOne = 1;
        const mod = sum % 10;
        const div = sum / 10;
        if (div < 1) {
            result[index] = mod;
            addOne = 0;
        } else if (div > 1) {
            result[index] = mod;
        } else {
            result[index] = 0;
        }
        return result;
    }, sortArray)
    if(addOne){
        result.push(1);
    }
    if (!result[result.length - 1]) {
        result.pop(1)
    }
    return result;
}

/** * 數組構建成 ListNode 結構 * @param {*} numList */
function numToListNode(numList) {
    let preNode = undefined;
    return numList.reduce((result, val) => {
        let node = new ListNode(val);
        if (preNode) {
            preNode.next = node;
            preNode = node
        } else {
            result = preNode = node
        }
        return result
    }, new ListNode(0))
}
var addTwoNumbers = function (l1, l2) {
    return numToListNode(addListNode(l1, l2));
};
複製代碼

看完代碼,你們是否是以爲代碼很是長,尤爲是 arrayItemSum 這個求和的函數,其實,這題考的是鏈表的操做,但被我硬生生的把鏈表拆數組,最後變成了js如何實現大數相加,手動狗頭.jpg

我leetcode上看到個很是優秀的解法,在遞歸中將每一個節點中的val相加,在將餘數傳入遞歸函數中,直到兩個鏈表都遍歷完成

var addTwoNumbers = function(l1, l2) {
    const addNumbers = (l1, l2, extra) => {
        let sum = (l1 ? l1.val : 0) + (l2 ? l2.val : 0) + extra;
        const node = new ListNode(sum % 10);
        let nl1 = l1 ? l1.next : null;
        let nl2 = l2 ? l2.next : null;
        if (nl1 || nl2 || sum > 9) {
            node.next = addNumbers(nl1, nl2, Math.floor(sum / 10))
        }
        return node;
    };
    return addNumbers(l1, l2, 0);
};
複製代碼

小結

刷leetcode一時苦,一直刷終會爽,加油ヾ(◍°∇°◍)ノ゙

相關文章
相關標籤/搜索