面试题 36(*),数组中的逆序对(类似归并排序,不过归并时添加计数器记录逆序对的数量)

思路:如果用O(n^2)自然可以完成。我并没有想到比较好的思路。

书中给出了类似归并排序的做法,在O(nlogn)时间内完成了计算。

思路就是在递增归并排序的基础上,做了改动:每次在merge两个子序列时,统计a和b组成的逆序对,a来自前一个递增子序列,b来自后一个递增子序列。

由于两个子序列都是递增的,这时候求a和b构成逆序对的数量就可以在O(n)内完成了。

当a前进一步时,就把第二个子序列中b所在位置及之前所有遍历过的元素的数量添加到count中。

 

count = 两个子序列内部的逆序对(用递归求出) + a和b所产生的逆序对个数

自己实现的代码如下:

#include <stdio.h>

int FindInversePairCore(int *list, int* cache, int start, int end){
    if(list == NULL)
        return 0;
    if(end - start <= 1){
        return 0;
    }
    int mid = (start + end)/2;
    int count = 0; //逆序对计数器 
    count += FindInversePairCore(list, cache, start, mid);
    count += FindInversePairCore(list, cache, mid, end);
    for(int i = start;i < end;i++)
        cache[i] = list[i];
    int j = start, k = mid, p = start;
    while(j < mid && k < end){
        if(cache[j] <= cache[k]){
            list[p++] = cache[j++];
            count += (k - mid);
        }else{
            list[p++] = cache[k++];
        }    
    }
    while(j < mid){
        list[p++] = cache[j++];
        count += (k - mid);
    }
    while(k < end){
        list[p++] = cache[k++];
    }
    
    return count;
}

int FindInversePair(int* list, int size){
    int *cache = new int[size];
    return FindInversePairCore(list, cache, 0, size);
     
}

// ====================测试代码====================
void Test(char* testName, int* data, int length, int expected)
{
    if(testName != NULL)
        printf("%s begins: ", testName);

    if(FindInversePair(data, length) == expected)
        printf("Passed.\n");
    else
        printf("Failed.\n");
}

void Test1()
{
    int data[] = {1, 2, 3, 4, 7, 6, 5};
    int expected = 3;

    Test("Test1", data, sizeof(data) / sizeof(int), expected);
}

// 递减排序数组
void Test2()
{
    int data[] = {6, 5, 4, 3, 2, 1};
    int expected = 15;

    Test("Test2", data, sizeof(data) / sizeof(int), expected);
}

// 递增排序数组
void Test3()
{
    int data[] = {4, 5, 6, 1, 2, 3};
    int expected = 9;

    Test("Test3", data, sizeof(data) / sizeof(int), expected);
}

// 数组中只有一个数字
void Test4()
{
    int data[] = {1};
    int expected = 0;

    Test("Test4", data, sizeof(data) / sizeof(int), expected);
}


// 数组中只有两个数字,递增排序
void Test5()
{
    int data[] = {1, 2};
    int expected = 0;

    Test("Test5", data, sizeof(data) / sizeof(int), expected);
}

// 数组中只有两个数字,递减排序
void Test6()
{
    int data[] = {2, 1};
    int expected = 1;

    Test("Test6", data, sizeof(data) / sizeof(int), expected);
}

// 数组中有相等的数字
void Test7()
{
    int data[] = {1, 2, 1, 2, 1};
    int expected = 3;

    Test("Test7", data, sizeof(data) / sizeof(int), expected);
}

void Test8()
{
    int expected = 0;

    Test("Test8", NULL, 0, expected);
}

int main()
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();
    Test8();

    return 0;
}

 

 

书上代码:

// InversePairs.cpp : Defines the entry point for the console application.
//

// 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛

#include "stdafx.h"

int InversePairsCore(int* data, int* copy, int start, int end);

int InversePairs(int* data, int length)
{
    if(data == NULL || length < 0)
        return 0;

    int* copy = new int[length];
    for(int i = 0; i < length; ++ i)
        copy[i] = data[i];

    int count = InversePairsCore(data, copy, 0, length - 1);
    delete[] copy;

    return count;
}

int InversePairsCore(int* data, int* copy, int start, int end)
{
    if(start == end)
    {
        copy[start] = data[start];
        return 0;
    }

    int length = (end - start) / 2;

    int left = InversePairsCore(copy, data, start, start + length);
    int right = InversePairsCore(copy, data, start + length + 1, end);

    // i初始化为前半段最后一个数字的下标
    int i = start + length; 
    // j初始化为后半段最后一个数字的下标
    int j = end; 
    int indexCopy = end;
    int count = 0;
    while(i >= start && j >= start + length + 1)
    {
        if(data[i] > data[j])
        {
            copy[indexCopy--] = data[i--];
            count += j - start - length;
        }
        else
        {
            copy[indexCopy--] = data[j--];
        }
    }

    for(; i >= start; --i)
        copy[indexCopy--] = data[i];

    for(; j >= start + length + 1; --j)
        copy[indexCopy--] = data[j];

    return left + right + count;
}

 

posted on 2014-02-05 12:00  Felix Fang  阅读(208)  评论(0)    收藏  举报

导航