• [LeetCode]两数之和


    1、题目

      给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

      你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

      示例:

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

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

    class Solution {
        public int[] twoSum(int[] nums, int target) {
              
            }
    }

     

    2、分析

       转换一下思路,求一个数组中是否存在两个数其和为目标值target的问题等价于对于数组中的任意一个数值x,数组中是否存在数值(target-x)。而对于数组中是否存在某数值的问题,本质上是查找问题,可以使用常见的查找算法如遍历查找、二分查找等算法来实现。这里我们使用Java中的一种特殊的数据结构Map,利用Map中时间复杂度为O(1)的方法containsKey来进行查找。所以需要先利用已有的数组构造一个map,然后利用map逐个进行遍历查找。

     

    3、代码

      (1)方法一

        代码:

     public int[] twoSum(int[] nums, int target) {
                 //构造Map,注意此处指定了map中键和值的类型为Integer,因为数组和数组下标都是整型
                Map<Integer,Integer> hashmap = new HashMap<>();
                //初始化map,简历数组值和下标的对应关系
                for(int i=0;i<nums.length;i++){
                    hashmap.put(nums[i], i);
                }
                //for循环进行遍历查找
                for(int i=0;i<nums.length;i++){
                    //对于数组中的每个值nums[i],判断数组中是否存在target - nums[i]
                    int goal = target - nums[i];
                    /*
                     * 当hashmap.containsKey(goal)返回值为true时候,只能说明存在两个数nums[i]和goal,使得两数之和为
                     * target,但是,题目还要求不能重复利用这个数组中同样的元素,所以还要加上判断条件hashmap.get(goal) != i
                       当两个条件均满足时候,才能满足题目要求
                    */
                    if(hashmap.containsKey(goal) && hashmap.get(goal) != i){
                        //返回两个的下标
                        return new int[]{i,hashmap.get(goal)};
                    }
                }
               return null;
            }

        复杂度分析:

        • 时间复杂度O(n):算法中两次遍历大小为n的数组,而且在每个for循环内部都是时间复杂度为O(1)的操作,所以最终的时间复杂度为O(n)
        • 空间复杂度O(n):算法中需要额外的空间来存放包含n个键值对元素的map对象,所以空间复杂度O(n)。

      (2)方法二

        此方法对上述算法进行些许优化,采用一次时间复杂度为O(n)的遍历。上述算法先遍历一次构造map,然后遍历一次进行查找。本方法采用边查找边构造的方法,只需要遍历一次即可。

        代码:

         //此算法仍然采用Map的数据结构,但是采用的是边查找边构造map的过程
            Map<Integer,Integer> map = new HashMap<>();
            for(int i=0;i<nums.length;i++){
                int goal = target - nums[i];
                /*如果map.containsKey(nums[i]返回值为true,则查找到了两个不重复的数值nums[i]和goal,其和为target
                 *此处不用进行上述算法中的hashmap.get(goal) != i判断,因为下标为i的元素nums[i]还没有加入map中
                 *也即goal和nums[i]不能是重复的元素,可能数值相同,但是在数组中不是同一个元素,没有重复使用
                 */
                if(map.containsKey(goal)){
                    return new int[]{map.get(goal),i};
                }
                //map.containsKey(goal)为false时候,执行此put操纵
                map.put(nums[i], i);
            }
            return null;

        复杂度分析:

        • 时间复杂度O(n):算法中只需要一次遍历大小为n的数组,而且在此for循环内部都是时间复杂度为O(1)的操作,所以最终的时间复杂度为O(n)
        • 空间复杂度O(n):算法中需要额外的空间来存放包含n个键值对元素的map对象,所以空间复杂度O(n)。

     本文为个人思考并参考网上部分资料所写,如有不合理、不正确的地方,欢迎下方留言交流。

  • 相关阅读:
    java线程实现和集合类综合问题
    软件体系结构风格总结
    java如何实现对象的克隆
    24小时实现盲打(程序员快速入门)
    测试面向对象软件时,设计集成测试用例的方法
    对白盒测试的一些理解
    对于工程建模需要画的图的分析及体会
    在软件开发的早期阶段为什么要进行可行性研究?应该从哪些方面研究目标系统的可行性?
    谭静第一周任务
    陈林艳第一周任务
  • 原文地址:https://www.cnblogs.com/xwwbb/p/11380243.html
Copyright © 2020-2023  润新知