JS算法題之leetcode(21~30)

JS算法題之leetcode(21~30)

clipboard.png
題目均來自樂扣(leetcode)node

合併兩個有序鏈表

題目描述

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。算法

示例

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

解答

這題不難,利用遞歸就能實現,兩個鏈表雙雙比較便可數組

var mergeTwoLists = function(l1, l2) {
    if(l1 == null){
        return l2;
    }
    if(l2 == null){
        return l1;
    }

    if(l1.val < l2.val){
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    }
    else{
        l2.next = mergeTwoLists(l1, l2.next)
        return l2
    }
};

括號生成

題目描述

給出 n 表明生成括號的對數,請你寫出一個函數,使其可以生成全部可能的而且有效的括號組合。網絡

例如,給出 n = 3,生成結果爲:ide

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

解答

這題咱們用遞歸來實現,判斷左括號數是否小於n切大於右括號數,不然就退出遞歸函數

var recursiveFun = (str, l, r, n, res) => {
    // str是字符串,l是左括號數量,r是右括號數量,n是雙括號數量,res是返回結果
    if(l == n && r == n){
        res.push(str);
        return;
    }
    // 左括號數>右括號數,下一個能夠爲左括號,也能夠爲右括號
    if(l < n){
        recursiveFun(str + '(', l+1, r, n, res);
    }
    if(l > r){
        recursiveFun(str + ')', l, r+1, n ,res)
    }
}

var generateParenthesis = function(n) {
    if(n == 0){
        return []
    }
    else if(n == 1){
        return ["()"]
    }
    else{
        let res = []
        recursiveFun("", 0, 0, n, res)
        return res;
    }
};

合併K個排序鏈表

題目描述

合併 k 個排序鏈表,返回合併後的排序鏈表。spa

示例

輸入:
[
  1->4->5,
  1->3->4,
  2->6
]
輸出: 1->1->2->3->4->4->5->6

解答

這題其實不太難,跟上面合併兩個同樣,只是多一層判斷而已,直接看代碼指針

var mergeKLists = function(lists) {
    if(lists.length == 0){
        return null
    }
    else if(lists.length == 1){
        return lists[0]
    }
    else if(lists.length == 2){
        let l1 = lists[0], l2 = lists[1];
        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1
        }

        if(l1.val <= l2.val){
            l1.next = mergeKLists([l1.next, l2])
            return l1;
        }
        else{
            l2.next = mergeKLists([l1, l2.next])
            return l2;
        }
    }
    else if(lists.length == 3){
        return mergeKLists([lists[0], mergeKLists(lists.slice(1))])
    }
    else{
        return mergeKLists([mergeKLists(lists.slice(0, 2)), mergeKLists(lists.slice(2))])
    }
};

兩兩交換鏈表中的節點

題目描述

給定一個鏈表,兩兩交換其中相鄰的節點,並返回交換後的鏈表。
你不能只是單純的改變節點內部的值,而是須要實際的進行節點交換。code

示例

給定 1->2->3->4, 你應該返回 2->1->4->3.

解答

這題也是用遞歸來作,兩兩互換(不足兩個直接返回剩餘的),第一個指向第二個的next(實際上是另一個遞歸函數),而第二個指向第一個,最終返回第二個節點便可blog

var swapPairs = function(head) {
    if(head == null || head.next == null){
        return head;
    }
    else{
        let nextList = head.next;
        if(nextList.next){
            head.next = swapPairs(nextList.next)
        }
        else{
            head.next = null
        }
        nextList.next = head;
        return nextList;
    }
};

K 個一組翻轉鏈表

題目描述

給你一個鏈表,每 k 個節點一組進行翻轉,請你返回翻轉後的鏈表。
k 是一個正整數,它的值小於或等於鏈表的長度。
若是節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/probl...
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。

示例

給定這個鏈表:1->2->3->4->5

當 k = 2 時,應當返回: 2->1->4->3->5
當 k = 3 時,應當返回: 3->2->1->4->5

