前言
一不小心做了個阿里今年校招的在線筆試題,轉眼畢業兩年了,幾乎沒再正正經經的做過這種類似ACM的編程題了,腦子還是一如既往的不好使啊,既然做了就分享出來吧,希望我題目沒有理解錯,O(∩_∩)O哈哈~
題目
菜鳥倉庫是一個很大很神奇的地方,各種琳瑯滿目的商品整整齊齊地擺放在一排排貨架上,通常一種品類(sku)的商品會放置在貨架的某一個格子中,格子設有統一的編號,方便工人們揀選。 有一天沐哲去菜鳥倉庫參觀,無意中發現第1個貨架格子編碼為1,第2-3個分別為1,2,第4-6個格子分別是1,2,3,第7-10個格子編號分別是1,2,3,4,每個格子編號都是0-9中的一個整數,且相鄰格子的編號連在一起有如下規律 1|12|123|1234|...|123456789101112131415|...|123456789101112131415……n 這個倉庫存放的商品品類非常豐富,共有1千萬多個貨架格子。沐哲很好奇,他想快速知道第k個格子編號是多少?
分析
這個題一看感覺很復雜,但其實就是在闡述一個計數規律,這種最容易想到的就是用 循環 或者 遞歸 來實現了,問題是求第k個格子編號,最傻的辦法就是按規律挨個推導出所有位置的編號就ok了,也就是實現一下打印出這串復雜的編號咯【當然,相信更高端的做法是不需要挨個推導的,可惜我腦子不夠好使,只能簡單粗暴了】
循環實現邏輯
這個題的編號邏輯其實就是三層循環,每次都是從1數到一個最大值max_num【一層循環】,數到max_num后max_num就加一【兩層循環】,這里還要考慮數字是按位輸出的,比如:123(一百二十三)是輸出成1,2,3,也就是循環輸出從最高位到最低位的值【三層循環】,總共三層循環就可推導出所有的格子編號了
遞歸實現邏輯
遞歸核心思想就是:當知道上一個數的信息時,就能預測當前數是多少
所以我需要完整的一個對上一個格子編號的描述,這里參考循環邏輯,也就是需要知道三個信息:
- 當前計數最大值max_num
- 當前計數值cur_num
- 當前輸出的位cur_num_idx,相對于cur_num的
有了這三個值就可以描述出當前格子編號了,格子具體編號是:no = str(cur_num)[cur_num_idx]
遞歸的結束條件是推導到k=1
時我們明確知道 max_num=1,cur_num=1,cur_num_idx=0,no=1
k=2
時:max_num=2,cur_num=1,cur_num_idx=0,no=1
k=3
時:max_num=2,cur_num=2,cur_num_idx=0,no=2
。。。
一直反推下去就可以得到所有位置的編號了
【注意】:遞歸有個很大的問題,當遞歸層數過高會棧溢出的,這里只要k是多少就要遞歸多少層,因為每次都要遞歸到k=1
時才能往上推導,而這邊有1千多萬個格子,所以,遞歸實現其實是不行的,但用這個題來練習遞歸實現還是很不錯的
代碼
以上邏輯用python實現
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# by vellhe 2017/8/25
def get_no1(k):
'''
循環實現
:param k:
:return: 編號
'''
max_num = 0
idx = 0
while True:
# 外層循環負責增大計數最大值
max_num += 1
for cur_num in range(1, max_num + 1):
# 內層循環負責從1數到max_num
cur_num_str = str(cur_num)
# 輸出完當前數字后的index
tmp_idx = idx + len(cur_num_str)
# index是否大于k,大于的話說明k位編號就在當前數字里
if tmp_idx >= k:
return cur_num_str[k - idx - 1]
else:
idx = tmp_idx
def get_no2(k):
'''
遞歸實現
:param k:
:return: 計數最大值,當前數字,當前輸出的位
'''
ret = None
if k == 1:
ret = 1, 1, 0
else:
# 計數最大值,當前數字,當前輸出的位
max_num, cur_num, cur_num_idx = get_no2(k - 1)
cur_num_str = str(cur_num)
if cur_num_idx < len(cur_num_str) - 1:
# 還有未輸出的則繼續輸出
ret = max_num, cur_num, cur_num_idx + 1
else:
if cur_num == max_num:
# 當當前計數已經是最大值了,則最大值加1,并初始化當前數值為起始數字
ret = max_num + 1, 1, 0
else:
# 還不是最大值則自增
cur_num += 1
ret = max_num, cur_num, 0
return ret
if __name__ == "__main__":
# 循環結果
tmp_str = ""
for k in range(1, 101):
tmp_str += get_no1(k)
print("循環結果: ", tmp_str)
# 遞歸結果
tmp_str = ""
for k in range(1, 101):
max_num, cur_num, cur_num_idx = get_no2(k)
cur_num_str = str(cur_num)
tmp_str += cur_num_str[cur_num_idx]
print("遞歸結果: ", tmp_str)
運行結果: