15. 3Sum

Description:

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: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

Solutions:

Approach 1: failed with time complexity of O(n^3)

This approach is simple and time cost. It uses 3 loops (i in first loop, j in second loop and k in third loop) to scan the arrays and finds all the combination of 3 elements in the array. If the sum of any of the combinations is zero, the triplets can be added into the list. However, the description requires that the solution cannot contain duplicate triplets. So we have to check if all the triplets are unique. This is another time-costing process.

If we first sort the array and use some tricks, we may well handle the duplicates. However, what I think of is that every time we check in every loop if num[i] == num[i-1], if so, we just let i++. But this doesn't work because, for example, we would get i to 3 if the array is [0, 0, 0, 0].

But we know that the first three elements can form a list that satisfy the condition. What if we just do not check first time in the loop? For example, we would change the if clause to if (i > 0 && i < len-2 && num[i] == num[i-1]) i++, where i would not increase to 3 at the first time. In the same way we change the if clause in the second loop to if (j > 1 && j < len-1 && num[j] == num[j-1]) j++ and in the third loop to if (k > 2 && k < len && num[k] == num[k-1]) k++. However, this doesn't work, either. This is because, for example, if the array is

[-4, -1, -1, 0, 1, 2]

and when i = 1 and j = 2, we know that if k = 5, nums[1] + nums[2] + nums[5] = -1 -1 + 2 = 0. But the algorithm would say: since j = 2 and nums[2] == nums[1], so j++. This would lead j= 3. So the algorithm fails. I haven't think of other good solutions to this issue. So I looked at the discuss and the approach 2 is as followings.

Approach 2: Use 3 pointers with time complexity of O(n^2)

In this approach, we use 3 pointers where the first pointer i just goes from the start to the end and divides the array into the left part and the right part, while the other two named j and k sweep from the right-part array from both of the ends until they meet or cross, which means j = i+1 and k = nums.length-1 at first.
To deal with the duplicate situation, we have 2 steps to go:

  • First, we check if nums[i] == nums[i-1], which means we check if the present element is equal to the previous one, if so, we let i++. So in this way, we can guarantee that i always points to a new elements.
  • Second, since we let j = i+1 and k = nums.length-1, we always check if nums[j] == nums[j+1] and nums[k] == nums[k-1], if so, we let j++ and k--. So please pay attention that this is different from i case. We check if the present element is equal to the future element but not the previous element.
    The codes are as followings:
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> list = new ArrayList<>();
        for (int i = 0; i < nums.length-2; i++) {
            if (nums[i] > 0) break;
            // if there is several same numbers in the arary, skip to a different one
            if (i > 0 && nums[i] == nums[i-1]) continue;
            int lo = i+1, hi = nums.length-1, target = -nums[i];
            while (lo < hi) {
                if (nums[lo] + nums[hi]  == target) {
                    list.add(Arrays.asList(nums[i], nums[lo], nums[hi]));
                    while (lo < hi && nums[lo] == nums[lo+1]) lo++;
                    while (lo < hi && nums[hi] == nums[hi-1]) hi--;
                    lo++;
                    hi--;
                } else if (nums[lo] + nums[hi] < target) {
                    lo++;
                } else {
                    hi--;
                }
            }
            
        }
        return list;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,768評(píng)論 0 33
  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,828評(píng)論 0 23
  • 知識(shí)貢獻(xiàn)收益渠道很多啊:專(zhuān)頭、知識(shí)星球(原小密圈)、小鵝通、三分鐘、百度問(wèn)咖、社會(huì)斜杠職業(yè)協(xié)作有:有輕功又高又冷又...
    咸叔說(shuō)閱讀 248評(píng)論 0 1
  • 首先,我是在單親家庭長(zhǎng)大的,但父母都沒(méi)有再婚,我還是感覺(jué)受到了傷害,我不是輕易哭的女孩,如果我哭就會(huì)痛哭一場(chǎng)。...
    安海希閱讀 258評(píng)論 0 0
  • 寶寶臉上長(zhǎng)濕疹了之后,一定要給孩子及時(shí)采取合理的治理方法,防止寶寶濕疹的進(jìn)一步擴(kuò)大,從而不讓寶寶進(jìn)一步受到濕疹的影...
    貝安寧beianning閱讀 354評(píng)論 0 0