题目一:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。例如输入数组{1,2,4,7,11,15}和数字15.由于4+11 = 15,因此输出4和11。
思路:如果固定一个数,再判断其与其他n-1个数的和是不是要求的和,时间复杂度是O(n^2)。很明显不是好的做法,而且注意到数组是已排序的,忽略了这个条件。既然是两个数的和,那么先指定两个数,用指针分别指向数组首元素和尾元素。如果和大于我们要求的sum,说明我们要减小这两个数中的一个,那么可以将后面的指针向前移动。如果小于和sum,则将前面的指针向后移动,直到等于sum。这种指针移动方向的相对的方法可以做到不重复不遗漏。
bool FindNumbersWithSum(int* a, int length, int sum)
{
if(a == NULL || length <= 0)
return false;
int* num1 = a;
int* num2 = a + length - 1;
while(num1 != num2)
{
if(*num1 + *num2 == sum)
{
cout << *num1 << " " << *num2 << endl;
return true;
}
else if(*num1 + *num2 < sum)
++num1;
else
--num2;
}
return false;
}题目二:输入一个正数s,打印出所有和为s的连续正数序列(至少含两个数)。例如输入15,由于1+2+3+4+5 = 4+5+6 = 7+8=15,所以结果打印出3个连续序列1~5,4~6和7~8。
思路:和上一题类似,这道题也可以用两个指针的办法,每次求两个指针之间的正数和。指针初试化samll =1和big =2,注意到可能有多个结果,例如输入15当发现1~5这个区间后,整体区间应该后移,所以当我们发现一个合适的答案时应该将big后移。程序终止的条件是什么呢?注意到题目要求至少有两个元素,如果small和big相邻,要求small + big <= sum即small+small+1 <= sum,可以推出small <= (sum-1)/2,注意整数除法会舍去小数造成偏差,因此区间放缩一点点即samll < (sum+1)/2,可以分别将sum取奇数和偶数验证一下。
void FindContinuousSequence(int n)
{
if(n < 3)
{
cout << "Invalid input!" << endl;
return;
}
int small = 1;
int big = 2;
int sum = small + small;
while(small < (n+1)/2)
{
if(sum == n)
{
PrintContinuousSeq(small, big);
sum += ++big;
}
else if(sum < n)
sum += ++big;
else
sum -= small++;
}
}
void PrintContinuousSeq(int start, int end)
{
for(int i = start; i <= end; ++i)
cout << i << " ";
cout << endl;
}
本文解析了两道数组搜索算法题目,一是寻找数组中和为特定值的两个数;二是找出所有连续正数序列,使其和等于给定的正数。通过双指针技巧,实现了高效解法。

414

被折叠的 条评论
为什么被折叠?



