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) {
        int [] ret = new int[2];
        boolean flag = false;
        for(int i = 0; i < nums.length-1; i++)
        {
            if(flag)
            {
                break;
            }
            for(int j=i+1; j < nums.length; j++)
            {
                if(nums[i] + nums[j] == target)
                {
                    ret[0] = i;
                    ret[1] = j;
                    flag = true;
                    break;
                }
            }
        }
        return ret;
    }
}

答案思路

    要从一个数组中找到两个数之和为给定数,我想到的就是暴力查询,由于同样的数不能用两次,所以内层循环是从i+1开始,又因为j是要小于nums.length的,所以外层循环是到nums.length-1结束。咋内层循环体中,判断nums[i] + nums[j]是否等于target,如果等于就Break,不等就继续向下。双层的循环没办法用一个break进行解决,所以我添加了一个判断条件,来控制外层循环。

 

解答——两遍哈希

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();

        for(int i =0; i < nums.length; i++)
        {
            map.put(nums[i], i);
        }

        for(int i =0; i < nums.length; i++)
        {
            int need = target-nums[i];
            if(map.containsKey(need) && map.get(need) != i)
            {
                return new int[]{i, map.get(need)};
            }
        }
        throw new IllegalArgumentException("no such two numbers");
    }
}

思路

主要分为几个点:

1. 为什么要将值作为key而下标作为value

2. 如果数组中的值出现了重复,hashMap会丢掉前一个下标,答案不会出错吗?

首先,为什么要用哈希表?因为哈希表的查找速度很快,可以将O(n)降到O(1),这里是采用了使用空间来换取时间的方法,不需要嵌套循环就可以查找出满足题目要求的数组下标。即便数组中有重复的值也不会出错。

哈希表可以通过函数  containsKey( )  来判断表中是否存在某个key,而且可以通过key使用get() 来取出value值。

循环遍历数组nums,将数组中的值存入哈希表中,值为Key而下标为value。

再次循环数组nums,从0开始循环,取出nums[i],用target减去nums[i],我们就得到了如果当前 i 是答案的其中一个下标的话,那么另一个答案的值应为多少,将这个值存放在need变量中,然后到hashmap中使用containsKey去查询是否存在key为need的键值对,如果存在,取出need对应的value值也就是下标,查看是否与当前的 i 相同(题目要求不能为同一个元素),若不同,则查询结束,返回当前 i 的值以及need对应的value值。

其实这边有一个很巧妙的点(或许不算巧妙八,只是我太菜),我在做的时候,只考虑到了将两个数相加来判断是否与target相等,没有考虑到可以用target来减去一个数得出结果然后判断数组中是否存在这个得出的结果。这样思考的话,就把思路从根据下标找数变成了根据数来找下标。

 

然后说明为什么即便数组中存在两个相同的数也能得出正确的结果。我们知道,哈希表中的Key是不能相同的,而如果数组中存在两个相同的数的话,在第一次循环的时候,第二个数的下标会覆盖掉第一个数的下标,注意,是下标,这很重要。虽然覆盖了,但是我们第二次循环循环的是数组,是从数组的下标0开始的,我举个栗子,测试用例数组为[2,2,3,4],target为4,我们直接看的话可以知道这个用例的返回值应该为[0,1]。而程序运行也会给我们相同的结果。第一次循环,将数组的值和下标存放到hashmap中:<2,1> <3,2><4,3> ; 第二次循环,i从0开始,取出nums[i]为2,用target减去2等于2,也就是说,如果hashmap中存在一个Key为2的键值对,且value不等于i,就说明找到了结果。主要是,循环数组的时候是从前向后循环,而hashmap中存放的是后一个数的下标,如果题目target只能由重复的数得到,那么在循环到第一个数的时候,就可以直接返回正确的结果了。这里可以看出,正是由于hashmap中无法存放两个相同的kay,题目才能得到正确的输出。

 

 

解答——一遍哈希

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
     Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i < nums.length; i++)
        {
            int need = target - nums[i];
            if(map.containsKey(need))
            {
                return new int[]{ map.get(need),i};
            }
            map.put(nums[i] ,i);
        }
        throw new IllegalArgumentException();
    }
}

思路

        在两遍哈希的时候,我们是第一次循环将数组中的值保存进去,第二次循环的时候再去查询匹配,那么我们可不可以在一次循环中就搞定呢?当然可以。在循环的时候,我们先判断hashmap中是否存在能与nums[i]相加为target的键存在,如果不存在,将当前的nums[i]和下标i存放到hashmap中,i++,继续判断。

     也就是说,数组中的每一个都只需要和在它前面的数进行匹配,因为在它后面的数会去匹配它,如果匹配不上的话,把自己也加入到Hashmap中,交给后面的数去匹配。

 

 

 

 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值