leetcode-1. 两数之和

103 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

  1. 两数之和

题目

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6 输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6 输出:[0,1]

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

代码

暴力法

int n = nums.length;
for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
        if (nums[i] + nums[j] == target) {
            return new int[]{i, j};
        }
    }
}
return new int[0];

HashMap法

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

Stream法

暴力流

IntStream.range(0, nums.length)
    .boxed()
    .flatMap(i -> IntStream.range(i + 1, nums.length)
             .filter(j -> nums[i] + nums[j] == target)
             .mapToObj(j -> new int[]{i, j})
            )
    .findFirst().orElse(new int[0]);
执行结果:通过
显示详情
添加备注
执行用时:1362 ms, 在所有 Java 提交中击败了5.14% 的用户
内存消耗:42.4 MB, 在所有 Java 提交中击败了5.41% 的用户
通过测试用例:57 / 57

暴力二开流

IntStream.range(0, nums.length)
    .boxed()
    .flatMap(i -> IntStream.range(i + 1, nums.length)
             .filter(j -> nums[i] + nums[j] == target)
             .mapToObj(j -> new int[]{i, j})
            )
    .findAny().orElse(new int[0]);
执行用时:1139 ms, 在所有 Java 提交中击败了5.14% 的用户
内存消耗:42.3 MB, 在所有 Java 提交中击败了6.08% 的用户
通过测试用例:57 / 57

暴力三开流

IntStream.range(0, nums.length)
    .mapToObj(i -> IntStream.range(i + 1, nums.length)
              .filter(j -> nums[i] + nums[j] == target)
              .mapToObj(j -> new int[]{i, j})
              .findAny().orElse(null)
             )
    .filter(x->x!=null)
    .findAny().orElse(new int[0]);
执行用时:1048 ms, 在所有 Java 提交中击败了5.14% 的用户
内存消耗:42.1 MB, 在所有 Java 提交中击败了10.43% 的用户
通过测试用例:57 / 57

二开里面,使用findAny替代findFirst。

三开努力去除了装箱,并在内部流里面使用findAny提前返回数据。

实在优化不了了。😂

暴力流和这个题的暴力循环没区别,并且boxed()的性能消耗很大,findAny()与findFirst()会返回Optional类型,又是一次性能消耗。

HashMap流

Map<Integer, Integer> map = new HashMap<>();
IntStream.range(0, nums.length)
    .filter(i -> {
        if (map.containsKey(target-nums[i])){
            return true;
        }else {
            map.put(nums[i],i);
            return false;
        }
    })
    .mapToObj(i -> new int[] {map.get(target - nums[i]), i})
    .findAny().orElse(new int[0]);
执行用时:5 ms, 在所有 Java 提交中击败了48.56% 的用户
内存消耗:41.4 MB, 在所有 Java 提交中击败了82.69% 的用户
通过测试用例:57 / 57

本题算法的核心性能保证是hashmap,hashmap的理想状态下查找时间复杂度是O(1)。外部迭代时间复杂度是O(n),实际上流使用的是内部迭代,这里外部迭代是相对于hashmap操作来说的。

总结

Stream中findAny()性能比findFirst()性能高。据说这题通过率只有50%。