📅  最后修改于: 2023-12-03 15:06:44.453000             🧑  作者: Mango
在计算机科学中,计数问题是一个非常基础且重要的问题。给定一个数组,我们需要计算有多少对(x,y)满足x<y。
最简单的方法是使用两个嵌套循环来遍历每一个可能的(x,y)对,判断它们是否满足x<y。这个算法的时间复杂度为O(N^2)。
count = 0
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] < nums[j]:
count += 1
return count
我们可以使用归并排序来优化暴力法。在归并排序的过程中,如果左边的元素小于右边的元素,那么左边的元素就会与右边的所有元素匹配。因此我们可以在归并排序的merge函数中加入一个计数器count,用来统计有多少次左边的元素比右边的元素小。
count = 0
def merge(nums, left, mid, right, temp):
i, j, k = left, mid+1, left
while i <= mid and j <= right:
if nums[i] <= nums[j]:
temp[k] = nums[i]
i += 1
else:
temp[k] = nums[j]
j += 1
count += mid - i + 1
k += 1
while i <= mid:
temp[k] = nums[i]
i += 1
k += 1
while j <= right:
temp[k] = nums[j]
j += 1
k += 1
nums[left:right+1] = temp[left:right+1]
def mergeSort(nums, left, right, temp):
if left < right:
mid = (left + right) // 2
mergeSort(nums, left, mid, temp)
mergeSort(nums, mid+1, right, temp)
merge(nums, left, mid, right, temp)
def countPairs(nums):
global count
count = 0
temp = [0] * len(nums)
mergeSort(nums, 0, len(nums)-1, temp)
return count
时间复杂度为O(NlogN)。
树状数组是一个非常高效的数据结构,可以在O(logN)的时间复杂度内修改和查询区间和。我们可以使用树状数组来快速计算(x,y)对使得x<y的个数。
首先将数组从小到大排序,遍历数组,对于每一个元素x,用树状数组查询0~x之间的元素个数sum,那么(x,y)对使得x<y的个数就是sum。
def countPairs(nums):
def lowbit(x):
return x & (-x)
n = len(nums)
sorted_nums = sorted(nums)
tree = [0] * (n+1)
def query(x):
res = 0
while x > 0:
res += tree[x]
x -= lowbit(x)
return res
def update(x, val):
while x <= n:
tree[x] += val
x += lowbit(x)
count = 0
for i in range(n):
x = nums[i]
rank = bisect.bisect_left(sorted_nums, x) + 1
count += i - query(rank-1)
update(rank, 1)
return count
时间复杂度为O(NlogN)。