算法 三数之和

采用三种方法,两种暴力,一种前后指针,相比来说,前后指针易懂,且时间复杂度为O(n^2),空间复杂度为O(1),比较友好,其他两种方法,写到一半,感觉太麻烦,没写。


public class ThreeSum {
    //暴力1:去重麻烦,且时间复杂度为O(N^3)
    public List<List<Integer>> threeSum1(int[] nums) {
        int n=nums.length;
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0; i < n-2; i++) {//i的最后一位为n-3
            for (int j = i+1; j < n-1; j++) {
                for (int k = j+1; k < n; k++) {
                    if (nums[i]+nums[j]+nums[k]==0)
                        result.add(Arrays.asList(nums[i],nums[j],nums[k]));//数组转list加入list
                }
            }
        }
        return result;
    }
    //暴力2:哈希表,逻辑太复杂,去重更麻烦
    public List<List<Integer>> threeSum2(int[] nums) {
        int n=nums.length;
        List<List<Integer>> result = new ArrayList<>();
        //hashmap中key为除了要找的那个数之外的两个数之和,value为另外两个数
        HashMap<Integer, List<Integer>> hashMap = new HashMap<>();
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n-1; j++) {
                hashMap.put(nums[i]+nums[j],Arrays.asList(nums[i],nums[j]));
            }
        }

        for (int i = 0; i < n; i++) {
            //nums[i]为那个数。thatNum为key
            int thatNum=0-nums[i];
            if (hashMap.containsKey(thatNum)){
                //已经在表中找到另外两数
                List<Integer> list = hashMap.get(thatNum);
                Integer[] array = (Integer[]) list.toArray();
                result.add(Arrays.asList(nums[i],array[0],array[1]));
            }

        }


        return result;
    }
    //前后指针:时间复杂度O(N^2)
    public List<List<Integer>> threeSum3(int[] nums){
        int n = nums.length;
        List<List<Integer>> result = new ArrayList<>();
        // 先对数组进行排序,快排O(NlogN)
        Arrays.sort(nums);
        for( int i = 0; i < n; i++ ){
            //核心大于0,则左右指针必大于0,退出
            if( nums[i] > 0 )
                break;
            //相等的核心跳过,去重,并且防止数组越界,保证核心为最左边的数,也防止了下面左指针会和核心相等的情况
            if( i > 0 && nums[i] == nums[i-1] )
                continue;
            // 定义左右指针(索引位置)
            int lp = i + 1;
            int rp = n - 1;
            // 只要左右不重叠,就继续移动指针
            while( lp < rp ){
                int sum = nums[i] + nums[lp] + nums[rp];
                if( sum == 0 ){
                    result.add(Arrays.asList(nums[i], nums[lp], nums[rp]));
                    lp ++;
                    rp --;
                    //lp<rp防止rp=lp,如果左右指针相同,向内移动
                    while( lp < rp && nums[lp] == nums[lp - 1] )
                        lp ++;
                    while( lp < rp && nums[rp] == nums[rp + 1] )
                        rp --;
                }
                //左指针右移,增大值
                else if( sum < 0 )
                    lp ++;
                else//右指针左移,减小值
                    rp --;
            }
        }
        return result;
    }
    public static void main(String[] args) {
        int[] nums = {-1,0,1,2,-1,-4,-2,-3,3,0,4};
        ThreeSum threeSum = new ThreeSum();
        List<List<Integer>> lists = threeSum.threeSum3(nums);
        System.out.println(lists);
    }
}

涉及知识点:

1.list已经重写tostring,可以直接打印,并且有序可重复,set无序不可重复。

2.数组可以直接转为list,list也可转数组。

3.前后指针实际上有分治的思想

4.左右指针相遇,结束循环

5.一般说的时间复杂度都为平均复杂度

6.元组一般无顺序一说。

7.暴力法搜索时间复杂度为O(N^3),要进行优化,可通过双指针动态消去无效解来提高效率。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值