LeetCode-846.一手順子
LeetCode-846.一手順子
題目連結(微信開啟):https://mp.weixin.qq.com/s/RWzrpg1Q4Dke7UNR4T34PA
一、題目描述
Alice有一手牌:整數陣列hand,需要將它分組,問是否可以將其分成每組牌數都是groupSize張,且每組牌數的數字需要連續。可以的話輸出:true,否則:false。
示例 1:
輸入:hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
輸出:true
解釋:Alice 手中的牌可以被重新排列為 [1,2,3],[2,3,4],[6,7,8]。
示例 2:
輸入:hand = [1 ,2,3,4,5], groupSize = 4
輸出:false
解釋:Alice 手中的牌無法被重新排列成幾個大小為 4 的組。
注意:
-
1 <= hand.length <= 104
-
0 <= hand[i] <= 109
-
1 <= groupSize <= hand.length
二、題目分析
我先說說自己能想到的和不能想到的一些問題吧,
(I)能想到的
這個hand陣列能不能分成每組為:groupSize個數,首要條件需要滿足:
1、hand的個數能被groupSize 除盡,即:
hand.length mod groupSize == 0
2、需要對整個hand陣列,進行從小到大的排序
3、要統計每個數字的出現次數
用另一個數組cnt,cnt[hand[i]] 表示hand[i] 這個數的出現次數。比如,未對陣列hand排序前,hand[2],hand[7],hand[11],hand[18]都是數字3,那麼cnt[3]=4。
4、當某個hand[i]能分成一對順子後,這個hand[i]要被剔除,然後出現次數要遞減1。
拿上面的示例2來說,沒成順子前應得到次數陣列:
cnt[1]= 1 cnt[2]= 2 cnt[3]= 2 cnt[4]= 1 cnt[6]= 1 cnt[7]= 1 cnt[8]= 1
當把1,2,3成一對順子後,次數陣列變成:
cnt[1]= 0 #成順子,次數減去1 cnt[2]= 1 #成順子,次數減去1 cnt[3]= 1 #成順子,次數減去1 cnt[4]= 1 cnt[6]= 1 cnt[7]= 1 cnt[8]= 1
5、最後就是成順子的一些組合,數字有重疊的是情況1~3,數字不重疊的是情況4
(II)不能想到的
上面都是些零碎的分析,不知道怎麼轉化為程式碼。
主要體現在:
(1)當從hand陣列拿走一對groupSize牌數後,次數陣列遞減1,之後如何保證hand陣列,最終剩下的數能不能剛好都成順子;
(2)另外一個問題是,這個位置移動怎麼去走,例如上面圖的情況1,需要分成每組groupSize=2的順子,當從中拿走1、2成順子後,下一個順子位置是從3,4,還是從1,2去拿。然後就被自己搞混了。
三、最終解析
後來我看了題解,發現沒想象中複雜!以下摘自題解:
假設尚未分組的牌中,最小的數字是 x,則如果存在符合要求的分組方式,x 一定是某個組中的最小數字(否則 x 不屬於任何一個組,不符合每張牌都必須被分到某個組),該組的數字範圍是 [x,x+groupSize−1]。在將 x 到 x+groupSize−1 的 groupSize 張牌分成一個組之後,繼續使用貪心的策略對剩下的牌分組,直到所有的牌分組結束或者無法完成分組。如果在分組過程中發現從最小數字開始的連續 groupSize 個數字中有不存在的數字,則無法完成分組
對我第一個疑問,首先hand陣列能被groupSize除得盡,如果都能成順子配對的話,是不會存在多餘的數成不了順子的
第二個疑問:怎麼移動下一對順子的位置。排完序順著來,直到次數陣列遞減到0,我們再移動位置就好了。剛不是提到情況1,如果1、2成順子,下一個順子位置應從1、2去配對,而不是直接走到3,4。 因為cnt[1]和cnt[2]還沒成0。
用虛擬碼控制這個移動的位置,這個晚點我再補充。。。。