【動圖演示】頭條和滴滴的一道面試題:smartRepeat 函數

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。git

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。github

在講解這道題以前咱們先來看下一個數據結構:,由於咱們須要用棧來解決這道題。面試

棧(stack)又名堆棧,它是一種運算受限的線性表,僅在表尾能進行插入和刪除操做。這一端被稱爲棧頂,相對地,把另外一端稱爲棧底。數組

向一個棧插入新元素又稱做進棧、入棧或壓棧;從一個棧刪除元素又稱做出棧或退棧。微信

後進先出(LIFO)特色:棧中的元素,最早進棧的一定是最後出棧,後進棧的必定會先出棧。數據結構

JavaScript中,棧能夠用數組模擬。須要限制只能使用push()pop(),不能使用unshift()shift()。即,數組尾是棧頂。函數

固然,能夠用面向對象等手段,將棧封裝的更好。工具

image.png

面試題

這是頭條和滴滴的一道面試題,題目是這樣的:spa

試編寫「智能重複」smartRepeat函數,實現:debug

  • 將 3[abc] 變爲abcabcabc
  • 將 3[2[a]2[b]] 變爲 aabbaabbaabb
  • 將 2[1[a]3[b]2[3[c]4[d]]] 變爲abbbcccddddcccddddabbbcccddddcccdddd

不用考慮輸入字符串是非法的狀況,好比:

  • 2[a3[b]]是錯誤的,應該補一個1,即2[1[a]3[b]]
  • [abc]是錯誤的,應該補一個1,即1[abc]

你們一看到這題目,應該想到的用遞歸的方式來作,實際上這道題用遞歸是比較難的。也是能作,但相比棧,棧的方式會簡單的多。

初學者大坑:棧的題目和遞歸很是像,這類題目給人的感受都是用遞歸解題。信心滿滿動手開始寫了,卻發現遞歸怎麼都遞歸不出來。此時就要想到,不是用遞歸,而是用棧。

這道題目咱們可使用兩個棧來解,第一個棧存放數字,第二個棧存放字符串

image.png

這時候能夠發現咱們指針只須要遍歷一次就好了,怎麼看?

規則是這樣的子:遍歷到數字就把數字壓棧

image.png

而後繼續遍歷,這時遍歷到方括號,或者說是遍歷到數字和方括號,那麼咱們就把另外一個棧放入一個空字符串 ''

image.png

而後下移,遇到 3,一樣也是壓棧:

image.png

而後下移,遇到方括號了,壓入一個空字符串 ''

image.png

而後下移,遇到字母 a,那麼遇到字母是什麼規則呢,如圖中所示:

image.png

而後下移,遇到 ],注意,遍歷到結束的右大括號的時候,是一個很是重要的時間,那這個規則又是啥呢,以下圖所示:

image.png

是否是有點看不懂了,那麼咱們重頭在跑一次

而後下移遇到 4[,分別把數字 4 和 空字符串壓入:

image.png

而後下移遇到 1[,分別把數字 1 和 空字符串壓入:

image.png

而後下移遇到 b,壓入:

image.png

而後下移,遇到結束符 ],分別要 1 和 'b' 彈出來,此時在把 'b' 重複一遍後拼接到第二個棧頂元素

image.png

而後下移,遇到 2,一樣的操做:

image.png

而後下移遇到 c,直接寫入:

image.png

而後下移,遇到結束符 ],分別把 2 和 'c',彈出,此時在把 'c' 重複二遍後拼接到第二個棧頂元素

image.png

而後下移,遇到倒數第二個結束符 ],分別把 4 和 'bccc',彈出,此時在把 'bccc' 重複四四遍後拼接到第二個棧頂元素

image.png

而後下移,遇到最後一個結束符 ],分別把 2 和 'aaabccbccbccbcc',彈出,此時在把 'aaabccbccbccbcc' 重複兩遍,這時個就不用拼到上一個元素了,由於已是最後一個了:

image.png

這個答案是否是就是咱們最後的答案了,神奇吧~

這時個咱們在按上面的流程來演示一上這題:

2[1[a]3[b]2[3[c]4[d]]] 變爲abbbcccddddcccddddabbbcccddddcccdddd

代碼實現

建立 index.js,輸入如下內容:

// 試編寫「智能重複」smartRepeat函數,實現:
// 將3[abc]變爲abcabcabc
// 將3[2[a]2[b]]變爲aabbaabbaabb
// 將2[1[a]3[b]2[3[c]4[d]]]變爲abbbcccddddcccddddabbbcccddddcccdddd

function smartRepeat(templateStr) {
  // 指針
  var index = 0;
  // 棧1,存放數字
  var stack1 = [];
  // 棧2,存放臨時字符串
  var stack2 = [];
  // 剩餘部分
  var rest = templateStr;

  while (index < templateStr.length - 1) {
    // 剩餘部分
    rest = templateStr.substring(index);

    // 看當前剩餘部分是否是以數字和[開頭
    if (/^\d+\[/.test(rest)) {
      // 獲得這個數字
      let times = Number(rest.match(/^(\d+)\[/)[1]);
      // 就把數字壓棧,把空字符串壓棧
      stack1.push(times);
      stack2.push("");
      // 讓指針後移,times這個數字是多少位就後移多少位加1位。
      // 爲何要加1呢?加的1位是[。
      index += times.toString().length + 1;
    } else if (/^\w+\]/.test(rest)) {
      // 若是這個字符是字母,那麼此時就把棧頂這項改成這個字母
      let word = rest.match(/^(\w+)\]/)[1];
      stack2[stack2.length - 1] = word;
      // 讓指針後移,word這個詞語是多少位就後移多少位
      index += word.length;
    } else if (rest[0] == "]") {
      // 若是這個字符是],那麼就①將stack1彈棧,②stack2彈棧,③把字符串棧的新棧頂的元素重複剛剛彈出的那個字符串指定次數拼接到新棧頂上。
      let times = stack1.pop();
      let word = stack2.pop();
      // repeat是ES6的方法,好比'a'.repeat(3)獲得'aaa'
      stack2[stack2.length - 1] += word.repeat(times);
      index++;
    }

    console.log(index, stack1, stack2);
  }

  // while結束以後,stack1和stack2中確定還剩餘1項。返回棧2中剩下的這一項,重複棧1中剩下的這1項次數,組成的這個字符串。若是剩的個數不對,那就是用戶的問題,方括號沒有閉合。
  return stack2[0].repeat(stack1[0]);
}

var result = smartRepeat("3[2[3[a]1[b]]4[d]]");
console.log(result);

~完,我是小智,刷牛客網去了,咱們下期見~

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。

相關文章
相關標籤/搜索