算法总结(3)--k-Sum求和,找到和为定值的多个数

2Sum,3Sum,4Sum,…,nSum这类问题

主要用到了hashmap结构,二分法思路,前后指针等
需要将2Sum问题的几种方法,算法时间和空间复杂度深刻理解,并能手写出代码来

1. Two Sum

题目地址

https://leetcode.com/problems/two-sum/

题目描述

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.

Example:
Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

求解思路一,采用map结构,时间复杂度O(n)

ac代码如下

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        int len = nums.size();
        if ( len < 2) 
            return res;

        map<int, int> mp;

        for (int i = 0; i < len ; i++){
            if (mp[target - nums[i]] != 0){
                res.push_back(mp[target - nums[i]] - 1);
                res.push_back(i);
            }
            else{
                mp[nums[i]] = i + 1;
            }
        }
        //sort(res.begin(), res.end());
        return res;
    }
};

求解思路二,排序+二分搜索 O(nlogn)

class Solution {
public:

    int bsearch(vector<int> nums, int left, int right, int key)
    {
        while (left <= right)
        {
            int mid = right + (left - right) / 2;
            if (nums[mid] == key)
                return mid;
            else if (nums[mid] < key)
                left = mid + 1;
            else
                right = mid - 1;
        }
        return -1;
    }

    vector<int> twoSum(vector<int>& nums, int target) {
        int len = nums.size();
        vector<int> nums2 = nums;
        if (len < 2)
        {
            vector<int> v;
            return v;
        }

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

        for (int i = 0; i < len - 1; i++)
        {
            int findpos = bsearch(nums2, i + 1, len - 1, target - nums2[i]);
            if (findpos != -1)
            {
                int val1 = nums2[i];
                int val2 = nums2[findpos];

                // 返回结果
                vector<int> v;
                int vlen = 0;
                for (int j = 0; j < len; j++)
                {
                    if (nums[j] == val1 || nums[j] == val2)
                    {
                        v.push_back(j);
                        vlen++;
                    }
                    if (vlen == 2)
                        break;
                }
                return v;
            }
        }

        vector<int> v;
        return v;
    }
};

求解思路三,排序+前后指针法 O(nlogn)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        int len = nums.size();
        if (len < 2)
            return res;
        vector<int> numsTmp = nums;
        sort(nums.begin(), nums.end()); //使得有序

        //收尾指针法
        int sta = 0;
        int end = len - 1;

        while (sta < end)
        {
            if (nums[sta] + nums[end] == target)
            {
                bool f1 = false;
                bool f2 = false;
                for (int i = 0; i < len; i++)
                {
                    if (f1 && f2)
                        break;
                    if (!f1 && numsTmp[i] == nums[sta]) // nums[sta] 可能等于 nums[end]
                    {
                        res.push_back(i);
                        f1 = true;
                    }
                    else if (!f2 && numsTmp[i] == nums[end]) // 这里是else if 不是if
                    {
                        res.push_back(i);
                        f2 = true;
                    }
                }
                break;
            }
            else if (nums[sta] + nums[end] < target)
            {
                sta++;
            }
            else{
                end--;
            }
        }

        return res;
    }
};

15. 3Sum

题目地址

https://leetcode.com/problems/3sum/

16. 3Sum Closest

题目地址

https://leetcode.com/problems/3sum-closest/

18. 4Sum

题目地址

https://leetcode.com/problems/4sum/

找到和为定值的多个数

类似 背包问题

参考
http://www.jianshu.com/p/3d1791cfba53

主要是递归,动态规划等方法

416. Partition Equal Subset Sum(leetcode)

题目地址

https://leetcode.com/problems/partition-equal-subset-sum/

求解思路

这题采用dfs查找会超时,采用动态规划来做
参考
http://blog.csdn.net/buptzhengchaojie/article/details/52827357

对比零钱问题(每种数值的钱可以使用多次)
http://blog.csdn.net/qq_26437925/article/details/52101224

ac代码

class Solution {
public:

    bool canPartition(vector<int>& nums) {
        int len = nums.size();
        int sums = 0;
        int maxVal = -1;
        for (int i = 0; i < len; i++)
        {
            sums += nums[i];
            if (nums[i] > maxVal){
                maxVal = nums[i];
            }
        }
        if (sums % 2 == 1)
            return false;
        int m = sums / 2;
        if (maxVal > m)
            return false;
        if (maxVal == m)
            return true;

        vector<bool> dp(m + 1, false); //dp[i] 表示能租构成值为i的子集合
        dp[0] = true;

        for (int i = 0; i < len; ++i) 
        {
            /*
                nums[i] 只会影响 dp[j - nums[i]]到dp[m],
                因为这其间的数 dp[] 可以选择使用它,那么看dp[j - nums[i]] 是否是真的
                (或不使用用)还是看dp[j]自身

                组成m时,每个数字只能使用一次
                例如m = 14 ,nums[0] = 7第一次遍历,dp[7] = true,dp[14] = false

                j应该从大到小,大的数不会影响前面的数
            */
            for (int j = m; j >= nums[i]; --j) 
            {
                dp[j] = dp[j] || dp[j - nums[i]];
            }
        }

        return dp[m];
    }
};

超时代码(dfs)

class Solution {
public:
    bool flag;
    //vector<int> ans;

    void dfs(int m, int index,vector<int>& nums,int len)
    {
        if (flag)
            return;
        if (m < 0)
            return;
        if (m == 0 && index <= len)
        {
            flag = true;
            /*int alen = ans.size();
            for (int i = 0; i < alen; i++){
                cout << ans[i] << " ";
            }
            cout << endl;*/
            return;
        }
        if (index >= len)
            return;
        //ans.push_back(nums[index]);
        dfs(m - nums[index], index + 1,nums,len);
        //ans.pop_back();
        dfs(m, index + 1,nums,len);
    }

    bool canPartition(vector<int>& nums) {
        int len = nums.size();
        int sums = 0;
        int maxVal = -1;
        for (int i = 0; i < len; i++)
        {
            sums += nums[i];
            if (nums[i] > maxVal){
                maxVal = nums[i];
            }
        }
        if (sums % 2 == 1)
            return false;
        int m = sums / 2;
        if (maxVal > m)
            return false;
        if (maxVal == m)
            return true;
        flag = false;
        dfs(m, 0, nums, len);
        return flag;
    }
};
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值