数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,有一个数组为Array[0..n] 其中有元素a[i],a[j].如果 当i<j时,a[i]>a[j],那么我们就称(a[i],a[j])为一个逆序对。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。

花了很长时间想还是没有想出来怎么做,怎么也不服气。。。

最后还是折服了,上网查。。。

才看到文章的 “排序算法汇总->归并排序”这句话的时候,兴奋不已(你妹啊!分治法~)。。

放弃继续看下去的念头,立马动笔。。。

心未平息,洋洋洒洒的codes,问题一堆,接着只有IDE写。。

发现思路已经出了问题,亡羊补牢为时未晚。。。

逐静心细想,直接上机,N次的debug之后。。。

才完成最终的代码。。。。 

#include <iostream>

using namespace std;

int merge(int a[], int s, int e)
{
    int *tmp;
    int mid, lend, rend, i, j, k;
    int lc, cnt, snum,  tlc; // lc for left count, cnt for count, tlc for temporary left count

    if (s>=e)
    {
        return 0;
    }

    mid = s+ (e-s)/2;

    tmp = (int *)malloc(sizeof(int)* (e-s+1));

    i = s;
    j = mid+1;
    lend = mid;
    rend = e;
    lc = 0;
    cnt = 0;
    k = 0;
    snum = 0; //same num

    while(i<=lend && j<=rend)
    {
        if (a[i]<a[j])
        {
            snum = a[j];
            while(j<=rend && a[j]==snum)
            {
                tmp[k++] = a[j++];
                cnt += lc;
            }
        }
        else if (a[i]> a[j])
        {
            snum = a[i];
            while(i<=lend && a[i]== snum)
            {
                tmp[k++] = a[i++];
                lc++;
            }
        }
        else //if same
        {
            tlc = 0 ;
            snum = a[i];
            while(i<=lend && a[i]== snum)
            {
                tmp[k++] = a[i++];
                tlc++;
            }
            while(j<=rend && a[j]==snum)
            {
                tmp[k++] = a[j++];
                cnt += lc;
            }
            
            lc += tlc;
        }
    }


    if (j<= rend && tmp[k]== a[j])  //上次最后两个是相等的
    {
        while(j<= rend && tmp[k]== a[j])
        {
            cnt += lc - tlc;
            tmp[k++] = a[j++];
        }
        
    }
    
    while(j<= rend)
    {
        cnt += lc;
        
        tmp[k++] = a[j++];
    }

    while (i<= lend )
    {        
        tmp[k++] = a[i++];    
    }

    memcpy(&a[s], tmp, sizeof(int)* (e-s+1));

    free(tmp);

    return cnt;

}

int func(int a[], int s, int e)
{
    int mid, lcnt, rcnt,mcnt;

    if (s>=e)
    {
        return 0;
    }

    mid = s+ (e-s)/2;
    
    lcnt = func(a, s, mid);
    rcnt = func(a, mid+1, e);

    mcnt = merge(a, s, e);

    return lcnt+ rcnt + mcnt;
}
int main()
{

//    int a1[] = {7,5,6,2};
    int a1[] = {1,3,7,6,6,5,5,4,6,5};
    
    cout<<func(a1, 0, sizeof(a1)/sizeof(int)-1)<<endl;
    
    return 0;
}

之后和同学一番吐槽,忽闻说有使用快速排序的思想。

基本思路:先是记录没一个的元素的位置,然后根据比较的时候,移动时判断两个位置之间的关系。

排序可以升序或降序(看你怎么处理了),假设我们使用排升序,

要比较两个数,大者放在key前,否则之后;

比如:a[i]和a[j],i<j,如果a[i]<a[j], a[j]移key前,a[i]移到key后;因为i<j,所以不是逆序对;

否则,a[j]移key后,a[i]移到key前,是逆序对。

例子:

array:2 3 1

pos:1 2 3

比较3和1,因为3的位置为2,而1的位置为3,即1在3后,说明它们是逆序对 

array:2 3 1

pos:1 2 3

比较并对换了3和2,因为3的位置为2,而2的位置为1,即3在2后,说明它们不是逆序对

array:3 2 1

pos:2 1 3

到此完成了排序,结果也出来了。

 

P.S. 算法思路过于死板,未能灵活利用各种算法的思想,发散思维。

未能静心分析,过早落于细节,混淆思维。

这题目花了我太多的时间,感觉真不值,效率啊~需要好好总结!

posted @ 2013-04-13 12:15  legendmaner  阅读(247)  评论(0编辑  收藏  举报