劍指 offer 17. 列印從1到最大的n位數
題目描述:
輸入數字n
,按順序列印出從 1 到最大的 n 位十進位制數。比如輸入 3,則列印出 1、2、3 一直到最大的 3 位數 999。
示例:
輸入: n = 1
輸出: [1,2,3,4,5,6,7,8,9]
說明:1.用返回乙個整數列表來代替列印
2.n 為正整數
# solo
# 解題思路:根據n來確定列表的最大值9的個數為n個。如n=2,輸出列表最後乙個數即最大值是99
class solution:
def printnumbers(self, n: int) -> list[int]:
while n !=0:
max=0
for i in range(n): # 找出最大的數即9的個數
max=max*10+9
result = list(range(1, max+1)) #排除掉0,加上1因為range(n)不包括n
return result
# good
"""最大的 nn 位數(記為 endend )和位數 nn 的關係: 例如最大的 11 位數是 99 ,最大的 22 位數是 9999 ,最大的 33 位數是 999999
則可推出公式:end=10*n-1 #比9的個數方法簡單多了。
"""class solution:
def printnumbers(self, n: int) -> list[int]:
res = # 建立空列表的兩種方式:1.res=list() 注意是()不是 2. res=
for i in range(1, 10 ** n):
return res
大數列印解法:
實際上,本題的主要考點是大數越界情況下的列印。需要解決以下三個問題:
表示大數的變數型別:
無論是 short / int / long … 任意變數型別,數字的取值範圍都是有限的。因此,大數的表示應用字串 string 型別。
生成數字的字串集:
使用 int 型別時,每輪可通過 +1+1 生成下個數字,而此方法無法應用至 string 型別。並且, string 型別的數字的進製操作效率較低,例如 「9999」 至 「10000」 需要從個位到千位迴圈判斷,進製 4 次。
觀察可知,生成的列表實際上是 n 位 0 - 9 的 全排列 ,因此可避開進製操作,通過遞迴生成數字的 string 列表。
遞迴生成全排列:
基於分治演算法的思想,先固定高位,向低位遞迴,當個位已被固定時,新增數字的字串。例如當 n=2 時(數字範圍 1 - 99),固定十位為 0 - 9 ,按順序依次開啟遞迴,固定個位 0 - 9 ,終止遞迴並新增數字字串。
根據以上方法,可初步編寫全排列**:
class solution:
def printnumbers(self, n: int) -> [int]:
def dfs(x):
if x == n: # 終止條件:已固定完所有位
return
for i in range(10): # 遍歷 0 - 9
num[x] = str(i) # 固定第 x 位為 i
dfs(x + 1) # 開啟固定第 x + 1 位
num = ['0'] * n # 起始數字定義為 n 個 0 組成的字元列表
res = # 數字字串列表
dfs(0) # 開啟全排列遞迴
return ','.join(res) # 拼接所有數字字串,使用逗號隔開,並返回
在此方法下,各數字字串被逗號隔開,共同組成長字串。返回的數字集字串如下所示:
輸入:n = 1
輸出:"0,1,2,3,4,5,6,7,8,9"
輸入:n = 2
輸出:"00,01,02,...,10,11,12,...,97,98,99"
輸入:n = 3
輸出:"000,001,002,...,100,101,102,...,997,998,999"
觀察可知,當前的生成方法仍有以下問題:
1.諸如 00, 01, 02,⋯ 應顯示為 0, 1, 2,⋯ ,即應 刪除高位多餘的 0 ;
2.此方法從 0 開始生成,而題目要求 列表從 1 開始 ;
以上兩個問題的解決方法如下:
刪除高位多餘的 0 :
字串左邊界定義: 宣告變數start 規定字串的左邊界,以保證新增的數字字串 num[start:] 中無高位多餘的 00 。例如當 n = 2時, 1 - 91−9 時 start = 1 , 10 - 9910−99 時 start = 0 。
左邊界 start 變化規律: 觀察可知,當輸出數字的所有位都是 99 時,則下個數字需要向更高位進 11 ,此時左邊界 start 需要減 1 (即高位多餘的 0 減少乙個)。例如n=3 (數字範圍 1−999 )時,左邊界 start 需要減 1 的情況有: 「009」 進製至 「010」 , 「099」 進製至 「100」 。設數字各位中 99 的數量為nine ,所有位都為 99 的判斷條件可用以下公式表示:
n - start = nine
n−start=nine
統計 nine 的方法: 固定第 x 位時,當i=9 則執行 nine=nine+1 ,並在回溯前恢復nine=nine−1 。
列表從 1 開始:
在以上方法的基礎上,新增數字字串前判斷其是否為 「0」 ,若為 「0」 則直接跳過。
複雜度分析:
時間複雜度 o(10^n)
遞迴的生成的排列的數量為 10^n
空間複雜度 o(n) : 字元列表 num 使用線性大小的額外空間。
**:為 正確表示大數 ,以下**的返回值為數字字串集拼接而成的長字串。
class solution:
def printnumbers(self, n: int) -> [int]:
def dfs(x):
if x == n:
s = ''.join(num[self.start:])
if n - self.start == self.nine: self.start -= 1
return
for i in range(10):
if i == 9: self.nine += 1
num[x] = str(i)
dfs(x + 1)
self.nine -= 1
num, res = ['0'] * n,
self.nine = 0
self.start = n - 1
dfs(0)
return ','.join(res)
本題要求輸出 int 型別陣列。為 執行通過 ,可在新增數字字串 s 前,將其轉化為 int 型別。**如下所示:
class solution:
def printnumbers(self, n: int) -> [int]:
def dfs(x):
if x == n:
s = ''.join(num[self.start:])
if n - self.start == self.nine: self.start -= 1
return
for i in range(10):
if i == 9: self.nine += 1
num[x] = str(i)
dfs(x + 1)
self.nine -= 1
num, res = ['0'] * n,
self.nine = 0
self.start = n - 1
dfs(0)
return res
劍指offer17 列印從1到最大的n位數
題目 輸入數字n,按順序列印從1到最大的n為十進位制數。比如輸入3,則列印出1,2,3一直到最大的3位數999。看到這個問題之後,最容易想到的辦法就是先求出最大的n位數,然後用乙個迴圈從1開始逐個列印。於是很容易寫出以下 void print1tomaxofndigits 1 int n for i...
劍指 Offer 17 列印從1到最大的n位數
題目 輸入乙個位數n,把1到最大的n位數 如當n 2時,為99 放到int裡返回。public int printnumbers int n 思路 1.直接用for來放入,不考慮大數問題。不考慮大數問題 public int printnumbers int n return array 2.當n變...
劍指 Offer 17 列印從1到最大的n位數
輸入數字n,按順序列印出從 1 到最大的 n 位十進位制數。比如輸入 3,則列印出 1 2 3 一直到最大的 3 位數 999。示例 1 輸入 n 1 輸出 1,2,3,4,5,6,7,8,9 越來越覺得越是簡單的問題,遇到大數的時候就越難想出來處理的方式,感覺像是一種思維上的定式限制了我會用別的方...