TypeScript 練習題:30 天 LeetCode 挑戰(第 22 天至第 30 天)

TypeScript 練習題:30 天 LeetCode 挑戰(第 22 天至第 30 天)

LeetCode 挑戰題目總覽:30 Days of LC JavaScript Challenge(從 5 月 5 日起,台灣時間每天早上八點釋出新題目)

第 22 天:Flatten Deeply Nested Array

題目說明

給定一個多維陣列 arr 和深度 n,回傳該陣列的扁平化版本。多維陣列是一個遞迴資料結構,裡面包含整數或其他多維陣列。扁平化陣列是該陣列的版本,其中某些或全部的子陣列被移除,並用該子陣列中的實際元素取代,只有當目前的嵌套深度小於 n 時,才能執行扁平化操作,第一個陣列中元素的深度被認為是 0,在不使用內建的 Array.flat 方法的情況下解決這個問題。

解題方法

先拆解成基本情況

  1. n 為 0 時,直接返回。

  2. 會遇到的值有可能是整數或是陣列,只有值為陣列時才需要決定是否要處理。

  3. 當值為陣列時用遞迴扁平化。

解題程式碼

本來用 Array.concat() 來組陣列,但發現 Test Case 4 會 Timeout,問 ChatGPT 才知道由於 Array.concat() 會不停建立新的 Array,會增加時間複雜度。

type MultiDimensionalArray = (number | MultiDimensionalArray)[];

const flat = function (
  arr: MultiDimensionalArray,
  n: number
): MultiDimensionalArray {
  if (n === 0) return arr;
  return arr.reduce<MultiDimensionalArray>(
    (acc, cur) => acc.concat(Array.isArray(cur) ? flat(cur, n - 1) : cur),
    []
  );
};
type MultiDimensionalArray = (number | MultiDimensionalArray)[];

const flat = function (
  arr: MultiDimensionalArray,
  n: number
): MultiDimensionalArray {
  if (n === 0) return arr;

  return arr.reduce<MultiDimensionalArray>((acc, cur) => {
    Array.isArray(cur) ? acc.push(...flat(cur, n - 1)) : acc.push(cur);
    return acc;
  }, []);
};

官方解題說明

https://leetcode.com/problems/flatten-deeply-nested-array/editorial/

使用情境

  • 數據處理(Data Processing):當使用嵌套格式的資料(例如 JSON 或 XML )時,平坦化結構可以簡化資料處理任務。例如,如果從 API 獲得了嵌套的 JSON 回應,並且只需要某些字段,則平坦化 JSON 可以使提取和分析所需資料變得更容易。

      const people = [
        { name: "Mike", items: ["hammer", "axe"] },
        { name: "Steve", items: ["rock", "stick"] },
      ];
    
      const allItems = people.map((d) => d.items).flat();
    
  • 樹狀遍歷(Tree Traversal):在計算機科學中,樹常用於表示層次結構。遍歷樹狀結構時,可以使用平坦化將樹轉換為線性表示,以便更容易導航和操作資料。

  • 遞歸演算法(Recursive Algorithms):許多演算法涉及資料結構的遞歸操作。對嵌套陣列進行平坦化可以在此情況下有益,例如,在實現深度優先搜索或遞歸回溯算法時,平坦化可以通過提供資料的線性視圖來簡化過程。

  • 資料庫查詢(Database Queries):在資料庫系統中,可以將嵌套結構儲存為陣列或 JSON 對象。執行查詢時,平坦化嵌套陣列可以用於檢索特定元素或跨不同結構級別進行聚合。

官方解法 1:遞迴方法

時間複雜度在最壞的情況下,每個 arr 中的元素都是一個陣列,且達到最大深度 n,遞迴函式將為每個巢狀陣列在每個層級上進行呼叫,總共 O(k*n) 次遞迴呼叫,其中 k 表示每個層級上的平均巢狀陣列數量,n 是最大深度層級。

空間複雜度取決於深度層級 n,每次遞迴呼叫會在呼叫堆疊上消耗額外的空間,因此為 O(n)

type MultiDimensionalArray = (number | MultiDimensionalArray)[];

