LeetCode Weekly Contest 96 解題報告

caibirdme發表於2018-08-08

Contest 96

三維形體投影面積

題目連結

題目描述

每個物體長寬高都是 1,告訴三維座標系裡每個座標點 i (x,y) 上有 Ti 個物體堆疊,求所有物體在每個面的投影面積。(原題是求總投影面積,實際上求出每個面的投影面積,三個加起來就行了)

題解

  • 最簡單的,在 xy 平面裡的投影面積,其實就是有多少個座標上有物體
  • 在 xz 平面上的投影:看看兩個點 (x1,y1,z1), (x1,y2,z1),這兩個點在 xz 平面上的投影面積是什麼? 因為在 xz 平面上,所以從 y 軸來看,對於同樣的 x,不論 y 怎麼變,只能看到最高的那個。也就是說,當 x=x1 時,求出所有 (x1, yi) 的最大值 k1,投影就是 k1。列舉所有 x,求出所有 kx 即可。
  • yz 軸同理

很簡單的題目,詳見AC 程式碼

救生艇

題目連結

題目描述

有 N 個人,每個人體重是 people[i]。已知救生艇最大載重為 limit,且每艘救生艇不論如何最多載兩人。問需要多少救生艇。

題解

這道題是個貪心,先把體重按從小到大排序。兩個指標 left,right,分別指向剩下的人中最輕和最重的。每個人都要上一艘救生艇,因此 people[left] 先選一艘。left 選了一艘之後,這艘救生艇還可以載一個人,那肯定在能力範圍內載一個越重的人越好,因此就是 right 了。如果 people[left]+people[right]>limit,那 right 那位兄臺只能自己做一艘船了(因為當前最輕的人和他一起坐都超重了)。

詳見AC 程式碼

索引處的解碼字串

原題連結

題目描述

對於一個字串a2b2c2d2和一個空串 S,每當遇到字元 c,就往 S 後面追加一個 c。如果遇到一個數字 t,就把 S repeat t 次。 對於a2b2c2d2,S 最後就成了:aabaabcaabaabcdaabaabcaabaabcd。 給定這個字串,問最後 S 第 k 個字元是什麼

題解

暴力的做法就是模擬 S 串的生成過程,然後輸出第 K 位。但是這個不論是時間複雜度還是空間複雜度都太高。我們一起來想一想,純模擬的方法到底哪些步驟浪費了時間或空間。首先我們可以把整個過程劃分成兩個狀態:

  • append
  • repeat

append 狀態是說,最近一次 S 串的 repeat 操作完成了,現在讀到了字元,直接 append 到 S 後面。repeat 狀態是說,讀到了一個數字,現在把串 S repeat N 次。串 S 要麼處在 append 狀態要麼處在 repeat 狀態。

那麼如果已知串 S,repeat N 次,這時候我們真的需要開闢一個 N*len(S) 的空間來存新的串嗎?是不是隻需要存成 (S,N) 這樣的 tuple 就好了?由於串是以 len(S) 的長度迴圈的,因此求第 K 位,等價於求第 K%len(S) 位。

想清楚了這個,我們就接著繼續思考。要求整個串的第 K 位,實際上當 S 擴充套件到長度 K 時,它要麼是通過 append 擴充套件的,要麼是通過 repeat 擴充套件的。那我們怎麼知道它是從 append 還是 repeat 擴充套件出來的呢?——記錄最後一次 repeat。怎麼理解記錄最後一次repeat?假設我們有一個 sum[i] 表示第 i 次 repeat 之後 S 串的總長度,接下來假設讀到了連續 T 個字元,第 T+1 是數字 M。我們很容易發現:

  • 下一次迴圈節的長度是 sum[i]+T
  • 下一次 repeat 之後的總長度是 (sum[i]+T)*M

假設K>sum[i] && K<=sum[i]+T,說明第 K 位是 append 狀態擴充套件而來,這時直接輸出新讀到的第 K-sum[i] 個字元就行了。

假設K>sum[i]+T && K<(sum[i]+T)*M,說明第 K 位是 repeat 擴充套件得到的,迴圈節長度是 sum[i]+T。由前面的推論得知,此時第 K 位是第 K%(sum[i]+T) 位是一樣的,因此問題轉化成了求 S 的第 K%(sum[i]+T) 位。

這就變成了一個相同子問題,我們通過遞迴就能求解了。再想一想遞迴的邊界是什麼?一個字元首先得經過 append,才會進入後續的 repeat 狀態,因此對於某個字元 c,它第一次一定是由 append 擴充套件得到的。所以我們的遞迴只要有判斷 append 的分支,是一定能到達遞迴邊界的。

詳見AC 程式碼

細分圖中的可到達結點

原題連結

題解

這道題我的解法比較繞,官方的題解簡單易懂。下面說說我的做法吧: 首先用最短路演算法來先求出點 0 到其它所有點的最短路,我這裡使用的是 SPFA。求最短路有什麼用呢?考慮以下 case,假設從 0 出發,經過各種繞走到了 3 號點,耗費了 8 步。假設最多走 10 步,這就意味著從 3 號點繼續走還剩兩步可以走。但是如果從 0 走到 3 的最短路是 5,那麼意味著沿著最短路徑走到 3,此時從 3 出發還能再走 5 步,這意味著可達的點更多。 也就是說,如果某條邊屬於最短路徑上的邊,那麼這條邊上所有點一定是可達的,累加到答案 ans。如果某條邊不是最短路徑上的邊,那麼這條邊能走多長是多長。但是走完之後得記錄這條邊有多長已經是被走過了。

具體實現還有很多細節處理,詳見AC 程式碼

總結

這套題還是有點兒難度的,能在 1 個半小時內全部 AC 的都是大佬,我最後一道題加上除錯花了差不多一個晚上…

更多原創文章乾貨分享,請關注公眾號
  • LeetCode Weekly Contest 96 解題報告
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章