493. Reverse Pairs
题目链接:
https://leetcode.com/problems...
和Count of Smaller Numbers After Self还有count of range sum是一类题,解法都差不多。BST可以做,但是这道题如果输入是有序的,简单的bst会超时,所以得用AVL来做。
然后就是binary index tree的做法,计算大于nums[j]2的时候就是拿全部的sum减去sum(nums[j] 2)
public class Solution {
public int reversePairs(int[] nums) {
int res = 0;
int n = nums.length;
if(n == 0) return res;
// reflection
Map<Long, Integer> map = new HashMap();
long[] sorted = new long[2*n];
for(int i = 0; i < n; i++) {
sorted[2*i] = nums[i];
sorted[2*i + 1] = (long) nums[i] * 2;
}
Arrays.sort(sorted);
int idx = 1;
for(long num : sorted) {
if(!map.containsKey(num)) map.put(num, idx++);
}
BIT t = new BIT(idx);
int sum = 0;
for(int j = 0; j < n; j++) {
// find how many number > 2 * nums[j]
long num = (long) nums[j];
res += sum - t.sum(map.get(num*2));
t.add(map.get(num), 1);
sum++;
}
return res;
}
class BIT {
int n;
int[] tree;
BIT(int n) { this.n = n; tree = new int[n]; }
protected int sum(int i) {
int res = 0;
while(i > 0) {
res += tree[i];
i -= i & -i;
}
return res;
}
protected void add(int i, int val) {
while(i < n) {
tree[i] += val;
i += i & -i;
}
}
}
}
merge sort的做法,同样是每次要统计左边有多少结果是 > 2 * nums[j]的,每次sort完之后先算有多少pairs再merge。算pairs的方法是:
比如给的例子,现在分成了左右两部分[1, 1, 2], [3, 3],拿两个指针i和j。
if
nums[i]/2.0 > nums[j]
,表示所有小与等于nums[j]的值都满足这个条件,一直增大到不满足条件的,最后j - (mid+1)
就是全部满足该条件且包含nums[i]的pair数目else, 表示nums[i]小了,需要i++
loop的invariant用包含nums[j]的也行:
if
nums[i]/2.0 > nums[j]
表示所有大于等于nums[i]的都满足条件,res += mid - i + 1
,同时j++else表示i小了,所以i++
每次重新开一个aux就超时了,所以把aux当全局变量,开一次
public class Solution {
public int reversePairs(int[] nums) {
int n = nums.length;
if(n == 0) return 0;
// merge sort
res = 0;
aux = new int[n];
sort(nums, 0, n - 1);
return res;
}
int res;
int[] aux;
private void sort(int[] nums, int l, int r) {
if(l >= r) return;
int mid = l + (r - l) / 2;
sort(nums, l, mid);
sort(nums, mid + 1, r);
int i = l, j = mid + 1;
while(j <= r) {
while(i <= mid && nums[i]/2.0 <= nums[j]) i++;
// count number of pairs include nums[j]
res += mid - i + 1;
j++;
}
merge(nums, l, mid, r);
}
private void merge(int[] nums, int l, int mid, int r) {
for(int k = l; k <= r; k++) aux[k] = nums[k];
int i = l, j = mid + 1;
for(int k = l; k <= r; k++) {
if(i > mid) nums[k] = aux[j++];
else if(j > r) nums[k] = aux[i++];
else if(aux[i] > aux[j]) nums[k] = aux[j++];
else nums[k] = aux[i++];
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。