問題:有一組寫著數字 1
11~100
10010
0 的紙牌,按照從小到大的順序排列著。最開始所有的紙牌都背面朝上。接下來按照規則翻牌:第一次從第 2
22 張紙牌開始,隔一張牌翻牌,於是第 2、4
、6、8
、...
、100
2、4、6、8、... 、100
2、4、6、
8、..
.、10
0 位置的牌會變成正面朝上;第二次從第 3
33張紙牌開始,每隔 2
22 張牌翻牌,於是第 3、6
、9、.
..、99
3、6、9、... 、99
3、6、9、
...、
99位置的牌中,原本正面朝上的變成背面朝上,原本背面朝上的牌變成正面朝上;依次類推,從第 n
nn張牌開始,每隔 n−1
n-1n−
1 張牌翻牌,直到沒有可以翻的牌為止。
求當所有的牌都不再變動的時候,所有背面朝上的紙牌數字是哪些?
分析:
演算法:
python**實現
cards =
[true
for i in
range
(100)]
for i in
range(2
,101):
for j in
range
(i,101
, i)
:if cards[j-1]
: cards[j-1]
=false
else
: cards[j-1]
=true
print
([i+
1for i in
range
(100
)if cards[i]
istrue])
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
演算法優化
分析:
演算法:
python**實現
cards =
[true
for i in
range
(100)]
for i in
range(1
,101):
# 如果除不盡有餘數,則說明沒有約數是奇數個
if i % i**(1
/2):
cards[i-1]
=false
print
([i+
1for i in
range
(100
)if cards[i]
istrue])
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
這樣**只需要一次遍歷就能夠得出結果了,這樣演算法的時間複雜度是:o(n
)o(n)
o(n)
。事實上,還可以將演算法的**進一步抽象為對數字的處理,而不是停留在紙牌的翻動處理上。這樣的演算法不但簡潔,而且又進一步地降低了演算法的時間複雜度,最終的時間複雜度為:o(n
)o( \sqrt )
o(n) 。
最好的演算法
import math
cards =
[i**
2for i in
range(1
,int
(math.sqrt(
101))+
1)if i**
2<=
101]
print
(cards)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
問題:假設要把長度為 n 厘公尺的木棒切分為 1 厘公尺長的小段,但是 1 根木棒只能由 1 個人切分。當木棒被切成大於等於 m 段時,可以同時由 m 個人同時切分木棒。分別求當 n = 20,m = 3 時,當 n = 100,m = 5時,最少的切分次數?
分析:
演算法:
python**實現
def
cutbar
(n, m, current)
:"""
:param n: 木棒的長度
:param m: 人數
:param current: 當前小木棒的數量
:return:切分操作的次數
"""if current >= n:
return
0elif current < m:
return
1+ cutbar(n, m, current *2)
else
:return
1+ cutbar(n, m, current + m)
print
(cutbar(20,
3,1)
, cutbar(
100,5,
1))# 8 22
另一種演算法
按照順序的思維來解決這道題,會難以發現演算法無需擔心木棒是否可再分割的關鍵,這是上面演算法的難點所在。
其實對於本題,問題的關鍵就在於:木棒的原長度與小木棒的數量之間的關係
分析:
演算法:
def
cutbar
(n, m)
:"""
:param n:原木棒長度
:param m: 人數
:return:拼接的次數
"""count =
0 current =
1while current < n:
# 實現三目運算子
current += current if current < m else m
count +=
1return count
print
(cutbar(20,
3), cutbar(
100,5)
)# 8 22
同樣的,這個演算法也是無法避免小木棒數量的增多的問題。但通過轉換思路的角度考慮,不再顯得很難懂了。 二叉樹演算法趣題
二叉樹中的節點x含有乙個變數wealth表徵了該節點的財富,定義二叉樹中節點x的heritage為其祖先節點 包括x 的所有wealth之和減去節點x的子孫節點的所有wealth之和。求二叉樹中heritage最大的節點及其值。要求不能改變原有二叉樹的結構,不能在節點之上儲存別的資訊,演算法複雜度盡...
程式設計師的演算法趣題Perl版 (二)
竟然一月一更。第四題 假設一根木棒n厘公尺,需要切分為一厘公尺長的木棒,每根木棒只可以乙個人切,木棒切成兩根可以兩個人切 求 n厘公尺長木棒,m個人最少要切幾次,比如n 8,m 3,則需要切4次。perl 20170930 use strict sub cut elsif currentparts ...
演算法趣題Q3 翻牌
這裡有100 張寫著數字1 100 的牌,並按順序排列著。最開始所有 牌都是背面朝上放置。某人從第2 張牌開始,隔1 張牌翻牌。然後第2,4,6,100 張牌就會變成正面朝上。接下來,另乙個人從第3 張牌開始,隔2 張牌翻牌 原本背面朝上 的,翻轉成正面朝上 原本正面朝上的,翻轉成背面朝上 再接下來...