offer46的题意要求是:先定义在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。然后input一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果output, 即输出P%1000000007。
暴力法
对时间复杂度不作要求时,顺序扫描整个数组,每扫描到一个数字的时候,逐个比较该数字和它后面的数字的大小。如果后面的数字比它小,则这两个数字就组成一个逆序对。这样时间复杂度是 O ( n 2 ) O(n^2) O(n2)
# offer46-solution 1
def InversePairs(self, data):
if len(data) <= 1:
return 0
count = 0
length = len(data)
for i in range(length - 1):
for j in range(i + 1, length):
if data[i] > data[j]:
count += 1
return count % 1000000007
暴力优化+排序
在暴力法的基础上进行sort及时排序和一些优化,可以让时间复杂度降低至 O ( n l o g n ) O(nlogn) O(nlogn)
# offer46-solution 2
def InversePairs(self, data):
if len(data) <= 0:
return 0
count = 0
copy = [] # 预处理
for i in range(len(data)):
copy.append(data[i]) # 对于每一个data,先加进copy数组中
copy.sort() # 然后立刻排序
i = 0
while len(copy) > i:
count += data.index(copy[i]) # 由于输入的数不相同,对于每一个数,count+
data.remove(copy[i])
i += 1
return count % 1000000007
归并排序
关于归并排序,其实我一开始也没想到,而且自己写代码也写得奇奇怪怪,请参考下面的链接的解说。以下是我照猫画虎写的代码。
剑指Offer(三十五):数组中的逆序对
# offer46-solution 3
class Solution:
# 归并排序法
def InversePairs(self, data):
if len(data) <= 0:
return 0
length = len(data)
copy = [0] * length
for i in range(length):
copy[i] = data[i]
# copy数组为原数组data的复制,在后面充当辅助数组
count = self.Core(data, copy, 0, length - 1)
return count % 1000000007
def Core(self, data, copy, start, end):
if start == end:
copy[start] = data[start]
return 0
length = (end - start) // 2 # length为划分后子数组的长度
left = self.Core(copy, data, start, start + length)
right = self.Core(copy, data, start + length + 1, end)
# 初始化i为前半段最后一个数字的下标
i = start + length
# 初始化j为后半段最后一个数字的下标
j = end
# indexCopy为辅助数组的指针,初始化其指向最后一位
indexCopy = end
# 准备开始计数
count = 0
# 对两个数组进行对比取值的操作:
while i >= start and j >= start + length + 1:
if data[i] > data[j]:
copy[indexCopy] = data[i]
indexCopy -= 1
i -= 1
count += j - start - length
else:
copy[indexCopy] = data[j]
indexCopy -= 1
j -= 1
# 剩下一个数组未取完的操作:
while i >= start:
copy[indexCopy] = data[i]
indexCopy -= 1
i -= 1
while j >= start + length + 1:
copy[indexCopy] = data[j]
indexCopy -= 1
j -= 1
return count + left + right