LeetCode15三数之和

题目:

LeetCode15三数之和

思路:

虽然上一种做法有问题,不过双指针的想法还是正确的。所以,应该换个思路。
先对列表进行排序,然后从头到尾遍历。这样每次都固定住一个值,而不是用双指针来解决三值问题,好像是可行的。
在固定一个值之后,剩下的有序列表中,用双指针法寻找两个值的和是否是固定值的负数。这样指针移动的标准也就出来了。如下图:
LeetCode15三数之和
当两值之和大于固定值的负数时,右边的指针左移
当两值之和小于固定值的负数时,左边指针右移
当两值之和恰好为固定值负数,保存结果。此时有个很有必要的操作:判断 start+1的值,end-1的值,是否与上一个一样,相同的话,则跳过处理,我一开始就没处理,想偷懒最后保存结果的时候去重即可,但是去重要使用in方法,O(n)O(n)的复杂度,增加了时间复杂性。

解题步骤:

难点1:时间;难点2:重复元素。

  • 1.数组排序。
  • 2.设置固定点,前指针和后指针。
  • 每一次固定点不动,前指针后移,后指针前移,三数之和为0,即为需要找的元素。
  • 前后指针之和大于固定点,后指针前移(因为已排序)
  • 同理,处理小于情况。
  • (以上都为节省时间服务)
  • 每一次指针移动都要提前判断后面的值是否与当前指针元素相同,避免向集合加入相同元素。

代码:

public class Solution {
    public List<List<Integer>> threeSum(int[] nums){
        List<List<Integer>> list = new ArrayList<>();
        if (nums == null || nums.length<3){
            return list;
        }
        int length = nums.length;
        int fix = 0;//固定点
        int start ;//前指针
        int end ;//后指针
        Arrays.sort(nums);//原数组排序
        for (int i = fix; i < length-2; i++) {//-2原因:不能包括前后指针
            if(i == 0 ||(i > 0 && nums[i] != nums[i-1])  ){//去重
                start = i + 1;
                end = length -1;
                while (start<end){
                    if (nums[start] + nums[end] == -nums[i]){
                        list.add(Arrays.asList(nums[start],nums[end],nums[i]));
                        while (start<end && nums[start] == nums[start + 1]){start++;}//去重
                        while (start<end && nums[end] == nums[end - 1]){end--;}//去重
                        start++;
                        end--;
                    }else if (nums[start] + nums[end] > -nums[i]){
                        while (start<end && nums[end] == nums[end - 1]){end--;}//去重
                        end--;
                    }else if (nums[start] + nums[end] < -nums[i]){
                        while (start<end && nums[start] == nums[start + 1]){start++;}//去重
                        start++;
                    }

                }
            }
        }
        return list;
    }
}