劍指 Offer 17 列印從1到最大的n位數

2021-10-23 17:57:04 字數 3971 閱讀 9008

劍指 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 越來越覺得越是簡單的問題,遇到大數的時候就越難想出來處理的方式,感覺像是一種思維上的定式限制了我會用別的方...