天天一道算法題(第四期)

如你須要掌握三種核心的能力:編程、寫做、設計??

前言

這個活動是從2019年7月中旬開始的,人數不算多,也就幾個好友和好友的好友,過程當中也會有人由於工做的緣故或其餘緣由放棄,或許將來還會有人離開。javascript

活動的主要形式就是在leetcode刷題,每一個工做日一道題,每週作總結,目前已是第十四期,接下來我會把每期的題作一個總結,因爲我是側重javascript,因此活動中的每道題都是以js語言來實現解題方法。java

活動的規則比較嚴謹,羣裏天天早上10點以前發題,晚上10點審覈,審覈有管理員專門審覈,稱爲打卡,沒有打卡的人,須要發紅包給管理員做爲天天統計費用。node

活動的目的就是培養算法思惟,瞭解常見的算法,好比分治算法、貪心算法、動態優化等等。面試

微信公衆號驚天碼盜同步天天一道算法題(第四期)​算法



上期回顧:
編程

本期題目

一、數組形式的整數加法

假設你是一位很棒的家長,想要給你的孩子們一些小餅乾。可是,每一個孩子最多隻能給一塊餅乾。對每一個孩子 i ,都有一個胃口值 gi ,這是能讓孩子們知足胃口的餅乾的最小尺寸;而且每塊餅乾 j ,都有一個尺寸 sj 。若是 sj >= gi ,咱們能夠將這個餅乾 j 分配給孩子 i ,這個孩子會獲得知足。你的目標是儘量知足越多數量的孩子,並輸出這個最大數值。數組

注意:bash

你能夠假設胃口值爲正。
一個小朋友最多隻能擁有一塊餅乾。微信

示例 1:app

輸入: [1,2,3], [1,1]

輸出: 1

解釋:
你有三個孩子和兩塊小餅乾,3個孩子的胃口值分別是:1,2,3。雖然你有兩塊小餅乾,因爲他們的尺寸都是1,你只能讓胃口值是1的孩子知足。因此你應該輸出1。複製代碼

示例 2:

輸入: [1,2], [1,2,3]

輸出: 2

解釋: 
你有兩個孩子和三塊小餅乾,2個孩子的胃口值分別是1,2。你擁有的餅乾數量和尺寸都足以讓全部孩子知足。因此你應該輸出2.複製代碼

題解:

思路1:逐位查找法

有一數組長爲0,則返回爲0,先排序,而後循環小孩胃口值,num用來存儲返回值;ll用來存儲餅乾的索引(跟以前跳針法相似);當小孩的胃口值大於餅乾的時候,須要在餅乾中查找大於等於相應餅乾尺寸,若是沒找到返回最大值,若是找到則記錄索引;而後進入下次循環。

執行用時:192ms;內存消耗:38.7MB;

var findContentChildren = function(g, s) {
    let {num=0,ll=0}={};
    if(!s.length||!g.length)return 0;
    let gArray=g.sort((a,b)=>a-b);
    let sArray=s.sort((a,b)=>a-b);
    for(let i=0;i<g.length;i++){
        if(sArray[ll]){
            if(gArray[i]>sArray[ll]){
                const cur=sArray.filter(a=>a>=gArray[i])[0]||null;
                if(cur){
                    ll=sArray.indexOf(cur)+1
                    num++
                }
            }else{
                ll++
                num++
            }
        }
        
    }
    return num
}
複製代碼

思路2:倒序遞減法

餅乾尺寸和胃口值都從大到小排序,循環胃口值,逐一刪除餅乾尺寸。(經常從小到大排序,偶爾換個思路可能更方便)

執行用時:144ms;內存消耗:37.6MB;

var findContentChildren = function(g, s) {
    let num=0;
    let gArray=g.sort((a,b)=>b-a);
    let sArray=s.sort((a,b)=>b-a);
    gArray.forEach((item,i)=>{
        if(sArray[0]>=item){
            num++;
            sArray.shift()
        }
    })
    return num
}
複製代碼

