【贪心法】和为s的两个数字,和为s的连续正整数序列

版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/83305168

面试题57-1:和为s的两个数字

输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。

两个游标一个在数组最左一个在最右,分别指示最小和最大的数。在循环里每次检查他们的加和,如果小了就把左边游标向右移,因为此时左边游标及其左边的所有数都不可能和当前右边游标及其左边的所有数组成符合条件的数对:
在这里插入图片描述
而左边游标以左与右边游标以右能否组成合适的数对,在前面的循环中就已经判断过了(这点比较难理解,可以画个实例一步一步看一下比较过程)。

同理,加和如果大了就把右边游标往左移。这就是这题的贪心选择策略。

#include<bits/stdc++.h>
using namespace std;

//在长为length的data数组里找和为sum的一对数字,存在*num1和*num2里,找到返回true 
bool FindNumbersWithSum(int data[], int length, int sum,
                        int* num1, int* num2) {
	bool found = false;//指示是否找到 
	if(length < 1 || num1 == nullptr || num2 == nullptr)//输入合法性检查 
		return found;

	int ahead = length - 1;//右边的游标 
	int behind = 0;//左边的游标 

	while(ahead > behind) {//游标还未相遇,可以继续找 
		long long curSum = data[ahead] + data[behind];//加和,int+int可能溢出所以用long long 

		if(curSum == sum) {//加起来正好相等即找到了 
			//将两数写进去 
			*num1 = data[behind];
			*num2 = data[ahead];
			found = true;//指示找到了 
			break;//结束循环 
		} else if(curSum > sum)//太大了 
			ahead --;//右边游标左移 
		else//太小了 
			behind ++;//左边游标右移 
	}
	return found;//指示找没找到 
}


int main() {
	int data[] = {1, 2, 4, 7, 11, 15};
	int n1,n2;
	if(FindNumbersWithSum(data,sizeof(data)/sizeof(int),15,&n1,&n2))
		cout<<n1<<","<<n2<<endl;//4,11
	return 0;
}

面试题57-2:和为s的连续正整数序列

输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。

这个不涉及数组,因为是连续正整数序列,只要有第一个数和最后一个数就能指示中间的所有数(step为1)。至少有两个数,初始small为1,big为2。在循环中计算加和,因为前面的序列都已经算过了,整个序列基本思路是要往后移动。如果加和小了就把big增大,如果加和大了就把small增大,small不能超过 ( s + 1 ) / 2 (s+1)/2 ,不然因为big比small大,加和一定会超过s的。

#include<bits/stdc++.h>
using namespace std;

//输出从small到big的step为1的正整数序列
void PrintContinuousSequence(int small, int big) {
	for(int i = small; i <= big; ++ i)
		printf("%d ", i);
	printf("\n");
}

//寻找和为sum的全部正整数序列,将其输出 
void FindContinuousSequence(int sum) {
	if(sum < 3)//1+2尚且为3,小于3的没有 
		return;

	int small = 1;//序列头数字 
	int big = 2;//序列尾数字 
	int middle = (1 + sum) / 2;//终止条件:small不能超过这个值 
	int curSum = small + big;//保存当前的序列加和 

	while(small < middle) {//终止条件small=middle
		//当从"序列和太小了"->"序列和恰好"时,是由这个if来判定输出的 
		if(curSum == sum)//如果当前得到的序列和和要找的一样 
			PrintContinuousSequence(small, big);//输出序列 

		//如果序列和太大了 
		while(curSum > sum && small < middle) {
			//small向前走,同步更新当前序列和 
			curSum -= small;
			small ++;
			
			//当从"序列和太大了"->"序列和恰好"时,是由这个if来判定输出的
			//找到了,输出序列 
			if(curSum == sum)
				PrintContinuousSequence(small, big);
		}

		//至此,可能已经找到并输出了,也可能序列和太小了
		//不论是哪种情况,都应该让big往后走 

		big ++;
		curSum += big;//同步更新当前序列和 
	}
}

int main() {
	FindContinuousSequence(100);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SHU15121856/article/details/83305168