LeetCode热题100#5 15.三数之和(java)

ps:本文章仅用来记录日常学习的所思所想,各位看到可取之处也可纳为己用,说的不对的地方还请多多指教。


1.题目描述

 15.三数之和(中等)


2.题目分析 

        按照惯例,先理解我们要干什么;

        最关键的就是三元组是什么,按照题意,三元组是从给的数组中取出来三个元素来组成一个新数组,而且元组不能重复,那么我们该怎么取三个元素出来,我第一个想到的就是定一个值然后用两个指针来遍历,看代码先吧。

public 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 - 2; i++) {
            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];
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return result;
    }
}

        首先说说为什么要先排序数组 

Arrays.sort(nums);

         排序后,我们可以固定一个数值(例如,将其作为第一个元素),然后使用双指针在剩余数组中寻找另外两个数,使得它们的和为当前固定数值的相反数。这样,我们可以将三数之和问题转化为两数之和问题。总之,有序总比无序好处理。

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

        这个if语句就是避免三元组重复的最关键的地方,当当前起始值等于上一次循环的起始值时,会执行continue 跳出当前循环,执行下一次的循环,这样就避免了起始值的重复,但还不足以避免三元组的重复,三元嘛当然三个元素都要避免。

            int left = i + 1;
            int right = nums.length - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }

        然后就是我们喜闻乐见的双指针环节,按照国际惯例 我的惯例,都是用一个指针在前,一个在后,然后while(left<right)就是循环到他们相遇,保证不漏循。

Arrays.asList(nums[i], nums[left], nums[right])

        这里特别说明一下这个方法, 作用是将里面的三个元素组成一个列表。同时如果传进去的参数是数组的话还有数组转换为列表的作用。

while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;

        这一块就是避免后面两元重复了 ,当各自的值跟上一次循环的值相等时跳过当前值,但如果你问我为什么第一个元跟这后面两元的避免方式不一样,我只能说避免审美疲劳(bushi)。

                  else if (sum < 0) {
                    left++;
                } else {
                    right--;

         这里的逻辑就是如果当前三个数的和 sum 小于 0,意味着当前的和偏小,又因为数组是排序过的,自然需要增加一些数值以达到 0的话,就是left++,反之自然就是right--


3.总结

        双指针问题不要用for循环去限制双指针的发挥

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值