Leetcode题库-两数之和(java语言版)

第一种方法(for循环嵌套暴力求解)

根据题目描述:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
这样大多数人的思路都很明确,就是从头遍历数组找到两个数和目标数相同则返回下标
核心代码如下:

   for (int i =0;i<num.length;i++){
        for (int j=i+1;j<num.length;j++ ){
           if ((num[i]+num[j])==target){
                System.out.println("序号为:["+i+","+j+"]");
            }
       }
   }

这样确实可以得到结果,但是用时较长,在数组较大时,速度较慢。也就是时间复杂度很高O(n^2),一般在我们的程序中,时间复杂度不能为指数递增。这个方法虽然方便,大多数人都能想到,但是程序不是最优。
程序执行结果:
在这里插入图片描述
提交程序用时

第二种方法-(map)

在第一种方法的基础上,我们不能允许程序中有指数递增的时间复杂度存在,我们得进行优化。怎么优化呢?我们想到java中有Map接口Map接口一一映射. 可以通过键来获取值。给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值。
我们可以将数组中的元素和下标存储到map中,因为map键值对映射的时间复杂度为O(1),这样的话就大大增加了程序的执行速度。
核心代码如下

Map<Integer,Integer> map = new HashMap ();
    for (int i=0;i<num.length;i++){
        map.put ( num[i] ,i);
    }
    for (int i = 0;i<num.length;i++){
        int shuzhi = target-num[i];//对应map中的键
        //这个判断当目标数减去数组里的数时,有可能在数组中不存在,也就是没有对应的建
         if (map.containsKey ( shuzhi )&&map.get ( shuzhi)>i){
            System.out.println("序号为:["+i+","+map.get ( shuzhi )+"]");
        }
    }

这样得到的结果用的时间比第一种大大减少,时间复杂度为O(n).这样就对第一种方法进行了优化。提高了效率。
程序执行结果:
在这里插入图片描述
提交程序用时

第三种方法-终极方法(时间复杂度最低)

有人可能会想,第二种方法已经很快了,还有比这个更快的方法吗,当然。
观察第二种方法我们不难发现,他将数组元素存储map与目标元素的具体比较分别进行了处理。我们是不是可以这样想,将他们放到一起,在一个for中进行处理,这样就减少了一个步骤。速度能比第二种方法较快一点。时间复杂度与第二种相同都是O(n).
核心代码如下

for (int i=0;i<num.length;i++){
        int shuzi = target-num[i];
        if (map.containsKey ( shuzi )){
            System.out.println("序号为:["+map.get ( shuzi )+","+i+"]");
        }
        map.put ( num[i],i );
    }

代码量相比第二种减少了一些,效率也更高。这个代码将找找两个数的和等于目标数的操作数组元素存储到map中的操作放到了一起,先进行判断,再进行存储。
程序执行结果:在这里插入图片描述
提交程序用时

第四种方法-先排序在根据位置进行比较

第四种方法用时介于第一中和第二种方法之间,时间复杂度是log级别的。
具体思路就是:首先得进行排序(排序方法有好多,冒泡,快速,选择,或者用java自带的排序函数),然后标记排好序数组元素的首位置和末位置,将两者对应元素相加与目标数进行比较,大于目标数则将末尾值向前移动,小于目标数首位置向后移动,直到找到等于目标数的两个元素停止,输出下标。
需要一个存储下标的容器,我选择map。但是map中的key是不能重复的,所以,我们可以想到,让一个key拥有多个value。例如[3,3]数组,存储到map中就是,key:3,value:[0,1]。这样就可以解决遇到数组中重复元素时,map键不能重复的问题。
核心代码如下

  int a=0;
    int b=num.length-1;
    Map<Integer,List<Integer>> map = new HashMap();
    for (int i = 0; i < num.length; i++) {
        //当不存在键时,正常插入
        if (!map.containsKey ( num[i] )){
            List<Integer> list1 = new ArrayList <> (  );
            list1.add ( i );
            map.put ( num[i],list1 ); // 将值和下标存入Map
        }
        else {
            //当存在键时,将键对应的值添加道列表里,这样就形成了一个键对应多个值
            List<Integer> list2 = map.get ( num[i]);
            list2.add ( i );
            map.put ( num[i],list2 );
        }
    }
    System.out.println(map);
    Arrays.sort (num);//用自带的排序函数
    for (int i=0;i<num.length;i++){
         if ((num[a]+num[b])>target){
                 b=b-1;
         }
         else if((num[a]+num[b])<target)
         {
                 a=a+1;
         }
         else {
             if (num[a]!=num[b]){
                 System.out.println("序号为:"+map.get (num[a])+"<><><>"+map.get (num[b]));


             }else if(a!=b){
                 System.out.println("序号为:"+map.get (num[a]));
             }
             a=a+1;
         }
    }

程序执行结果:
在这里插入图片描述
这个结果测试了极端问题,数组中有重复元素时,map一个键
对应多个值,可以实现。其他的测试数据也与前三种相同。时间复杂度O(nlogn)级别。

总结

leetcode第一题,两数之和,看似不难,但背后需要考虑很多问题。时间与空间转换问题,数组极端值问题等等。通过这一道题我收获很多,明白了考虑问题得全面。本博客由于本人能力有限,肯定有很多的问题,再此大家谅解。
2019-1-15记录

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值