一、两数之和

1、问题描述

image

2、问题提示

image

3、分析

给定数组,要求从数组中抽取两个不等的元素a,b来构成a+b=target

3.1 使用排序后指针夹击法

描述:当一个数组是有序的,那么如果要求a,b之和等于target,那么可以把数组最小的值代为a,数组最大的值代为b,判断此时的ab之和是否满足条件;
1)如果当前ab之和大于目标值,可以将b左移,
2)反之可以将a右移。
3)如果在ab重合之前找到符合条件的值,那么就返回当前ab代入的值的当前下标。
4)如果ab重合了,那么则没有答案。
5)此题所给数组是无序的,并且需要返回解的下标值。所以我们需要在排序前将之前元素的下标使用map记录下来。因为答案是唯一的,所以不需要担心key会重复。除非是相同的元素出现两次,并且这个元素*2恰好是答案。那么直接返回这俩元素下标即可。
5.1举例)数组:3 3 1 target:6 答案是 0 1。
5.2举例)数组 3 3 2 1 target:5 这个是不符合题意的,所以不用考虑。
6)最后我们可以拿到ab的值去map中找到对应的下标。

3.1.2 实现代码

public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.getOrDefault(nums[i],-1)!=-1){
                if(nums[i]*2==target){
                    return new int[]{map.get(nums[i]),i};
                }else{
                    map.put(nums[i],i);
                }
            }else{
                map.put(nums[i],i);
            }
        }
        Arrays.sort(nums);
        int a = 0;
        int b = nums.length-1;
        while(a<b) {
            while (a < b && (nums[a] + nums[b]) < target) {
                a++;
            }
            while (a < b && (nums[a] + nums[b] > target)) {
                b--;
            }
            if ((nums[a] + nums[b]) == target) {
                return new int[]{map.get(nums[a]), map.get(nums[b])};
            }
        }
        return new int[]{};
    }

3.1.3 算法分析

时间复杂度:O(n)循环次数和数组长度成一次函数正比例。
空间复杂度:O(n)使用了map结构来存储数组元素,使用空间和数组长度成一次函数正比例。




3.2 使用map结构存储法

描述:首先实例一个map的映射结构。key是数组元素,value是数组下标。
1)遍历数组,遍历时逻辑如下,假如遍历到位置i,首先判断target-i是否存在map的value中。
2)如果不存在,那么map.put(nums[i],i);
3)如果存在,那么直接返回map.get(target-i)i的下标
4) 注意,在遍历的过程中,同时需要判断是否元素冲突,如果冲突按照方法3.1.1的冲突来解决。
5)如果遍历完成之后,没有结果,那么返回空数组

3.2.1 代码实现

public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.getOrDefault(nums[i],-1)!=-1){
                if(nums[i]*2==target){
                    return new int[]{map.get(nums[i]),i};
                }
            }else{
                if(map.keySet().contains(target-nums[i])){
                    return new int[]{map.get(target-nums[i]),i};
                }else{
                    map.put(nums[i],i);
                }
            }
        }
        return new int[]{};
    }

3.2.2 算法分析

时间复杂度:O(n)循环次数和数组长度成一次函数正比例。
空间复杂度:O(n)使用了map结构来存储数组元素,使用空间和数组长度成一次函数正比例。

3.3 使用暴力破解

描述:

1.外层循环进行遍历,i从0开始到数组结束

2.内层循环j从i的后一位进行遍历

3.内层遍历逻辑:如果发现i+j = targe那么直接返回结果,如果没有发现则返回空

4.注意这里j是从i后面一位开始遍历,是因为j如果从0开始遍历,其实是和i从0开始遍历冲突,所以才选择j= i+1

3.3.1 代码实现

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

3.3.2 算法分析

时间复杂度:O(n^2) 循环次数和数组长度成二次函数正比例。
空间复杂度:O(1) 定义了两个循环变量i,j。没有开辟多余空间。

posted @ 2021-04-18 18:09  keinojust  阅读(53)  评论(0)    收藏  举报