leetcode Sum 系列----寻找和为定值的多个数

38 篇文章 4 订阅

july 大神有个程序员编程艺术系列,第五章《寻找和为定值的多个数》,现在我们站在大牛的肩膀上,对leetcode上n个数求和的系列问题做个阶段性总结。


1.leetcode No.1 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].

http://blog.csdn.net/gatieme/article/details/50596965

1.1 双向扫描

时间复杂度O(N),空间复杂度O(N)

暴力穷举的办法我们就不说了任选两个数判断和是否为输入即可
a[i]在序列中,如果a[i]+a[k]=sum的话,那么sum-a[i](a[k])也必然在序列中,举个例子,如下:

原始序列:1、2、4、7、11、15
用输入数字15 减一下各个数,得到对应的
序列为:
对应序列:14、13、11、8、4、0

第一个数组以一指针i从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,如果下面出现了和上面一样的数,即a[*i]=a[*j],就找出这俩个数来了。如上,i,j最终在第一个,和第二个序列中找到了相同的数4 和11,所以符合条件的两个数,即为4+11=15。

然后用两个指针i,j,各自指向数组的首尾
两端,令i=0,j=n-1,然后i++,j–,逐次判断a[i]+a[j]?=sum,如果某一刻a[i]+a[j]>sum,
则要想办法让sum 的值减小,所以此刻i 不动,j–,如果某一刻a[i]+a[j]

// leetcode1-2Sum.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
//进阶解法–基于排序O(nlogn)


#include <stdlib.h>
#include <malloc.h>

#define DEBUG

///////////////////////////////////////////////////////////////////////////
///
///  快速排序--QuickSort
///  http://www.cnblogs.com/RootJie/archive/2012/02/13/2349649.html
///
///////////////////////////////////////////////////////////////////////////


#include <stdio.h>
#include <time.h>

#define MAX_SIZE 20000

#define SWAP(x, y) {int t=x; x=y; y=t;}

void QuickSort(int *array, int left, int right);
int Partition(int *array, int left, int right);

int position[MAX_SIZE]; //  用于存储位置信息

void InitPosion(int *position, int length)
{
    for (int pos = 0; pos < length; pos++)
    {
        position[pos] = pos + 1;
    }
}

int Partition(int *array, int left, int right)
{
    int pivot = array[left];

    while (left < right)
    {
        while (left < right && array[right] >= pivot)
        {
            --right;
        }
        SWAP(array[left], array[right]);
        SWAP(position[left], position[right]);

        while (left < right && array[left] <= pivot)
        {
            ++left;
        }
        SWAP(array[right], array[left]);
        SWAP(position[left], position[right]);

    }

    return left;
}

void QuickSort(int *array, int left, int right)
{
    int pivot;

    if (left < right)
    {
        pivot = Partition(array, left, right);

        QuickSort(array, left, pivot - 1);
        QuickSort(array, pivot + 1, right);
    }
}



int cmp(const void *left, const void *right)
{
    int *left_num = (int *)left;
    int *right_num = (int *)right;

    return (*left_num - *right_num);

    //qsort(nums, numsSize, sizeof(nums[0]), cmp);
}


int* twoSum(int* nums,      /*  the pointer which point to the array  */
    int numsSize,   /*  the size of the array  */
    int target)     /*  the sum of the two num  */
{
    //qsort(nums, numsSize, sizeof(nums[0]), cmp);
    InitPosion(position, numsSize);

#ifdef DEBUG   
    printf("Before Quick Sort : \n");
    printf("Array    : ");
    for (int pos = 0; pos < numsSize; pos++)
    {
        printf("%3d", nums[pos]);
    }
    printf("\n");
    printf("Position : ");
    for (int pos = 0; pos < numsSize; pos++)
    {
        printf("%3d", position[pos]);
    }
    printf("\n");
#endif  

    QuickSort(nums, 0, numsSize - 1);

#ifdef DEBUG   

    printf("After Quick Sort : \n");
    printf("Array    : ");
    for (int pos = 0; pos < numsSize; pos++)
    {
        printf("%3d", nums[pos]);
    }
    printf("\n");
    printf("Position : ");

    for (int pos = 0; pos < numsSize; pos++)
    {
        printf("%3d", position[pos]);
    }
    printf("\n");
#endif  


    int *answer = (int *)malloc(sizeof(int) * 2);

    int left = 0, right = numsSize - 1, sum;
    while (left < right)
    {
        sum = nums[left] + nums[right];

#ifdef DEBUG
        printf("[%d, %d], %d + %d = %d\n",
            left, right,
            nums[left], nums[right], sum);
#endif  

        if (sum == target)
        {
#ifdef DEBUG
            printf("[%d, %d], %d + %d = %d\n",
                left, right,
                nums[left], nums[right], target);
#endif
            break;
        }
        else if (sum < target)
        {
#ifdef DEBUG
            printf("[%d, %d], %d + %d = %d\n",
                left, right,
                nums[left], nums[right], target);
#endif
            left++;
        }
        else if (sum > target)
        {
#ifdef DEBUG
            printf("[%d, %d], %d + %d = %d\n",
                left, right,
                nums[left], nums[right], target);

#endif
            right--;
        }
    }
    if (position[left] < position[right])
    {
        answer[0] = position[left];
        answer[1] = position[right];
    }
    else
    {
        answer[0] = position[right];
        answer[1] = position[left];
    }

    return answer;
}