二、二叉樹的層平均值

給定一個非空二叉樹, 返回一個由每層節點平均值組成的數組.

示例 1:

輸入:
    3
   / \
  9  20
    /  \
   15   7
輸出: [3, 14.5, 11]
解釋:第0層的平均值是 3,  第1層是 14.5, 第2層是 11. 所以返回 [3, 14.5, 11].複製代碼

注意:

1.節點值的範圍在32位有符號整數範圍內。

題析:

關於圖形算法,是比較複雜的,尤爲是樹的遍歷,涉及到遞歸的邏輯。通常簡單的狀況下能夠用條件語句while等來實現簡單的遞歸。這道題一樣能夠,不管使用遞歸仍是while語句均可以實現。

這道題的結果是一數組,數組的每個值是當前層的節點值除以節點數;因此咱們要明確咱們須要獲得的東西,層數,層數表示咱們數組的長度;當前層的節點值與當前層的節點數。

這道題的核心思路有兩,一是層序遍歷,一層一層推動只有當前層執行完才能夠推動下一層;另外一種是不限制,不管當前層是否執行完,均可以執行下一層。這就會涉及到圖形的兩個概念:廣度優先搜索和深度優先搜索。

題解:

思路1:廣度優先遍歷法

利用廣度優先搜索的方法,逐層推動。利用queue的長度來限制是否向下推動,當所在層無值時向下推動。

執行用時:108ms;內存消耗:35.7MB;

var averageOfLevels = function(root) {
    let queue = [root], result = [], arr = [], sum = 0, length = 1
    while (queue.length) {
        let node = queue.shift()
        sum += node.val
        node.left && arr.push(node.left)
        node.right && arr.push(node.right)
        if (queue.length === 0) {
            result.push(sum/length)
            queue = arr
            length = queue.length
            arr = []
            sum = 0
        }
    }
    return result
}
複製代碼

思路2:深度優先遍歷法

經過每層的索引來肯定當前的值。同層相加。

執行用時:100ms;內存消耗:38.1MB;

var averageOfLevels = function(root) {
        let ans = [];
        let levelNum = [];//每一層的節點數
        let levelSum = [];//每一層的節點總數
        
        //遞歸函數
        let rescurse=(node, index, levelNum, levelSum)=>{
            if (node == null) {
                return;
            }

            if (levelNum.length <= index) {
                levelNum.push(1);
                levelSum.push(node.val);
            } else {
                levelNum[index]++;
                levelSum[index]+=node.val
            }

            rescurse(node.left, index + 1, levelNum, levelSum);
            rescurse(node.right, index + 1, levelNum, levelSum);

        }
    
        rescurse(root, 0, levelNum, levelSum);
    
        for (let i = 0; i < levelNum.length; i++) {
            ans.push(levelSum[i] / levelNum[i]);
        }
    

        return ans;
}
複製代碼

三、整數反轉

給出一個 32 位的有符號整數,你須要將這個整數中每位上的數字進行反轉。

示例 1:

輸入: 123
輸出: 321複製代碼

示例 2:

輸入: -123
輸出: -321複製代碼

示例 3:

輸入: 120
輸出: 21複製代碼

注意:

假設咱們的環境只能存儲得下 32 位的有符號整數,則其數值範圍爲 [−231, 231 − 1]。請根據這個假設,若是反轉後整數溢出那麼就返回 0。

題解:

思路1:數組化

先轉化爲數組,反轉後,再轉化爲字符串,須要逐一限制條件。

這個思路是數組思惟。

執行用時:108ms;內存消耗:35.7MB;

var reverse = function(x) {
    let num=String(Math.abs(x)).split('').reverse().join('');
    if(Math.pow(2,31)>=num&&x>0){
        return Number(num)
    }
    if(0-Math.pow(2,31)<0-num&&x<0){
         return 0-Number(num)
    }
    return 0
}
複製代碼

