zoukankan      html  css  js  c++  java
  • 求和问题总结(leetcode 2Sum, 3Sum, 4Sum, K Sum)

    (一)前言

    做过leetcode的人都知道, 里面有2sum, 3sum(closest), 4sum等问题, 这些也是面试里面经典的问题, 考察是否可以合理利用排序这个性质, 一步一步得到高效的算法. 经过总结, 本人认为这些问题都可以使用一个通用的K sum求和问题加以概括消化, 这里我们先直接给出K Sum的问题描写叙述和算法(递归解法), 然后将这个一般性的方法套用到详细的K, 比方leetcode中的2Sum, 3Sum, 4Sum问题. 

    还有求最接近target的2、3、4个数,是上述问题的变形,思路变化不大。

    (二)leetcode求和问题描写叙述(K sum problem):

    K sum的求和问题通常是这样子描写叙述的:给你一组N个数字(比方 vector<int> num), 然后给你一个常数(比方 int target) ,我们的goal是在这一堆数里面找到K个数字。使得这K个数字的和等于target。


    (三)注意事项

    注意这一组数字可能有反复项:比方 1 1 2 3 , 求3sum, 然后 target  = 6, 你搜的时候可能会得到 两组1 2 3, 1 2 3,1 来自第一个1或者第二个1, 可是结果事实上仅仅有一组,所以最后结果要去重。

    去重的方法有两个:

    (1)前后移动探測,发现反复数字

    //寻找其它可能的2个数,顺带去重  
                        while (++p < q  && num[p-1] == num[p])  
                        {  
                            //do nothing  
                        }  
                        while (--q > p && num[q+1] == num[q])  
                        {  
                            //do noghing  
                        }  

    (2)借助STL容器 set:set<vector<int> >

    set不同意有反复的值出现。

    (四)K Sum求解方法, 适用leetcode 2Sum, 3Sum, 4Sum

    方法一: 暴力,就是枚举全部的K-subset, 那么这种复杂度就是 从N选出K个,复杂度是O(N^K)


    方法二: 排序+贪心  

    这个方案适用于2sum。3sum。 3sum cloest(找3个数的和最接近target),4sum ,4sum cloest(4个数的和最接近target)问题

    整体思路:

    2sum:先排序,默认非递减排序,固定0个数,头尾双指针选定2个数。利用贪心策略(sum-target>0,则尾指针左移,相反头指针右移,非常easy证明),直至找到sum=target 

                  相似于二分查找,时间复杂度O(N)       

    3 sum:先排序。固定1个数(外层一个for循环遍历)。再採用头尾双指针选定两个数。仍然採用贪心策略移动指针,得到3sum =target

    时间复杂度O(N*N)

    3 sum cloest:原理同3sum。仅仅只是多了比較,以下有代码贴出,看一眼就明确,时间复杂度O(N*N)

    4 sum:因为贪心策略仅仅适用于双指针,所以这里须要固定2个数。怎么固定?双层for循环遍历。!

    !再引入头尾双指针,时间复杂度O(N*N*N)

    4sum cloest:同上 ,时间复杂度O(N*N*N)

    //2 sum
    
    int i = starting; //头指针
    int j = num.size() - 1; //尾指针
    while(i < j) {
        int sum = num[i] + num[j];
        if(sum == target) {
            store num[i] and num[j] somewhere;
            if(we need only one such pair of numbers)
                break;
         otherwise
                do ++i, --j;
        }
        else if(sum < target)
            ++i;
        else
            --j;
    }

    //3 sum
    //对原数组非递减(递增)排序
    		InsertSort(num,num.size()); 
            
            for (int i = 0; i < num.size(); ++i)
            {
    			//去重
                if (i != 0 && num[i] == num[i-1])
    				continue;
    
                int p = i + 1, q = num.size() - 1;
                int sum = 0;
                
    			//收缩法寻找第2,第3个数
                while (p < q)
                {
                    sum = num[i] + num[p] + num[q];
                    
                    if (sum == 0)
                    {
                        vector<int> newRes;
                        newRes.push_back(num[i]);
                        newRes.push_back(num[p]);
                        newRes.push_back(num[q]);
    					InsertSort(newRes,newRes.size());
                        res.push_back(newRes);
    
    			
    					//寻找其它可能的2个数。顺带去重
    					while (++p < q  && num[p-1] == num[p])
    					{
    						//do nothing
    					}
    					while (--q > p && num[q+1] == num[q])
    					{
    						//do noghing
    					}
                    }
                    else if (sum < 0)  //和太小,p向后移动
    				{
                        ++p;
    				}
                    else            //和过大,q向前移动
    				{
                        --q;
    				}
                }
            }

    <span style="font-family: Arial, Helvetica, sans-serif;">// 3 sum cloest
    class Solution {</span>
    public:
        int threeSumClosest(vector<int> &num, int target) {
        int index;
        bool flag=true;
        sort(num.begin(),num.end());
            if(num.at(0)+num.at(1)+num.at(2)>target)
                index=num.at(0)+num.at(1)+num.at(2)-target ;
            else
               {
                    index=target-(num.at(0)+num.at(1)+num.at(2));
                    flag=false;
                }
    
            for (int i = 0; i < num.size(); ++i)
            {
    
                int p = i + 1, q = num.size() - 1;
    
                int sum=0;
    
                while (p < q)
                {
                    sum = num[i] + num[p] + num[q];
    
                    if (sum == target)
                    {
                        return sum;
                    }//if
                    else if (sum < target)  //和太小,p向后移动
                    {
                        ++p;
                        if(target-sum<index)
                        {
                            index=target-sum;
                            flag=false;
                        }
                    }
                    else            //和过大。q向前移动
                    {
                        --q;
                        if(sum-target<index)
                        {
                            index=sum-target;
                            flag=true;
                        }
                    }//else
                }//while
            }//for
            if(flag)
                return index+target;
            else
                return target-index;
    
        }
    };
    

    //4 sum
    class Solution
    {
    public:
        vector<vector<int> > fourSum(vector<int> &num, int target) {
            // Note: The Solution object is instantiated only once.
            vector<vector<int>> res;
        	int numlen = num.size();
    		if(num.size()<4)return res;
    		
    		sort(num.begin(),num.end());
    		set<vector<int>> tmpres;
    		for(int i = 0; i < numlen; i++)
    		{
    			for(int j = i+1; j < numlen; j++)
    			{
    				int begin = j+1;
    				int end = numlen-1;
    				while(begin < end)
    				{
    					int sum = num[i]+ num[j] + num[begin] + num[end];
    					if(sum == target)
    					{
    						vector<int> tmp;
    						tmp.push_back(num[i]);
    						tmp.push_back(num[j]);
    						tmp.push_back(num[begin]);
    						tmp.push_back(num[end]);
    						tmpres.insert(tmp);
    						begin++;
    						end--;
    					}else if(sum<target)
    						begin++;
    					else
    						end--;
    				}
    			}
    		}
    		set<vector<int>>::iterator it = tmpres.begin();
    		for(; it != tmpres.end(); it++)
    			res.push_back(*it);
    		return res;
        }
    };










  • 相关阅读:
    第二次作业循环语句
    c语言01次作业分支,顺序结构
    PAT 1027. Colors in Mars
    PAT 1026 Table Tennis
    PAT 1035 Password
    PAT 1038. Recover the Smallest Number
    PAT 1028 List Sorting (25)
    PAT 1041 Be Unique (20)
    PAT 1025 PAT Ranking
    1037. Magic Coupon
  • 原文地址:https://www.cnblogs.com/llguanli/p/8486691.html
Copyright © 2011-2022 走看看