LeetCode 2217. Find Palindrome With Fixed Length
周賽286。看到回文真是又驚又喜,數不清我曾經被他害死幾次。這題要推算的東西有夠多,好險有成功算出來。
然後範例竟然還有打錯,只是錯得太明顯,應該大部分人都有發現。
題目
回文數字指的是沒有前導零,且順讀與逆讀相同的數字。
輸入整數intLength,代表回文數字的位數,陣列queries[i]代表要找第n小的回文數字。
回傳一個陣列保存queries所對應的回文數字,若找不到則為-1。
例:
queries = [1,2,3,4,5,90], intLength = 3
[101,111,121,131,141,999]
解法
範例雖然沒有明說,但很明顯999就是最後一個回文數,從91開始就是出界的-1。
我就想說把數字當成洋蔥分層,數字長度1~2的是一層,2~3是兩層,類推計算。只有一層的話總數為9,每多一層總數*10。計算出總數後就很好過濾了。
遍歷queries,若超出總數則為-1,否則以函數轉換成回文數字。
重點在這個轉換函數,搞了我好久才出來,還感覺不太有效率,特地加上快取看能不能稍微加速。
因為題目要求的是第n小的回文數,所以數字一定要從內部開始向外增長且而最外圈不能用0,所以一進去先把q-1。
我們知道999是第90個,實質上對應q=89,可以推導出是從101生成,最裡面那層+9,而第二層+8。所以只要從最內層開始,逐漸往外加,直到q用完,再把最外層加上1,就得到每層對應的數字。
最後最後依據數字長度決定最內層需不需要重複,外層逐一包起來轉回數字就大功告成了。
class Solution:
def kthPalindrome(self, queries: List[int], intLength: int) -> List[int]:
N=len(queries)
ans=[]
layer=(intLength+1)//2
mx=9*10**(layer-1)
@lru_cache(None)
def getPal(q):
q-=1
pal=[]
for _ in range(layer):
l=q%10
pal.append(l)
q//=10
pal[-1]+=1
s=[str(pal[0])]
if intLength%2==0:
s*=2
for i in range(1,layer):
s=[str(pal[i])]+s+[str(pal[i])]
return ''.join(s)
for q in queries:
if q>mx:
ans.append(-1)
else:
ans.append(getPal(q))
return ans
2022-4-6複習。
之前把問題過度複雜化,大概多走了兩三個彎路,今天重寫後變得更容易理解。
一樣先計算出總共幾層,還有最後一個項數。但是這次多計算首項的左半邊first,即為11, 101, 1001之類的。
可以發現第i個回文的左半邊,剛好是first+(i-1):
intLength = 4, first = 10, q = 32
左半邊 = first+(q-1) = 41
回文 = 4114
最後根據長度的奇偶來決定最內層是否重複即可。
從2656ms加速到585ms,擊敗98.98%。
class Solution:
def kthPalindrome(self, queries: List[int], intLength: int) -> List[int]:
layer=(intLength+1)//2
mx=9*10**(layer-1)
first=10**(layer-1)
odd=intLength%2
ans=[]
for q in queries:
if q>mx:
ans.append(-1)
else:
n=str(first+(q-1))
if odd:
ans.append(n+n[:-1][::-1])
else:
ans.append(n+n[::-1])
return ans