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

如果每天做一道算法題,那是不是每天都在進(jìn)步粟焊?

前言

這個(gè)活動(dòng)是從2019年7月中旬開(kāi)始的,人數(shù)不算多孙蒙,也就幾個(gè)好友和好友的好友,過(guò)程中也會(huì)有人因?yàn)楣ぷ鞯木壒驶蚱渌蚍艞壉ǎ蛟S未來(lái)還會(huì)有人離開(kāi)挎峦。

活動(dòng)的主要形式就是在leetcode刷題,每個(gè)工作日一道題合瓢,每周做總結(jié)坦胶,目前已經(jīng)是第十二期,接下來(lái)我會(huì)把每期的題做一個(gè)總結(jié),由于我是側(cè)重javascript顿苇,所以活動(dòng)中的每道題都是以js語(yǔ)言來(lái)實(shí)現(xiàn)解題方法峭咒。

活動(dòng)的規(guī)則比較嚴(yán)謹(jǐn),群里每天早上10點(diǎn)之前發(fā)題纪岁,晚上10點(diǎn)審核凑队,審核有管理員專(zhuān)門(mén)審核,稱(chēng)為打卡幔翰,沒(méi)有打卡的人漩氨,需要發(fā)紅包給管理員作為每天統(tǒng)計(jì)費(fèi)用。

活動(dòng)的目的就是培養(yǎng)算法思維遗增,了解常見(jiàn)的算法叫惊,比如分治算法、貪心算法做修、動(dòng)態(tài)優(yōu)化等等霍狰。

微信公眾號(hào)驚天碼盜同步第一期

兩個(gè)數(shù)組的交集 II

給定兩個(gè)數(shù)組饰及,編寫(xiě)一個(gè)函數(shù)來(lái)計(jì)算它們的交集蔗坯。

  • 示例 1:
    輸入: nums1 = [1,2,2,1], nums2 = [2,2]
    輸出: [2,2]
    
  • 示例 2:
    輸入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
    輸出: [4,9]
    
題解:
  • 替換法
    循環(huán)nums1,在循環(huán)中判斷nums2中是否存在當(dāng)前元素旋炒,如果存在就push到新的數(shù)組步悠,然后在通過(guò)splice替換到當(dāng)前元素,最后排序瘫镇;
    執(zhí)行用時(shí):88ms鼎兽;內(nèi)存消耗:35.5MB;
    var intersect = function(nums1, nums2) {
        let arr = [];
        nums1.forEach((cur, i) => {
          if (nums2.indexOf(cur) > -1) {
            arr.push(cur)
            nums2.splice(nums2.indexOf(cur), 1, null)
          }
        })
        return arr.sort()
    }; 
    
  • 雙指針?lè)?/strong>
    兩個(gè)數(shù)組排序,設(shè)定兩個(gè)為0的指針铣除,比較兩個(gè)指針的元素是否相等谚咬,如果相等,元素push到返回值里尚粘,兩個(gè)指針同時(shí)往前择卦,如果不相等,元素小的指針往前郎嫁。
    執(zhí)行用時(shí):84ms秉继;內(nèi)存消耗:35MB;
    var intersect = function(nums1, nums2) {
        let p1 = 0
        let p2 = 0
        let res = []
        nums1 = nums1.sort((a, b) => a - b)
        nums2 = nums2.sort((a, b) => a - b)
        while(p1 < nums1.length && p2 < nums2.length) {
            if(nums1[p1] == nums2[p2]) {
                res.push(nums1[p1])
                p1++
                p2++
            } else if(nums1[p1] < nums2[p2]) {
                p1++
            } else {
                p2++
            }
        }
        return res
    }
    

1比特與2比特字符

有兩種特殊字符泽铛。第一種字符可以用一比特0來(lái)表示尚辑。第二種字符可以用兩比特(10 或 11)來(lái)表示。

