周賽298。超級多edge case的數學題,吃了一個WA兩個TLE才釐清所有狀況。

題目

輸入兩個整數num和k,試找出符合以下規則的正整數集合:

  • 每個數的個位數字為k
  • 所有數的總和為num

回傳此集合的最小大小,若不存在則回傳-1。
註:集合可包含重複數字,且空集合的總和視為0。

解法

既然例題三都說了空集合視為0,只少可以先確定num為0時答案一定是0。

我想著每次增加k,答案也加1,直到個位數的數字和num相同為止,反正超過10的部分都可以分散在任意的數字中填補。結果來了個k=0,尾數永遠不變,造成死循環TLE。
這下知道要特別處理k=0,如果num尾數也是0,那剛好可以用一個數字來達成,否則回傳-1。

那繼續從k開始,每次遞增k,直到個位數相同。考慮以下例子:

num=10, k=8
需要5個k才能使尾數變成0,但是總和已經是40了

如果總和超過num,也代表不可能達成,回傳-1;否則回傳使用了多少個k。

class Solution:
    def minimumNumbers(self, num: int, k: int) -> int:
        if num==0:
            return 0

        if k==0:
            if num%10==0:
                return 1
            return -1
        
        sm=k
        ans=1
        while num>sm and num%10 != sm%10:
            sm+=k
            ans+=1
            
        if sm>num:
            return -1

        return ans

看了幾個大神解答,實在很佩服他們能在短時間內歸納出這麼精簡的解法。
數字集合的大小只會介於1和9之間,為什麼不會是10呢?因為10個k和0個k尾數相同,11個k和一個k尾數也相同,以此類推。
遍歷過程中確保i個k不會超過num,否則跳出迴圈,直接回傳-1。

class Solution:
    def minimumNumbers(self, num: int, k: int) -> int:
        if num==0:
            return 0
        
        for i in range(1,11):
            if k*i>num:
                break
            if (num-k*i)%10==0:
                return i
            
        return -1