解答

這題稍微有點複雜,先獲取k個節點,而後打斷這k個節點跟其餘節點的鏈接,而後利用三指針的方法翻轉這k個節點,而後從新放進總體中,仔細看代碼註釋就能懂。

// 獲取第k個節點
let getEndNode = (start, k) => {
    let cur = start, end = null;
    while(cur){
        if(k == 1){
            end = cur;
            break;
        }
        else{
            cur = cur.next;
            k--;
        }
    }
    return end;
}

// 三指針方法 翻轉鏈表
let reverserFun = (start) => {
    let curNode = start, prevNode = null, res = null;
    while(curNode){
        let nextNode = curNode.next;
        if(curNode.next){
            res = curNode.next;
        }
        curNode.next = prevNode;
        prevNode = curNode;
        curNode = nextNode;
    }
    return res;
}

var reverseKGroup = function(head, k) {
    if(k < 2 || head == null || head.next == null){
        return head;
    }
    let cur = head, res = null, prev = null;
    while(cur && cur.next){
        let start = cur;
        let end = getEndNode(start, k);
        if(end == null){
            // 剩餘節點不足k個
            break;
        }
        else{
            cur = end.next;
        }
        // 打斷要翻轉的k個節點
        end.next = null;
        // 翻轉鏈表,start變成最後一個節點,end變成第一個節點
        reverserFun(start);
        // 再將鏈表鏈接起來
        start.next = cur;
        // 將prev指向翻轉後的最後一個節點,用於下次指向翻轉後的第一個節點
        if(prev == null){
            // 第一次處理
            prev = start;
        }
        else{
            prev.next = end;
            prev = start;
        }
        // 最終返回的結果處理
        if(res == null){
            res = end;
        }
    }
    if(res == null){
        return head;
    }
    else{
        return res;
    }
};

刪除排序數組中的重複項

題目描述

給定一個排序數組,你須要在原地刪除重複出現的元素,使得每一個元素只出現一次,返回移除後數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。

示例

給定數組 nums = [1,1,2], 
函數應該返回新的長度 2, 而且原數組 nums 的前兩個元素被修改成 1, 2。 

給定 nums = [0,0,1,1,1,2,2,3,3,4],
函數應該返回新的長度 5, 而且原數組 nums 的前五個元素被修改成 0, 1, 2, 3, 4。

你不須要考慮數組中超出新長度後面的元素。

解答

這題簡單,基於一個已經排好序的數組進行去重,可是注意的是不能使用額外空間,那就只能原地去重,既然已經排好序了,直接兩兩比較,遍歷一次即可。

var removeDuplicates = function(nums) {
    let i = 1;
    while(i < nums.length){
        if(nums[i] == nums[i-1]){
            nums.splice(i, 1);
        }
        else{
            i++;
        }
    }
    return nums.length;
};

移除元素

題目描述

給定一個數組 nums 和一個值 val,你須要原地移除全部數值等於 val 的元素,返回移除後數組的新長度。
不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。
元素的順序能夠改變。你不須要考慮數組中超出新長度後面的元素

示例

給定 nums = [3,2,2,3], val = 3,
函數應該返回新的長度 2, 而且 nums 中的前兩個元素均爲 2。

給定 nums = [0,1,2,2,3,0,4,2], val = 2,
函數應該返回新的長度 5, 而且 nums 中的前五個元素爲 0, 1, 3, 0, 4。

注意這五個元素可爲任意順序。
你不須要考慮數組中超出新長度後面的元素。

解答

這題跟上面的那道差很少,直接看代碼

var removeElement = function(nums, val) {
    let i = 0;
    while(i < nums.length){
        if(nums[i] == val){
            nums.splice(i, 1);
        }
        else{
            i++;
        }
    }
    return nums.length;
};

實現 strStr()

題目描述

