Leetcode第136場比賽回顧
零、背景
這次比賽,涉及四種題型:簡單計算、貪心、動態規劃、字尾樹或二分查詢。
上篇文章《 Leetcode第95場比賽回顧 》提到,我這次比賽嘗試在頁面上寫程式碼,結果被坑了。
前兩道題在頁面上寫了半個小時,各種不順,最後趕緊切換到本地,幾分鐘就過了。
到最後一題的時候,我的解題思路是對的,但是題目有問題看錯題了,最終沒過。
下面來看看這四道題吧。
PS:上篇文章還提到,做的演算法題目前沒有很好的分類關係,可以使用自己的部落格或者知識星球的標籤來管理。
最終決定使用知識星球來管理,這個是一個免費的知識星球,感興趣的同學可以加入。
一、困於環中的機器人
題意:一個機器人在原點 (0,0)
,預設方向朝北,按下面三個指令行動。
-
G
朝當前方向前進一步 -
L
左轉90
度 -
R
右轉90
度
機器人然後按順序執行一串指令,並且可以重複執行下去。
問機器人是否會在一個固定路線轉圈?
思路:既然機器人是重複執行這串指令,若在固定路線轉圈,則肯定是重複若干次後,回到了原點。
否則路線肯定不能固定。
接下來看什麼時候可以回到原點。
如果第一次執行完一串指令後,就在原點,則可以保證是固定路線。
如果第一次執行完執行後,不在原點,假設此時新的方向是 dir
。
如果 dir
不是北方,則一定可以回到原點。
證明如下:
如果 dir
指向南方,則下一次執行完,機器人就回到原點(180度映象原理)。
如果 dir
指向東方或北方,則第四次執行完,機器人就回到原點(90度映象原理)。
所以,為了簡單起見,只需要讓機器人重複執行四次指令串,然後判斷是否在原點即可。
當然,也可以直接判斷方向是不是北方。
二、不鄰接植花
題意:有 N 個花園,按從 1 到 N 標記。在每個花園中,你打算種下四種花之一。
paths[i] = [x, y] 描述了花園 x 到花園 y 的雙向路徑。
你需要為每個花園選擇一種花,使得通過路徑相連的任何兩個花園中的花的種類互不相同。 四種花的編號分別是 1,2,3,4
。
思路:考慮到這道題難度是 easy
,那果斷進行貪心了。
貪心:從左到右依次判斷當前花園可以染什麼色,隨機選一個即可。
判斷標準:只要和前面染色的花園不衝突即可。
就這樣,我就過了這道題。
疑問:怎麼證明貪心一定正確呢?
我們的目標不是把這道題通過,而是要理解這道題為什麼可以這樣做。
有 4
種顏色,每個花園的度數最多為 3
。
假設某個花園周圍都已經染色了,會不會當前花園沒法選顏色呢?
什麼時候沒法選?周圍把所有顏色都用完了。
那周圍用了多少個顏色?最多 3
個。
也就是永遠也用不完,即永遠可以找個一個顏色來染色。
好無聊是不是?
但就是這樣一個邏輯推理,很多人理解不了。
甚至有大牛這道題沒做出來。
三、分隔陣列以得到最大和
題意:給出整數陣列 A,將該陣列分隔為長度最多為 K 的幾個(連續)子陣列。
分隔完成後,每個子陣列的中的值都會變為該子陣列中的最大值。
返回給定陣列完成分隔後的最大和。
思路:最最基礎的動態規劃題。
定義 f(n)
為前 n
個數字可以得到的最大和。
則對於最後一個數字可以劃分為兩部分:
-
[n-k+1, n]
劃分為一個整體,結果為max(n-k+1, n) * k
-
[1, n-k]
遞迴去計算,即f(n-k)
這種劃分,共有 K
中情況,我們要取結果最大的那個。
複雜度: O(n*K)
思考題:這道題能繼續優化嗎?比如利用單調性,把複雜度優化到 O(n)
嗎?
四、最長重複子串
題意:給出一個字串 S,求重複子串的最大長度。
注:重複子串允許兩個串有部分重疊。
PS:原題的描述有很大的問題,很容易錯誤的理解為兩個重複子串必須連續。
賽後看了其他人的程式碼,才知道是任意子串。
思路:這道題顯然是字尾陣列的模板題,可是我不會後綴陣列。
看到是求最大值,於是我就往二分的方向思考,發現二分確實可以做這道題。
對最大長度k 進行二分 log(n)
,然後判斷這個長度 k 是否有答案 O(n)
。
對於判斷是否存在長度 k 的重複子串,最笨的方法需要 O(n^2*k)
的複雜度。
使用 set
把子串存起來,後面只需要在 set
裡判斷子串是否出現過,此時需要 O(n*k*log(n))
的複雜度。
而使用 hash
與滑動視窗的方法,則可以把 k
優化掉,從而變成 O(n*log(n))
的複雜度。
綜合複雜度就是 O(n*log(n)^2)
。
這裡的 hash
需要滿足滑動視窗的性質,可以快速從左邊出一個字元,右邊快速進入一個字元,更新hash只需要 O(1)
的複雜度。
這個方法的一種實現是把字串當做 26
進位制的數字(假設都是小寫字母),然後計算出這個字串對應十進位制數字的值。
由於數字可能很大,這裡想固定的數字取模。
由於在加減乘三個運算裡先取模與後取模不影響結果,所以最終 hash
出的數字也相等。
PS:對於字尾陣列,如果有機會,後面我會進行專題講解(目前專題講解到二分查找了)。
思考題:你能構造出一個 case
,使得 hash
衝突的嗎? 即對於不同的兩個字串 S1
和 S2
,按照上面的 hash
運算後,得出的數字一樣。
五、最後
這次比賽最後一題有點坑,前兩天雖說簡單,但是不簡單邏輯推理一番,也不容易得到結論。
PS:以後我還是在自己的 IDE 上寫程式碼吧。 如果你不在瀏覽器上寫程式碼的話,可以考慮用我的模板。
地址:https://github.com/tiankonguse/leetcode-solutions/tree/master/include
-EOF-