算法初探LeetCode-三数之和

93 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

LeetCode15:三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入: nums = [0,1,1]
输出: []
解释: 唯一可能的三元组和不为 0 。

示例 3:

输入: nums = [0,0,0]
输出: [[0,0,0]]
解释: 唯一可能的三元组和为 0

提示:

  • 3 <= nums.length <= 3000
  • 105<=nums[i]<=105-10^5 <= nums[i] <= 10^5

思路分析

题中目的是要找元素的组合,没有要求原始顺序,因此可以排序,若数组是有序的,查找的效率就有提升。

寻找三元素之和为0,固定一个数[i],则变成了在余下的元素中寻找和为 -[i] 的组合。

有序数组,所以可以用双指针来获取目标组合。Left指针从头开始,right从尾开始,碰上时则结束寻找,或者找到结果后就停止。移动的条件是[i]+[j]小于目标时,向右移动左指针,大于目标时向左移动右指针,如果相等,则找到了一对解。

另外不能有重复的,去重逻辑就是,每找到一组元素就向后跨过相同元素。从头向尾遍历的,同一个元素找到的结果 肯定是相同,所以可以直接跨过相同元素。

算法代码

public List < List < Integer >> threeSum(int[] nums) {
    Arrays.sort(nums);
    int i = 0;
    List < List < Integer >> result = new ArrayList < > ();
    while (i < nums.length) {
        twoSum(nums, i, result);
        int temp = nums[i++];
        while (i < nums.length && temp == nums[i]) {
            i++;
        }
    }

    return result;
}

private void twoSum(int[] nums, int i, List < List < Integer >> result) {
    int j = i + 1;
    int k = nums.length - 1;
    while (j < k) {
        if (nums[i] + nums[j] + nums[k] == 0) {
            result.add(Arrays.asList(nums[i], nums[j], nums[k]));
            int temp = nums[j++];
            while (j < nums.length && temp == nums[j]) {
                j++;
            }
        } else if (nums[i] + nums[j] + nums[k] < 0) {
            j++;
        } else {
            k--;
        }
    }
}

算法复杂度

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n2)O(n^2)

掘金(JUEJIN)一起进步,一起成长!