刷題筆記 — Array (4)

黃翌軒
CityChaser
Published in
8 min readFeb 19, 2021

本系列文章是分享我在 Leetcode 及 Algoexpert 的刷題經驗,這篇文章是 Array 篇的第四篇文章。

本系列文章都假定讀者具有基礎的 complexity analysis 概念以及基礎的 Java 能力。為了不讓閱讀時間過長,每篇都只會講解 3 道題目。

每道題目我都會分為 Description(問題描述)、Examples(測資範例)、Solution(解法)、Implementation(實作) 等區塊來進行講解。但如果礙於篇幅問題或是該解法比較不理想(太複雜、效率太差)我可能就只會進行概念上的講解,並不會實際寫出 code implementation。

另外,為了讓讀者能更佳地了解,當我提及程式碼的變數時,我會將該字反白(如 variable )。

👉 上一篇:刷題筆記 — Array (3)

如欲觀看所有系列文章,可點下面連結前往。

https://medium.com/citychaser/coding-questions/home

好了,廢話不多說,讓我們開始吧!

1. Two-Sum

Description

給定一個 non-empty array of integers array 以及一個 integer target ,從 array 當中找出一組兩個數字,使得這兩個數字相加會等於 target

如果有該組數字的話,將兩個 integer 以一個 array 回傳;如果找不到,則回傳一個空的 array。

array 中至多只會有一組數字相加等於 target ,同一個數字不能使用兩次,所謂的同一個數字並非指數值相同,而是在 array 中同個位置的數字只能使用一次。

Examples

Input:
array = [3, 5, -4, 8, 11, 1, -1, 6]
value = 10
Output: [11, -1] (順序相反也可)
------------------------------------
Input:
array = [4, 6, 1, -3]
value = 3
Output: []

Solution 1 — Brute Force

第一個解法就是用暴力解,我們要找兩個數字相加會等於 target,那就找出所有組合。第一層 for-loop 迭代每個整數,第二層再迭代該整數往右的所有整數,這樣就會得到所有組合。

兩兩一組,總共會有 N(N-1)/2 這麼多組。接著,一組一組去檢查兩數相加是否等於 target,這樣一來,總 time complexity 會是 O(N²)

Solution 2 — Binary Search

如果今天把 array 進行 sorting ,那麼在每個整數要去找另一個整數時,就不需要將剩下的所有整數都找一遍,我們可以用 binary search 去找,這樣就只需要 O(logN)

array = […, 3, 10, -1, 6, 17, ….]
target = 10
array = […, 3, 5, 6, 10, 12, …]

可以看到,假設現在第一層輪到 3 這個整數,如果 array 沒有進行過 sorting,那就必須要往後找每一個數字 (10 -> -1 -> 6 -> 17…),因為我們不曉得哪一個才會剛好等於 target - 3。但是如果 array 是 sorted,那就不用一個一個找,只要從 array 的中間開始找,太大就往左邊找、太小就往右邊,每次都可以砍掉一半,最多只需要找 logN+1 次。

迭代每個整數會需要 N 個 operation,而每個整數又會花 logN 個 operation 去進行 binary search,所以找到相加等於 target 的兩個數字的 time complexity 為 O(NlogN)

但是別忘了,我們還要再加上 sorting 本身消耗的時間,大部分程式語言內建的 sorting method 基於 merge sort, quick sort, heap sort 這些方法,它們的 time complexity 大多都接近 O(NlogN)

所以 total time complexity 會是 O(2NlogN),但是係數會被去掉,因此是 O(NlogN)

Solution 3 — Two Pointer

跟 solution 2 一樣,我們要先將 array 進行 sorting,但是這次我們不使用 binary search,而是在 array 的頭跟尾放上兩個 pointer ( head , tail)。

查看 head , tail 指到的整數相加是否等於 target,如果等於就回傳這兩個整數。如果小於 target,那就把 head 往左移,因為 array 是 sorted,所以越往右會是越大的整數;反之,如果大於 target,則把 tail 往左移,如此重複直到兩者重疊為止。

相比於 binary search 的 O(NlogN),two pointer 只需 O(N) 即可完成,雖然說因為 sorting 就已經花掉 O(NlogN),所以從總體來看兩者的 time complexity 是一樣的,但是當 input data 沒有很大的時候,兩者就會有差別。

Solution 4 — Hash / Set

這個方法是以「空間」換取「時間」,我們把出現在 array 裡的整數丟進去 Set 中。在迭代的過程中,我們只需要去找 target 跟現在迭代到的整數的「差」是不是在已經存在於 Set 中,如果存在的話,則回傳這兩個數字;如果不存在,則把現在迭代到的整數加進去 Set。

2. Validate Subsequence

Description

給定兩個 non-empty array of integers array, sequence,撰寫一個 function 判斷 sequence 是不是 array 的 subsequence。

所謂 subsequence 是指 subsequence array 中整數排列的順序與 main array 一致,但是並不需要完全相鄰。

舉例來說,array = [1, 2, 3, 4][1, 3, 4] 是一個 valid subsequence,[2, 4][1][1, 2, 3, 4] 也都是,但是 [1, 3, 2] 不是。

Examples

Input:
array = [5, 1, 22, 25, 6, -1, 8, 10]
sequence = [1, 6, -1, 10]
Output: true

Solution — Two Pointer

是的,又要來用我們用到爛的 two pointer 了 😂

使用兩個 pointer 分別指向 arraysequence 的開頭。如果當下兩個指到的整數相同,則將兩者都往右移;如果不一樣,那就只移動 array 的 pointer,直到 array 或是 sequence 所有的元素都迭代完為止。

最後只要看 sequence 的 pointer 是不是指到最後一個元素,就可以知道 sequence 的每個整數是不是按照此順序都出現在了 array 裡。

因為只有將 arraysequence 迭代一次,所以 time complexity 為 O(N)

3. Spiral Traverse

Description

給定一個 nxm 的二維陣列,回傳一個一維陣列,陣列裡的元素必須照螺旋的順序排列。

所謂螺旋是指從陣列的左上角開始往右移動,到最右邊後開始往下,到最下面再往左,到最左邊後往上。

Spiral Traverse 示意圖

Examples

Input: [
[1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7]
]
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

Solution 1 — Change Directions

使用一個變數紀錄方向,最一開始是往右,接著碰到邊緣後變成往下,再碰到邊緣就往左,再碰到邊緣往上,以此類推。但是這個做法稍嫌複雜,我們就不介紹這個方法。

Solution 2 — Divide and Conquer

另一個作法是,我們把這個矩陣想像成一個洋蔥,洋蔥的皮都是一層一層的,我們每次先專注在最外面那層,從最左上依照順時鐘順序走,走完了之後,我們就把這層給剝掉,然後從下一層的起點開始繼續。

用上面 example 的矩陣來舉例,第一層就會是 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12

原本是 4x3 的矩陣,現在我們迭代完了最外面的這一層,所以只剩下裡面 2x1 的矩陣了,然後我們再對這個 2x1 的矩陣做一樣的操作,2x1 的走完了以後,發現只剩 0x0,也就走完了。

我們必須要知道現在剝掉的這一層的界線在哪,所以我們必須要有變數來紀錄邊界,總共會需要四個邊界來紀錄(上、下、左、右)。

以下就來看要怎麼實作。

因為要 traverse 將 array 裡的所有元素,所以不管是使用哪個 solution,time complexity 都是 O(NM)

今天的刷題分享就到這邊了,如果有什麼指教或是建議,歡迎在這篇文章底下留言;如果覺得這篇文章不錯,也歡迎給我點掌聲!

--

--