const flat = function (arr: MultiDimensionalArray, n: number): MultiDimensionalArray {
    let res: MultiDimensionalArray = [];
    // 建立遞迴函式 flattening 接受兩個參數:一個陣列 nums 和一個表示當前深度層級的 l
    const flattening = (nums: MultiDimensionalArray, l: number) => {
        // 使用 for...of 迴圈遍歷 nums 陣列中的元素
        for (const num of nums) {
            // 檢查它是否為陣列,並且當前層級 l 是否在指定範圍內
            if (Array.isArray(num) && l > 0 && l <= n) {
                // 以遞迴的方式調用 flattening 函式,並將巢狀陣列作為參數,同時將層級減 1
                flattening(num as MultiDimensionalArray, l - 1);
            } else {
                // 如果元素不是陣列或層級條件未滿足,則將該元素推入結果陣列 res
                res.push(num);
            }
        }
    };

    flattening(arr, n);
    return res;
};

官方解法 2:使用迭代佇列(Iterative Queue)

type MultiDimensionalArray = (number | MultiDimensionalArray)[];

const flat = function (arr: MultiDimensionalArray, n: number): MultiDimensionalArray {
    // 是否還有待攤平的巢狀陣列
    let nestedArrayElement = true;
    // 儲存在攤平過程中的元素
    let queue: MultiDimensionalArray;
    // 目前的深度層級
    let depth = 0;

    // 只要還有單一陣列元素要處理(nestedArrayElement 為 true)且當前深度小於 n,就會繼續執行
    while (nestedArrayElement && depth < n) {
        // 每次迴圈的開始,先將 nestedArrayElement 重設為 false,表示尚未遇到內嵌陣列
        nestedArrayElement = false;
        // 儲存目前迴圈的元素
        queue = [];

        // 遍歷 arr 的每個元素
        for (let i = 0; i < arr.length; i++) {
            // 如果元素是陣列
            if (Array.isArray(arr[i])) {
                // 將其元素展開並放入佇列
                queue.push(...arr[i] as MultiDimensionalArray);
                // 將 nestedArrayElement 設置為 true,表示遇到了巢狀陣列
                nestedArrayElement = true;
            } else {
                // 元素不是陣列,則直接將其推入佇列
                queue.push(arr[i]);
            }
        }
        // 在處理完 arr 的所有元素後,將 arr 更新為佇列中的元素
        arr = [...queue];
        depth++;
    }

    return arr;
};

官方解法 3:使用迭代堆疊(Iterative Stack)

type MultiDimensionalArray = (number | MultiDimensionalArray)[];

const flat = function (arr: MultiDimensionalArray, n: number): MultiDimensionalArray {
    // 初始化一個堆疊 stack,將 arr 的元素與對應的深度層級一起放入堆疊
    // 每個項目表示為一對 [item, depth]
    const stack: [MultiDimensionalArray, number][] = arr.map((item) => [item, n] as [MultiDimensionalArray, number]);
    // 初始化一個空陣列 res,用於儲存攤平後的結果
    const res: MultiDimensionalArray = [];

    // 只要堆疊中還有元素就進入 while 迴圈
    while (stack.length > 0) {
        // 使用 pop() 方法從堆疊中彈出頂部項目 [item, depth]
        const [item, depth] = stack.pop()!;
        // 如果 item 是一個陣列且當前深度 depth 大於 0 代表該元素是一個包含需要進一步攤平的項目的容器
        if (Array.isArray(item) && depth > 0) {
            // 將陣列 item 的每個元素映射為一對 [el, depth - 1]
            // 表示元素以及降低的深度層級(depth - 1)
            stack.push(...item.map((el) => [el, depth - 1] as [MultiDimensionalArray, number]));
        } else {
            // 如果 item 不是陣列或深度為 0,可以直接添加到 res 陣列中
            res.push(item);
        }
    }
    // 將包含攤平元素的 res 陣列返回,為了保持原始順序,使用 reverse() 進行反轉
    return res.reverse();
};

第 23 天:Array Prototype Last(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/array-prototype-last/editorial/

第 24 天:Group By(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/group-by/editorial/

第 25 天:Check if Object Instance of Class(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/check-if-object-instance-of-class/editorial/

第 26 天:Call Function with Custom Context(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/call-function-with-custom-context/editorial/

第 27 天:Event Emitter(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/event-emitter/editorial/

第 28 天:Array Wrapper(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/array-wrapper/editorial/

第 29 天:Generate Fibonacci Sequence(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/generate-fibonacci-sequence/editorial/?gio_link_id=xo040MEo

第 30 天:Nested Array Generator(待補寫)

題目說明

解題方法

解題程式碼

官方解題說明

https://leetcode.com/problems/nested-array-generator/editorial/