給定一個 haystack 字符串和一個 needle 字符串,在 haystack 字符串中找出 needle 字符串出現的第一個位置 (從0開始)。若是不存在,則返回  -1。

示例

輸入: haystack = "hello", needle = "ll"
輸出: 2

輸入: haystack = "aaaaa", needle = "bba"
輸出: -1

解答

坦白講,這題。。。不知道是否是我理解的問題,這題直接indexOf就完事了。。。

var strStr = function(haystack, needle) {
    if(needle == ""){
        return 0;
    }
    return haystack.indexOf(needle)
};

兩數相除

題目描述

給定兩個整數,被除數 dividend 和除數 divisor。將兩數相除,要求不使用乘法、除法和 mod 運算符。
返回被除數 dividend 除以除數 divisor 獲得的商。

說明:
被除數和除數均爲 32 位有符號整數。
除數不爲 0。
假設咱們的環境只能存儲 32 位有符號整數,其數值範圍是 [−231,  231 − 1]。本題中,若是除法結果溢出,則返回 231 − 1。

示例

輸入: dividend = 10, divisor = 3
輸出: 3

輸入: dividend = 7, divisor = -3
輸出: -2

解答

這題也挺簡單的,就是實現一個除法,不能使用加法乘法以及mod,那就用減法即可,不過要注意符號。

let MAX = Math.pow(2, 31) - 1
let MIN = -1 * Math.pow(2, 31)

var divide = function(dividend, divisor) {
    if(dividend == 0){
        return 0;
    }
    else{
        let num1 = Math.abs(dividend), num2 = Math.abs(divisor), res = 0;
        if(num2 == 1){
            res = num1;
        }
        else{
            while(num1 >= num2){
                res++;
                num1 -= num2;
            }
        }
        if((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)){
            res = Number(`-${res}`);
        }
        if(res < MIN){
            return MIN;
        }
        else if(res > MAX){
            return MAX;
        }
        else{
            return res
        }
    }
};

串聯全部單詞的子串

題目描述

給定一個字符串 s 和一些長度相同的單詞 words。找出 s 中剛好能夠由 words 中全部單詞串聯造成的子串的起始位置。
注意子串要與 words 中的單詞徹底匹配,中間不能有其餘字符,但不須要考慮 words 中單詞串聯的順序。

示例

輸入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
輸出:[0,9]
解釋:
從索引 0 和 9 開始的子串分別是 "barfoor" 和 "foobar" 。
輸出的順序不重要, [9,0] 也是有效答案。

輸入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
輸出:[]

解答

這題稍微有點複雜,咱們採用窗口移動的方法,先計算出數組元素字符的總長度windowLen,從s的0下標開始,逐windowLen個的字符串提取出來,而後拿去跟words對比,將該字符串拆分爲若干個單詞,若這若干個單詞恰好跟words一一對應,那便返回true,記錄下標。認真看代碼註釋便可

let isMatch = (str, words, itemLen) => {
    let arr = [...words];
    while(str.length && words.length){
        let word = str.slice(0, itemLen);
        let idx = arr.indexOf(word);
        if(idx == -1){
            // 不匹配
            return false;
        }
        else{
            arr.splice(idx, 1);
            str = str.slice(itemLen);
        }
    }
    return true;
}

var findSubstring = function(s, words) {
    if(s == "" || words.length == 0){
        return []
    }
    else{
        let res = [];
        if(words[0] == ""){
            for(let i = 0; i < s.length; i++){
                res.push(i);
            }
        }
        else{
            // 窗口移動法
            // 單個單詞長度、窗口長度、窗口下標、
            let itemLen = words[0].length, windowLen = itemLen * words.length, windowIdx = 0;
            while(windowIdx + windowLen <= s.length){
                if(isMatch(s.slice(windowIdx, windowIdx + windowLen), words, itemLen)){
                    res.push(windowIdx)
                }
                windowIdx++;
            }
        }
        return res;
    }
};
相關文章
相關標籤/搜索