老师,问个使用归并求逆序对问题

来源:3-9 归并排序和快速排序的衍生问题

相信光变成光

2019-01-29

我在牛客网找了一道求逆序对的题,网址:(https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=13&tqId=11188&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)我自己写的代码是只有百分之75的通过率。后来用了你的也是75%。下面的代码用的就是你的,我也不知道哪里错了。知道老师很忙,老师有时间的时候帮我看看,谢谢啦。

 public int InversePairs(int [] array) {
        return solve(array,0,array.length-1)%1000000007;
        
    }
    private static int merge(int[] arr, int l, int mid, int r) {

        int[] aux = Arrays.copyOfRange(arr, l, r+1);

        // 初始化逆序数对个数 res = 0
        int res = 0;
        // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
        int i = l, j = mid+1;
        for( int k = l ; k <= r; k ++ ){

            if( i > mid ){  // 如果左半部分元素已经全部处理完毕
                arr[k] = aux[j-l];
                j ++;
            }
            else if( j > r ){   // 如果右半部分元素已经全部处理完毕
                arr[k] = aux[i-l];
                i ++;
            }
            else if( aux[i-l]<=aux[j-l] ){  // 左半部分所指元素 <= 右半部分所指元素
                arr[k] = aux[i-l];
                i ++;
            }
            else{   // 右半部分所指元素 < 左半部分所指元素
                arr[k] = aux[j-l];
                j ++;
                // 此时, 因为右半部分k所指的元素小
                // 这个元素和左半部分的所有未处理的元素都构成了逆序数对
                // 左半部分此时未处理的元素个数为 mid - j + 1
                res +=(mid - i + 1);
            }
        }
        return res;
    }

    // 求arr[l..r]范围的逆序数对个数
    // 思考: 归并排序的优化可否用于求逆序数对的算法? :)
    private static int solve(int[] arr, int l, int r) {

        if (l >= r)
            return 0;

        int mid = l + (r-l)/2;
        // 求出 arr[l...mid] 范围的逆序数
        int res1 = solve(arr, l, mid);
        // 求出 arr[mid+1...r] 范围的逆序数
        int res2 = solve(arr, mid + 1, r);

        return res1%1000000007+ res2%1000000007 + merge(arr, l, mid, r)%1000000007;
    }

图片描述

写回答

1回答

liuyubobobo

2019-01-29

res +=(mid - i + 1); 这句话可能产生整形溢出,应该改成:

res = (res +(mid - i + 1)) % 1000000007;


另外,solve最后return了三个数:

return res1%1000000007+ res2%1000000007 + merge(arr, l, mid, r)%1000000007;


三个大小为1000000007的数相加,也有可能产生整形溢出。最好改成如下:

return (res1%1000000007+ res2%1000000007) % 1000000007 + merge(arr, l, mid, r)%1000000007;

(但貌似测试用例这里并不会溢出,不过逻辑上是有可能溢出的。)


==========


我是怎么找到问题的?


因为题目里说了,75%的数据规模和100%的数据规模不一样。现在你的代码执行通过了75%,说明问题出在增大数据规模上。那增大数据规模,最可能的问题就是整形溢出了:)


==========


问我牛客网上的算法问题没有问题,请附上问题链接(这个提问很好),如果你有完整代码请附上完整代码。如果你对具体语句执行有疑问,请详细说明你的疑问(你认为执行的效果应该是怎样的,为什么你认为是这样的,但实际是怎样的。)


这个问题附的代码没有最外层的class Solution声明,以及相应的import,又让我花了一些额外的时间做这些工作。下次请附上让我整体复制粘贴就能浮现你的错误的完整代码:)


继续加油!:)

3
2
相信光变成光
老师,你这个思考问题的思路学到了,谢谢
2019-01-30
共2条回复

算法与数据结构(C++版) 面试/评级的算法复习技能包

课程专为:短时间内应对面试、升职测评等艰巨任务打造

11187 学习 · 1614 问题

查看课程