## 题目

> - 题号：15
> - 难度：中等
> - https://leetcode-cn.com/problems/3sum/

给定一个包含`n`个整数的数组`nums`，判断`nums`中是否存在三个元素`a，b，c`，使得`a + b + c = 0`？找出所有满足条件且不重复的三元组。

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

示例：

```c
给定数组 nums = [-1, 0, 1, 2, -1, -4]，

满足要求的三元组集合为：
[
  [-1, 0, 1],
  [-1, -1, 2]
]
```





---
## 实现

**第一种：利用 排序 + 三索引 的方法**



为了避免三次循环，提升执行效率。首先，对`nums`进行排序。然后，固定3个索引`i,l(left),r(right)`，`i`进行最外层循环，`l`指向`nums[i]`之后数组的最小值，`r`指向`nums[i]`之后数组的最大值。模仿快速排序的思路，如果`nums[i] > 0`就不需要继续计算了，否则计算`nums[i] + nums[l] + nums[r]`是否等于零并进行相应的处理。如果大于零，向`l`方向移动`r`指针，如果小于零，向`r`方向移动`l`索引，如果等于零，则加入到存储最后结果的result链表中。当然，题目中要求这个三元组不可重复，所以在进行的过程中加入去重就好。

**C# 实现**

- 执行结果：通过
- 执行用时：348 ms, 在所有 C# 提交中击败了 99.54% 的用户
- 内存消耗：35.8 MB, 在所有 C# 提交中击败了 6.63% 的用户

```c
public class Solution 
{
    public IList<IList<int>> ThreeSum(int[] nums) 
    {
        IList<IList<int>> result = new List<IList<int>>();

        nums = nums.OrderBy(a => a).ToArray();
        int len = nums.Length;
        
        for (int i = 0; i < len - 2; i++)
        {
            if (nums[i] > 0) 
                break; // 如果最小的数字大于0, 后面的操作已经没有意义

            if (i > 0 && nums[i - 1] == nums[i])
                continue; // 跳过三元组中第一个元素的重复数据

            int l = i + 1;
            int r = len - 1;

            while (l < r)
            {
                int sum = nums[i] + nums[l] + nums[r];
                if (sum < 0)
                {
                    l++;
                }
                else if (sum > 0)
                {
                    r--;
                }
                else
                {
                    result.Add(new List<int>() {nums[i], nums[l], nums[r]});
                    // 跳过三元组中第二个元素的重复数据
                    while (l < r && nums[l] == nums[l + 1]) 
                    {
                        l++;
                    }
                    // 跳过三元组中第三个元素的重复数据
                    while (l < r && nums[r - 1] == nums[r]) 
                    {
                        r--;
                    }
                    l++;
                    r--;
                }
            }
        }
        return result;    
    }
}
```



**Python 实现**

- 执行结果：通过
- 执行用时：660 ms, 在所有 Python3 提交中击败了 95.64% 的用户
- 内存消耗：16.1 MB, 在所有 Python3 提交中击败了 75.29% 的用户

```python
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums = sorted(nums)

        result = []

        for i in range(0, len(nums) - 2):
            # 如果最小的数字大于0, 后面的操作已经没有意义
            if nums[i] > 0:
                break
            # 跳过三元组中第一个元素的重复数据
            if i > 0 and nums[i-1] == nums[i]:
                continue
            
            # 限制nums[i]是三元组中最小的元素
            l = i + 1
            r = len(nums) - 1            
            while l < r:
                sum = nums[i] + nums[l] + nums[r]
                if sum < 0:
                    l += 1
                elif sum > 0:
                    r -= 1
                else:
                    result.append([nums[i], nums[l], nums[r]])
                    # 跳过三元组中第二个元素的重复数据
                    while l < r and nums[l] == nums[l+1]:
                        l += 1
                    # 跳过三元组中第三个元素的重复数据
                    while l < r and nums[r] == nums[r-1]:
                        r -= 1                    
                    l += 1
                    r -= 1
        return result
```
