题意:给定一个1~n的排列a0,a1,a2,.....,a(n-1),求对这个数列进行冒泡排序所需要的交换次数。
在数据较大时,用常规的双重for循环来求解交换次数就会因为复杂度太高而存在TLE的情况,所以可以利用树状数组善于查询两个数之间的数字和的优势进行解题。
首相树状数组的基本操作就是BIT的求和以及BIT的值的更新,那么如何要在没有if语句比较的情况下进行前后数值大小的比较进而求出交换次数和,首相应该了解交换的次数和即为数组中存在的i<j,array[i]>array[j]的逆序树对的和,所以对于每个位置的数array[i]只要能够求出其之前存在的大于这个数的个数即可,而在数组中两个数在不满足i<j&&array[i]<=array[j]的情况就是逆序数对的数量,则可以将其转变成i-非逆序数对的个数。
以数组array[9]={1,2,3,4,5,6,7,8,9}为例,用sum(array[i])函数求出在在这次操作之前i位置前有多少个比array[i]要小的数,即非逆序数,再用add(array[i],1)函数在i位置后面说明该位置之前已有多少比这个数要小的数的个数,经过一重for循环即可计算出所有的i位置前的逆序树,相加和即为冒泡排序需要交换的交换次数。每次进行sum和add操作的负复杂度为O(log n),所以该方法的复杂度为O(n*log n)。注意:BIT中的下标表示的是array数组中的元素值,所以在数组元素少或者元素的值分别为1~n中的整数,则可以直接进行树状数组BIT的建立,不然需要先将数组元素值进行离散化来达到符合题目限制条件。
体悟:树状数组利用位置特性做到了不用if语句比较前后数值大小而求出了交换次数,在算法的复杂度上也较朴素算法有大的提升。这主要是依赖于树状数组的善于计算区间数值和做到的。树状数组使用的难点主要还是用的次数太少,写起代码来不足够熟练,还以还是应该通过训练来解决这一问题。