leetcode笔记:3Sum

一.题目描述

二.解题技巧

这道题和另外一道题Two Sum很类似,不过这道题是在数组中寻找三个数,使得其和为0,同时要求这三个数只能出现一次。如果单纯得使用暴力算法来做的话,时间复杂度为O(n^3),且很难判断这一组数是否已经出现过。

若是选择先排序,然后左右夹逼,复杂度:O(n2)。

这个方法可以推广到k-sum,先排序,然后做k-2 次循环,在最内层循环左右夹逼,时间复杂度是:O(max(n*logn, n^(k-1)))。

如果考虑将数组A(元素个数为n)进行升序排序,那么按照顺序将数组中的第i个数作为三个数中最小的数,寻找从A的第i+1个数到n-1个数中满足和为-A[i]的数,就可以找到满足三个数和为0的组合了,但是,单独考虑这种情况,会出现重复的问题。要保证不出现重复的情况,当i!=0时,如果第i个数与第i-1个数相同的话,则不进行处理,直接处理第i+1个元素。这样,只要保证三个数中最小的数是按照顺序递增的,那么算法找到的解就都是不重复的。

这道题的边界条件在于:由于我们选择的是三个数中的最小值,因此,对于这个数的循环是[0, n-2),同时,要对最小值进行消除重复的元素时,需要从第1个元素开始判断,如果从第0个元素开始判断的时候,可能会将0,0,0这种情况忽略掉,因此,在消除重复的最小元素时,必须从第1个元素才开始。

这道题在寻找数组A中的两个数的和为-A[i]时,可以考虑利用数组A是已经排序的条件,进行左右夹逼操作。在进行左右搜索的时候,需要将左右两边收缩到与当前元素不同的元素为止,这样做有两个原因:1.可以减少计算量;2.当当前的两个元素的和刚好等于-A[i]的时候,如果没有进行上面的缩放操作,那么就可能将重复的三个数保存下来,导致结果出错。

三.实现代码

class Solution
{
public:
    vector<vector<int> > threeSum(vector<int> &num)
    {
        int Size = num.size();

        vector<vector<int> > Result;

        if (Size < 3)
        {
            return Result;
        }

        sort(num.begin(), num.end());

        for (int Index_outter = 0; Index_outter < (Size - 2); Index_outter++)
        {
            int First = num[Index_outter];
            int Second = num[Index_outter + 1];
            const int Target = 0;

            if ((Index_outter != 0) && (First == num[Index_outter - 1]))
            {
                continue;
            }

            int Start = Index_outter + 1;
            int End = Size - 1;

            while (Start < End)
            {
                Second = num[Start];
                int Third = num[End];

                int Sum = First + Second + Third;

                if (Sum == Target)
                {
                    vector<int> Tmp;
                    Tmp.push_back(First);
                    Tmp.push_back(Second);
                    Tmp.push_back(Third);

                    Result.push_back(Tmp);

                    Start++;
                    End--;
                    while (num[Start] == num[Start - 1])
                    {
                        Start++;
                    }
                    while (num[End] == num[End + 1])
                    {
                        End--;
                    }

                }

                if (Sum < Target)
                {
                    Start++;
                    while (num[Start] == num[Start - 1])
                    {
                        Start++;
                    }
                }

                if (Sum > Target)
                {
                    End--;
                    if (num[End] == num[End + 1])
                    {
                        End--;
                    }
                }

            }

        }
        return Result;

    }
};

以下是网上的一种解决方法:

// LeetCode, 3Sum
// 先排序,然后左右夹逼,注意跳过重复的数,时间复杂度O(n^2),空间复杂度O(1)
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& num) {
        vector<vector<int>> result;
        if (num.size() < 3) return result;
        sort(num.begin(), num.end());
        const int target = 0;
        auto last = num.end();
        for (auto i = num.begin(); i < last - 2; ++i) {
            auto j = i + 1;
            if (i > num.begin() && *i == *(i - 1)) continue;
            auto k = last - 1;
            while (j < k) {
                if (*i + *j + *k < target) {
                    ++j;
                    while (*j == *(j - 1) && j < k) ++j;
                }
                else if (*i + *j + *k > target) {
                    --k;
                    while (*k == *(k + 1) && j < k) --k;
                }
                else {
                    result.push_back({ *i, *j, *k });
                    ++j;
                    --k;
                    while (*j == *(j - 1) && *k == *(k + 1) && j < k) ++j;
                }
            }
        }
        return result;
    }
};

四.总结

我自己的想法时,将数组进行排序,然后按照顺序选择数组A[1, n-1)中的元素作为三个数中的中位数来在剩下的已经排好序的数组中寻找满足条件的其他两个数。但是,选择中位数的这种情况需要考虑的边界条件比较复杂,并没有选择最小值来得方便一些,同时,选择中位数之后,将已经排序的数组分成了两段,这样在进行收缩的时候,需要分别判断两个两边与i的关系,也比较容易出错。

这道题通过对数组进行排序,从而按照顺序选择不同的最小值来避免出现重复的情况,这确实是一个比较好的编程技巧。

时间: 2024-11-06 17:42:07

leetcode笔记:3Sum的相关文章

leetcode笔记

leetcode 笔记 Linked List 2. Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a

LeetCode 015 3Sum

[题目] Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) The

LeetCode 016 3Sum Closest

[题目] Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution. For example, given array S = {

[leetcode笔记] Remove Duplicates from Sorted List II

问题描述: Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. For example,Given 1->2->3->3->4->4->5, return 1->2->5.Given 1->1->1->2->3, return 2-&

[Leetcode][016] 3Sum Closest (Java)

题目: https://leetcode.com/problems/3sum-closest/ [标签]Array; Two Pointers [个人分析] 这道题和它的姊妹题 3Sum 非常类似, 就不再多说了,具体一些的分析可以参考 [Leetcode][015] 3Sum 1 public class Solution { 2 public int threeSumClosest(int[] nums, int target) { 3 int result = target; 4 int

leetcode笔记:Pascal&amp;#39;s Triangle

一. 题目描写叙述 Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Return: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 二. 题目分析 关于帕斯卡三角形的定义,可參考:http://baike.baidu.com/link?url=qk_-urYQnO4v6v3P4BuMtCa0tMNUqJUk

[LeetCode] 015. 3Sum (Medium) (C++/Java/Python)

索引:[LeetCode] Leetcode 题解索引 (C++/Java/Python/Sql) Github: https://github.com/illuz/leetcode 015.3Sum (Medium) 链接: 题目:https://oj.leetcode.com/problems/3sum/ 代码(github):https://github.com/illuz/leetcode 题意: 在给定数列中找出三个数,使和为 0. 分析: 先排序,再左右夹逼,复杂度 O(n*n).

[C++]LeetCode: 70 3Sum

题目: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) The s

[leetcode笔记] Longest Consecutive Sequence

随机挑选一题试试手气.   问题描述: Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your al