题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。例如输入数组{1, 2, 4, 7, 11, 15}和数字15。由于4 + 11 = 15,因此输出4和11。
解题思路:
- 先在数组中选择两个数(第一个数和最后一个数),如果它们的和等于输入的s,那么就找到了数字。
- 如果小于s,由于数组是递增排序的,所以可以选择将第一个数字递增到下一个数字。
- 如果大于s,可以将最后一个数字递减到前一个数字
- 依次不断查找
测试用例:
int main(){
//输入数组
int arr[6] = {1, 2, 4, 7, 11, 15};
//找到的两个数字
int num1 = 0, num2 = 0;
int s = 15;
//执行查找和为s的两个数字
if( FindNumbersWithSum(arr, 6, s, &num1, &num2) )
std::cout << num1 << " + " << num2 << " = " << s;
else
std::cout << "Not found!\n";
return 0;
}
函数实现:
//查找和为s的两个数字
bool FindNumbersWithSum(int data[], int length, int sum, int *num1, int *num2){
bool found = false;
if(data == NULL || length < 1 || num1 == NULL || num2 == NULL)
return found;
//“第一个数字”
int ahead = 0;
//“最后一个数字”
int behind = length - 1;
//循环查找
while(behind > ahead){
//当前和
long long curSum = data[ahead] + data[behind];
if(curSum == sum){
*num1 = data[ahead];
*num2 = data[behind];
found = true;
break;
}else if(curSum > sum)
behind--;
else
ahead++;
}
return found;
}
题目二(针对题目一的扩展):输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5 = 4 + 5 + 6 = 7 + 8 = 15,所以结果打印出3个连续序列1~5、4~6、7~8。
解题思路:
- 使用small和big分别表示序列的最小值和最大值。
- 如果small到big的序列大于s,去掉序列中较小的值,即增大small。
- 如果small到big的序列小于s,去掉序列中较大的值,即增大big。
- 因为序列至少两个数字,我们一直增加small到(1+s) / 2为止。
测试用例:
//测试用例
int main(){
//输入正数
int sum = 15;
//打印所有和为s的正数序列
FindContinuousSequence(sum); //Output: 1 2 3 4 5 和 4 5 6 和 7 8
return 0;
}
函数实现:
//打印函数
void PrintContinuousSequenve(int small, int big){
for(int i = small; i <= big; ++i)
std::cout << i << " ";
std::cout << std::endl;
}
//主函数
void FindContinuousSequence(int sum){
if(sum < 3)
return;
int small = 1;
int big = 2;
//循环终止的条件
int middle = (1 + sum) / 2;
int curSum = small + big;
while(small < middle){
if(curSum == sum)
PrintContinuousSequenve(small, big);
while(curSum > sum && small < middle){ //如果当前和大于s,增大small,否则--
curSum -= small; //去掉较小的值
small++;
if(curSum == sum)
PrintContinuousSequenve(small, big);
}
//--否则直接增大big
big++;
curSum += big;
}
}