首页 > 试题广场 >

数组中的逆序对

[编程题]数组中的逆序对
  • 热度指数:846830 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007

数据范围:  对于 的数据,
对于 的数据,
数组中所有数字的值满足 0 \le val \le 10^9

要求:空间复杂度 ,时间复杂度

输入描述:
题目保证输入的数组中没有的相同的数字

示例1

输入

[1,2,3,4,5,6,7,0]

输出

7
示例2

输入

[1,2,3]

输出

0

function InversePairs(data) {
    let count = 0;
    const calc = (arr) => {
        if (arr.length <= 1) {
            return arr;
        }
        let left = [];
        let right = [];
        let base = arr[0];
        for (let i = 1, iLen = arr.length; i < iLen; i += 1) {
            const el = arr[i];
            if (el > base) {
                right.push(el);
            } else {
                count += right.length + 1;
                left.push(el);
            }
        }
        return [...calc(left), base, ...calc(right)];
    }
    calc(data);
    return count % 1000000007;
}
const res = InversePairs([2, 3, 4, 1, 5, 6, 7, 0]);
console.log(res, count);
发表于 2022-04-05 13:37:43 回复(0)
function InversePairs(data)
{
    // write code here
    let count = 0    //计算逆序对数量
    merge_sort(data)
    function merge_sort(data){    //递归
        if (data.length == 1) return data;
        let left = data.slice(0,data.length / 2)
        let right = data.slice(data.length / 2)
        return merge(merge_sort(left),merge_sort(right))
    }
    function merge(left,right){    //合并
    let temp = []
    let lLength = left.length
    let rLength = right.length
    let lIndex = 0    //记录left的数的下标
    let rIndex = 0    //记录right的数的下标
    while(lLength > lIndex && rLength > rIndex){
        let x = left.shift()
        let y = right.shift()
        if(x <= y ){
            temp.push(x)
            right.unshift(y)
            lIndex++
        }else{    //
            temp.push(y)
            left.unshift(x)
            rIndex++
            count += lLength - lIndex    //左边开头的数字大于右边那个数,那么左边里的数都大于
        }
    }
    if(lLength === lIndex)return temp.concat(right)
    if(rLength === rIndex)return temp.concat(left)
    }
    return count % 1000000007
    
}
module.exports = {
    InversePairs : InversePairs
};
发表于 2021-11-16 11:28:22 回复(0)

提供一个JS的可读性最好的解法(效率击败90%的解法): Code is the best note

function InversePairs(data)
{
    let count = 0
    if (!Array.isArray(data) || data.length < 2){
        return count
    }

    // 以下两个箭头函数构成一个归并排序
    const merge = (left, right) => {
        const arr = []
        while (left.length && right.length) {
            if (left[0] > right[0]) {
                arr.push(right.shift())
                count += left.length
            } else {
                arr.push(left.shift())
            }
        }
        left.length && arr.push(...left)
        right.length && arr.push(...right)
        return arr
    }

    const mergeSort = (arr) => {
        if (arr.length < 2) {
            return arr
        }
        const middle = Math.ceil(arr.length / 2)
        const leftPart = arr.slice(0, middle)
        const rightPart = arr.slice(middle)
        return merge(mergeSort(leftPart), mergeSort(rightPart))
    }

    mergeSort(data)
    return count % 1000000007
}


编辑于 2021-06-23 22:56:09 回复(0)
归并排序
function InversePairs(data)
{
    // write code here
 let sum = 0
 mergeSort(data)
 return sum
    function mergeSort(nums){
        if(nums.length<2) return nums
        const mid = Math.floor(nums.length/2)
        let left =  nums.slice(0, mid)
        let right = nums.slice(mid)
        console.log(left, right)
        return merge(mergeSort(left), mergeSort(right))
        
    }
    function merge(left, right){
        let res = []
        let lenL = left.length
        let lenR = right.length
        let len = lenL + lenR
        for(let index = 0, i = 0,j = 0;index<len;index++){//i为arrLL的数组下标,j为arrLR的数组下标, index为新数组res的下标,初始值都为0
            if(i>=lenL) res[index] = right[j++]
            else if(j>=lenR) res[index] = left[i++]
            else if(left[i]<= right[j]) res[index] = left[i++]
            else{
                res[index] = right[j++] 
                sum =((lenL - i)+sum)%1000000007// 核心代码,mergeSort和merge皆为归并排序代码
            }
        }
        console.log(res)
        return res
    }
}


