忘記是哪題的相似題,加入代辦清單之後就不記得了,反正就是多寫幾次。

題目

有n個士兵排成一列,且每個士兵都被分配了一個獨特的等級值。
你必須根據以下規則來將士兵分組:

  • 選擇三個士兵,索引分別為i,j,k,且i<j<k
  • 必須滿足rating[i]<rating[j]<rating[k]或是rating[i]>rating[j]>rating[k]

求有多少可以分組的方法。

解法

要三個不同的數,呈現嚴格遞增或遞減,最簡單的方法是三個迴圈列舉(i,j,k)組合並判斷,複雜度O(N^3)。
聽說一開始N只有100,所以還不會超時,現在變成1000,這種方法肯定是不行。

將暴力法稍微改進一下,變成列舉中間點,然後分別計算左右大小數,倆倆相乘就是可行的組合數。
題目有特別提到,每個數字都是獨特的,意味著不需要考慮數字相等的問題。因此,若左方較小數有x,那麼左方較大數則為(左方總數-x)。

class Solution:
    def numTeams(self, rating: List[int]) -> int:
        N=len(rating)
        ans=0
        
        for i in range(1,N-1):
            lsmall=rsmall=0
            for j in range(i):
                if rating[j]<rating[i]:
                    lsmall+=1
            for j in range(i+1,N):
                if rating[j]<rating[i]:
                    rsmall+=1
            lbig=i-lsmall
            rbig=N-i-1-rsmall
            ans+=(lsmall*rbig)+(lbig*rsmall)
            
        return ans

使用BIT來計算較小的數。
lt和rt分別記錄左右方的數字,一開始要先遍歷一次rating,全部加入rt裡面做初始化。
之後再遍歷一次rating的每個數字n,計算出可用的組合數量後,對lt加入n,對rt扣除n。

class BinaryIndexedTree:

    def __init__(self, n):
        self.bit = [0]*(n+1)
        self.N = len(self.bit)

    def update(self, index: int, val: int) -> None:
        index += 1
        while index < self.N:
            self.bit[index] += val
            index = index + (index & -index)

    def prefixSum(self, index: int) -> None:
        index += 1
        res = 0
        while index > 0:
            res += self.bit[index]
            index = index - (index & -index)
        return res

class Solution:
    def numTeams(self, rating: List[int]) -> int:
        N=len(rating)
        lt=BinaryIndexedTree(10**5+5)
        rt=BinaryIndexedTree(10**5+5)
        ans=0
        
        for r in rating:
            rt.update(r,1)
        
        for i,n in enumerate(rating):
            lsmall=lt.prefixSum(n-1)
            rsmall=rt.prefixSum(n-1)
            lbig=i-lsmall
            rbig=N-i-1-rsmall
            ans+=(lsmall*rbig)+(lbig*rsmall)
            lt.update(n,1)
            rt.update(n,-1)
            
        return ans