現(xiàn)給一個(gè)由若干比特組成的字符串盔腔。問(wèn)最后一個(gè)字符是否必定為一個(gè)一比特字符杠茬。給定的字符串總是由0結(jié)束月褥。

  • 示例 1:
    輸入: bits = [1, 0, 0]
    輸出: True
    解釋: 唯一的編碼方式是一個(gè)兩比特字符和一個(gè)一比特字符。所以最后一個(gè)字符是一比特字符瓢喉。
    
  • 示例 2:
    輸入: bits = [1, 1, 1, 0]
    輸出: False
    解釋: 唯一的編碼方式是兩比特字符和兩比特字符宁赤。所以最后一個(gè)字符不是一比特字符。
    
題解:
  • 正則
    這是我見(jiàn)過(guò)最暴力直接的方式栓票,由群內(nèi)小伙伴提出的解題方式决左。
    執(zhí)行用時(shí):84ms;內(nèi)存消耗:34.4MB逗载;(我感覺(jué)這個(gè)測(cè)試不準(zhǔn)哆窿,每次提交的用時(shí)和消耗均不同)

     var isOneBitCharacter = function(bits) {
      return /^(10||11||0)*0$/.test(bits.join(""))
     };
    
  • 對(duì)象存儲(chǔ)
    通過(guò)對(duì)象的方式;在循環(huán)中判斷厉斟,如果遇到0挚躯、10或者11等情況添加到對(duì)象的屬性上,這種方式可以有效的記錄一共出現(xiàn)1比特和2比特出現(xiàn)的次數(shù)和順序擦秽;最后判斷最后一個(gè)比特是1比特還是2比特码荔。
    執(zhí)行用時(shí):88ms;內(nèi)存消耗:37.6MB感挥;

    var isOneBitCharacter = function(bits) {
        let obj = {};
        let count = 1;
        bits.forEach((item, i) => {
          if (!obj[count]) obj[count] = [];
          if (obj[count].length >= 2) {count++; obj[count] = []};
          obj[count].push(item)
          if (obj[count][0] == 0 && i!=bits.length-1) count++;
        })
        return obj[count]&&obj[count][0] === 0 ? true : false
    };
      //對(duì)象結(jié)構(gòu)如下
      {
        1:[0],
        2:[1,1],
        3:[1,0],
        ...
      } 
    
  • 循環(huán)跳躍法
    循環(huán)缩搅,遇1就++,如果++后跳出循環(huán)触幼,就返回false硼瓣,如果還在循環(huán)內(nèi),當(dāng)循環(huán)到最后一個(gè)的時(shí)候返回true置谦;
    執(zhí)行用時(shí):72ms堂鲤;內(nèi)存消耗:34.2MB;

    var isOneBitCharacter = function(bits) {
      let bitsSize = bits.length
      for (let i = 0; i < bitsSize; ++i) {
        if (i == bitsSize - 1) return true
        if (bits[i])++i;
      }
      return false;
    };
    

二進(jìn)制求和

給定兩個(gè)二進(jìn)制字符串媒峡,返回他們的和(用二進(jìn)制表示)瘟栖。
輸入為非空字符串且只包含數(shù)字 1 和 0。

  • 示例 1:
    輸入: a = "11", b = "1"
    輸出: "100"
    
  • 示例 2:
    輸入: a = "1010", b = "1011"
    輸出: "10101"
    
題析:

面對(duì)這道題谅阿,很多人立馬想到的是2轉(zhuǎn)10半哟,然后轉(zhuǎn)2,但是這會(huì)面臨精度丟失的問(wèn)題签餐,如果解決了精度丟失的問(wèn)題寓涨,那么也不失為一個(gè)好的解題方法。那么就只有一種方法那就是逐位相加法氯檐。

