算法:两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

代码如下,类似冒泡排序的写法,i从0到num.length-1,j从i+1到nums.length:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        for(int i=0;i<nums.length-1;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    return new int[]{i,j};
                }
            }
        }
        return null;
    }
}

但是上面这种写法存在几个问题,首先没有异常处理,然后效率也不行,下面的这个算法要好很多:

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int [] res = new int[2];
        if(numbers==null||numbers.length<2)
            return res;
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i = 0; i < numbers.length; i++){
            if(!map.containsKey(target-numbers[i])){
                map.put(numbers[i],i);
            }else{
                res[0]= map.get(target-numbers[i]);
                res[1]= i;
                break;
            }
        }
        return res;
    }
}

异常处理就不细说了,从时间复杂度上来说,算法1是T(n^2),空间复杂度O(1);算法2是T(n),空间复杂度O(n);
提升的关键,就在于使用了一个map,用array元素的值作为key,array的下表作为value,利用哈利表的快速查找优势,用空间换取了时间。

用空间换时间,以前算法课经常到,不理解,但是我们后来常用的很多手段,比如memcached、redis等缓存,都属于是空间换取时间。

根据leetcode的测试,算法1平均需要31ms,算法2仅需要8ms,一个普通的加减法,时间就缩短到原来的1/4,真的是很恐怖的提升,算法的力量。

需要注意的是,算法2也不是绝对优势,因为空间复杂度相对提升,这个例子里面,我们不太能感受到空间复杂度提升带来的副作用,但是如果我们要计算的数据很大,比如大到100GB,而你可支配的内存只有64GB,那算法2就不行了。那算法1呢,可能内存是不需要太多,但是需要1个月来计算,那也不行。最好的办法可能就是“折中”,找到一个最适合自己的那个“度”,不浪费空间,又节省时间。

突然想到一句话叫“万法皆有度”,这个万法应该也包括算法吧,哈哈。

    原文作者:老胡de博客
    原文地址: https://www.jianshu.com/p/8691e444b0a4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