算法通关村第五关——n数之和专题

77 阅读1分钟

1.两数之和

使用map集合,来减少时间复杂度;

public class TwoNumSum{
    public static int[] twoSum(int[] nums,int target){
        //集合中记录的是之前出现过的值,和当时该值的下标
        Map<Integer,Integer> map =new HashMap<>();
        for(int i=0;i<nums.length;i++){
            // 如果map中记录有当前的target-nums[i],那么就找到了一组数据满足a+b=target;只需要从map中取出记录的a的下标以及当前值b的下标i,返回即可;
            if(map.containsKey(target-nums[i])){
                return new int[]{map.get(target-nums[i]),i};
            }else{
                // 说明map中还没有添加过当前下标所对应的值,需要进行记录,用于后续比较
                map.put(nums[i],i);
            }
        }
        return new int[0];
    }
}

2.三数之和

使用排序+双指针

将无序数组排好序的目的是为了让碰撞双指针的移动方向更加明确,也方便去重;

 public static List<List<Integer>> sumOfThreeNums(int[] nums) {
        if (nums.length < 3) {
            return new ArrayList<>();
        }
        // 使用util包下默认的排序(快排)
        Arrays.sort(nums);
        // 返回结果集合
        List<List<Integer>> resList = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            // 如果当前的选定的数字已经大于0,说明该下标之后的数字全部是大于0的,所以不可能出现三数之和为0的情况;
            if (nums[i] > 0) {
                break;
            }
            // 如果当前数和前一个数相同,那么直接跳过
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            // 定义碰撞双指针
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                // 如果三数之和等于0
                if (sum == 0) {
                    // 先在返回结果集合中添加一条新的集合数据;
                    resList.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 去重,如果数组出现这种情况(-1,-1,-1,0,2,2,2)不去重很有可能会记录相同的结果,不符合题意 
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    //不管是去重后,还是本来就不用去重,都需要left++,right--,改变指针;
                    left++;
                    right--;
                } else if (sum < 0) { //如果sum<0 说明nums[left]还太小,需要left往后移,使nums[left]变大
                    left++;
                } else { // 如果sum > 0 说明nums[right] 太大了,需要right往前移,使nums[right]减小
                    right--;
                }
            }

        }
        return resList;
    }