编程之美之高速寻找多个数满足给定条件

一、寻找三个数之和等于给定值

分析:方法类似与2Sum。就是先对数组进行排序,时间复杂度为O(nlogn),然后固定一个数,用两个指针进行遍历,找到三个数之和等于给定的值就可以,时间复杂度为O(n^2)。详细可提交于leetcode:https://oj.leetcode.com/problems/3sum/,代码例如以下:

vector<vector<int> > threeSum(vector<int> &num,int target){
	vector<vector<int> >res;
	int i,j,k,size = num.size();
	sort(num.begin(),num.end());
	for(i=0;i<size;i++)//固定一个数
	{
		if(i>0 && num[i] == num[i-1])continue;//防止反复计算,比如1 1 -1 0,target=0,假设没有该推断,结果会有两个 1 -1 0
		j = i + 1;//循环遍历另外两个指针
		k = size-1;
		while(j < k)
		{
			if(num[i]+num[j]+num[k] == target)
			{
				vector<int> tmp;
				tmp.push_back(num[i]);
				tmp.push_back(num[j]);
				tmp.push_back(num[k]);
				res.push_back(tmp);
				j++;
				k--;
				while(num[j] == num[j-1])j++;
				while(num[k] == num[k+1])k++;
			}
			if(num[i]+num[j]+num[k] > target)k--;
			else j++;
		}
	}
	return res;
}

二、寻找三个数之和最接近给定值

分析:要找出的三个数可能不是恰好等于目标值。方法类似于上面的分析,仅仅是在每次三个数之和推断时。当三个数之和小于等于或大于等于给定target时,不光要移动指针,还要还当前最接近的和比較。留下最接近的和。题目见leetcode:3Sum Closet,代码例如以下:

bool flag = true;//用于第一次记录最接近的三个数之和
int threeSumClosest(vector<int> &num, int target)
{
	sort(num.begin(),num.end());
	int i,j,k,currentSum=0,size = num.size();
	for(i=0;i<size;i++)
	{
		if(j>0 && num[j] == num[j-1])continue;
		j = i+1;
		k = size -1;
		while(j < k)
		{
			if(abs(num[i]+num[j]+num[k]-target)<abs(currentSum-target) || flag)
			{
				currentSum = num[i]+num[j]+num[k];//替换最接近的三个数
			}
			flag = false;
			if(abs(num[i]+num[j]+num[k]) < target)
			{
				j++;
				while(num[j] == num[j-1])j++;
			}
			else
			{
				k--;
				while(num[k] == num[k+1])k--;
			}
		}
	}
	return currentSum;
}

三、寻找四个数之和等于给定值

方法和三个数的和一样,仅仅是多了一层循环,据说有更快的方法。能力有限,没写出来,希望高手指点。见leetcode上4Sum,代码例如以下:

vector<vector<int> > fourSum(vector<int> &num, int target)
{
	sort(num.begin(),num.end());
	vector<vector<int> > res;
	int i,j,k,t,size = num.size();
	for(i=0;i<size-3;i++)
	{
		if(i>0 && num[i]==num[i-1])continue;
		for(j=i+1;j<size-2;j++)
		{
			if(j> i+1 && num[j] == num[j-1])continue;
			k = j+1;
			t = size-1;
			while(k < t)
			{
				if(num[i] + num[j] + num[k] + num[t] == target)
				{
					vector<int> tmp;
					tmp.push_back(num[i]);
					tmp.push_back(num[j]);
					tmp.push_back(num[k]);
					tmp.push_back(num[t]);
					res.push_back(tmp);
					k++;
					t--;
					while(k < t && num[k] == num[k-1])k++;
					while(k < t && num[t] == num[t+1])t--;
				}
				else if(num[i] + num[j] + num[k] + num[t] > target) t--;
				else k++;
			}
		}
	}
	return res;
}

四、寻找随意个和等于给定值

分析:因为能够是随意个数,所以使用递归比較方便,简单的说就是顺序遍历每个数。类似于背包问题。取的话结果有哪些,不取的话结果有哪些,从而得出全部的结果,不知道还有没有高效的算法,代码例如以下:

void anySum(vector<int> numbers,int target,int index,vector<int>& currSum,vector<vector<int> >& res)
{
	if(index > numbers.size())return;
	if(target == 0)
	{
		res.push_back(currSum);//获得一个结果
		return;
	}
	currSum.push_back( numbers[index]);//本次取该数进行递归
	target -= numbers[index];
	anySum(numbers,target,index+1,currSum,res);
	currSum.pop_back();//本次不取该数进行递归
	target += numbers[index];
	anySum(numbers,target,index+1,currSum,res);
}
vector<vector<int> > anySum(vector<int> numbers,int target)
{
	vector<vector<int> > res;
	vector<int> currSum;
	anySum(numbers,target,0,currSum,res);
	return res;
}

