2020-01算法刷題集
-
(0101)-(等差數列求項數)
數學老師給小明出了一道等差數列求和的題目。但是粗心的小明忘記了一部分的數列,只記得其中N 個整數。
現在給出這N 個整數,小明想知道包含這N 個整數的最短的等差數列有幾項?
【輸入格式】
輸入的第一行包含一個整數N。
第二行包含N 個整數A1,A2,...,ANA_{1}, A_{2}, ..., A_{N}A【輸出格式】
輸出一個整數表示答案。【樣例輸入】
5
2 6 4 10 20【樣例輸出】
10【樣例說明】
包含2、6、4、10、20 的最短的等差數列是2、4、6、8、10、12、14、16、18、20。
題目來源:第十屆藍橋杯-H題
解題過程:
沒啥好講的,因爲馬虎,導致錯誤理解題意,將最小項和次最小項作爲數列的前兩項。
最後發現數列的第二項可以不在輸入樣例中,所以需要使用控制變量,當an一定時,使得d儘可能地大,n纔會小
需要使用輾轉相除法求得最大公因數,另外,需要排序算法
代碼(python實現):
#author:zhj1121
#等差數列問題
def get_list():
print("input:")
num = eval(input(""))
list_ele = input().split(' ')
list1 = list(list_ele)
intlist = []
#list to int
for i in list1:
intlist.append(int(i))
return intlist
def get_list_d(list):
d = [''for i in range(len(list)-1)]
for i in range(1,len(list)):
d[i-1] = list [i]-list[i-1]
return d
def get_d(list):
d = 10000
for i in range(1,len(list)):
a = list[i-1]
b = list[i]
if(a>=b):
c = zzxcgetgys(a,b)
else:
c = zzxcgetgys(b,a)
if(c<d):
d = c
return d
def zzxcgetgys(a,b):
if(b==0):
return a
else:
return zzxcgetgys(b,a%b)
def main():
list = get_list()
list_sort = sorted(list)
list_d = get_list_d(list_sort)
d = get_d(list_d)
print("output:")
if(d==0):
print(len(list))
else:
print(int((list_sort[-1]-list_sort[0])/d+1))
main()
運行結果:
、
-
(0103)-(最後四位數字)
給定數列1, 1, 1, 3, 5, 9, 17, …,從第4 項開始,每項都是前3 項的和。求
第20190324 項的最後4 位數字。
題目來源:第十屆藍橋杯-C題
解題過程:這道題就是斐波那契數列的變形,由於所求數值過大,所以不使用遞歸,直接迭代遍歷
當然也有兩個思路:
1.使用列表裝載,但這道題沒必要這樣做,所以有第2種思路;
2.每一次迭代,只保存3個數,因爲程序運行每一次運行就只是需要這三個數而已,沒必要保存其它數據。
同樣的道理,由於題目只要求出最後4位數字,所以可以同時將三位數求餘,舉個例子就可以知道是沒有影響的
兩種思路的代碼分別如下
思路1:
#author:zhj1121
#time:0103
def fibonacci(n):
fib = [i for i in range(n)]
fib[0] = 1
fib[1] = 1
fib[2] = 1
for i in range(3,n):
fib[i] = (fib[i-1]+fib[i-2]+fib[i-3])%10000
return fib[-1]
def main():
num = fibonacci(20190324)
print(num)
main()
思路2:
#author:zhj1121
#time:0103
def fibonacci2(n):
a = 1
b = 1
c = 1
for i in range(4,n+1):
t = (a+b+c)%10000
a = b
b = c
c = t
return t
def main():
t = fibonacci2(20190324)
print(t)
main()
運行結果:
總結:通過這道題,可以明顯地感受到通過修改算法可以提高程序運行速率,而且因題制宜,如果像之前的算法一樣,使用遞歸,將會導致程序運行的時間非常地長。
-
(0105)-(排列)
用1,3,5,8這幾個數字,能組成的互不相同且無重複數字的三位數各是多少? 總共有多少可能?
題目來源:第十屆藍橋杯-Python組-第1題
解題過程:這道題就是全排列問題,創建一個全排列函數生成所有的可能就可以了,需要i注意的是,這道題是4個數生成3個全排列,所有的可能和全排列可能是一樣的,也是4*3*2=24種,至於結果,可以默認將最後一位不輸出即可
代碼如下:
#0105.py
#藍橋杯python組第1題
per_result = []
def per(lst,s,e):
if s == e:
per_result.append(list(lst))
else:
for i in range(s,e):
lst[i],lst[s] = lst[s],lst[i]#試探
per(lst,s+1,e)#遞歸
lst[i],lst[s] = lst[s],lst[i]
def main():
lst = [1,3,5,8]
per(lst,0,4)
for i in per_result:
for j in range(3):#只輸出3個元素
print(i[j],end="")
print("")
print(len(per_result))
main()
運行結果:
總結:由於放假回家,所以忙活了幾天,這幾天持續補更。
-
(0107)-(特殊的標記)
編程實現:
打印出1-1000之間包含3的數字:
如果3是連在一起的(如33)則在數字前加上&;
如果這個數字是質數,則在數字後加上*,例:(3,13*,23*,&33,...,&233*...)
題目來源:第十屆藍橋杯-Python組-第2題
解題思路:
可以把這道題分爲2步,3個“過濾器”,
把整個程序看成3個過濾器,對象是1-1000,
經過過濾器1:含有3的數,可以使用 字符串語法實現
將整數轉換爲字符串,如果字符3在字符串中,則符合過濾器要求,過濾出去
if('3' in str(num)):
...
將過濾器1獲得的對象全部存儲到一個列表中
創建兩個函數:
如果經過過濾器2的數:含有 33 或者 333 的數,則返回 True
如果經過過濾器3的數:即質數(除1和自身不能被任何數整除),則返回True
根據題意條件進行輸出即可
代碼如下:
#第十屆藍橋杯python組第2題
#test
#過濾器1
# num = 1222
# strnum = str(num)
# print('3' in strnum)
#過濾器2
# num = 1333
# if('33' in str(num) or '333' in str(num)):
# num_str = str('&')+str(num)
# print('&',end="")
# print(num)
#過濾器3 簡單寫
def hasnum():
lst_num = []
for i in range(1,1001):
num_str = str(i)
if('3' in num_str):
num_int = int(num_str)
lst_num.append(num_int)
return lst_num
# print(type(lst_result[0]))#success
def manynum(num):
if('33' in str(num) or '333' in str(num)):
return True
else:
return False
def isPrime(num):
if(num==1):
return False
else:
for i in range(2,num):
if(num%i==0):
return False
return True
#print(isPrime(233))#success
def main():
f_result_lst = hasnum()
for i in f_result_lst:
if(manynum(i) and isPrime(i)==False):
print('&{}'.format(i))
elif(manynum(i)==False and isPrime(i)):
print('{}*'.format(i))
elif(manynum(i) and isPrime(i)):
print('&{}*'.format(i))
else:
print(i)
main()
運行結果(由於過長,只截部分):
總結:在解題思路已完成總結
-
(0109)-(數字處理)
讓用戶在一次輸入時輸入N個數字(2<=N<=15,即每次輸入的數字數量不同),數字之間以”,“作爲分割
然後組合顯示:
1.用戶輸入的數字個數
2.用戶輸入的最小的數字
3.將用戶輸入的數字按從大到小進行排列輸出,數字之間以’,‘作爲分割
4.如果用戶輸入的數字小於等於26,則找到相對應的26個大寫英文字母(1 對應 ’A‘,26對應’Z‘,並拼接在一起打印顯示
如果輸入的數字在1-26之外,則不顯示相應的字母。(例:程序輸入214,則顯示輸出'[bad]').
輸入:
N個數字,2<=N<=15
輸出:
輸入的數字個數
輸入的最小數字
輸入的數字從大到小排列
輸入的數字所對應的字母
題目來源:第十屆藍橋杯-Python組-第3題
解題思路:沒啥好說,當回顧基礎吧
代碼如下:
#第十屆藍橋杯-Python組-第3題)
#test
# print(chr(65))
def str_int(list):
int_lst = []
for i in list:
int_lst.append(int(i))
return int_lst
def main():
lst = input().split(",")
int_lst=str_int(lst)
# print(int_lst)
sort_lst = sorted(int_lst)
#1
print(len(sort_lst))
#2
print(sort_lst[0])
#3
sort_lst.reverse()
for i in sort_lst:
print(i,end=",")
print("")
#4
for i in int_lst:
if(i<=26):
print(chr(64+i),end="")
else:
print("[bad]")
main()
運行結果:
-
(0111)-(特別數的和)
標題:特別數的和
小明對數位中含有2,0,1,9的數字很感興趣(不包括前導0),在1到40中這樣的數包括1,2,9,10至32,39,和40,共28個,他們的和是574.
請問,在1到n中,所有這樣的數的和是多少?
輸入格式:輸入一行包含兩個整數n
輸出格式:輸出一行,包含一個整數,表示滿足條件的數的和
題目來源:第十屆藍橋杯-F題
解題思路:和 第十屆藍橋杯-Python組-第2題 類似
代碼如下:
#(0111)-(第十屆藍橋杯-F題)
def add(list):
sum = 0
for i in list:
sum +=i
return sum
def main():
sum = 0
lst_result = []
num = eval(input(""))
for i in range(1,num+1):
if('2' in str(i) or '0' in str(i) or '1' in str(i) or '9' in str(i)):
lst_result.append(i)
sum = add(lst_result)
print(sum)
main()
運行結果:
-
(0113)-(巨人排隊)
巨人國的小學生放假了,老師要給小朋友們排隊了。可是這個老師有強迫症,一定要隊伍上的小朋友按照身高從高到矮排序(也就是排在前面的不能比後面的矮)。小朋友呢也很調皮,一旦老師給他排好隊就不願意動了。這個時候小朋友們一個一個的從教室裏出來了,每個小朋友一出來老師就要給小朋友安排好位置。請問老師最少要給小朋友排幾條路隊呢?
輸入:
兩個數兩行,第一行是人數(1<=n<=100000),第二行的身高,身高不超過30000
輸出:
最少隊伍數
#0113-巨人排隊
def findindex(list):
for i in range(len(list)):
if(list[i]==1):
return i
return -1
def trueorfalse(ele,list):
tf_list = [0 for i in range(len(list))]
for i in range(len(list)):
if(list[i]>=ele):
tf_list[i] = 1
return tf_list
def main():
num = eval(input())
list_input = input().split(" ")
int_list = []
for i in list_input:
int_list.append(int(i))
#print(int_list)
troops_list = []
troops_list.append(int_list[0])
for i in range(1,len(int_list)):
tf_list = trueorfalse(int_list[i],troops_list)
if(findindex(tf_list)==-1):
troops_list.append(int_list[i])
else:
troops_list[findindex(tf_list)]=int_list[i]
#print(troops_list)
print(len(troops_list))
main()
題目來源:中南大學複試上機:1023: 巨人排隊
解題思路:
—數據類型對象:
創建一個列表,爲學生列表,用於存儲教室中所有學生的身高,以遍歷的方式模擬走出教室這一行爲
創建一個列表,爲矮列表,用於存儲所有隊伍中最矮學生的身高,即每隻隊伍的最後一名學生
—情景模擬(代碼邏輯):
從教室走出一個學生,這時有兩種情況:
(遍歷學生列表)
情況1:走出的學生比某隻隊伍中最矮學生的身高還矮或者相等,直接插入對應的隊伍中
(情況1,將這個學生的身高替代矮列表對應的元素)
情況2:走出的學生比所有隊伍中最矮學生的身高要高,這個學生自己站一隻隊伍
(情況2:將這個學生的身高直接插入矮列表中)
情景模擬如下:
運行結果:
補充(0116)
看了其它解法,都說需要貪心算法。但我覺得不需要貪心算法,因爲貪心算法的前提就是需要對元素進行排序和貪心選擇。
這個解法沒用到並沒有對元素進行排序,但是也正確的,例如以下描述:
因爲其它解法都有一個共同點,就是儘量使相鄰的學生的身高儘可能接近
所以可以將學生的身高數據時集中,時差距大
當教室的學生的順序和身高如:385 287 387 286 384
—如果使用上述解法,也將會產生正確答案,即2支隊伍
演算過程:
原因:因爲整個程序演算過程已經將每支隊伍的相鄰學生的身高儘可能地接近,
當學生無法排在已產生的隊伍時,將會獨自產生一個隊伍,
同時,前面隊伍的最後一個學生的身高肯定比後面隊伍的最後一個學生的身高要矮,
所以不必對每支隊伍學生的身高進行排序操作
運行結果:
、
-
(0115)-(漫漫上學路)
對於csuxushu來說,能夠在CSU(California State University)上學是他一生的榮幸。CSU校園內的道路設計的十分精巧,由n+1條水平道路和n+1條豎直道路等距交錯而成,充分體現了校園深厚的文化底蘊。然而不幸的是CS市每到夏季,天降大雨,使得CSU常常形成“CS海”的奇觀,今年,也就是2016年同樣也不例外,校園有一半的區域被淹了。
由於要進行一年一度激動人心的省賽選拔了,起遲了的csuxushu趕緊從寢室揹着一包模板前往機房,好奇的csuxushu發現雖然道路被淹了,但是隻有左上三角區域受到影響,也就是說他可以在副對角線以下的道路暢通行走。在這個驚人的場景下,csuxushu做了一個驚人的決定,他要算出他有多少種前往機房的最短路線。然而只有10分鐘了,這時候他想到了你——全CSU最厲害的程序員來幫助他解決這個問題。
需要指出的是CSU可以看做左下頂點爲csuxushu的寢室(0,0),右上頂點爲機房(n,n)的方形區域。輸入:
多組數據。每組數據只有一行,爲一個整數n(1 ≤n ≤30)。
輸出:
每組數據輸出一行,即由寢室到機房的最短路線方案數。測試數據保證結果爲64位整數。
題目來源:中南大學ACM1772: 漫漫上學路
題目重讀:
由於中南大學ACM題目的背景敘述過多,所以題目重讀,如下:
副對角線:在代數學中,n階行列式,從左上至右下的數歸爲主對角線,從左下至右上的數歸爲副對角線。
有一個人下圖的左下角到右上角,有多少種路線?
解題思路:
可以知道這是卡特蘭數,相關知識:卡特蘭數-百度百科
例如先假設輸入1,就是2*2的格子
2*2 有2種可能:
1->4->2->5->3
1->4->6->5->3
3*3 有5種可能,在這裏不進行敘述
所以這道題可以直接使用卡特蘭數公式直接獲得結果
程序代碼:
#科特蘭數
#0115
def Catalannumber(n):
n+=1
lst = []
for i in range(n):
lst.append([])
for j in range(n):
lst[i].append(1)
for x in range(n):
for y in range(n):
if(x>y):
lst[x][y] = 0
elif(x==0 and y!=0):
lst[x][y]=1
elif(x!=0 and y==0):
lst[x][y]=0
elif(x==0 and y==0):
lst[x][y]=0
else:
lst[x][y]=lst[x][y-1]+lst[x-1][y]
return lst
#print(Catalannumber(4))
def main():
num = eval(input("input:"))
num = Catalannumber(num)[num][num]
print("output:{}".format(num))
main()
運行結果:
-
(0117)-(一二三)
你弟弟剛剛學會寫英語的一(one)、二(two)和三(three)。他在紙上寫了好些一二三,可惜有些字母寫錯了。已知每個單詞最多有一個字母寫錯了(單詞長度肯定不會錯),你能認出他寫的啥嗎?
input:
第一行爲單詞的個數(不超過10)。以下每行爲一個單詞,單詞長度正確,且最多有一個字母寫錯。所有字母都是小寫的。
output:
對於每組測試數據,輸出一行,即該單詞的阿拉伯數字。輸入保證只有一種理解方式。
題目來源:中南大學ACM1110-一二三
(偷懶一天,最近有點忙,解道簡單的題)
解題思路:直接暴力解題吧
首先進行單詞長度的獲取,再通過長度進行判斷,如果長度是3,則是一或者二
如果長度大於3,則是三
再假設通過字符串的對比,進行判斷
程序代碼:
#0117
#一二三
def createone():
one = []
for i in range(26):
ele1 = chr(97+i)+'ne'
ele2 = 'o'+chr(97+i)+'e'
ele3 = 'on'+chr(97+i)
one.append(ele1)
one.append(ele2)
one.append(ele3)
return one
def getnum(list):
chinalist = []
one = createone()
for i in list:
if(len(i)==3):
if(i in one):
chinalist.append('一')
else:
chinalist.append('二')
else:
chinalist.append('三')
return chinalist
def main():
num = eval(input())
list = []
for i in range(num):
ele = input()
list.append(ele)
result = getnum(list)
print(result)
main()
運行結果:
-
(0119)-(真三國無雙)
真三國無雙是魔獸的一個遊戲,該遊戲是以中國三國的歷史背景而製作的,該遊戲是5 V 5的遊戲模式,敵對雙方各5個英雄,推掉了對方的大本營就算取得了勝利。
ZYH和SN都喜歡玩這個遊戲,但是他們誰也不服誰,都覺得自己的操作比對方厲害,因此他們兩人決定以單挑的方式來一決高下。ZYH選擇了他最喜歡的英雄:關羽,SN也選擇了他喜歡的英雄:典韋。
在他們開始正式比賽前,裁判介紹了一下關羽和典韋的技能。典韋有個腳踢地面而造成羣暈的技能,簡稱爲T,由於是遊戲,它會有個動畫效果,因此典韋使用T分爲三個階段:
點擊T -> T的動畫 -> T的釋放
點擊T的時間可以忽略,T的動畫需要a(MS);T的釋放時間爲b(MS),在這段時間內,如果對方英雄在地面,就會被擊暈。
而關羽使用技能D,過程是這樣的:
點擊D -> 選擇方向 -> 轉身(英雄會逆時針轉身到選擇的方向)-> 跳到空中-> 落下
點擊D和選擇方向的時間可以忽略,轉身時間爲c(MS),跳到空中停留的時間爲d(MS)。英雄當前方向與選擇方向之間的逆時針夾角叫做旋轉角度。轉身時間c = 旋轉角度 × 10 (MS)。在遊戲中,旋轉角度的範圍爲[0, 360),不可能小於0或者大於等於360。
因此關羽和典韋單挑的時候,關羽喜歡用自己的技能D躲典韋的技能T,這就必須滿足在典韋技能T釋放的b(MS)時間內,關羽必須在空中。爲了簡化問題,我們認爲,關羽在起跳或者落地的瞬間,典韋的技能T對他是無效的。
裁判正式介紹技能後,ZYH(關羽)就和SN(典韋)開始單挑了,他們在打架多次後,ZYH(關羽)和SN(典韋)的血量都處於死亡的邊緣,此時SN(典韋)果斷使用了自己的技能T,希望可以把ZYH(關羽)殺了,而ZYH(關羽)也在同時使用了技能D。
現在ZYH(關羽)求救於你,希望你能幫他計算關羽能選擇的最小旋轉角度,他的命就掌握在你的手上,你可不能隨便應付吧。另外注意一點的就是,他們的技能現在只能釋放一次。
input:
輸入的第一行表示測試數據的組數N。
下面輸入包括N行,每行包括三個整數,分別表示a, b, d (1 ≤ a ≤ 10000, 1 ≤ b ≤ 10000, 1 ≤ d ≤ 10000)。
output:
如果ZYH(關羽)可以成功躲掉SN(典韋)的技能T,則輸出能成功躲避的最小旋轉角度(小數點後保留兩位有效數字)。否則輸出IMPOSSIBLE;每個輸出後都換一行。
題目來源:中南大學1020-真三國無雙
題目重讀:
有兩個角色,典韋和關羽
典韋的技能T主要有兩個階段a+b,a表示技能動畫,沒有傷害,b表示技能,帶有傷害
關羽的技能D主要有兩個階段c+d,
c表示轉身的時間,可以受到傷害,而且時間與旋轉的角度有關,c=角度*10;
d表示飛天,這段時間不受傷害
條件:
典韋和關羽同時使用技能,需要使關羽不受傷害
解題思路(好簡單,直接考慮恆等就行)
程序代碼
#0119.py
#真三國無雙
def getdata():
num = eval(input())
list = []
for i in range(num):
ele = input().split(" ")
list.append(ele)
return list
def main():
lst = getdata()
for i in lst:
if(i[1]>i[2]):
print("IMPOSSIBLE")
else:
num = (int(i[0])-int(i[2])+int(i[1]))/10
print("{:.2f}".format(num))
main()
運行結果:
-
(0121)-(最小子集)
給一
非負
整數數組. 取數組中的一部分元素, 使得它們的和大於數組中其餘元素的和, 求出滿足條件的元素數量最小值.
題目來源:領釦761—最小子集
題目重讀:
有幾個關鍵字,非負、大於、其餘、最小值
其中最小值即代表需要對數組進行降序排列,因爲只有不斷取出數組中的最大值,才能夠滿足最小這個條件;
其餘則表示取數即是對原數組進行彈出操作,數組的狀態是有所改變的
解題思路:
首相將數組中的數進行降序排列,再創建一個空的結果列表
不斷彈出已排序好的數組的第一個元素,並存入結果列表中;
每一次彈出存入,都對數組的元素進行求和操作
當結果列表的元素和大於問題數組的元素和時,返回結果解表的長度,即是答案。
程序代碼:
#lintcode-761-最小子集問題
#date:200121
#author:zhj1121
def getnums():
str = input("").split(",")
list_num = list(str)
list_int = []
for i in list_num:
list_int.append(int(i))
list_num = list_int
return list_num
def getlistsum(list):
sum = 0
for i in list:
sum+=i
return sum
def getresult(list):
list_result = []
for i in range(len(list)):
list_result.append(list.pop(0))
if(getlistsum(list_result)>getlistsum(list)):
return list_result
def main():
list = getnums()
list_sort = sorted(list)
list_sort.reverse()
list_result = getresult(list_sort)
print(len(list_result))
main()
運行結果:
-
(0123)-(夫妻手牽手)
N
對夫婦坐在2N
個排成一排的座位上. 現求最小的交換數量,使每對夫婦並坐一起,他們可以手牽着手。一次交換可選擇任何兩個人交換座位。
人和座位由從
0
到2N-1
的整數表示,夫妻按順序編號,第一對是(0,1)
,第二對是(2,3)
,以此類推,最後一對是(2N-2,2N-1)
。初始座位由
row [i]
給出,表示坐在第i
座位的人的編號。示例1:
input
3,2,0,1
output:
0
示例2:
input:
0,2,1,3
output:
1
題目來源:領釦LintCode—1043夫妻手牽手
題目重讀:
這裏提幾個關鍵的詞語和結論:
最大的數一定是奇數
當處理時,假定偶數是丈夫或者妻子都不會影響。
一個數只對應一個數,即一位丈夫對應一位妻子。且丈夫和妻子的位置誰在左誰在右都不會有影響
最少交換,即是不出現無效的交換,如果不規定最少,那麼可以通過多次交換實現排序,最後也是滿足條件的。
同時,如果每一次交換都有意義,那麼就是最少交換
例如,4對夫妻:
可以發現,只要保證每一次交換都有意義,即每一次交換都要“成全”一對夫妻,那麼就是最少交換。
解題思路:
將所有夫婦進行兩兩組合,不管是否是同一對夫妻。
對兩兩相鄰的人進行判斷,不僅對夫婦的編號,還對所處的位置進行處理。
例如[2,1,3,0]
這裏假定偶數是丈夫,奇數是妻子,妻子的編號爲丈夫的編號+1,這裏默認0是偶數
拿編號爲2來說,位置和編號都是偶數,該位置上是丈夫,所以需要找到對應的妻子,即3
丈夫在左邊,妻子在右邊
拿編號爲1來說,位置和編號都是奇數,那麼該位置上是妻子,所以需要找到對應的丈夫,即妻子的編號-1,即0
丈夫在左邊,妻子在右邊
拿編號爲3來說,位置是偶數,編號是奇數,則該位置是妻子,所以需要找到對應的丈夫,即妻子的編號-1,即2
放置在這位妻子的右邊 ,妻子在左邊,丈夫在右邊
拿編號爲0來說,位置是奇數,編號是偶數,則該位置是丈夫,所以需要找到對應的妻子,即丈夫的編號+1,即1
放置在這位丈夫的左邊,妻子在左邊,丈夫在右邊
這裏需要注意位置關係,左右,因爲只有這樣,才能保證不會造成一對夫婦分別在這排座位的兩側。
另外,當從左到右交換完成後,完成交換的部分不能進行再次交換,保證滿足最少交換的條件
程序代碼:
#lintcode-1043-夫妻手牽手
#author:zhj1121
def getrole(num):
if(num==0):
return True
else:
if(num%2==0):
return True
else:
return False
#找到一個數值i的位置list.index(x)
#交換列表i 和j的元素
def swap(i,j,list):
intermediray = list[i]
list[i] = list[j]
list[j] = intermediray
def getdata():
lst = input().split(",")
str_lst = list(lst)
int_lst = []
for i in str_lst:
int_lst.append(int(i))
return int_lst
def seegroup(list):
time = 0
#[1,2,3,0]
for i in range(len(list)-1):
#[2,1,0,3]第一個元素2
#最大的肯定不是偶數
if(getrole(list[i]) and getrole(i)):
if(list[i+1]!=list[i]+1):
swap(i+1,list.index(list[i]+1),list)
time+=1
#[0,2,1,3]的第二個元素 2
if(getrole(list[i]) and getrole(i)==False):
if(list[i-1]!=list[i]+1):
swap(i-1,list.index(list[i]+1),list)
time+=1
#[1,2,0,3]的第一個元素1
if(getrole(list[i])==False and getrole(i)):
if(list[i+1]!=list[i]-1):
swap(i+1,list.index(list[i]-1),list)
time+=1
#[2,1,0,3]的第二個元素1,3
if(getrole(list[i])==False and getrole(i)==False):
if(list[i-1]!=list[i]-1):
swap(i-1,list.index(list[i]-1),list)
time+=1
return time
def main():
lst = getdata()
time = seegroup(lst)
print(time)
main()
運行結果:
-
(0125)-(人民幣轉換)
描述:
將財務數字轉換漢語中人民幣的大寫
input:
107000.53
output:
壹拾萬柒仟元伍角叄分
題目來源:之前的一道算法作業題目,之前的代碼量將近200多行,而且存在bug,所以重寫
解題思路:(分治法)
首先對輸入的金額,進行分離,分離小數點前後兩部分。分開處理。
小數部分,有4種可能,見函數marklittlenum(num)
整數部分,以4個數字爲一個整體,因爲人民幣金額就是這種模式,例如:
1234,5678,9123:
12個數字,有3部分,第一部分是9123,單位是元
第二部分是5678,單位是萬
第三部分是1234,單位是億
如果有第四部分,單位是萬
當億億出現時,即是兆
所以處理好每一部分,4位數字,則處理好整體。
另外還有一些細節,不再贅述。
程序改進:有多處判斷結構可以優化。另外,之前的多個金額出現bug,現在經過多次測試,暫時未發現存在的bug。
程序代碼:
#name:人民幣轉換
author:zhj1121
date:200127
def textList(list):
result = []
str0 = "拾佰仟"
str2 = "零壹貳叄肆伍陸柒捌玖"
for i in list:
if(len(i)==1):
result.append(str2[int(i)])
if(len(i)==2):
result.append(str2[int(i[0])]+'拾'+str2[int(i[1])])
if(len(i)==3):
result.append(str2[int(i[0])]+'佰'+str2[int(i[1])]+'拾'+str2[int(i[1])])
if(len(i)==4):
result.append(str2[int(i[0])]+'仟'+str2[int(i[1])]+'佰'+str2[int(i[2])]+'拾'+str2[int(i[3])])
return result
def split_num(num):
num_str = str(num)
len_num = len(num_str)
data = []
#如果長度是4的倍數
if(len_num%4==0):
total = int(len_num/4)
for i in range(total):
data.append(num_str[4*i:4*i+4])
#如果長度不是4的倍數
else:
for i in range(4-len_num%4):
num_str = '0'+num_str
total = int(len(num_str)/4)
for i in range(total):
data.append(num_str[4*i:4*i+4])
return data
def markzero(list):
result =[]
#處理單位左邊爲零的情況
for i in list:
#零仟零佰肆拾壹
#list = ['零仟伍佰陸拾肆', '陸仟零佰捌拾柒', '陸仟伍佰零拾肆']
#'零仟零佰零拾柒'
if("零仟" in i or "零佰" in i or "零拾" in i):
while("零仟" in i):
i = i.replace("零仟","零")
while("零佰" in i):
i = i.replace("零佰","零")
while("零拾" in i):
i = i.replace("零拾","零")
result.append(i)
else:
result.append(i)
#處理2個零
list = result
result = []
for i in list:
while("零零" in i):
i = i.replace("零零","零")
while("拾零" in i):
i = i.replace("拾零","拾")
result.append(i)
return result
def marklittlenum(num):
str1 = str(num)
list1 = list(str1)
littlnum = []
while("." in list1):
littlnum.append(list1.pop(-1))
while("." in littlnum):
littlnum.pop(-1)
littlnum.reverse()
if(len(littlnum)!=0):
int_list = []
for i in littlnum:
int_list.append(int(i))
str2 = "零壹貳叄肆伍陸柒捌玖"
if(len(int_list)>1):
if(int_list[0] ==0 and int_list[1] != 0):
result_str = '零'+str2[int_list[1]]+'分'
if(int_list[0] !=0 and int_list[1] != 0):
result_str = str2[int_list[0]]+"角"+str2[int_list[1]]+"分"
else:
if(int_list[0] ==0):
result_str = '整'
else:
result_str = str2[int_list[0]]+"角"
else:
result_str='整'
return result_str
def main():
num = eval(input())
data_lst = split_num(int(num))
lst = textList(data_lst)
delzero = markzero(lst)
list = ['元','萬','億','萬']
while(len(list)!=len(delzero)):
list.pop(-1)
list.reverse()
result = []
while(len(delzero)!=0):
result.append(delzero.pop(0))
result.append(list.pop(0))
if(result[0][0]=="零"):
result[0] = result[0][1:]
if(result[-2][-1]=="零"):
result[-2] = result[-2][:-1]
for i in result:
print(i,end="")
print(marklittlenum(num))
main()
運行結果:
-
(0127)-(不同的二叉查找樹)
給出 n,問由 1...n 爲節點組成的不同的二叉查找樹有多少種?
input:
3
output:
5
解釋:
題目來源:領釦LintCode163—不同的二叉查找樹
解題思路:
卡特蘭數的變形,所以可以像之前的走迷宮的一樣,引用模板就可以了
程序代碼:
def katelanshu(n):
if(n==0):
return 1
else:
n+=1
lst = []
for i in range(n):
lst.append([])
for j in range(n):
lst[i].append(1)
for x in range(n):
for y in range(n):
if(x>y):
lst[x][y] = 0
elif(x==0 and y!=0):
lst[x][y]=1
elif(x!=0 and y==0):
lst[x][y]=0
elif(x==0 and y==0):
lst[x][y]=0
else:
lst[x][y]=lst[x][y-1]+lst[x-1][y]
n -=1
return lst[n][n]
def main():
num = eval(input())
result = katelanshu(num)
print(result)
main()
運行結果:
-
(0129)-(加油站)
在一條環路上有 N 個加油站,其中第 i 個加油站有汽油
gas[i]
,並且從第_i_個加油站前往第_i_+1個加油站需要消耗汽油cost[i]
。你有一輛油箱容量無限大的汽車,現在要從某一個加油站出發繞環路一週,一開始油箱爲空。
求可環繞環路一週時出發的加油站的編號,若不存在環繞一週的方案,則返回
-1
。(!注意:數據保證算法答案只有一個)
示例1:
input:
gas[i]=[1,1,3,1],cost[i]=[2,2,1,1]
output:
2
示例2:
input:
gas[i]=[1,1,3,1],cost[i]=[2,2,10,1]
output:
-1
題目來源:領釦LintCode—187加油站
解題思路:
題目有個地方需要注意,就是公路是環形公路,最後一站和第一站是相連的。即如下圖:
另外,汽車是可以從任何一個站出發,但只有從其中的一個站出發,才能環路一週。
法1:
對所有的可能進行遍歷,n個站,就有從n個站出發的可能。例如[0,1,2]
就有以下:[0,1,2],[1,2,0],[2,0,1]種可能
再對每一種可能進行模擬,當出現costSum>gasSum時,則這種方案不可能
當某一種可能滿足後,即彈出這種可能的出發的站點,即第0個元素
法2:
也是以上的解決方法,但拿到數據後,首先會每個加油站的油量以及到達下一個加油站的耗油量作差,當差值爲負值時,即從該站出發時,連下一個加油站都無法到達,那麼這種可能即被排除。
另外,將到達每個加油站的差值相加,當出現負值時,即代表無法到達下一個加油站,則進行排除。
當滿足條件的可能出現時,彈出出發加油站的序號即可。
程序代碼:
法1:(直接遍歷查找所有的可能)
#0129.py
#加油站
def listSum(list):
sum = 0
for i in list:
sum+=i
return sum
def possResult(num):
resultList = []
numList = []
count = 0
while(count<2):
count+=1
for i in range(num):
numList.append(i)
for x in range(num):
lst = []
for y in range(num):
lst.append(numList[x+y])
resultList.append(lst)
return resultList
def getResult(gas,cost,possResult):
if(listSum(cost)>listSum(gas)):
return -1
else:
for i in possResult:
gasSum = 0
costSum = 0
indexSum = 0
for j in range(len(i)):
indexSum +=gas[i[j]]
if(gasSum>=costSum):
gasSum+=gas[i[j]]
costSum+=cost[i[j]]
else:
break
if(gasSum==indexSum):
return i[0]
def main():
gas = []
cost = []
inputlst1 = input().split(",")
for i in list(inputlst1):
gas.append(int(i))
inputlst2 = input().split(",")
for i in list(inputlst2):
cost.append(int(i))
listlen = len(gas)
possList = possResult(listlen)
print(getResult(gas,cost,possList))
main()
法2:
#加油站
#date:200130
def takeSecond(elem):
return elem[1]
def getdiffvalue(gas,cost):
result = []
for i in range(len(gas)):
tuple = (i,gas[i]-cost[i])
result.append(tuple)
return result
def getPosResult(list):
result = []
for i in range(len(list)):
if(list[i][1]>=0):
result.append(list[i])
return result
def possList(diffList,posList):
numList = []
lenList = len(diffList)
count = 0
while(count<2):
count+=1
for i in range(lenList):
numList.append(i)
#return numList
middList = []
for x in range(lenList):
lst = []
for y in range(lenList):
lst.append(numList[x+y])
middList.append(lst)
result = []
for i in posList:
lst = []
for j in middList:
if(j[0]==i[0]):
result.append(j)
return result
def run(possList,diffList):
Listsum = 0
for i in diffList:
Listsum+=i[1]
if(Listsum<0):
return -1
else:
for i in possList:
sum = 0
indexsum = 0
count = 0
for j in i:
indexsum += diffList[j][1]
if(sum>=0):
sum += diffList[j][1]
else:
break
if(indexsum==sum):
return i[0]
def main():
gas = []
cost = []
inputlst1 = input().split(",")
for i in list(inputlst1):
gas.append(int(i))
inputlst2 = input().split(",")
for i in list(inputlst2):
cost.append(int(i))
diffList = getdiffvalue(gas,cost)
# print(diffList)
sort_diffList= getdiffvalue(gas,cost)
sort_diffList.sort(key=takeSecond,reverse=True)#每個加油站差值#排好序的
#print(sort_diffList)
posList = getPosResult(sort_diffList)#能出發的加油站
#print(posList)
possResult = possList(sort_diffList,posList)#幾種可能
#print(possResult)
result = run(possResult,diffList)
print(result)
main()
運行結果:
-
(0131)-(會議室Ⅱ)
給定一系列的會議時間間隔intervals,包括起始和結束時間
[[s1,e1],[s2,e2],...] (si < ei)
,找到所需的最小的會議室數量。input:
s[0]=0
e[0]=30s[1]=5
e[1]=10s[2]=15
e[2]=20output:
2
解釋:
需要兩個會議室:會議室1:(0,30) ;會議室2:(5,10),(15,20)
題目來源:領釦LintCode—919會議室 II
解題思路:很像0113的巨人排隊,以及之前的貪心算法解決活動安排問題。具體見上
區別在於:會議安排是所有的會議都記錄在紙上的,所以是可以排序的。根據會議的開始時間進行升序排列
另外用一個會議室列表記錄數值,該數值應該是會議的結束時間。進行比較時,應該是會議室列表的數值,即會議的結束時間和會議的開始時間
程序代碼:
#0131—會議室2
def takeSecond(elem):
return elem[0]
def findindex(list):
for i in range(len(list)):
if(list[i]==1):
return i
return -1
def trueorfalse(ele,list):
tf_list = [0 for i in range(len(list))]
for i in range(len(list)):
if(list[i]<=ele):
tf_list[i] = 1
return tf_list
def meeting(meetList):
roomList = []
roomList.append(meetList[0][1])
for i in range(1,len(meetList)):
tf_list = trueorfalse(meetList[i][0],roomList)
if(findindex(tf_list)==-1):
roomList.append(meetList[i][1])
else:
roomList[findindex(tf_list)]=meetList[i][1]
return roomList
def main():
num = eval(input(""))
meetList = []
for i in range(num):
input_start =eval(input("s["+str(i)+"]="))
input_finish =eval(input("e["+str(i)+"]="))
tuple = ()#purpose:def tuple to save the act_start and act_finish
tuple = (input_start,input_finish)
meetList.append(tuple)
del tuple
print("")
#meetList = [(0,30),(5,10),(15,20),(7,20),(2,3)]
meetList.sort(key=takeSecond)#根據會議的開始時間進行排序
roomList = meeting(meetList)
print(len(roomList))
main()
運行結果:
-
總結
2020年的第一個月份,也是以月份爲單位開始寫算法刷題集的第一個月份。工作已經全部完成。之後可能會進行補充以及更新。
對於這套刷題集,怎麼說呢,感覺完成得不盡如意。
首先,很多題目都是使用窮舉法進行解答,列出所有可能,並對每一種可能進行排除,這樣做雖然能得到正確的答案,但是卻不是比較好的方式。
另外,有許多題目解決了,總結卻寫得不怎麼好,以及一些題目的多種解法突然想到了,卻沒有記錄下來。
不過,這一個月還是有所收穫的。二月份會繼續,但會設置爲3天/篇,其實到中間的時候,就想要這樣,但有始有終,定下的目標就得完成。從2月份開始,3天/篇,這樣就可以進行總結和不會干涉其它的安排。