雙周賽111。

題目

輸入長度n的整數陣列nums,以及整數target。

求有多少數對(i, j)滿足0 <= i < j < n 且 nums[i] + nums[j] < target。

解法

暴力枚舉所有數對。

時間複雜度O(N^2)。
空間複雜度O(1)。

class Solution:
    def countPairs(self, nums: List[int], target: int) -> int:
        N=len(nums)
        ans=0
        
        for i in range(N):
            for j in range(i+1,N):
                if nums[i]+nums[j]<target:
                    ans+=1
                    
        return ans

也可以從左向右枚舉j,左邊遍歷過的都是i的候補。
題目要求nums[i]+nums[j] < target,則nums[i]的最大值就是target-nums[j]-1,用二分搜去找到最後一個符合的位置。

時間複雜度O(N log N)。
空間複雜度O(N)。

from sortedcontainers import SortedList as SL

class Solution:
    def countPairs(self, nums: List[int], target: int) -> int:
        sl=SL()
        ans=0
        for x in nums:
            t=target-x-1
            idx=sl.bisect_right(t)-1
            ans+=idx+1
            sl.add(x)
            
        return ans

我們只在乎任意兩數的總和,不在乎其原始位置。
將nums排序後,以雙指針維護兩數的位置,如果nums[lo]+nums[hi]小於target,代表nums[lo]配上nums[lo+1,hi]之間的所有數都可以滿足;若大於等於target則將hi左移。

瓶頸在於排緒,時間複雜度O(N log N)。
空間複雜度O(1)。

class Solution:
    def countPairs(self, nums: List[int], target: int) -> int:
        N=len(nums)
        nums.sort()
        ans=0
        lo=0
        hi=N-1
        
        while lo<hi:
            if nums[lo]+nums[hi]<target:
                # nums[lo] can match any nums[i]
                # where lo+1 <= i <= hi
                ans+=hi-(lo+1)+1 
                lo+=1
            else:
                hi-=1
                
        return ans