演算法趣題(二)

2021-08-28 19:09:29 字數 3351 閱讀 2098

問題:有一組寫著數字 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 張牌翻牌 原本背面朝上 的,翻轉成正面朝上 原本正面朝上的,翻轉成背面朝上 再接下來...