剑指Offer-51:数组中的逆序对(InversePairs)

一、题目描述

在这里插入图片描述

二、解题思路

典型的归并排序方法
怎么计算count呢?
在每次归并进行比较时

  • 如果nums[i] <= nums[j]:说明当前位置没有逆序,继续向下比较;
  • 如果nums[i] > nums[j],说明在前半段中,位置i的已经都比nums[j]大了
    • 前半段中位置i及其后面的数字一定比nums[j]大。
    • 确定前半段比nums[j]大的个数:注意是“在前半段中i及其后面的数字一定比nums[j]大”,那么本轮结果就是i到前半段结尾的这段区间的个数,为mid - i + 1

之后递归就好了

三、解题代码

LeetCode代码

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        auto len = nums.size();
        if(len <= 1)    return 0;
        else return MergeSort(nums, 0, len - 1);
    }
private:
    int MergeSort(vector<int>& nums, int left, int right){
        if(left >= right)   return 0;
        int mid = left + (right - left) / 2;
        int count = MergeSort(nums, left, mid) + MergeSort(nums, mid + 1, right) + Merge(nums, left, mid, right);
        return count;
    }
    int Merge(vector<int>& nums, int left,  int mid, int right){
        auto tmp = new int[right - left + 1];
        int i = left, j = mid + 1, tmp_cur = 0;
        int count = 0;
        while(i <= mid && j <= right){
            if(nums[i] <= nums[j])
                tmp[tmp_cur++] = nums[i++];
            else{
                tmp[tmp_cur++] = nums[j++];
                count += mid - i + 1;
            }
        }
        while(i <= mid) tmp[tmp_cur++] = nums[i++];
        while(j <= right) tmp[tmp_cur++] = nums[j++];
        auto tmp_len = right - left + 1;
        for(int i = 0; i < tmp_len; i++)
            nums[left + i] = tmp[i];
        delete []tmp;
        tmp = nullptr;
        return count;
    }
};

剑指Offer代码

/*******************************************************************
Copyright(c) 2016, Harry He
All rights reserved.

Distributed under the BSD license.
(See accompanying file LICENSE.txt at
https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt)
*******************************************************************/

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

// 面试题51:数组中的逆序对
// 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组
// 成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

#include <cstdio>

int InversePairsCore(int *data, int *copy, int start, int end);
int InversePairs(int *data, int length);
/*
int InversePairs(int *data, int length)
{
    if (data == nullptr || 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;
}
*/
int Merge(int *data, int *copy, int start, int mid, int end)
{
    int i = start, j = mid + 1, tmp_cur = start;
    int count = 0;
    while (i <= mid && j <= end)
    {
        if (data[i] <= data[j])
            copy[tmp_cur++] = data[i++];
        else
        {
            copy[tmp_cur++] = data[j++];
            count += mid - i + 1;
        }
    }
    while (i <= mid)
        copy[tmp_cur++] = data[i++];

    while (j <= end)
        copy[tmp_cur++] = data[j++];

    for (int i = start; i <= end; i++)
        data[i] = copy[i];
    return count;
}
int InversePairsCore(int *data, int *copy, int start, int end)
{
    if (start >= end)
        return 0;
    int mid = (start + end) >> 1;
    int count = InversePairsCore(data, copy, start, mid) + InversePairsCore(data, copy, mid + 1, end) + Merge(data, copy, start, mid, end);
    return count;
}
int InversePairs(int *data, int length)
{
    if (data == nullptr || length <= 1)
        return 0;
    auto copy = new int[length];
    auto count = InversePairsCore(data, copy, 0, length - 1);
    delete[] copy;
    return count;
}
// ====================测试代码====================
void Test(char *testName, int *data, int length, int expected)
{
    if (testName != nullptr)
        printf("%s begins: ", testName);

    if (InversePairs(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[] = {1, 2, 3, 4, 5, 6};
    int expected = 0;

    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", nullptr, 0, expected);
}

int main(int argc, char *argv[])
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();
    Test8();

    return 0;
}

四、运行结果

在这里插入图片描述

InversePairs.cpp:138:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test1", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test2()':
InversePairs.cpp:147:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test2", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test3()':
InversePairs.cpp:156:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test3", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test4()':
InversePairs.cpp:165:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test4", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test5()':
InversePairs.cpp:174:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test5", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test6()':
InversePairs.cpp:183:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test6", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test7()':
InversePairs.cpp:192:61: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test7", data, sizeof(data) / sizeof(int), expected);
                                                             ^
InversePairs.cpp: In function 'void Test8()':
InversePairs.cpp:199:39: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     Test("Test8", nullptr, 0, expected);
                                       ^
Test1 begins: Passed.
Test2 begins: Passed.
Test3 begins: Passed.
Test4 begins: Passed.
Test5 begins: Passed.
Test6 begins: Passed.
Test7 begins: Passed.
Test8 begins: Passed.

猜你喜欢

转载自blog.csdn.net/weixin_44587168/article/details/105727795