• 《剑指offer》第五十一题:数组中的逆序对


    // 面试题51:数组中的逆序对
    // 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组
    // 成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
    
    #include <cstdio>
    
    int InversePairsCore(int* data, int* copy, int start, int end);
    
    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 number = InversePairsCore(data, copy, 0, length - 1);
        delete[] copy;
    
        return number;
    }
    
    int InversePairsCore(int* data, int* copy, int start, int end)  //这里注意输入, 始终用data更新copy排序
    {
        if (start == end)  //数组只有一个元素
        {
            copy[start] = data[start];
            return 0;
        }
    
        int length = (end - start) / 2;  //分割当前数组
    
        //copy和data分别作为辅助数组
        //递归调用时data作为辅助数组,递归调用完成后data前后半段已经排好序,下来程序中copy作为辅助数组对前后半段进行排序
        int left = InversePairsCore(copy, data, start, start + length);  //前半段数组逆序对数
        int right = InversePairsCore(copy, data, start + length + 1, end);
    
        //计算当前两个数组逆序对数
        int i = start + length;  //前半段数组最后一位数字
        int j = end;  //后半段数组最后一位数字
        int index = end;  //排序数组的索引
        int count = 0;
    
        while (i >= start && j >= start + length + 1)  //从后往前索引,直到前半段或者后半段数组索引完成
        {
            if (data[i] > data[j])  //如果左边数字大,则存在逆序数
            {
                copy[index--] = data[i--];
                //逆序对个数等于 j下标距离所处的段开头的距离
                count += j - (start + length + 1) + 1;
            }
            else
                //后面大于前面,只用赋值,不属于逆序对情况
                copy[index--] = data[j--];
        }
    
        //如果前半段数组未索引完
        for (; i >= start; --i)
            copy[index--] = data[i];
        //如果后半段数组未索引完
        for (; j >= start + length + 1; --j)
            copy[index--] = data[j];
    
        return left + right + 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.
    ");
        else
            printf("Failed.
    ");
    }
    
    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;
    }
    测试代码

    分析:归并排序,详情见博客

    class Solution {
    public:
        int InversePairs(vector<int> data) {
            
            int length = data.size();
            
            if (data.empty())
                return 0;
            
            vector<int> copy;
            for (int i = 0; i < length; ++i)
                copy.push_back(data[i]);
            
            long count = InversePairs(data, copy, 0, length - 1);
            
            return count%1000000007;
        }
        
        long InversePairs(vector<int> &data, vector<int> &copy, int start, int end)
        {
            if (start == end)
            {
                copy[start] = data[start];
                return 0;
            }
            
            int length = (end - start) / 2;
            long left = InversePairs(copy, data, start, start + length);
            long right = InversePairs(copy, data, start + length + 1, end);
            
            int i = start + length;
            int j = end;
            int index = end;
            long count = 0;
            while (i >= start && j >= start + length + 1)
            {
                if (data[i] > data[j])
                {
                    copy[index--] = data[i--];
                    count += j - (start + length + 1) + 1;
                }
                else
                    copy[index--] = data[j--];
            }
            
            for (; i >= start; --i)
                copy[index--] = data[i];
            for (; j >= start + length + 1; --j)
                copy[index--] = data[j];
            
            return count + left + right;
        }
    };
    牛客网提交代码
  • 相关阅读:
    LAMP环境搭建
    Centos系统下Lamp环境的快速搭建(超详细)
    主题:Windows系统服务器磁盘挂载
    云硬盘
    独立IP与共享IP的区别
    网站备案的注意事项
    云主机与vps虚拟主机的区别
    vim 命令大全 / vi 命令大全
    【Linux】Linux中常用操作命令
    Linux Shell常用技巧(一) RE
  • 原文地址:https://www.cnblogs.com/ZSY-blog/p/12649729.html
Copyright © 2020-2023  润新知