【LeetCode】15 三数之和3Sum

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0?
找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]


弯路:
1 最先想到的应该是三层for循环暴力求解,可写了也没什么意义。
2 之后又想到可不可以借鉴两数之和的思路,通过HashMap进行O(n^ 3) 向 O(n^2)的简化。事实证明,我想多了,经过两个小时的自闭debug和各种复杂数据结构的推演,得出了一个结论,不要妄图依赖Map的提供的api。也可能是对这道题来说,这种方法不好用。
附上使用HashMap的思路并在文章最后附上错误代码
(1)先用一个Map<Map<Integer, Integer>, Integer>将前两个元素i,j和他们加在一起的需要的数字连接起来,构造这个结构的时间需要是n^2
(2)排序后对每个nums中的元素进行遍历,对每个元素查询是否在上述Map的value集中存在该元素,若存在,进行去重后即可添加相应元素到结果中。
3 发现了一个用Map减少一重遍历的实现:https://blog.csdn.net/lnho2015/article/details/51314133
具体思路是只把第一个元素用Map连接

正确思路:
需要解决的问题是:如何把三重遍历变为双重遍历
解决思路也是重点:排序+双指针
1 先对nums进行排序,利用排序和两个“指针”,将三重遍历变为双重遍历,思路类似快排
2 另外,一定要对数据进行去重,否则一些极端输入如[0,0,0,0,0,0,0,0,0,0],速度会非常慢
具体思路:
1 对异常数据进行处理,如[1,2]和[0,0,0]
2 因为已经排过序了,所以如果当前的元素大于0,那么后面的元素一定也大于0,必不符合条件,所以直接return
3 对起点进行去重之后,对当前元素之后的元素进行遍历,设置两个指针left和right,分别从左右向中间移动,小则left右移,大则right左移。此处必须保证去重,每次进行判定的必须是“新”的组合。

下面的算法运行时间在55~59ms之间
在这里插入图片描述

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        
        if (nums.length < 3){
            return result;
        }
        if(nums.length == 3){
            if (nums[0] + nums[1] + nums[2] == 0){
                result.add(Arrays.asList(nums[0], nums[1], nums[2]));
                return result;
            }
        }
        
        for (int base = 0;base < nums.length - 3;base++){
            if(nums[base] > 0)
                return result;
            //起点去重
            if(base > 0 && nums[base] == nums[base - 1]){
                continue;
            }
            
            int left = base + 1;
            int right = nums.length - 1;
            List<Integer> temp = null;
            
            while (left < right){
                if (nums[left] + nums[right] + nums[base] == 0){
                    temp = Arrays.asList(nums[base], nums[left], nums[right]);
                    result.add(temp);
                    //左右去重
                    while (left < right && nums[left + 1] == nums[left])
                        left++;
                    while (left < right && nums[right - 1] == nums[right])
                        right--;
                    left++;
                    right--;
                }
                else if (nums[left] + nums[right] + nums[base] < 0)
                    left++;
                else if (nums[left] + nums[right] + nums[base] > 0)
                    right--;
            }
        }
        return result;
    }
}

错误代码

class Solution {
    
    public List<Map<Integer, Integer>> getKeys(Map map, Integer value){
        List<Map<Integer, Integer>> keys = new ArrayList<>();
        Set set = map.entrySet(); 
        Iterator<Map.Entry<Map<Integer,Integer>, Integer>> iterator = set.iterator();
        while(iterator.hasNext()){
            Map.Entry<Map<Integer,Integer>, Integer> entry = iterator.next();
            if(entry.getValue().equals(value)){
                keys.add(entry.getKey());
            }
        }
        return keys;
    }

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        Map<Map<Integer, Integer>, Integer> map = new HashMap<>();
        int need;
        //建立前两个元素与需求的第三个元素的HashMap
        for (int i = 0;i < nums.length;i++){
            if (i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            for (int j = i + 1;j < nums.length;j++){
                if (j > i + 1 && nums[j] == nums[j-1]){
                    continue;
                }
                need = 0 - nums[i] - nums[j];
                //System.out.println(need);
                Map<Integer, Integer> ij = new HashMap<>();
                ij.put(i,j);
                map.put(ij, need);
            }
        }
        System.out.println(map);
        List <Integer> temp = null;
        for (int i = 0;i < nums.length;i++){
            if (i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            if (map.containsValue(nums[i])){
                System.out.println(i);
                for (Map<Integer, Integer> it : getKeys(map,nums[i])){
                    System.out.println(i + "..." + it);
                    Iterator<Integer> iter = it.keySet().iterator();
                    Integer key = iter.next();
                    Integer value = it.get(key);
                    if(i == key || i == value)
                        continue;
                    System.out.println(i +"  "+ key +"  "+ value);
                    temp = Arrays.asList(nums[i],nums[key],nums[value]);

                    result.add(temp);
                }
            }
        }
        
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36269372/article/details/83476126