LeetCode 3Sum&&3Sum Closest&&4Sum

终于做了决定,开始做LeetCode,上来先做了3题都是关于sum的,这三题我认为都是从同一个问题变过来的,很多人都知道一个经典的问题就是给你一个数组a和一个数字tar,问你这个数组中有没有两个数的和等于这个给定的数字tar,显然要用O(N)的方法,这个问题的答案就是先排序,然后定义两个边界l和r,l一开始等于0,r一开始等于n-1,每次把边界指的两个数相加和给定的数tar比较一下,如果比tar小,那么l++,比tar大,那么r--,如果等于那么l++,r--。那么问题来了,为什么a[l]+a[r]<tar的时候,只需要l++就好了,这是这个做法的关键,这是因为当a[l]+a[r]<tar的时候,肯定有a[l]+a[k]<=a[l]+a[r]<tar,k=[l+1,r-1],因为数组是排好序的。同理也可以说明r--的原因。

这样说来的话,可以用O(N)的方法解决数组中是否有2个数的和等于给定一个数的问题,那么三个数只需要枚举一个数a[i],用这个tar减去枚举的这个数,然后再用O(N)的时间判断剩下的数有没有两个数的和等于tar-a[i]。时间复杂度是O(N*N)。

还有一个问题就是判重,实话说判重花了我很多时间。主要就是有两点:

第一,枚举i后,j一定是i+1开始枚举。

第二,对于枚举的i,j,k如果我发现当前枚举的量和上次循环枚举的值是相等的。那么这次直接continue。

3sum的代码如下:

class Solution {
public:
    vector<vector<int> > threeSum(vector<int> &num) {
        int i ,j,k;
        int n=num.size();
		vector<int>ans;
		vector<vector<int> >cl;
		sort(num.begin(),num.end());
		for(i=0;i<n;i++)
       	{
	     	if(num[i]==num[i-1]&&i>0)
	     	continue;
	 		for(j=i+1,k=n-1;j<k;)
	 		{
			 	if(num[j]==num[j-1]&&j>i+1)
			 	{
	 				j++;
	     			continue;
			 	}
			 	if(num[k]==num[k+1]&&k<n-1)
			 	{
	 				k--;
	 				continue;
	 			}
			 	if(num[j]+num[k]+num[i]==0)
			 	{
				 	ans.push_back(num[i]);
				 	ans.push_back(num[j]);
				 	ans.push_back(num[k]);
				 	cl.push_back(ans);
				 	ans.clear();
				 	j++;
				 	k--;
 				}
			 	else if(num[j]+num[k]+num[i]<0)	
	 				j++;
	 			else 
	 				k--;
 			}  	
       	}
       	return cl;
    }
};


接下来是3sumclosest,让你找出3个数的和与tar最接近,我觉得这个问题出的很好,他真的是考察了你到底是否真正理解O(N)的方法处理两个数的和等于一个tar。因为每次变化,l++或者r--,都是往tar的方向靠近(小于tar则增大,增大可能增的太大,如比tar小4变成了大5,大于tar则减小),而排除了往tar的反方向。所以closest的做法就由此产生了,我把所有能靠近tar的情况遍历一边,把每次与tar的差距选择一个最小的就是答案。

3sumclosest 代码如下:

class Solution {
int abs(int x)
{
    return x>0?x:-x;
}
public:
    int threeSumClosest(vector<int> &num, int target) {
        int n=num.size();
        int i,j,k;
        sort(num.begin(),num.end());
        int min=100000000;
        int ans;
        for(i=0;i<n;i++)
        {
            for(j=i+1,k=n-1;j<k;)
            {
                if(abs(num[i]+num[j]+num[k]-target)<min)
                {
                	min=abs(num[i]+num[j]+num[k]-target);
                	
                	ans=num[i]+num[j]+num[k];
                }
                if(num[j]+num[k]+num[i]>target)
                    k--;
                else if(num[j]+num[k]+num[i]<target)
                    j++;
				else 
					return target;
            }
            
        }
        return ans;
    }
};


最后4sum如果用O(N^3)的复杂度能过的话,这题也算是简单了,和3sum一样的去重法,一样的思想,代码如下:

class Solution {
public:
    vector<vector<int> > fourSum(vector<int> &num, int target) {
        int n=num.size();
        vector<vector<int> >ans;
        int i,k,j,l;
        vector<int>tmp;
        sort(num.begin(),num.end());
        for(i=0;i<n;i++)
        {
            if(i>0&&num[i]==num[i-1])
			    continue;

            for(j=i+1;j<n;j++)
            {
				if(j>i+1&&num[j]==num[j-1])
                    continue;
                int sum=target-num[i]-num[j];
                for(k=j+1,l=n-1;k<l;)
                {
					if(k>j+1&&num[k]==num[k-1])
                    {
                    	k++;
						continue;
                    }
                    if(l<n-1&&num[l]==num[l+1])
                    {
    					l--;
       	 				continue;
                    }
                    if(num[k]+num[l]==sum)
                    {
                        tmp.clear();
						tmp.push_back(num[i]);
                        tmp.push_back(num[j]);
                        tmp.push_back(num[k]);
                        tmp.push_back(num[l]);
                        ans.push_back(tmp);
                        k++;
                        l--;
                    }
                    else  if(num[k]+num[l]<sum)
						k++;
                    else 
                        l--;
                }
            }
        }
        return ans;   
    }
};



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章