题目:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
解析:如果数组是无序的,先排序(n*logn),然后用两个指针i,j,各自指向数组的首尾两端,令i=0,j=n-1,然后i++,j--,逐次判断 a[i]+a[j]?=sum,如果某一刻a[i]+a[j]>sum,则要想办法让sum的值减小,所以此刻i不动,j--,如果某一刻 a[i]+a[j]<sum,则要想办法让sum的值增大,所以此刻i++,j不动。所以,数组无序的时候,时间复杂度最终为 O(n*logn+n)=O(n*logn),若原数组是有序的,则不需要事先的排序,直接O(n)搞定,且空间复杂度还是O(1),此思路是相对于上述 所有思路的一种改进。(如果有序,直接两个指针两端扫描,时间O(N),如果无序,先排序后两端扫描,时间O(N*logN+N)=O(N*logN),空间始终都为O(1))。
总结:
- 不论原序列是有序还是无序,解决这类题有以下三种办法:1、二分(若无序,先排 序后二分),时间复杂度总为O(n*logn),空间复杂度为O(1);2、扫描一遍X-S[i] 映射到一个数组或构造hash表,时间复杂度为O(n),空间复杂度为O(n);3、两个指针两端扫描(若无序,先排序后扫描),时间复杂度最后为:有序 O(n),无序O(n*logn+n)=O(n*logn),空间复杂度都为O(1)。
- 所以,要想达到时间O(N),空间O(1)的目 标,除非原数组是有序的(指针扫描法),不然,当数组无序的话,就只能先排序,后指针扫描法或二分(时间n*logn,空间O(1)),或映射或 hash(时间O(n),空间O(n))。时间或空间,必须牺牲一个,自个权衡吧。
- 综上,若是数组有序的情况下,优先考虑两个指针两端扫描法,以达到最佳的时(O(N)),空(O(1))效应。否则,如果要排序的话,时间复杂度最快当然是只能达到N*logN,空间O(1)则是不在话下。
这里假定数组已经是有序的,代码可以如下编写(两段代码实现):
bool FindNumbersWithSum(int data[], int length, int sum, int *num1, int *num2) { bool found = false; if(length < 1 || num1 == NULL || num2 == NULL) return false; int ahead = length - 1; int behind = 0; while(ahead > behind) { long long curSum = data[ahead] + data[behind]; if(curSum == sum) { *num1 = data[behind]; *num2 = data[ahead]; found = true; break; } else if(curSum > sum) ahead--; else behind++; } return found; }
测试代码:
1 #include<iostream> 2 using namespace std; 3 4 bool find_num(int data[] , int length , int sum , int &first_num , int &second_num) 5 { 6 if(length < 1) 7 return true; 8 9 int begin = 0; 10 int end = length - 1; 11 12 while(begin < end) 13 { 14 int current_sum = data[begin] + data[end]; 15 16 if(current_sum == sum) 17 { 18 first_num = data[begin]; 19 second_num = data[end]; 20 return true; 21 } 22 else if(current_sum > sum) 23 end--; 24 else 25 begin++; 26 } 27 return false; 28 } 29 30 int main() 31 { 32 int data[] = {1 , 2 , 4 , 7 , 11 , 15}; 33 int length = sizeof(data)/sizeof(int); 34 int first_num = 0 ; 35 int second_num = 0; 36 int sum = 15; 37 38 if(find_num(data , length , 15 , first_num , second_num)) 39 { 40 cout<<first_num<<" "<<second_num<<endl; 41 } 42 else 43 cout<<"not exist!"<<endl; 44 45 return 0; 46 }
寻找和为定值的多个数:
2010年中兴面试题 编程求解: 输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数, 使其和等于 m ,要求将其中所有的可能组合列出来。 |
1 #include<list> 2 #include<iostream> 3 using namespace std; 4 5 list<int>list1; 6 void find_factor(int sum, int n) 7 { 8 // 递归出口 9 if(n <= 0 || sum <= 0) 10 return; 11 12 // 输出找到的结果 13 if(sum == n) 14 { 15 // 反转list 16 list1.reverse(); 17 for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++) 18 cout << *iter << " + "; 19 cout << n << endl; 20 list1.reverse(); 21 } 22 23 list1.push_front(n); //典型的01背包问题 24 find_factor(sum-n, n-1); //放n,n-1个数填满sum-n 25 list1.pop_front(); 26 find_factor(sum, n-1); //不放n,n-1个数填满sum 27 } 28 29 int main() 30 { 31 int sum, n; 32 cout << "请输入你要等于多少的数值sum:" << endl; 33 cin >> sum; 34 cout << "请输入你要从1.....n数列中取值的n:" << endl; 35 cin >> n; 36 cout << "所有可能的序列,如下:" << endl; 37 find_factor(sum,n); 38 return 0; 39 }
http://blog.csdn.net/v_JULY_v/article/details/6419466
来源:https://www.cnblogs.com/heyonggang/p/3386038.html