leetcode 1. 两数之和

78 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

题目描述

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

你可以假设每种输入只会对应一个答案。

但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。

例如:nums = [1,5,15,23]    target = 16 --> [0,2]

解法思路

假设存在任意两值 x,y ∈ nums 若存在 x + y = target --> y = target - x

在这里我们只需要求到 x 与 y 值相对应的nums索引假设为 i 与 j

1.暴力破解双循环法

循环遍历数组nums;x = nums[i],利用target - x = y 得到 y 去遍历数组nums 取得与之匹配的值的下标j 最后返回 [i,j]

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

    private int getIndexOfValue(int[] nums, int value) {
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == value) return i;
        }
        return -1;
    }
}

2.暴力破解优化版本

在上面循环中我们会发现,假如在一次循环中 x = nums[i] 通过计算的 y 找不到符合的 j 反之可得出 i 不可能是正确答案中的一个.

我们应该在内层寻找 y 的下标 j 的循环中排除 x 对应的下标 i

循环遍历数组nums; x = nums[i],利用target - x = y 得到 y 去遍历数组nums 这时从 i 以后开始遍历,取得与之匹配的值的下标j 最后返回 [i,j]

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

    private int getIndexOfValue(int[] nums, int value, int startIndex) {
        for (int i = startIndex + 1; i < nums.length; i++) {
            if (nums[i] == value) return i;
        }
        return -1;
    }
}

3.哈希破解法

在上面两次解法中我们会发现,最终影响效率的是寻找 y 的 下标 j 所耗费的时间复杂度较高

我们可以联想到Hash的查找效率非常之快达到了O(1) 而不是上述的O(n)

将数组转化为Hash结构,在java中我们知道典型的Hash的代表是Map函数,然后在进行相同的逻辑去寻找 y 的 下标 j

class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 转化为hash结构
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }

        int x, y;
        for (int i = 0; i < nums.length; i++) {
            x = nums[i];
            y = target - x;
            if (map.containsKey(y)) {
                return new int[]{i, map.get(y)};
            }
        }
        return new int[0];
    }
}

4.哈希破解优化版

我们可以不用一次性全部将nums的数值置入Map中之后再去统一查找,而是在每一次置入的时候去查找是否有匹配的 y 在map中.

不存在在将x 与 i 置入map中

这样可以大幅度减少相对空间复杂度

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

每一个解决方案的衍生都是一个思考的过程,我们不应该去一味的追求解题刷题的速度,而是提高自己思维,探求未知。

如有不当之处望指出

闻道有先后,术业有专攻,如是而已 -- 《师说》