【发布时间】:2020-02-05 10:51:24
【问题描述】:
我需要以尽可能低的时间复杂度找到所有子数组中的一些反转计数。
如果a[i] > a[j] 和i < j 两个元素a[i] 和a[j] 形成反演
我已经尝试使用 Fenwick Tree 实现,但超出了时间限制。
我想要一个优化版本的代码:
import java.util.*;
public class Main {
static BIT bit;
static long inversionCountBIT1(int[] arr, int start,
int end)
{
bit = new BIT(arr.length);
long count = 0;
for (int index = start; index >= end; index--) {
count += bit.read(arr[index]);
bit.update(arr[index], 1);
}
return count;
}
static long inversionCountBIT2(int[] arr, int start,
int end, long val)
{
bit.update(arr[start + 1], -1);
int numGreaterThanFirst = start - end - bit.read(arr[start + 1] + 1);
long count = val + bit.read(arr[end]) - numGreaterThanFirst;
bit.update(arr[end], 1);
return count;
}
public static long inversionCount(int n, int k, int[] arr)
{
bit = new BIT(n);
HashMap<Integer, Integer> freq = new HashMap<Integer, Integer>();
int[] asort = arr.clone();
Arrays.sort(asort);
int index = 0;
int current = 1;
for (int i = 0; i < n; i++) {
if (!freq.containsKey(asort[i])) {
freq.put(asort[i], current);
current++;
}
}
for (int i = 0; i < n; i++) {
arr[i] = freq.get(arr[i]);
}
long count = 0;
long val = 0;
for (int start = n - 1; start >= k - 1; start--) {
int end = start - k + 1;
if (start == n - 1) {
val = inversionCountBIT1(arr, n - 1, n - k);
} else {
val = inversionCountBIT2(arr, start, end, val);
}
count += val;
}
return count;
}
public static void main(String[] args) throws Exception
{
Scanner scn = new Scanner(System.in);
int t=scn.nextInt() ;
int n;
long k ;
while(t>0)
{
n= scn.nextInt() ;
k =scn.nextLong() ;
long result = 0;
int[] arr =new int[n];
for(int i=0;i<n;i++)
{
arr[i]=scn.nextInt() ;
}
for(int i=1;i<=n;i++)
result += inversionCount(n, i, arr);
System.out.println(result%k);
t--;
}
}
static class BIT {
int[] tree;
int maxVal;
public BIT(int N)
{
tree = new int[N + 1];
maxVal = N;
}
void update(int index, int val)
{
while (index <= maxVal) {
tree[index] += val;
index += (index & -index);
}
}
int read(int index)
{
--index;
int cumulative_sum = 0;
while (index > 0) {
cumulative_sum += tree[index];
index -= (index & -index);
}
return cumulative_sum;
}
};
}
超过时间限制
【问题讨论】:
-
所有子数组是指一个数组所有可能的子数组
-
我还没有阅读您的代码,但是有多种实现可以使用 C++ STL 多重集、修改的合并排序、增强的自平衡 BST 和 BIT 来计算数组中的反转。除了 STL 多集方法,它在最坏的情况下具有
O(n^2)complexity,其余具有O(nlog(n))复杂度。我建议使用修改后的合并排序来实现它,因为它是最简单的并且保证了O(nlog(n))的复杂性。 -
这不起作用
-
它是否也为 TLE 提供了合并排序?
-
是的,它也显示超出合并排序的时间限制
标签: data-structures combinatorics fenwick-tree