发表于 2021-01-29 21:25:24 回复(0)
有js的吗?改了好久都超时!!!自己用console.time()看时间也才8ms啊
发表于 2019-05-11 17:20:14 回复(0)

Javascript 二叉查找树 和 树状数组

1. 二叉查找树版

function InversePairs(data) {     if (data.length < 2) return 0;     let mod = 1000000007;     var ret = 0;     function TreeNode(x) {         this.val = x;         this.left = null;         this.right = null         this.lkids = 0;         this.rkids = 0;     }     function Insert(p, x) {         let n = 0;         while (true) {             if (x > p.val) {                 p.rkids++;                 if (p.right) p = p.right;                 else {                     p.right = new TreeNode(x);                     break;                 }             } else {                 p.lkids++;                 n += p.rkids + 1;                 if (p.left) p = p.left;                 else {                     p.left = new TreeNode(x);                     break;                 }             }         }         ret += n;         if (ret >= mod) ret -= mod;     }     let r = new TreeNode(data[0]);     for (let i = 1; i < data.length; i++) {         Insert(r, data[i]);     }     return ret; }

2. 树状数组版

function InversePairs(data) {     if (data.length < 2) return 0;     var ret = 0;     let mod = 1000000007;     let bit = new Array(2000002).fill(0);      function add(i, d) {         while (i < bit.length) {             bit[i] += d;             i += i & -i;         }     }     function sum(x) {         let sum = 0;         while (x > 0) {             sum += bit[x];             x -= x & -x;         }         return sum;     }     for (let i = 0; i < data.length; i++) {         ret += i - sum(data[i] + 1);         add(data[i] + 1, 1);     }     return ret % mod; }
发表于 2018-10-11 22:54:42 回复(0)
/* 这个超时了,我也不知道是为什么,思路是一样的,都是分治的思想
function InversePairs(data) {
  // write code here
  /**
   * 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总
   * 数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
   *
   * 借用分治的的思想,先两两等分,对每一份统计逆序对的数量,并进行排序,排序之后进行合并,边合并边统计逆序对的数量

  if (!data || data.length < 2) {
    return 0
  }
  let count = 0
  const mergeArr = (arr, first, mid, end) => {
    //传入的mid是取不到的,前半段为first~mid-1,后半段为mid~end-1
    // 将数组的一段进行合并排序
    let temp = []   // 临时数组,用于保存end-first排序之后的序列
    let i = 1, j = 1
    while (i <= mid - first && j <= end - mid) {
      if (arr[mid - i] > arr[end - j]) {
        temp.unshift(arr[mid - i])
        count += (end - j - mid + 1)
        i++
      } else {
        //此时说明前面的数小于后面的数,未形成逆序对
        temp.unshift(arr[end - j])
        j++
      }
    }

    while (i <= mid - first) {
      temp.unshift(arr[mid - i])
      i++
    }

    while (j <= end - mid) {
      temp.unshift(arr[end - j])
      j++
    }
    //console.log(temp)
    arr.splice(first, end - first, ...temp)
  }

  function mergeSort(arr, first, end) {
    //递归进行归并排序
    let mid = (first + end) >> 1
    if (first < mid) {
      mergeSort(arr, first, mid)
      mergeSort(arr, mid, end)
      mergeArr(arr, first, mid, end)
      //console.log(arr)
    }
  }

  mergeSort(data, 0, data.length)
  //console.log(count)
  return count % 1000000007
}

//InversePairs([2,5,1,4,6,8,3,7])
module.exports = {
    InversePairs : InversePairs
};
*/
    
function InversePairs(data)
{
    var copy = data.slice();
    return mergeInversePairs(data, copy, 0, data.length - 1) % 1000000007;
}
function mergeInversePairs(arr, copy, begin, end) {
    if(begin === end) {
        return 0;
    }
    var mid = begin + end >> 1;
    var left = mergeInversePairs(arr, copy, begin, mid);
    var right = mergeInversePairs(arr, copy, mid + 1, end);
    var num = 0, i = mid, j = end, k = end;
    while(i >= begin && j >= mid + 1) {
        if(arr[i] <= arr[j]) {
            copy[k--] = arr[j--];
        } else {
            num += j - mid;
            copy[k--] = arr[i--];
        }
    }
    while(i >= begin) copy[k--] = arr[i--];
    while(j >= mid + 1) copy[k--] = arr[j--];
    for(var s = begin; s <= end; s++)
    {
        arr[s] = copy[s];
    }
    return num + left + right;
}
module.exports = {
    InversePairs : InversePairs
};


