Leetcode. Add N Sum类问题

今天无意中听到同事面试, 问到了add n sum类的问题. 想到leetcode上有很多类似的问题, 特地整理一下。

Q1: 2Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example: Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].

算法

  • 用一个map保存各个元素和它对应的下标* 每遍历一个元素, 先在map中查找 target – curElement是否存在
  • 如果存在, 说明找到了一对满足要求的元素, 直接返回
  • 如果不存在, 将<当前元素, 下标>插入到map中时间复杂度是O(n), 空间复杂度是O(n)

实现

class Solution
{
public:
    vector<int> twoSum(vector<int>& nums, int target)
    {
        std::map<int, int> hashMap;
        std::vector<int> results;
        for (std::vector<int>::iterator it = nums.begin();
             it != nums.end();
             ++it)
        {
            if (hashMap.find(target - *it) != hashMap.end())
            {
                   results.push_back(hashMap[target - *it]);
                   results.push_back(it - nums.begin());
                   break;
            }
            else
            {
                   hashMap.insert(std::make_pair(*it, it - nums.begin()));
            }
        }
        return results;
    }};

Q2: 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: 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] ]

需要注意的是, 给定的数组中, 数字是可能重复的.
基本思路和2Sum类似, 先固定一个数字a, 然后在剩下的数字里, 找到2Sum等于 -a 的两个组合.
很显然, 如果我们采用暴力列举所有组合的方法的话, 时间复杂度是O(n^3).
在我们暴力列举的时候, 一定会有很多的重复, 所以下面我们的目标就是把重复的组合过滤掉.

  1. 为了能够高效地过滤掉重复数字, 我们首先对数组排序.排序后的结果为
    [-4, -1, -1, 0, 1, 2]
    i—– h ————p
  2. 固定下标为i的数字, 然后在h ~ p的子集中找到和为 4的组合, 方法是使用两个指针 h , p, 分别指向子数组的开头和结尾, 判断 arr[h] + arr[p]和第二目标数字(4)的大小
  • 如果 arr[h] + arr[p] > 0 – arr[i], –p 直到找到第一个和arr[h] 不相等的值
  • 如果 arr[h] + arr[p] < 0 – arr[i], ++h 直到找到第一个和arr[h] 不相等的值
  • 如果 arr[h] + arr[p] = 0 – arr[i], 说明找到了一组值, 记录下来. 然后同时更新h p直到分别找到第一个不相等的值.这三个地方的去重, 是第一个过滤重复的优化3. 找到所有arr[i]对应的组合后, ++i直到找到第一个不相等的值. 这里是第二个过滤重复的优化.排序的时间复杂度O(nlogn), 查找组合的时间复杂度是O(n^2),
    总体时间复杂度是O(n^2). 空间复杂度O(1)

实现

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int>& nums)
    {
        std::vector<std::vector<int> > results;
        std::sort(nums.begin(), nums.end());
        for (std::vector<int>::iterator it = nums.begin();
             it != nums.end();)
        {
            int target = 0 - *it;
            std::vector<int>::iterator head = it + 1;
            std::vector<int>::iterator tail = nums.end() - 1;
            while (head < tail)
            {
                std::vector<int> result;
                if (*head + *tail == target)
                {
                    --tail;
                    continue;
                }
                else if (*head + *tail < target)
                {
                    ++head;
                    continue;
                }
                else
                {
                    result.push_back(*it);
                    result.push_back(*head);
                    result.push_back(*tail);
                    results.push_back(result);
                   while (head < tail && *head == result[1]) ++head;
                   while (tail > head && *tail == result[2]) --tail;
                }
            }
            int curValue = *it;
            ++it;
            while (it < nums.end() && *it == curValue) ++it;
        }
           return results;
    }};

Q3: 4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target?
Find all unique quadruplets in the array which gives the sum of target.
Note: The solution set must not contain duplicate quadruplets.
For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

算法
基本思路和3Sum类似

  • 对数组排序
  • 先固定第一个元素, 然后对其后的子数组中, 求 三个元素之和 = target – *p1, 求三元素的方法就是利用3Sum的方法. 这里不再赘述.
    时间复杂度 O(n^3), 空间复杂度 O(1).
    4Sum的实现如下
class Solution 
{
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        std::vector<std::vector<int> > results;
        std::vector<int> result;
        result.resize(4);
        std::sort(nums.begin(), nums.end());
        for (std::vector<int>::const_iterator it1 = nums.begin();
             it1 != nums.end();)
        {
            int threeSumTarget = target - *it1;
            for (std::vector<int>::const_iterator it2 = it1 + 1;
                 it2 != nums.end();)
            {
                int twoSumTarget = threeSumTarget - *it2;
                std::vector<int>::const_iterator it3 = it2 + 1;
                std::vector<int>::const_iterator it4 = nums.end() - 1;
                while (it3 < it4)
                {
                    if (*it3 + *it4 < twoSumTarget)
                    {
                           while (++it3 < it4 && *it3 == *(it3 - 1)) continue;
                    }
                    else if (*it3 + *it4 > twoSumTarget)
                    {
                           while (--it4 > it3 && *it4 == *(it4 + 1)) continue;
                    }
                    else
                    {
                        result.clear();
                        result.push_back(*it1);
                        result.push_back(*it2);
                        result.push_back(*it3);
                        result.push_back(*it4);
                        results.push_back(result);
                        while (++it3 < it4 && *it3 == *(it3 - 1)) continue;
                        while (--it4 > it3 && *it4 == *(it4 + 1)) continue;
                    }
                   }
                   while (++it2 != nums.end() && *it2 == *(it2 - 1)) continue;
            }
            while (++it1 != nums.end() && *it1 == *(it1 - 1)) continue;
        }
        return results;
    }};

小结

Leetcode上还有一些变型的题目, 基础都是上面的三个问题.
从上面的三个问题, 我们可以推导出求xSum的方法:
即逐层固定元素, 将问题简化为求(x-1)Sum, (x-2)Sum ... 2Sum的问题.
时间复杂度为O(n^(x - 1)), 空间复杂度O(1).
    原文作者:周肃
    原文地址: https://www.jianshu.com/p/f94cca86f4cf
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