空间代价替代时间代价Map的使用-LeetCode15-三数之和

题目

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

思路

三重for循环超时,排除。先排序。找到第一个非负数的位置。这三个元素有三种情况:0个负数,3个非负数(0);1个负数,2个非负数;2个负数,1个非负数。前两个数用for循环遍历,第三个数使用map的containsKey方法找到,空间代价替代时间代价。注意:不能用list,list.contains(xxx)时间复杂度O(n),而map.containsKey(xxx)时间复杂度小于O(n),尽量使用map。

代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        if(nums.length<=2){
            return res;
        }
        Arrays.sort(nums);
        
        // 找到第一个非负数的位置
        int zeroindex=-1;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==0){
                zeroindex=i;
                break;
            }
            if(nums[i]>0&&i==0){
                zeroindex=i;
                break;
            }
            if(nums[i]>0&&nums[i-1]<0){
                zeroindex=i;
                break;
            }
        }
        
        // 第一个非负数的位置一些特殊情况
        if(zeroindex==-1){
            return res;
        }
        if(zeroindex==0&&nums[0]>0){
            return res;
        }
        if(zeroindex==0&&nums[0]==0){
            if(nums[1]==0&&nums[2]==0){
                List<Integer> list=new ArrayList<Integer>();
                list.add(0);
                list.add(0);
                list.add(0);
                res.add(list);
                return res;
            }else{
                return res;
            }
        }
        
        // 0个负数,3个非负数(0)
        if(zeroindex<nums.length-2){
            if(nums[zeroindex]==0&&nums[zeroindex+1]==0&&nums[zeroindex+2]==0){
                List<Integer> list=new ArrayList<Integer>();
                list.add(0);
                list.add(0);
                list.add(0);
                if(!res.contains(list)){
                    res.add(list);
                }
            }
        }
        
        // Map以空间换时间,containsKey方法时间复杂度小于O(n),找第三个数不用for循环而使用map降低时间复杂度
        Map<String,Integer> map_after0=new HashMap<String,Integer>();
        int repeatNum=1;
        for(int i=zeroindex;i<nums.length;i++){
            if(i!=zeroindex&&nums[i-1]==nums[i]){
                repeatNum++;
            }else{
                repeatNum=1;
            }
            map_after0.put(""+nums[i]+"-"+repeatNum,nums[i]);
        }
        // 1个负数,2个非负数
        for(int i=0;i<zeroindex;i++){
            // 重复,跳过
            if(i!=0&&nums[i-1]==nums[i]){
                continue;
            }
            if(zeroindex==nums.length-1){
                break;
            }
            
            for(int j=zeroindex;j<nums.length-1;j++){
                // 重复,跳过
                if(j!=zeroindex&&nums[j-1]==nums[j]){
                    continue;
                }
                // 减少j的一半冗余时间
                if(((float)nums[i])*(-0.5)<nums[j]){
                    break;
                }
                
                int expect=nums[i]*(-1)-nums[j];
                if(nums[j]==expect){
                    if(nums[j+1]==expect){
                         List<Integer> list=new ArrayList<Integer>();
                         list.add(nums[i]);
                         list.add(nums[j]);
                         list.add(expect);
                         // list.contains时间复杂度O(n),不用
                         // if(!res.contains(list)){
                         //     res.add(list);
                         // }
                         res.add(list);
                    }else{
                        
                    }
                }else{
                    
                    // 找第三个数不用for循环而使用map的containsKey降低时间复杂度
                    if(map_after0.containsKey(""+expect+"-"+"1")){
                        List<Integer> list=new ArrayList<Integer>();
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(expect);
                        // list.contains时间复杂度O(n),不用
                        // if(!res.contains(list)){
                        //     res.add(list);
                        // }
                        res.add(list);
                    }else{
                        
                    } 
                }
                
            }
        }
        
        // 2个负数,1个非负数
        if(zeroindex==1){
            return res;
        }else{
            
            // Map以空间换时间,containsKey方法时间复杂度小于O(n),找第三个数不用for循环而使用map降低时间复杂度
            Map<String,Integer> map_before0=new HashMap<String,Integer>();
            int repeatNum2=1;
            for(int i=0;i<zeroindex;i++){
                if(i!=0&&nums[i-1]==nums[i]){
                    repeatNum2++;
                }else{
                    repeatNum2=1;
                }
                map_before0.put(""+nums[i]+"-"+repeatNum2,nums[i]);
            }
            // 2个负数,1个非负数
            for(int k=zeroindex;k<nums.length;k++){
                // 重复,跳过
                if(k!=zeroindex&&nums[k-1]==nums[k]){
                    continue;
                }
                
                for(int j=zeroindex-1;j>0;j--){
                    // 重复,跳过
                    if(j!=zeroindex-1&&nums[j+1]==nums[j]){
                        continue;
                    }
                    // 减少j的一半冗余时间
                    if(((float)nums[k])*(0.5)<nums[j]*(-1)){
                        break;
                    }
                    
                    int expect=nums[k]*(-1)-nums[j];
                    if(nums[j]==expect){
                        if(nums[j-1]==expect){
                                List<Integer> list=new ArrayList<Integer>();
                                list.add(expect);
                                list.add(nums[j]);
                                list.add(nums[k]);
                                // list.contains时间复杂度O(n),不用
                                // if(!res.contains(list)){
                                //     res.add(list);
                                // }  
                                res.add(list);
                        }else{
    
                        }
                    }else{
                            // 找第三个数不用for循环而使用map的containsKey降低时间复杂度
                            if(map_before0.containsKey(""+expect+"-"+"1")){
                                List<Integer> list=new ArrayList<Integer>();
                                list.add(expect);
                                list.add(nums[j]);
                                list.add(nums[k]);
                                // list.contains时间复杂度O(n),不用
                                // if(!res.contains(list)){
                                //     res.add(list);
                                // }
                                res.add(list);
                            }                        
                    }
                    
                }

            }
        }
        return res;
    }
}

其他思路:

左右指针。http://www.cnblogs.com/liuliu5151/p/9124596.html

注意

1.Map以空间换时间,containsKey方法时间复杂度小于O(n),找第三个数不用for循环而使用map的containsKey方法降低时间复杂度。

2.注意list.contains(xxx)占用的时间复杂度O(n),不用。

3.左右指针较快。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值