關於JS括號匹配的面試題

之前在面試的過程中經常會遇到匹配括號的問題,比如下面這類題目:

1.編寫一個函數,該函數接收一個算術表達式作爲參數,返回括號缺失的位置。

2.3 + 23 / 12 + (3.14 * 0.24

2.實現一個normalize函數,能將特定的字符串轉化爲特定的結構化數據。

[a[b[c]]]
// 轉化爲
{ value: 'a', children: { value: 'b', children: { value: 'c' } } }

偷偷告訴你,第2題是阿里的面試題(這也太難了吧!)

之前看到這類的題目也是一臉懵逼,沒有半點思路,然後有一天我在《數據結構與算法JavaScript描述》書中瞭解到通過棧可以用來判斷一個表達式中括號是否匹配。

什麼是棧?

棧是一種特殊的列表,棧內的元素只能通過列表的一端訪問,這一端稱爲棧頂。

咖啡廳內的一摞盤子是現實世界中常見的棧的例子。只能從最上面取盤子,盤子洗淨後,也只能摞在這一摞盤子的最上面。棧被稱爲一種後入先出(LIFO,last-in-first-out)的數據結構。

對棧的兩種主要操作是將一個元素壓入棧和將一個元素彈出棧。入棧使用 push() 方法,出棧使用 pop() 方法。圖 演示了入棧和出棧的過程。

其實這些概念挺抽象的,慢慢理解吧。

實戰

好了,我們先來做一個題,判斷迴文:迴文是指這樣一種現象:一個單詞、短語或數字,從前往後寫和從後往前寫都是一樣的。

單詞“dad”、“racecar”就是迴文
數字 1001 也是迴文
function isPalindrome(word) {
  let s = [];
  for (let i = 0; i < word.length; ++i) {
    s.push(word[i]); // 入棧
  }
  let rword = "";
  while (s.length() > 0) {
    rword += s.pop(); // 出棧
  }
  if (word == rword) {
    return true;
  }
  else {
    return false;
  }
}

棧的特點就是先進後出,把字符添加到數組中的時候是正序,而取出來的時候是倒序,正是因爲這種先進後出剛好相反的順序,就可以判斷迴文了。

如果數字123,那麼入棧是1、2、3,出棧是3、2、1,入棧和出棧得到的結果不一樣,那麼他們就不是迴文。

如果字符dad,那麼入棧是d、a、d,出棧是d、a、d,入棧和出棧得到的結果是一樣,那麼他們就是迴文。

現在已經理解的棧的特點了吧。。。

前面有兩道題目,第一題判斷缺少的括號可以這麼寫,參考答案:

function demo (str) {
  let sign = '(){}[]'
  let map = {
    '(': ')',
    '{': '}',
    '[': ']'
  }
  let s = []
  for (let i = 0; i < str.length; i++) {
    if (sign.includes(str[i])) {
      let val = str[i];
      switch (val) {
        case '(':
        case '[':
        case '{': s.push(val); break;
        case ')':
          let map1 = s.pop();
          if (map1 !== '(') {
            return `位置${i}的)不匹配`
          }
          break;
        case ']':
          let map2 = s.pop();
          if (map2 !== '[') {
            return `位置${i}的]不匹配`
          }
          break;
        case '}':
          let map3 = s.pop();
          if (map3 !== '{') {
            return `位置${i}的}不匹配`
          }
          break;
      }
    }
  }
  if (s.length) {
    return `符號${s.join()}沒有閉合`
  } else {
    return '符號正確'
  }
}

我們的括號包括(){}[],然後入棧是左邊部分的括號,出棧是右邊部分的括號,當兩邊的括號有對應關係的時候,說明括號匹配是正確的。

然後下面是第二題[a[b[c]]]轉換爲樹結構的答案:

function normalize (str) {
  let s = [];
  let list = [];
  let obj = {}
  for (let i = 0; i < str.length; i++) {
    let value = str[i]
    switch (value) {
      case '[':
        s.push(i)
        break;
      case ']':
        let leftIndex = s.pop();
        list.unshift([leftIndex, i])
      default:
        break;
    }
  }
  let [start, end] = list[0]
  let parent = obj
  for (let i = 1; i < list.length; i++) {
    let [a, b] = list[i];
    let result = str.slice(start + 1, a) + str.slice(b + 1, end);
    start = a;
    end = b;
    parent.value = result;
    parent.children = {};
    parent = parent.children;
  }
  let [x, y] = list[list.length - 1]
  parent.value = str.slice(x + 1, y)
  return obj
}

先匹配了括號在字符串中的位置保存在數組list[ [ 0, 8 ], [ 2, 7 ], [ 4, 6 ] ],然後通過區間的範圍可以知道左右兩邊的內容(0到2和7到8是第一個括號裏面的內容,依次類推,注意最後的內容是4到6這個是閉合的關係),然後通過字符串截取的方式可以得到。最後通過對象之前的引用關係轉換爲樹狀結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章