題解:
  • 補(bǔ)位法
    字符串轉(zhuǎn)數(shù)組缅茉,然后翻轉(zhuǎn)數(shù)組,取數(shù)組最長(zhǎng)的length循環(huán)男摧,在循環(huán)中數(shù)組短的自動(dòng)補(bǔ)0蔬墩,在循環(huán)中相加,判斷相加為0或1或2的情況耗拓。然后push到新數(shù)組中拇颅,最后翻轉(zhuǎn),轉(zhuǎn)成字符串乔询。
    執(zhí)行用時(shí):108ms樟插;內(nèi)存消耗:35.6MB;(最笨的辦法)
    var addBinary = function(a, b) {
      const alist=a.split('').reverse();
      const blist=b.split('').reverse();
      const arr=[];
      const len=alist.length>blist.length?alist.length:blist.length;
      for (let i = 0; i <= len-1; i++) {
          if (alist[i] != 0 && alist[i] != 1) {
            alist[i] = 0
          }
          if (blist[i] != 0 && blist[i] != 1) {
            blist[i] = 0
          }
          alist[i] = alist[i] - 0
          blist[i] = blist[i] - 0
    
          if (alist[i] + blist[i] > 1) {
            if (arr[i] == 0) {
              arr[i] = 1
            } else if (arr[i] == 1) {
              arr[i] = 1
              arr.push(1)
           } else {
              arr[i] = 0
              arr.push(1)
            }
          }
          if (alist[i] + blist[i] == 1) {
            if (arr[i]) {
              arr[i] = 0
              arr.push(1)
            } else {
              arr[i] = 1
            }
          }
          if (alist[i] + blist[i] == 0) {
            if (arr[i]) {
              arr[i] = 1
            } else {
              arr[i] = 0
            }
          }
        }
        return arr.reverse().join('')
    };
    
  • 進(jìn)位拼接法
    與補(bǔ)位法類(lèi)似竿刁,區(qū)別就是在進(jìn)行計(jì)算時(shí)直接拼接字符串黄锤,會(huì)得到一個(gè)反向字符,需要最后再進(jìn)行翻轉(zhuǎn)食拜;按照位置給結(jié)果字符賦值鸵熟,最后如果有進(jìn)位,則在前方進(jìn)行字符串拼接添加進(jìn)位负甸。
    執(zhí)行用時(shí):112ms流强;內(nèi)存消耗:35.9MB;(性能不好)
    var addBinary = function(a, b) {
      let ans = "";
      let ca = 0;
      for(let i = a.length - 1, j = b.length - 1;i >= 0 || j >= 0; i--, j--) {
          let sum = ca;
          sum += i >= 0 ? parseInt(a[i]) : 0;
          sum += j >= 0 ? parseInt(b[j]) : 0;
          ans += sum % 2;
          ca = Math.floor(sum / 2);
      }
      ans += ca == 1 ? ca : "";
      return ans.split('').reverse().join('');
    }
    

兩數(shù)之和

給定一個(gè)整數(shù)數(shù)組 nums和一個(gè)目標(biāo)值 target呻待,請(qǐng)你在該數(shù)組中找出和為目標(biāo)值的那兩個(gè)整數(shù)打月,并返回他們的數(shù)組下標(biāo)。

你可以假設(shè)每種輸入只會(huì)對(duì)應(yīng)一個(gè)答案蚕捉。但是奏篙,你不能重復(fù)利用這個(gè)數(shù)組中同樣的元素。

  • 示例:
    給定 nums = [2, 7, 11, 15], target = 9
    因?yàn)閚ums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]
    
題解:
  • 雙循環(huán)法
    兩層循環(huán)迫淹,外層取第一元素秘通,內(nèi)層取相加元素;
    執(zhí)行用時(shí):164ms;內(nèi)存消耗:34.6MB千绪;
    var twoSum = function(nums, target) {
     for (let i = 0; i < nums.length; i++) {
      for (let j = i + 1; j < nums.length; j++) {
        if (nums[i] + nums[j] === target) {
          return [i, j]
         }
       }
     }
    };
    
  • 替換法
    復(fù)制原數(shù)組充易,循環(huán)原數(shù)組,防止重復(fù)荸型,通過(guò)splice替換復(fù)制的數(shù)組盹靴,如果復(fù)制數(shù)組中存在相加元素,找到索引瑞妇,即可得到結(jié)果數(shù)組稿静。
    執(zhí)行用時(shí):304ms;內(nèi)存消耗:36MB辕狰;
    var twoSum = function(nums, target) {
      let list = [...nums];
      let arr = []
      nums.forEach((item, i) => {
        list.splice(i, 1, null)
        const sum = target - item;
        if (list.includes(sum)) {
          arr = [i, list.indexOf(sum)].sort()
        }
      })
      return arr
    }
    
  • map
    通過(guò)新的數(shù)據(jù)類(lèi)型Map來(lái)實(shí)現(xiàn)改备;
    執(zhí)行用時(shí):72ms;內(nèi)存消耗:35.1MB蔓倍;
    var twoSum = function(nums, target) {
      let map = new Map()
      for (let i = 0; i < nums.length; i++) {
         if (map.has(target - nums[i])) {
            return [map.get(target - nums[i]), i]
          }
          map.set(nums[i], i)
       }
    }
    