思路2:分離取餘法

先分離數字(123),取得餘數(3)和剩餘數(12),而後餘數乘十(30)加剩餘數的餘數(2);記錄每次相加後所得餘數(32)與剩餘數(1);依次循環,獲得終數。

這個思路是利用的數學思惟。

執行用時:100ms;內存消耗:35.7MB;

var reverse = function (x) {
    let re = 0;
    while (parseInt(x / 10)) {
        re = 10 * re + x - 10 * parseInt(x / 10);
        x = parseInt(x / 10);
    }
    if (re > 214748364 || re < -214748364) return 0;
    if ((re == 214748364 && x > 7) || (re == 214748364 && x < -8)) return 0;
    re = 10 * re + x;
    return re
}
複製代碼

思路3:字符倒序法

轉化爲字符串,反轉字符串,而後在循環中逐一添加。須要注意的是,轉的時候要絕對值化,轉以後要取整。

這個思路是字符串思惟。

執行用時:112ms;內存消耗:35.7MB;

var reverse = function(x) {
    Math.abs(x)>(2**31-1)?x=0:x;
    if(x == 0) return 0
    let y = Math.abs(x).toString(),len='';
    for(var i =0;i<y.length;i++){len += y[y.length-i-1]}
    return parseInt(Math.abs(len)>(2**31-1)?len=0:(x<0?-len:len));
}
複製代碼

四、迴文數

判斷一個整數是不是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是同樣的整數。

示例 1:

輸入: 121
輸出: true複製代碼

示例 2:

輸入: -121
輸出: false
解釋: 從左向右讀, 爲 -121 。從右向左讀, 爲 121- 。所以它不是一個迴文數。複製代碼

示例 3:

輸入: 10
輸出: false
解釋: 從右向左讀, 爲 01 。所以它不是一個迴文數。複製代碼

進階:

你能不將整數轉爲字符串來解決這個問題嗎?

題析:

這道題本質上和上面整數反轉是一個題目,因此上面的思路下面都能用到,惟一的區別就是正負數。因此下面題解不會過多的介紹思路。

題解:

思路1:分離取餘法

先轉化爲數組,反轉後,再轉化爲字符串,須要逐一限制條件。

執行用時:360ms;內存消耗:42.5MB;

var isPalindrome = function(x) {
     if (x < 0) return false;
        let result = 0;
        let before = x;
        while (x > 0){
            result = result*10 + x%10;
            x = parseInt(x / 10);
        }
        return before == result?true:false;
}
複製代碼

五、實現strStr()

實現 strStr() 函數。

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

示例 1:

輸入: haystack = "hello", needle = "ll"
輸出: 2複製代碼

示例 2:

輸入: haystack = "aaaaa", needle = "bba"
輸出: -1複製代碼

說明:

needle 是空字符串時,咱們應當返回什麼值呢?這是一個在面試中很好的問題。

對於本題而言,當 needle 是空字符串時咱們應當返回 0 。這與C語言的 strstr() 以及 Java的 indexOf() 定義相符。

題解:

思路1:字符串索引法

利用字符串方法一步到位。

執行用時:64ms;內存消耗:33.8MB;

var strStr = function(haystack, needle) {
    if(!needle)return 0;
    return haystack.indexOf(needle)
    
}
複製代碼

執行用時:76ms;內存消耗:36MB;

var strStr = function (haystack, needle) {
    if (needle === "") return 0
    for (var i = 0; i < haystack.length; i++) {
        if (haystack[i] === needle[0]) {
            if (haystack.substring(i, i + needle.length) === needle) return i;
        }
    }
    return -1
}
複製代碼

四期結束,但願有更多的小夥伴加入。


關注公衆號回覆算法,一塊兒學習吧。

相關文章
相關標籤/搜索