给定正整数 k ,你需要找出可以被 k 整除的、仅包含数字 **1** 的最 小  正整数 n 的长度。
返回 n 的长度。如果不存在这样的 n ,就返回-1。
注意:  n 可能不符合 64 位带符号整数。
示例 1: 
**输入:** k = 1
**输出:** 1
**解释:** 最小的答案是 n = 1,其长度为 1。
示例 2: 
**输入:** k = 2
**输出:** -1
**解释:** 不存在可被 2 整除的正整数 n 。
示例 3: 
**输入:** k = 3
**输出:** 3
**解释:** 最小的答案是 n = 111,其长度为 3。
提示: 
问题提示 如何通过遍历找到能被 k 整除的最小正整数 n 的长度?
前置知识 
理解正整数、整除、余数的概念及其运算法则。 
掌握哈希表的基本操作。 
数论基础知识,包括欧拉定理和取模运算等。 
 
解题思路 方法一:遍历 思路与算法 
题目要求出长度最小的仅包含的 1 的并且被 k 整除的正整数。我们从 n = 1 开始枚举,此时对 k 取余得余数 resid} = 1 \bmod k。如果 resid 不为 0,则表示 n 当前还不能被 k 整除,我们需要增加 n 的长度。令 n_{new} = n_{old} \times 10 + 1,resid}{new} = n {new} \bmod k。将 n_{old 代入其中可得:
\begin{aligned}{new} &= (n {old} \times 10 + 1) \bmod k \
从上式可以发现,新的余数 resid}{new 可以由 resid} {old 推导得到。因此在遍历过程中不需要记录 n,只需记录 resid。由于 resid 是对 k 取余之后的余数,因此种类数不会超过 k。
在遍历过程中如果出现重复的 resid,表示遇到了一个循环,接着遍历下去会重复循环中的每一步,不会产生新的余数。所以我们用一个哈希表记录出现过的余数,当更新 resid 后发现该值已经在哈希表时,直接返回 -1。否则我们一直遍历,直到 resid 变为 0。最终哈希表中的元素个数或者遍历次数就是实际 n 的长度。
代码 
[sol1_1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class  Solution  {public :    int  smallestRepunitDivByK (int  k)           int  resid = 1  % k, len = 1 ;          unordered_set<int > st;          st.insert (resid);          while  (resid != 0 ) {              resid = (resid * 10  + 1 ) % k;              len++;              if  (st.find (resid) != st.end ()) {                  return  -1 ;             }             st.insert (resid);          }         return  len;      } }; 
[sol1_1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution  {    public  int  smallestRepunitDivByK (int  k)  {         int  resid  =  1  % k, len = 1 ;          Set<Integer> set = new  HashSet <Integer>();          set.add(resid);          while  (resid != 0 ) {              resid = (resid * 10  + 1 ) % k;              len++;              if  (set.contains(resid)) {                  return  -1 ;             }             set.add(resid);          }         return  len;      } } 
[sol1_1-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  class  Solution  {    public  int  SmallestRepunitDivByK (int  k         int  resid = 1  % k, len = 1 ;          ISet<int > set  = new  HashSet<int >();          set .Add(resid);          while  (resid != 0 ) {              resid = (resid * 10  + 1 ) % k;              len++;              if  (set .Contains(resid)) {                  return  -1 ;             }             set .Add(resid);          }         return  len;      } } 
[sol1_1-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 typedef  struct  {    int  key;     UT_hash_handle hh; } HashItem;  HashItem *hashFindItem (HashItem **obj, int  key)  {     HashItem *pEntry = NULL ;          HASH_FIND_INT(*obj, &key, pEntry);     return  pEntry; } bool  hashAddItem (HashItem **obj, int  key)  {    if  (hashFindItem(obj, key)) {         return  false ;     }          HashItem *pEntry = (HashItem *)malloc (sizeof (HashItem));     pEntry->key = key;          HASH_ADD_INT(*obj, key, pEntry);     return  true ; } void  hashFree (HashItem **obj)  {    HashItem *curr = NULL , *tmp = NULL ;          HASH_ITER(hh, *obj, curr, tmp) {                  HASH_DEL(*obj, curr);                    free (curr);     } } int  smallestRepunitDivByK (int  k)  {         int  resid = 1  % k, len = 1 ;     HashItem *st = NULL ;          hashAddItem(&st, resid);          while  (resid != 0 ) {                  resid = (resid * 10  + 1 ) % k;                  len++;                  if  (hashFindItem(&st, resid) != NULL ) {             hashFree(&st);             return  -1 ;         }                  hashAddItem(&st, resid);     }          hashFree(&st);     return  len; } 
[sol1_1-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var  smallestRepunitDivByK = function (k ) {         let  resid = 1  % k, len = 1 ;          const  set = new  Set ();     set.add (resid);          while  (resid != 0 ) {                  resid = (resid * 10  + 1 ) % k;                  len++;                  if  (set.has (resid)) {             return  -1 ;         }                  set.add (resid);     }          return  len; }; 
优化 
注意到当 k 为 2 或者 5 的倍数时,能够被 k 整除的数字末尾一定不为 1,所以此时一定无解。
那当 k 不为 2 或者 5 的倍数时一定有解吗?我们做进一步的分析。
resid 随着 1 的增加,最后一定进入循环,我们能找到两个对 k 同余的 n 和 m。假设 n \gt m,那么一定有以下等式成立:
(n - m) \equiv 0 \pmod k
n - m 可以表示为 11\dots 100\dots 0 的形式,因此有 11\dots 100\dots 0 \equiv 0 \pmod k。
如果此时 k 不为 2 或 5 的倍数,则 k 与 10 没有公因数,k 与 10 互质。n - m 末尾的 0 可以除掉,因此 11\dots 1 \equiv 0 \pmod k,问题一定有解。
[sol1_2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution  {public :    int  smallestRepunitDivByK (int  k)                    if  (k % 2  == 0  || k % 5  == 0 ) {             return  -1 ;         }                  int  resid = 1  % k, len = 1 ;                  while  (resid != 0 ) {                          resid = (resid * 10  + 1 ) % k;             len++;         }                  return  len;     } }; 
[sol1_2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class  Solution  {    public  int  smallestRepunitDivByK (int  k)  {                  if  (k % 2  == 0  || k % 5  == 0 ) {             return  -1 ;         }                  int  resid  =  1  % k, len = 1 ;                  while  (resid != 0 ) {                          resid = (resid * 10  + 1 ) % k;             len++;         }                  return  len;     } } 
[sol1_2-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public  class  Solution  {    public  int  SmallestRepunitDivByK (int  k                  if  (k % 2  == 0  || k % 5  == 0 ) {             return  -1 ;         }                  int  resid = 1  % k, len = 1 ;                  while  (resid != 0 ) {                          resid = (resid * 10  + 1 ) % k;             len++;         }                  return  len;     } } 
[sol1_2-C] 1 2 3 4 5 6 7 8 9 10 11 12 int  smallestRepunitDivByK (int  k)  {         if  (k % 2  == 0  || k % 5  == 0 ) {         return  -1 ;     }     int  resid = 1  % k, len = 1 ;     while  (resid != 0 ) {         resid = (resid * 10  + 1 ) % k;         len++;     }     return  len; } 
[sol1_2-Python3] 1 2 3 4 5 6 7 8 9 10 11 class  Solution :    def  smallestRepunitDivByK (self, k: int  ) -> int :         if  k % 2  == 0  or  k % 5  == 0 :               return  -1                   ans, resid = 1 , 1            while  resid % k != 0 :               resid = (resid % k) * (10  % k) + 1                ans += 1                         return  ans   
[sol1_2-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 var  smallestRepunitDivByK = function (k ) {         if  (k % 2  === 0  || k % 5  === 0 ) {         return  -1 ;     }     let  resid = 1  % k, len = 1 ;     while  (resid !== 0 ) {         resid = (resid * 10  + 1 ) % k;         len++;     }     return  len; }; 
[sol1_2-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func  smallestRepunitDivByK (k int ) int  {         if  k % 2  == 0  || k % 5  == 0  {         return  -1      }          cur, res := 0 , 1                for  {         cur = (10  * cur + 1 ) % k         if  cur == 0  {             return  res         }         res++     } } 
复杂度分析 
练习题目推荐 29. 两数相除  166. 分数到小数  1071. 字符串的最大公因子  
拓展思考 如果给定的 k 非常大,如何优化算法?