算法优化的神奇效果

算法优化的神奇效果(让你的代码瞬间优化100倍)

  1. 增长数量级的分类
  2. 2-sum问题(热身)
  3. 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
    }

优化之前和优化之后的运行时间对比(万级别的数据量),还是非常明显!!!

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值