以上列出了若干数求和的几种情况,也算是自己的一个总结,有错误的地方,还请指正,谢谢

时间: 2024-10-22 03:31:18

编程之美之高速寻找多个数满足给定条件的相关文章

编程之美——二进制数中1的个数

解法一:若二进制末尾为1,则除以2余1: int count(int a) { int num=0; while(a) { if(a%2==1) ++num; a=a/2; } return num; } 解法二:使用移位操作相除: int count(int a) { int num=0; while(a) { num+=a&0x01; a>>=1; } return num; } 解法三:以上两种算法复杂度log2(t),t为a的二进制表示位数,若要求复杂度仅与二进制表示中1的个数

编程之美-求二进制1的个数

一个在常见的题目,但是看到编程之美的时候才发现,方法真多,今天来总结一下: 解法一 可以举出一个八位的二进制例子来进行分析.对于一个二进制操作,我们知道,除以一个2,原来的数字将会减少一个0,如果除的过程中有余,那么就表示当前位置有一个1. 以10 100 010为例: 第一次除以2时,商为 1 010 001,余为 0. 第二次除以2时,商为 101 000,余为1. 因此可以根据整型除法的特点求解,代码如下: public int countBit1(int n) { int num = 0

【编程之美】快速寻找满足条件的两个数

能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解. 分析与解法 方法一:枚举 从数组中任取两个数字,判断是否满足条件. 显然时间复杂度为N(N-1)/2,即O(N2). 方法二:查找 我们可以把问题进行转化:对于任意数arr[i],查找sum-arr[i]是否在数组中. (1) 一般查找 在不做处理的情况下直接在数组中查找sum-arr[i]的时间复杂度为O(N),总时间复杂度仍为O(N2). (2) 折半查找 显然

编程之美 2.10寻找数组中的最大最小值

数组是最简单的一种线性数据结构,当得到一个数组,需要找出最大最小值的时候,通过什么样的方法可以高效的,找出最大最小值呢.对于一个N个整数组成的数组,需要比较多少次呢. 现在有一个N=8的数组{5,6,8,3,7,9,1,2}. 解法一: 将找最大和最小数看成2个独立的问题,分别求解,需要遍历数组2次,共需要2N次操作. 1 #include "iostream" 2 using namespace std; 3 void Search_max_and_min(int* a,int N)

2015编程之美资格赛 回文子序列个数

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个.内容相同位置不同的子序列算不同的子序列. 输入 第一行一个整数T,表示数据组数.之后是T组数据,每组数据为一行字符串. 输出 对于每组数据输出一行,格式为”Case #X: Y”,X代表数据编号(从1开始),Y为答案.答案对100007取模. 数据范围 

编程之美之2.5 寻找最大的K个数

[题目] 有很多无序的数,从中找出最大的K个数.假定他们都不相等. [解法一] 如果数据不是很多,例如在几千个左右,我们可以排一下序,从中找出最大的K个数.排序可以选择快速排序或者堆排序 [cpp] view plaincopy #include<stdio.h> #include<stdlib.h> int cmp(const void *a,const void *b){ return *(int *)a - *(int *)b; } int main(){ int n,k;

编程之美之寻找最大的k个数

这个题目很常见,方法也很多,这里总结了编程之美给出的几个比较好的方法,也算是对这个问题的一个总结. 方法一.partition算法,每次partition的复杂度为O(n),总的平均时间复杂度为O(nlogn) 分析:运用partition算法,如果返回的provit > k-1,则说明要找的数都在前面,把end= provit-1;如果provit < k-1,表明找到一部分,先把部分数据保存,然后start = provit + 1;如果正好相等,则保存后结束,具体代码如下: int pa

编程之美2.12 高速寻找满足条件的两个数

  这道题目的意思是,在一个数组中寻找两个数.使这两个数的和等于给定的数(找到随意一组就能够了).       题目读完之后,感觉这道题目还是非常easy的.就是遍历数组呗,走两遍,即能够在O(n2)时间复杂度内解决问题. 只是,细致想想之后.复杂度还是能够减少的.       首先,我们能够对数组进行排序,这样,得到的数组就是一个有序数组(如果数组是递增的).那么,我们能够利用两个指针.一个指针指向数组的第一个元素,一个指针指向数组的最后一个元素.所以,就是两个指针分别指向两个最值.然后前后每

【编程之美】2.5 寻找最大的k个数

有若干个互不相等的无序的数,怎么选出其中最大的k个数. 我自己的方案:因为学过找第k大数的O(N)算法,所以第一反应就是找第K大的数.然后把所有大于等于第k大的数取出来. 写这个知道算法的代码都花了2个多小时,反思,太慢了. 注意边界条件,不要混混沌沌的. /************我自己的解法*****************/ //选择数组a[N]中最大的第k个数 int Select(int * a, int N, int k) { if(k > N || a == NULL) { cou