加一

給定一個(gè)由整數(shù)組成的非空數(shù)組所表示的非負(fù)整數(shù)悬钳,在該數(shù)的基礎(chǔ)上加一盐捷。
最高位數(shù)字存放在數(shù)組的首位, 數(shù)組中每個(gè)元素只存儲(chǔ)一個(gè)數(shù)字默勾。
你可以假設(shè)除了整數(shù) 0 之外碉渡,這個(gè)整數(shù)不會(huì)以零開(kāi)頭。

  • 示例 1:
    輸入: [1,2,3]
    輸出: [1,2,4]
    解釋: 輸入數(shù)組表示數(shù)字 123母剥。
    
  • 示例 2:
    輸入: [4,3,2,1]
    輸出: [4,3,2,2]
    解釋: 輸入數(shù)組表示數(shù)字 4321滞诺。
    
題解:
  • 遞減相加法
    循環(huán)遞減,在循環(huán)中判斷相加是否為10环疼,如果為10习霹,就把當(dāng)前值改為0,下一值加一炫隶;
    執(zhí)行用時(shí):72ms淋叶;內(nèi)存消耗:33.6MB;(性能不好)
    var plusOne = function(digits) {
      for(let i=digits.length-1;i>=0;i--){
          if(i==digits.length-1){
              digits[i]++
          }
          if(digits[i]==10){
              digits[i]=0
              if(i-1<0){
                  digits.unshift(1)
              }else{    
                  digits[i-1]++
              }
          }
      }
      return digits
    };
    
  • 迭代
    for循環(huán)可以實(shí)現(xiàn)的等限,while也可以實(shí)現(xiàn)搏屑;
    執(zhí)行用時(shí):72ms代态;內(nèi)存消耗:34.2MB够傍;
    var plusOne = function(digits) {
      const values = digits.reverse();
      let i = 0;
      values[i] += 1;
      while (true) {
        if (values[i] >= 10) {
          values[i] = 0;
          if (values[i + 1] === undefined) {
            values[i + 1] = 1;
            break;
          } else {
            values[i + 1] += 1
          }
          i++
        } else {
          break;
        }
      }
      return values.reverse()
    };
    

第一期結(jié)束男图,下期見(jiàn)。如果有一起學(xué)習(xí)的朋友筹误,可以加微信群桐早。


圖片發(fā)自簡(jiǎn)書(shū)App
鎮(zhèn)樓
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市厨剪,隨后出現(xiàn)的幾起案子哄酝,更是在濱河造成了極大的恐慌,老刑警劉巖祷膳,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陶衅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡直晨,警方通過(guò)查閱死者的電腦和手機(jī)搀军,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)勇皇,“玉大人罩句,你說(shuō)我怎么就攤上這事×舱” “怎么了门烂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我屯远,道長(zhǎng)蔓姚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任慨丐,我火速辦了婚禮赂乐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咖气。我一直安慰自己,他們只是感情好挖滤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布崩溪。 她就那樣靜靜地躺著,像睡著了一般斩松。 火紅的嫁衣襯著肌膚如雪伶唯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天惧盹,我揣著相機(jī)與錄音乳幸,去河邊找鬼。 笑死钧椰,一個(gè)胖子當(dāng)著我的面吹牛粹断,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嫡霞,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓶埋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诊沪?” 一聲冷哼從身側(cè)響起养筒,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎端姚,沒(méi)想到半個(gè)月后晕粪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渐裸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年巫湘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橄仆。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剩膘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盆顾,到底是詐尸還是另有隱情怠褐,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布您宪,位于F島的核電站奈懒,受9級(jí)特大地震影響奠涌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜磷杏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一溜畅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧极祸,春花似錦慈格、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至稿械,卻和暖如春选泻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背美莫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工页眯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厢呵。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓窝撵,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親述吸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忿族,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349