#ifdef DEBUG

int main()
{
    int nums[5] = { -1, -2, -3, -4, -5 };
    int *answer = NULL;
    answer = twoSum(nums, 5, -8);
    printf("[%d, %d]\n", answer[0], answer[1]);
}
#endif



1.2 hash

class Solution:
    def twoSum(self, num, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        # python中字典dict类似于map的
        dict = {}

        for i in range(len(num)):   #  对于每一个num

            # 判断target - num[i]在不在在字典中
            if dict.get(target - num[i], None) == None: #如果不在

                dict[num[i]] = i   # 将该数存入字典中

            else:
                # 否则这两个数的和为target, 则返回
                return (dict[target - num[i]] , i )

2. leetcode No.15 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]
]

思路:
- 1,先按照由小到大把数组排序
- 2,循环取第i位,数值a[i], 后面剩余的由旁边向中间扫描,看是否符合 a[m]+a[n] == -a[i],如果a[m]+a[n]>-a[i],则向右边移动m,如果小于则向左边移动n

典型c++解法如下:

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
    vector<vector<int> >result;

    std::sort(nums.begin(), nums.end());

    for (unsigned int i = 0; i < nums.size(); i++)
    {
        int target = -nums[i];
        int front = i + 1;
        int back = nums.size() - 1;

        while (front < back)
        {
            int sum = nums[front] + nums[back];

            if (sum < target)
                front++;

            else if (sum > target)
                back--;

            else
            {
                vector<int> triplet(3, 0);
                triplet[0] = nums[i];
                triplet[1] = nums[front];
                triplet[2] = nums[back];
                result.push_back(triplet);

                //处理有两个同样的数的情况
                while (front < back && nums[front] == triplet[1])front++;
                while (front < back && nums[back] == triplet[2])back--;

            }

        }
        //处理有两个同样的数的情况
        while (i + 1 < nums.size() && nums[i + 1] == nums[i]) i++;

    }
    return result;
    }
};

3. leetcode No.16 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 = {-1 2 1 -4}, and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
class Solution
{
public:
    int threeSumClosest(vector<int>& nums,int target)
    {
        sort(nums.begin(),nums.end());
        int result = nums[0]+nums[1]+nums[2];

        for(int i =0;i<nums.size()-2;i++)
            {
                int j = i+1,k=nums.size()-1;
                while(j<k)
                {
                int num = nums[i] + nums[j] + nums[k];
                if(abs(num - target) < abs(res - target)) res = num;
                if(num < target) j++;
                else k--;
                }
            }
            return result;
        }
};

4. leetcode No.18 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]
]

// O(n^3)
class Solution {
public:
    vector<vector<int> > fourSum(vector<int> &nums, int target) {
        set<vector<int> > res;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < int(nums.size() - 3); ++i) {
            for (int j = i + 1; j < int(nums.size() - 2); ++j) {
                int left = j + 1, right = nums.size() - 1;
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        vector<int> out;
                        out.push_back(nums[i]);
                        out.push_back(nums[j]);
                        out.push_back(nums[left]);
                        out.push_back(nums[right]);
                        res.insert(out);
                        ++left; --right;
                    } else if (sum < target) ++left;
                    else --right;
                }
            }
        }
        return vector<vector<int> > (res.begin(), res.end());
    }
};

5. 举一反三 n Sum

https://www.jianshu.com/p/3d1791cfba53
http://blog.csdn.net/XingKong_678/article/details/50894322
http://blog.csdn.net/yuanwei1314/article/details/42963229

输入两个整数n 和m,从数列1,2,3…….n 中随意取几个数,
使其和等于m ,要求将其中所有的可能组合列出来。

// 21 题递归方法
//copyright@ July && yansha
//July、yansha,updated。
#include<list>
#include<iostream>
using namespace std;
list<int>list1;

void find_factor(int sum, int n)
{
    // 递归出口
    if(n <= 0 || sum <= 0)
    return;
    // 输出找到的结果
    if(sum == n)
    {
    // 反转list
    list1.reverse();

    for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
        cout << *iter << " + ";
        cout << n << endl;

    list1.reverse();

    list1.push_front(n); //典型的01 背包问题
    find_factor(sum-n, n-1); //放n,n-1 个数填满sum-n
    list1.pop_front();
    find_factor(sum, n-1); //不放n,n-1 个数填满sum
}

int main()
{
    int sum, n;
    cout << "请输入你要等于多少的数值sum:" << endl;
    cin >> sum;
    cout << "请输入你要从1.....n 数列中取值的n:" << endl;
    cin >> n;
    cout << "所有可能的序列,如下:" << endl;

    find_factor(sum,n);
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shiter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值