15. 三数之和

53 阅读2分钟

15. 三数之和

中等

相关标签

premium lock icon相关企业

提示

给你一个整数数组 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

题解:

这题利用固定一个数,另外两个用双指针遍历和比较容易。但是要满足解的集合互异很难。一开始我想对数组去重,结果不对,因为解集中可以有重复元素。后来选择设i,j,k三个,强行要求i < j < k,并且他们之间可以相同,但是更新时候不能更新到同样的值。也就是说i可以等j,但是遍历完这次i,下一个i不能等于上一个i。 跳过方法可以用continue,跳过当前循环剩余语句;或者用while自增直到不同。

事实上,做好什么时候需要去重,什么时候不需要去重复,这道题其实不难。

#include <stdio.h>
#include <stdlib.h>

void order(int* nums, int size)
{
    int i, j, temp;
    for (i = 1;i <= size - 1;i ++)
    {
        for (j = 0;j <= size - 1 - i;j ++)
        {
            if (nums[j] > nums[j + 1])
            {
                temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
    }   
}

int delorderedsame(int* nums, int size)
{
    int slow = 0, fast = 0, newsize;
    while (fast <= size - 1)
    {
        if (nums[fast] > nums[slow])
        {
            slow ++;
            nums[slow] = nums[fast];
            fast ++;
        }
        else
        {
            fast ++;
        }
    }
    newsize = slow + 1;
    return newsize;
}

int main()
{
    int size, i, j, k;
    scanf("%d", &size);
    int* nums = (int*)malloc(sizeof(int) * size);
    for (i = 0;i <= size - 1;i ++)
    {
        scanf("%d", &nums[i]);
    }
    order(nums, size);
    //size = delorderedsame(nums, size);//数组本身不能去重。
    for (i = 0;i <= size - 3;i ++)
    {
        j = i + 1;
        k = size - 1;
        if (i > 0 && nums[i] == nums[i - 1])//i更新值不能和之前i相同,i,j不同,数组有序,则k必不同
        {
            continue;
        }
        while (j < k)
        {
            if (nums[j] + nums[k] > nums[i] * (-1))
            {
                k --;
            }
            else if (nums[j] + nums[k] < nums[i] * (-1))
            {
                j ++;
            }
            else if (nums[j] + nums[k] == nums[i] * (-1))
            {
                printf("%d %d %d\n", nums[i], nums[j], nums[k]);
                while (j < k - 1 && nums[j] == nums[j + 1])  //j更新值不能和之前的j相同
                {
                    j ++;
                }
                j ++;
            }
        }
    }

    return 0;
}