寶寶也能看懂的 leetcode 周賽 - 169 - 2

1305. All Elements in Two Binary Search Trees

Hi 你們好,我是張小豬。歡迎來到『寶寶也能看懂』系列之 leetcode 題解。node

這裏是第 169 期的第 2 題,也是題目列表中的第 1305 題 -- 『All Elements in Two Binary Search Trees』git

題目描述

Given two binary search trees root1 and root2.github

Return a list containing all the integers from both trees sorted in ascending order.shell

Example 1:數組

example 1

Input: root1 = [2,1,4], root2 = [1,0,3]
Output: [0,1,1,2,3,4]

Example 2:數據結構

Input: root1 = [0,-10,10], root2 = [5,1,7,0,2]
Output: [-10,0,0,1,2,5,7,10]

Example 3:post

Input: root1 = [], root2 = [5,1,7,0,2]
Output: [0,1,2,5,7]

Example 4:優化

Input: root1 = [0,-10,10], root2 = []
Output: [-10,0,10]

Example 5:spa

example 5

Input: root1 = [1,null,8], root2 = [8,1]
Output: [1,1,8,8]

Constraints:code

  • Each tree has at most 5000 nodes.
  • Each node's value is between [-10^5, 10^5].

官方難度

MEDIUM

解決思路

題目內容很短,有兩個二叉搜索樹,須要把它們裏面的全部值放進一個數組中,而且結果是要保持順序遞增的。

讀完以後第一反應,這題還真是直白呀,沒包裝個什麼描述性的說法,搞的我都很差寫文章了,哼 >.<

關於什麼是二叉搜索樹,這個你們能夠自行搜索,固然我以後也會寫文章介紹常見的數據結構,一不當心給本身開了個新坑。

對於這道題目的要求,咱們能夠遍歷這兩個二叉搜索樹,獲得全部的值放進新數組中,而後再進行排序。固然,既然是很是科班的題目,天然有很套路的應對方式。畢竟一涉及到基於比較的排序,那複雜度就直接上 O(nlogn) 了。

直接方案

咱們想要獲得符合遞增順序的二叉搜索樹內的全部值,直接進行中序遍歷便可,須要的時間複雜度是 O(n)。關於什麼是中序遍歷,一樣我會在新坑裏面提到。這裏先不作過多展開。

而後對於兩個有序數組進行合併,咱們能夠這樣作:

  1. 取得兩個數組中各自的最小值,即第一個值
  2. 把它們進行比較,獲得的小值必定是當前全部剩餘的未合併元素中的最小值
  3. 把這個小值從數組開頭剔除掉,放進最終的結果的末端
  4. 重複回到步驟 1,直到有一個數組空了
  5. 把剩下的那個數組中的值直接添加進結果的末端

這樣咱們只須要 O(n) 的時間複雜度便可完成合並了。

固然在實際代碼中,咱們還能夠作一些優化,例如並不把數組開頭的值剔除掉,而是使用一個索引標識當前訪問的位置。由於對於數組這樣的線性表,咱們剃掉第一值也就意味着後續全部值的前移,代價仍是很大的。

const getAllElements = (root1, root2) => {
  const arr1 = [];
  const arr2 = [];
  traversal(root1, arr1);
  traversal(root2, arr2);
  const ret = [];
  let idx1 = idx2 = 0;
  while (idx1 < arr1.length && idx2 < arr2.length) {
    arr1[idx1] < arr2[idx2] ? ret.push(arr1[idx1++]) : ret.push(arr2[idx2++]);
  }
  while (idx1 < arr1.length) ret.push(arr1[idx1++]);
  while (idx2 < arr2.length) ret.push(arr2[idx2++]);
  return ret;

  function traversal(node, arr) {
    if (!node) return;
    traversal(node.left, arr);
    arr.push(node.val);
    traversal(node.right, arr);
  }
};

上面的代碼跑到了 208ms,暫時 beats 100%。不過我跑完以後回頭一看,不得不說,寫的真醜。要是 code review 看到這樣的代碼,我確定是不會合並的。那咱們把它改的稍微好看一點吧。

const traversal = (node, arr = []) => {
  if (node) {
    traversal(node.left, arr);
    arr.push(node.val);
    traversal(node.right, arr);
  }
  return arr;
};
const merge = (arr1, arr2) => {
  const ret = [];
  let idx1 = idx2 = 0;
  while (idx1 < arr1.length && idx2 < arr2.length) {
    arr1[idx1] < arr2[idx2] ? ret.push(arr1[idx1++]) : ret.push(arr2[idx2++]);
  }
  while (idx1 < arr1.length) ret.push(arr1[idx1++]);
  while (idx2 < arr2.length) ret.push(arr2[idx2++]);
  return ret;
};
const getAllElements = (root1, root2) => merge(traversal(root1), traversal(root2));

總結

這是一道比較套路的題,須要一點點科班知識,即二叉搜索樹和中序遍歷。相信你們應該很容易就能掌握這種套路了吧。

那麼最後加一個小思考,上面代碼中的 merge 方法是否能夠改成支持不定數量的數組合並呢,即 const merge = (...list) => {}。但願小夥伴們能幫幫張小豬,麼麼嗒 >.<

相關連接

相關文章
相關標籤/搜索