题目来源:[leetcode 剑指 Offer 51. 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
分析
- 定义一个res存入逆序对个数
- 判断当前值与之后所有的值进行比较,大于则 res++
代码实现
/**
* @param {number[]} nums
* @return {number}
*/
var reversePairs = function(nums) {
let res = 0;
const length = nums.length;
for (let i = 0; i < length; ++i) {
for (let j = i + 1; j < length; ++j) {
if(nums[i] > nums[j]) res++
}
}
return res;
};
分析2
- 利用有序数组的逆序对求法即可优化运行时间
- 利用归并排序,当right[j]小于left[i]的时候就说明i至leftLen都是逆序对(leftLen - i)
代码实现2
/**
* @param {number[]} nums
* @return {number}
*/
var reversePairs = function(nums) {
let sum = 0;
mergeSort(nums);
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);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let res = [];
let leftLen = left.length;
let rightLen = right.length;
let len = leftLen + rightLen;
let i = 0;
let j = 0;
for(let index = 0; index < len; index ++) {
if(i >= leftLen) res[index] = right[j ++];
else if (j >= rightLen) res[index] = left[i ++];
else if (left[i] <= right[j]) res[index] = left[i ++];
else {
res[index] = right[j ++];
sum += leftLen - i;
}
}
return res;
}
return sum;
};
分析3
- 代码实现2中由于多次定义数组,数组在创建与销毁的时候都会有时间的损耗
代码实现3
var reversePairs = function (nums) {
let res = 0;
let temp = [];
function reverse(nums, left, right) {
if (left >= right) {
return 0;
}
let mid = left + Math.floor((right - left) / 2);
reverse(nums, left, mid);
reverse(nums, mid + 1, right);
merge(left, right, mid, nums);
}
function merge(left, right, mid, nums) {
for (let x = left; x <= right; x++) {
temp[x] = nums[x];
}
let i = left,
j = mid + 1;
for (let k = left; k <= right; k++) {
if (i > mid) {
nums[k] = temp[j++];
} else if (j > right) {
nums[k] = temp[i++];
} else if (temp[i] <= temp[j]) {
nums[k] = temp[i++];
} else {
nums[k] = temp[j++];
res = res + mid - i + 1;
}
}
}
reverse(nums, 0, nums.length - 1);
return res;
};