您的位置:首页 > Web前端

【剑指offer之和为s的两个数字VS和为s的连续正数序列】

2017-05-18 21:37 429 查看
【题目一】:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。例如输入数组{1,2,4,7,11,15}和数字15.由于4+11 = 15,因此输出4和11。

【技能get &&思路】:

                          


【代码】:

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

bool find_number_with_sum(int arr[],int n,int sum,int* p1,int* p2)
{
bool find = false;
if(n<1 ||p1==NULL || p2==NULL) return find;
int ahead_pos =n-1;
int behind_pos= 0;
while(ahead_pos>behind_pos)
{
LL cur_sum=arr[ahead_pos]+arr[behind_pos];
if(cur_sum==sum)
{
*p1=arr[behind_pos];
*p2=arr[ahead_pos];
find=true;
break;
}
else if(cur_sum>sum)ahead_pos--;
else behind_pos++;
}
return find;
}

void Test(char* testName, int arr[], int length, int sum, bool expectedReturn)
{
if(testName != NULL)
printf("%s begins: ", testName);

int num1, num2;
int result = find_number_with_sum(arr, length, sum, &num1, &num2);
if(result == expectedReturn)
{
if(result)
{
if(num1 + num2 == sum)
printf("Passed. \n");
else
printf("Failed. \n");
}
else
printf("Passed. \n");
}
else
printf("Failed. \n");
}

/// 存在和为s的两个数字,这两个数字位于数组的中间
void Test1()
{
int arr[] = {1, 2, 4, 7, 11, 15};
Test("Test1", arr, sizeof(arr) / sizeof(int), 15, true);
}

/// 存在和为s的两个数字,这两个数字位于数组的两段
void Test2()
{
int arr[] = {1, 2, 4, 7, 11, 16};
Test("Test2", arr, sizeof(arr) / sizeof(int), 17, true);
}

/// 不存在和为s的两个数字
void Test3()
{
int arr[] = {1, 2, 4, 7, 11, 16};
Test("Test3", arr, sizeof(arr) / sizeof(int), 10, false);
}

/// 鲁棒性测试
void Test4()
{
Test("Test4", NULL, 0, 0, false);
}

int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
return 0;
}

【后记】在上述代码中,ahead为较小的数字的下标(从后往前),behind为较大的数字的下标(从前往后)。由于数组是排好序的,因此较小的数字一定位于较大数字的前面,因此while循环如此。代码中只有一个while循环从两端向因中间扫描数组,因此复杂度O(N)。

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

【技能get &&思路】:

 




【代码】:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

void print_continous_seq(int small,int big)
{
for(int i=small; i<=big; ++i)
printf("%d ",i);
printf("\n");
}

void find_continous_seq(int sum)
{
if(sum<3) return ;
int small=1;
int big =2;
int Big =(1+sum)/2;
int cur_sum=(small+big);
while(small<Big)
{
if(cur_sum==sum)
print_continous_seq(small,big);
while(cur_sum>sum && small<Big)
{
cur_sum-=small;
small++;
if(cur_sum==sum)
print_continous_seq(small,big);
}
big++;
cur_sum+=big;
}
}

/* ====================测试代码====================*/
void Test(char* testName, int sum)
{
if(testName != NULL)
printf("%s for %d begins: \n", testName, sum);
find_continous_seq(sum);
}

int main(int argc,char* argv[])
{
Test("test1", 1);
Test("test2", 3);
Test("test3", 4);
Test("test4", 9);
Test("test5", 15);
Test("test6", 100);
return 0;
}
【后记】在上述代码中,求连续序列的和应用了一个小技巧。通常我们可以用循环求一个连续序列的和,但考虑到每一次操作之后的序列和操作之前的序列相比大部分数字都是一样的,只是增加或者减少了一个数字,因此我们可以在前一个序列的和的基础上求操作之后的序列的和。从而减少很多不必要的运算,提高代码效率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