1. 程式人生 > 實用技巧 >“粉刷天花板”天池線上程式設計測試賽題九章演算法題解題思路

“粉刷天花板”天池線上程式設計測試賽題九章演算法題解題思路

你想給自己蓋棟房子。房子是正方形或長方形的,它的長和寬需要屬於集合s,並且其面積不超過a。請問有多少組可能的長寬的組合?
集合s的n個元素的計算方法如下,給定了一個種子s0,和引數k,b和m,並通過以下公式計算:
Si=((k*Si-1+b) mod m+ 1+Si-1) 1<=i<n

樣例
樣例 1

輸入:
s_0 = 2
n = 3
k = 3
b = 3
m = 2
a = 15
輸出: 5
說明:
對於樣例,給定了s0=2和總長度n=3,同時還有k=3、 b=3 和 m=2:

現在我們有了長度的集合,我們可以暴力的計算答案,當a=15時,有:

s = [2,4,6]s=[2,4,6]

思路:

  • 首先按照題意先把集合s計算出來。
  • 並按照升序排列
  • 下一步開始計算結果。

解法1: 雙迴圈的暴力遍歷(×)

def solve(s0,k,b,m,n,a):
    list1=[s0]
    temp=s0
    for x in range(n-1):#算出全部陣列
        temp=(k*temp+b)%m+1+temp
        list1.append(temp)
    list1.sort()  #排序
    print(list1)
    
    sum=0
    for x in range(n):
        for y in range(n):  #因為要包括正方形
            if (list1[x]*list1[y])<=a:
                sum+=1
#                 print(list1[x],list1[y],'True')
            else:
#                 print(list1[x],list1[y],'False')
                break  #已經超了,後面不必再算了
    print(sum)        
solve(2,3,3,2,3,15)

解法2:左右雙指標(√)

解題思路:以如下結果集s為例,a=60
[2, 4, 6, 8, 10, 12, 14, 16]

設定左右兩個指標

初始時 左指標指向2,右指標指向16
計算 216是否超過a
如果超過了,則 右指標減一 ,重新迴圈
如果沒超過,則開始計算 左指標到右指標中間這塊資料會產生多少種結果
以左指標2 右指標16 為例,
right=7
left=0
right-left=7
7
2=14
也就是
集合[[2,4],[2,6],[2,8],[2,10],[2,12],[2,14],[2,16],[4,2],[6,2],[8,2],[10,2],[12,2],[14,2],[16,2]]
最後別忘了還有一個 [2,2]

然後 右指標不動,左指標加一,再開始一輪

def painttheCeiling(s0, n, k, b, m, a):

    list1=[s0]
    temp=s0
    for x in range(n-1):
        temp=(k*temp+b)%m+1+temp
        list1.append(temp)
    list1.sort()

    sum=0       
    left=0
    right=n-1    
    
    while True:
        if left==right: #撞上的時候就可以結束迴圈了
            if (list1[left]*list1[right])<=a:
                sum+=1
            break
        if (list1[left]*list1[right])>a:
            right-=1
        else:
            sum=sum+(right-left)*2+1  #解法的數量有規律
            left+=1
        return sum
    
painttheCeiling(2,8,3,3,2,60)