发表于 2018-08-18 14:30:47 回复(0)
function mergeSort(arr){
        if(arr.length <= 1){
            return arr;
        }
        var left_arr = mergeSort(arr.slice(0, arr.length / 2));
        var right_arr = mergeSort(arr.slice(arr.length / 2, arr.length));
        return mergeList(left_arr, right_arr);
    }
    function mergeList(left_arr, right_arr){
        var left_index = 0;
        var right_index = 0;
        var sortArray = [];
        var rightCount = 0;   //该位置(包括)之前的来自右数组个数和
        while(left_index != left_arr.length && right_index != right_arr.length){
            if(left_arr[left_index] < right_arr[right_index]){
                sortArray.push(left_arr[left_index++]);
                sum += rightCount;
            }else{
                sortArray.push(right_arr[right_index++]);
                rightCount++;
            }
        }
        while(left_index != left_arr.length){
            sortArray.push(left_arr[left_index++]);
            sum += rightCount;
        }
        while(right_index != right_arr.length){
            sortArray.push(right_arr[right_index++]);
            rightCount++;
        }
        return sortArray;
    }
    var sum = 0;
    mergeSort(data);
    return sum % 1000000007;
发表于 2018-04-26 18:25:07 回复(0)
JS来啦来啦来啦
说实话这道题有点难,我也是参考剑指offer上的。那么难点在哪呢?
难点一:要想到基于归并排序去解决。
难点二:参数的问题,这里很巧妙地用了一个copy数组作为data参数。
难点三:合并时,count如何计数。
function InversePairs(data)
{
    if(!data||data.length<2) return 0;
    let copy=data.slice(),count=0;
    count=mergeCount(data,copy,0,data.length-1);
    return count%1000000007;
}
function mergeCount(data,copy,start,end){
    if(start==end) return 0;
    let mid=(end-start)>>1,
        left=mergeCount(copy,data,start,start+mid),//注意参数,copy作为data传入
        right=mergeCount(copy,data,start+mid+1,end),//注意参数,copy作为data传入         [p,q,count,copyIndex]=[start+mid,end,0,end];
    while(p>=start&&q>=start+mid+1){
        if(data[p]>data[q]){
            copy[copyIndex--]=data[p--];
            count=count+q-start-mid;
        }else{
            copy[copyIndex--]=data[q--];
        }
    }
    while(p>=start){
        copy[copyIndex--]=data[p--];
    }
    while(q>=start+mid+1){
        copy[copyIndex--]=data[q--];
    }
    return count+left+right;
}


发表于 2018-04-09 04:41:23 回复(0)
求一份能通过的JavaScript代码
发表于 2017-09-03 15:44:14 回复(0)
function InversePairs(data) {
    // write code here
    var sortedArray = getSorted(data);
    return sortedArray.count;
}

function getSorted(data) {
    var length = data.length;
    if (length <= 1) return data;
    var mid = Math.floor(length / 2),
        left = data.slice(0, mid),
        right = data.slice(mid, length);
    return merge(getSorted(left), getSorted(right));
}

function merge(left, right) {
    var li = left.length - 1,
        ri = right.length - 1;
    var ansArray = [];
    var count = (left.count ? left.count : 0) + (right.count ? right.count : 0);
    for (; li >= 0 && ri >= 0;) {
        if (left[li] > right[ri]) {
            count += ri + 1;
            if (count > 1000000007) count = count % 1000000007;
            ansArray.unshift(left[li]);
            li--;
        } else {
            ansArray.unshift(right[ri]);
            ri--;
        }
    }
    while (li >= 0) {
        ansArray.unshift(left[li--]);
    }
    while (ri >= 0) {
        ansArray.unshift(right[ri--]);
    }
    ansArray['count'] = count % 1000000007;
    return ansArray;
}
//超时............

发表于 2017-04-04 22:26:39 回复(0)