Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2877457
  • 博文数量: 471
  • 博客积分: 7081
  • 博客等级: 少将
  • 技术积分: 5369
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-04 21:55
文章分类

全部博文(471)

文章存档

2014年(90)

2013年(69)

2012年(312)

分类: C/C++

2012-08-31 16:21:05

3.找出两个数组中满足给定和的数对,如果数组没序,先排序

问题描述:有两个数组arr1和arr2,两个数组均已经排好序,现在要找出这样的x和y使得x+y=sum,其中sum已知,x是arr1中某个元素,y是arr2中的某个元素。

解决方案:既然数组arr1和arr2中的元素已经排好序了,那么问题就简单了不少。假设arr1[i] + arr2[j] > sum,若arr1下标不变,那么要找到满足条件的x和y,只能取arr2中下标< j 的元素和arr1[i]相加,结果才可能等于sum;假设arr1[i] + arr2[j] < sum,若arr2的下标不变,那么要找到满足条件的x和y,只能取arr1中下标 > i 的元素和arr2[j]相加,结果才可能等于sum。因此我们可以设置两个指针 i 和 j ,分别指向arr1的开始位置和结束位置,这时 i 只能不断变大,j 只能不断变小,直到超过了数组的范围。通过代码更好理解,看代码吧~~时间复杂度是O(n+m),n和m分别是arr1和arr2的大小。

点击(此处)折叠或打开

  1. #include

  2. //这里是两个有序数组,找出数组中两个数的和是固定值
  3. //其实跟一个有序数组找给定和也差不多
  4. void fin2m(int *a,int m,int *b,int n,int x)
  5. {
  6.     int i=0,j=n-1;
  7.     while(i=0)
  8.     {
  9.         if(a[i]+b[j]>x)
  10.             j--;
  11.         else if(a[i]+b[j]
  12.             i++;
  13.         else
  14.         {
  15.             printf("the two: %d %d\n",a[i],b[j]);
  16.             i++;
  17.             j--;
  18.         }
  19.     }
  20. }
  21. int main()
  22. {
  23.     int a[10]={1,4,6,8,9,13,15,16,18,20};
  24.     int b[11]={11,14,16,18,19,23,25,26,28,30,31};
  25.     fin2m(a,10,b,11,22);
  26.     return 0;
  27. }

  28. /*
  29. the two: 4 18
  30. the two: 6 16
  31. the two: 8 14
  32. Press any key to continue
  33. */


其实这题,可扩展为在一个有序数组中,找出满足给定和的数对
总结

  • 不论原序列是有序还是无序,解决这类题有以下三种办法: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)则是不在话下。

3.编程求解输入两个整数n和m,从数列中1,2,3,...,n,随意取几个数,使其和等于m。要求将所有的组合列出来

求解思路:每个数都有两种选择,加入与不加入 实际上就是一个背包问题,可用回溯法求解

1.首先判断,如果n>m,则n中大于m的数不可能参与组合,此时置n = m;

2.将最大数n加入且n == m,则满足条件,输出;

3.将n分两种情况求解,(1)n没有加入,取n = n - 1; m = m;递归下去;(2)n加入,取n = n - 1l, m = m - n,递归下去



点击(此处)折叠或打开

  1. #include
  2. #include
  3. using namespace std;
  4.   
  5. listlist1;//相当于栈,不过出入比栈效率高
  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.         for(list::iterator iter = list1.begin(); iter != list1.end(); iter++)
  16.             cout << *iter << " + ";
  17.         cout << n << endl;//n不在栈里面的,这里的实现有点技巧
  18.     }
  19.       
  20.     list1.push_front(n); //还没找到,所以要进栈,典型的01背包问题,每个数都可以放或者不放
  21.     find_factor(sum-n, n-1); //放n,n-1个数填满sum-n
  22.     list1.pop_front();
  23.     find_factor(sum, n-1); //不放n,n-1个数填满sum
  24. }
  25.   
  26. int main()
  27. {
  28.     int sum, n;
  29.     cout << "请输入你要等于多少的数值sum:" << endl;
  30.     cin >> sum;
  31.     cout << "请输入你要从1.....n数列中取值的n:" << endl;
  32.     cin >> n;
  33.     cout << "所有可能的序列,如下:" << endl;
  34.     find_factor(sum,n);
  35.     return 0;
  36. }

  37. /*
  38. 请输入你要等于多少的数值sum:
  39. 10
  40. 请输入你要从1.....n数列中取值的n:
  41. 6
  42. 所有可能的序列,如下:
  43. 6 + 4
  44. 3 + 6 + 1
  45. 4 + 5 + 1
  46. 3 + 5 + 2
  47. 2 + 3 + 4 + 1
  48. Press any key to continue
  49. */






阅读(1452) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~