算法优化的神奇效果(让你的代码瞬间优化100倍)
- 增长数量级的分类
- 2-sum问题(热身)
- 3-sum问题(快速算法)
1、增长数量级的分类
2、2-sum问题(热身)
它是3-sum的简化问题:即找出一个数组中所有的和为0的整数对的数量。一般的解决方案如下:
/**
* 2-sum问题:统计和为0的整数对的数目(平方级别)
* 时间复杂度:N²
* @param arr
* @return
*/
public static int count(int[] arr) {
int length = arr.length;
int ans = 0;
for (int indexI = 0; indexI < length; indexI++) {
for (int indexJ = indexI + 1; indexJ < length; indexJ++) {
if (arr[indexI] + arr[indexJ] == 0) {
ans++;
}
}
}
return ans;
}
接下来我们将这个平方级别的算法,优化为线性对数级别的算法。并没有线性级别的算法。
我们要用到递归排序和二分查找来实现这个优化。
优化之后的思想:当且仅当 -arr[i] 存在于数组中(且arr[i] 非零)时,arr[i] 存在于某个和为 0 的整数对之中。
/**
* 2-sum问题的线性对数级别的解法
* 时间复杂度:NlogN
* @param arr
* @return
*/
public static int countFast(int[] arr) {
Arrays.sort(arr); //此处使用的是归并排序
int length = arr.length;
int ans = 0;
for (int indexI = 0; indexI < length; indexI++) {
//此处大于 indexI ,为了避免重复计数(二分查找,详情请见http://blog.csdn.net/tinydolphin/article/details/71305450)
if (BinarySearch.rank(-arr[indexI], arr) > indexI) {
ans++;
}
}
return ans;
}
测试代码:
public static void main(String[] args) {
int[] arr = new int[100000];
Random random = new Random();
for (int indexI = 0; indexI < arr.length; indexI++) {
arr[indexI] = random.nextInt(2000) - 1000;
}
long start = System.currentTimeMillis();
count(arr);
long end = System.currentTimeMillis(); //单位毫秒
System.out.println("优化之前,count:"+(end - start)); //优化之前,count:24057
long startFast = System.currentTimeMillis();
countFast(arr);
long endFast = System.currentTimeMillis(); //单位毫秒
System.out.println("优化之后,countFast:"+(endFast - startFast)); //优化之后,countFast:103
}
优化之前和优化之后的运行时间对比(十万级别的数据量),非常明显!!!
3-sum问题(快速算法)
问题描述:统计和为0的元组的数目(即统计 arr[i] + arr[j] + arr[k] == 0 的数目),一般的解决方案如下:
/**
* 3-sum:统计和为0的元组的数目(立方级别)
* 时间复杂度:N³
* @param arr
* @return
*/
public static int count(int[] arr) {
int length = arr.length;
int ans = 0;
for (int indexI = 0; indexI < length; indexI++) {
for (int indexJ = indexI + 1; indexJ < length; indexJ++) {
for (int indexK = indexJ + 1; indexK < length; indexK++) {
if (arr[indexI] + arr[indexJ] + arr[indexK] == 0) {
ans++;
}
}
}
}
return ans;
}
接下来我们继续优化以上算法。可能会存在比这个级别更加优化的算法,即可能存在最优算法—平方级别。
/**
* 3-sum问题的N²lgN级别的解法
* 时间复杂度:N²lgN
* @param arr
* @return
*/
public static int countFast(int[] arr) {
Arrays.sort(arr); //此处使用的是归并排序
int length = arr.length;
int ans = 0;
for (int indexI = 0; indexI < length; indexI++) {
for (int indexJ = indexI + 1; indexJ < length; indexJ++) {
//此处大于 indexJ ,为了避免重复计数(二分查找,详情请见http://blog.csdn.net/tinydolphin/article/details/71305450)
if (BinarySearch.rank(-arr[indexI]-arr[indexJ], arr) > indexJ) {
ans++;
}
}
}
return ans;
}
测试代码:
public static void main(String[] args) {
int[] arr = new int[10000];
Random random = new Random();
for (int indexI = 0; indexI < arr.length; indexI++) {
arr[indexI] = random.nextInt(2000) - 1000;
}
long start = System.currentTimeMillis();
count(arr);
long end = System.currentTimeMillis();//单位毫秒
System.out.println("优化之前,count:"+(end - start)); //优化之前,count:638519
long startFast = System.currentTimeMillis();
countFast(arr);
long endFast = System.currentTimeMillis();//单位毫秒
System.out.println("优化之后,countFast:"+(endFast - startFast)); //优化之后,countFast:3780
}
优化之前和优化之后的运行时间对比(万级别的数据量),还是非常明显!!!