力扣网-三数之和等于0

问题简介

在这里插入图片描述
在这里插入图片描述

编程思路

  • 三层循环-暴力方法必须掌握
  • 双向遍历
    • image-20220210105937281

代码实现

第一个版本

ThreeNum类

import java.util.Objects;

/**
 * 三数之和等于0
 *
 * @author songquanheng
 * 2022/2/10-8:52
 */
public class ThreeNum {
    private Integer a;
    private Integer b;
    private Integer c;

    public ThreeNum(Integer a, Integer b, Integer c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ThreeNum threeNum = (ThreeNum) o;
        return Objects.equals(a, threeNum.a) &&
                Objects.equals(b, threeNum.b) &&
                Objects.equals(c, threeNum.c);
    }

    @Override
    public int hashCode() {

        return Objects.hash(a, b, c);
    }

    public Integer getA() {
        return a;
    }

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getB() {
        return b;
    }

    public void setB(Integer b) {
        this.b = b;
    }

    public Integer getC() {
        return c;
    }

    public void setC(Integer c) {
        this.c = c;
    }
}

主体方法

    public List<List<Integer>> threeSum(int[] nums) {
        Set<ThreeNum> result = new HashSet<>();
        for(int i=0; i<nums.length; i++) {
            for(int j=i+1;j<nums.length; j++) {
                for (int k=j+1; k<nums.length; k++) {
                    if (nums[i] + nums[j] + nums[k] != 0) {
                        continue;
                    }
                    List<Integer> list = new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[k]));
                    Collections.sort(list);
                    result.add(new ThreeNum(list.get(0), list.get(1), list.get(2)));
                }
            }
        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

image-20220210091452321

 通过了315/318个测试用例,说明算法主题思想是正确的。

第二个版本

 在构造过程中进行了排序,我们首先对于nums数组进行排序。

ThreeNum类没有变化。

主体方法

    public List<List<Integer>> threeSum(int[] nums) {
        List<Integer> param = Arrays.stream(nums)
                .boxed().sorted().collect(Collectors.toList());

        Set<ThreeNum> result = new HashSet<>();
        int size = param.size();
        for(int i = 0; i< size; i++) {
            for(int j=i+1;j<size; j++) {
                for (int k=j+1; k<size; k++) {
                    Integer first = param.get(i);
                    Integer second = param.get(j);
                    Integer third = param.get(k);
                    if (first + second + third != 0) {
                        continue;
                    }

                    result.add(new ThreeNum(first, second, third));
                }
            }
        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

image-20220210092825124

转化为二层循环-实质上还是三层循环

    public List<List<Integer>> threeSum(int[] nums) {
        List<Integer> param = Arrays.stream(nums)
                .boxed().sorted().collect(Collectors.toList());

        Set<ThreeNum> result = new HashSet<>();
        int size = param.size();
        for (int i = 0; i < size; i++) {

            for (int j = i + 1; j < size; j++) {
                Integer first = param.get(i);
                Integer second = param.get(j);
                Integer thirdShould = 0 - first - second;
                if (param.lastIndexOf(thirdShould) > j) {
                    result.add(new ThreeNum(first, second, thirdShould));
                } else {
                    continue;
                }

            }
        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

第三个版本

主体方法

    public List<List<Integer>> threeSum(int[] nums) {
        List<Integer> param = Arrays.stream(nums)
                .boxed().sorted().collect(Collectors.toList());

        Set<ThreeNum> result = new HashSet<>();
        int size = param.size();
        for (int i = 0; i < size; i++) {
            Integer first = param.get(i);
            for (int j = i + 1; j < size; j++) {
                Integer second = param.get(j);
                Integer thirdShould = 0 - first - second;

                for (int k=j+1; k<size; k++) {
                    if (param.get(k)>thirdShould) {
                        break;
                    }
                    if (param.get(k).equals(thirdShould)) {
                        result.add(new ThreeNum(first, second, thirdShould));

                    }

                }

            }
        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

参考别人思想-左右移动

 到此,笔者已经黔驴技穷了,只好参考别人的思路了。

image-20220210102341351

第一个版本

 说到底这个思想与盛最多的水是异曲同工的事情。

    public List<List<Integer>> threeSum(int[] nums) {
        List<Integer> param = Arrays.stream(nums)
                .boxed().sorted().collect(Collectors.toList());

        Set<ThreeNum> result = new HashSet<>();
        int size = param.size();
        for (int i = 0; i < size; i++) {
            Integer first = param.get(i);
            int j = i + 1;
            int k = size - 1;
            while (j < k) {
                Integer second = param.get(j);
                Integer third = param.get(k);
                int sum = first + second + third;
                if (sum > 0) {
                    k--;
                } else if (sum < 0) {
                    j++;
                } else {
                    result.add(new ThreeNum(first, second, third));
                    break;
                }
            }

        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

image-20220210103331053

image-20220210103536505

 如果直接break,则只会找到一组解

[[-2, 0, 2]]

[-2, 1, 1]会丢失掉

所以,不是找到一个就返回,而是找到一组解之后,继续移动指针。

所以

image-20220210104833281

主体方法-AC版本

    public List<List<Integer>> threeSum(int[] nums) {
        List<Integer> param = Arrays.stream(nums)
                .boxed().sorted().collect(Collectors.toList());

        Set<ThreeNum> result = new HashSet<>();
        int size = param.size();
        for (int i = 0; i < size; i++) {
            Integer first = param.get(i);
            int j = i + 1;
            int k = size - 1;
            while (j < k) {
                Integer second = param.get(j);
                Integer third = param.get(k);
                int sum = first + second + third;
                if (sum > 0) {
                    k--;
                } else if (sum < 0) {
                    j++;
                } else {
                    result.add(new ThreeNum(first, second, third));
                    j++;
                    k--;
                }
            }

        }
        List<List<Integer>> res = new ArrayList<>();
        for (ThreeNum threeNum : result) {
            List<Integer> temp = new ArrayList<>();
            temp.addAll(Arrays.asList(threeNum.getA(), threeNum.getB(), threeNum.getC()));
            res.add(temp);

        }

        return res;
    }

image-20220210104916957

优化

image-20220210105708761

引入去重移除ThreeNum类

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
                return result;
            }

            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            int left = i + 1;
            int right = nums.length - 1;
            while (right > left) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum > 0) {
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
					// 这个地方是关键
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;
                    
                    right--; 
                    left++;
                }
            }
        }
        return result;
    }
}

总结

 昨天和父母聊天,聊的很晚,自己以后要扩充心凉心眼小是藏不住的。自己一定要把心整的很大。海纳百川有容乃大,一定不要心里装太多不满的事情,要看开放下,达观处世。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值