LeetCode - 493. 翻转对(归并排序)
- 翻转对
题目:
给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
输入: [1,3,2,3,1]
输出: 2
示例 2:
输入: [2,4,3,5,1]
输出: 3
注意:
给定数组的长度不会超过50000。
输入数组中的所有数字都在32位整数的表示范围内。
注意:
归并排序
class Solution{
public int reversePairs(int[] nums){
if (nums == null || nums.length == 0) return 0;
return mergeSort(nums,0,nums.length - 1);
}
private int mergeSort(int[] nums, int l, int r) {
if (l >= r) return 0;
int mid = l + (r - l)/2;
int count = mergeSort(nums,l,mid) + mergeSort(nums,mid+1,r);
int[] cache = new int[r - l + 1];
int i = l,t = 1,c = 0;
for (int j = mid + 1;j <= r;j++,c++){
while (i <= mid && nums[i] <= 2 * (long)nums[j]) i++;
while (t <= mid && nums[t] < nums[j]) cache[c++] = nums[t++];
cache[c] = nums[j];
count += mid - i + 1;
}
while(t <= mid)
cache[c++] = nums[t++];
System.arraycopy(cache,0,nums,l,r - l + 1);
return count;
}
}
class Solution {
public int reversePairs(int[] nums) {
return mergeSort(nums,0,nums.length-1);
}
private int mergeSort(int[] nums,int s,int e){
if(s >= e) return 0;
//把数组分成两部分,分别对两部分进行归并
int mid = s + (e-s)/2;
//统计左右两边的翻转对加到cnt值上,且左右两边已经排好序
int cnt = mergeSort(nums,s,mid) + mergeSort(nums,mid+1,e);
//遍历两边的数组,并进行判断是否nums[i] > 2*nums[j],统计翻转对的个数
for(int i = s,j = mid + 1;i <= mid;i++){
while(j <= e && nums[i]/2.0 > nums[j])
j++;
cnt += j-(mid+1);
}
Arrays.sort(nums,s,e+1);//把整个算法从复杂度O(nlogn) 变成了 O(nlogn*logn)
return cnt;
}
}
class Solution {
public int ret;
public int reversePairs(int[] nums) {
ret = 0;
mergeSort(nums,0,nums.length-1);
return ret;
}
private void mergeSort(int[] nums, int left, int right) {
if (right <= left){
return;
}
int middle = left + (right - left)/2;
mergeSort(nums, left, middle);
mergeSort(nums,middle+1,right);
int count = 0;
for (int l = left,r = middle + 1;l <= middle;){
if (r > right || (long)nums[l] <= 2*(long)nums[r]){
l++;
ret += count;
}else {
r++;
count++;
}
}
Arrays.sort(nums,left,right+1);
}
}