天天看點

程式員的算法趣題Q10: 輪盤的最大值1. 問題描述2. 解題分析3. 代碼及測試

目錄

1. 問題描述

2. 解題分析

3. 代碼及測試

1. 問題描述

        輪盤遊戲被稱為“賭場女王”。流傳較廣的輪盤數字排布和設計有“歐式規則”和“美式規則”兩種。兩種輪盤上的數字序列分别如下所示:

        歐式規則:

0,32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1,20,14,31,9,22,18,29,7,28,12,35,3,26

        美式規則:

0,28,9,26,30,11,7,20,32,17,5,22,34,15,3,24,36,13,1,00,27,10,25,29,12,8,19,31,18,6,21,33,16,4,23,35,14,2

        下圖是歐式規則的輪盤示意圖(侵删)。

程式員的算法趣題Q10: 輪盤的最大值1. 問題描述2. 解題分析3. 代碼及測試

        下面我們找到這些規則下“連續n個數字之和”最大的位置。舉個例子,當n=3時,按照歐式規則得到的最大的組合是36,11,30這個組合,和為77;而美式規則下則是24,36,13這個組合,得到的和為73.(圖中所示輪盤為歐式規則的輪盤,注意輪盤是圓形的)

        問題:當 2 ≤ n ≤ 36時,求連續n個數之和最大的情況,并找出滿足條件“歐式規則下的最大和小于美式規則下的最大和”的n的個數。

2. 解題分析

        求連續n個數字的平均(本題是求和,但是求和與求平均隻差一個平均系數,求平均也是也先求和再除以參與求和的資料的個數)在信号處理領域中稱為求移動平均(moving average, or running average),其計算方式有一個小小的trick。令資料序列用x[k]表示,則從第m數開始的連續n個數的累加和的計算可以表示如下:

程式員的算法趣題Q10: 輪盤的最大值1. 問題描述2. 解題分析3. 代碼及測試

        這樣就得到了一個遞推關系,從上一個連續和sum[m-1]開始,隻要把減去最前面一個數,加上後面一個數就可以得到新的sum[m]。這樣可以極大地降低運算複雜度,在信号處理領域是常用技巧。

       本題還有另外一個需要注意的要點就是輪盤是圓形的,用線性數組表示輪盤上的數字排列數組的話,一部分的連續和涉及到頭上一部分數字和尾巴上一部分數字的求和。最基本的做法就是用位址對數字長度進行求模運算。也可以用對數組進行線性擴充的方法以避免位址求模的處理。由于這個問題比較簡單,本題解就用“簡單粗暴”的前者對付一下了。

3. 代碼及測試

# -*- coding: utf-8 -*-
"""
Created on Sun Aug 29 07:14:15 2021

@author: chenxy
"""

import sys
import time
import datetime
# import random
from   typing import List
# from   queue import Queue
# from   collections import deque

class Solution:

    euroRule= [0,32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1,20,14,31,9,22,18,29,7,28,12,35,3,26]
    usaRule = [0,28,9,26,30,11,7,20,32,17,5,22,34,15,3,24,36,13,1,0,27,10,25,29,12,8,19,31,18,6,21,33,16,4,23,35,14,2]
    
    def maxSum(self, nums:List, n:int) -> int:
        runningSum = sum(nums[0:n]) # The sum of the first n numbers as initial value
        sumMax     = runningSum

        M = len(nums)
        for k in range(1,len(nums)):
            runningSum += nums[(k+n-1)%M] - nums[k-1]
            if sumMax < runningSum:
                sumMax = runningSum
            # print('k ={0},runningSum={1},sumMax={2}'.format(k,runningSum,sumMax))        
        return sumMax
    
    def maxCoronaSum(self, nMin:int, nMax:int) -> List:
        """
        :
        :ret:   The list of numbers satisfying the condition.
        """                
        ans     = []
        
        for n in range(nMin, nMax+1):
            euroMax = self.maxSum(self.euroRule,n)
            usaMax  = self.maxSum(self.usaRule,n)
            # print('n ={0},euroMax={1},usaMax={2}'.format(n,euroMax,usaMax))
                
            if euroMax < usaMax:
                print('n={0}, euroMax={1}, usaSum={2}'.format(n,euroMax,usaMax))
                ans.append(n)
        
        return ans
                
if __name__ == '__main__':        
            
    sln    = Solution()    

    tStart = time.time()
    ans    = sln.maxCoronaSum(2,36)
    tCost  = time.time() - tStart
    print('nums ={0}, tCost = {1:6.3f}(sec)'.format(len(ans),tCost))        
    print('ans  ={0}'.format(ans))   
           

        運作結果:

程式員的算法趣題Q10: 輪盤的最大值1. 問題描述2. 解題分析3. 代碼及測試

       上一篇:Q08: 優秀的機器人

        下一篇:

        本系列總目錄參見:程式員的算法趣題:詳細分析和Python全解