给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

【题目】给定一个数t以及n个整数,在这n个数中找到加和为t的所有组合,例如t = 4, n = 6,6个数为 [4, 3, 2, 2, 1, 1],这样输出就有4个不同的组合它们的加和为4: 4, 3+1, 2+2, and 2+1+1.  请设计一个高效算法实现这个需求。-----阿里2011实习生笔试题

之前只是看了一下网上这个题的写法没自己动手写,以下为自己所写的程序。

注:此题可与创新工厂的那个题目(http://blog.csdn.net/zhizunwudi/article/details/11709115)对比着看一下,两者有点不同:本题数组中数字是有限的,而创新工场的那个题目每一个数字有无限个。

[cpp] view plain copy
  1. int partition(int *a,int low,int high)  
  2. {  
  3.     int pivotKey=a[low];  
  4.     while(low<high)  
  5.     {  
  6.         while (low<high && pivotKey<=a[high])  
  7.             high--;  
  8.         swap(a[low],a[high]);  
  9.   
  10.         while(low<high && pivotKey>=a[low])  
  11.             low++;  
  12.         swap(a[low],a[high]);  
  13.     }  
  14.     return low;  
  15. }  
  16.   
  17. void QSort(int *a,int low,int high)  
  18. {  
  19.     if (low<high)  
  20.     {  
  21.         int pivot=partition(a,low,high);  
  22.         QSort(a,low,pivot);  
  23.         QSort(a,pivot+1,high);  
  24.     }  
  25. }  
  26.   
  27. void QucikSort(int *a,int n)//自己写的快排  
  28. {  
  29.     QSort(a,0,n-1);  
  30. }  
  31.   
  32. void PrintCombination(int *a,int n,int sum,vector<int>& vec)  
  33. {   //a为输入数组,n为数组长度,sum为待查找的和,vec用于保存查找到的组合  
  34.     if (sum==0)  
  35.     {  
  36.         vector<int>::iterator iter=vec.begin();  
  37.         for (;iter!=vec.end();iter++)  
  38.         {  
  39.             cout<<*iter<<" ";  
  40.         }  
  41.         cout<<endl;  
  42.         return;  
  43.     }  
  44.     else if(sum<0 || n<=0)  
  45.         return;  
  46.     vec.push_back(a[0]);//a[0]即*a,注指针a是变化的,每次指向后一个  
  47.     PrintCombination(a+1,n-1,sum-a[0],vec);  
  48.     vec.pop_back();  
  49.   
  50.     while(*a == *(a+1) && a < a+n) //【重要】跳过重复的数字    
  51.              a++;   
  52.     PrintCombination(a+1,n-1,sum,vec);  
  53. }  
  54.   
  55. void main()  
  56. {  
  57.     int a[8]={8,3,6,5,7,2,4,1};  
  58.     cout<<"原来的数组:";  
  59.    PrintArray(a,8);  
  60.    QucikSort(a,8);  
  61.    cout<<"排序后数组:";  
  62.    PrintArray(a,8);  
  63.    cout<<"-----------------------------"<<endl;  
  64.     vector<int> vec;  
  65.    int sum=10;  
  66.    cout<<"和为"<<sum<<"的组合如下:"<<endl;  
  67.    PrintCombination(a,8,sum,vec);  
  68. }  

 

【注】:感觉对数组“排序”的作用就是为了跳过重复的数字,如果没有重复数字,完全不需要对数组进行排序。

测试1:(排序情况)
给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试2:(不排序情况,前提是无重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试3:(不跳过重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试4:(跳过重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合


【题目】给定一个数t以及n个整数,在这n个数中找到加和为t的所有组合,例如t = 4, n = 6,6个数为 [4, 3, 2, 2, 1, 1],这样输出就有4个不同的组合它们的加和为4: 4, 3+1, 2+2, and 2+1+1.  请设计一个高效算法实现这个需求。-----阿里2011实习生笔试题

之前只是看了一下网上这个题的写法没自己动手写,以下为自己所写的程序。

注:此题可与创新工厂的那个题目(http://blog.csdn.net/zhizunwudi/article/details/11709115)对比着看一下,两者有点不同:本题数组中数字是有限的,而创新工场的那个题目每一个数字有无限个。

[cpp] view plain copy
  1. int partition(int *a,int low,int high)  
  2. {  
  3.     int pivotKey=a[low];  
  4.     while(low<high)  
  5.     {  
  6.         while (low<high && pivotKey<=a[high])  
  7.             high--;  
  8.         swap(a[low],a[high]);  
  9.   
  10.         while(low<high && pivotKey>=a[low])  
  11.             low++;  
  12.         swap(a[low],a[high]);  
  13.     }  
  14.     return low;  
  15. }  
  16.   
  17. void QSort(int *a,int low,int high)  
  18. {  
  19.     if (low<high)  
  20.     {  
  21.         int pivot=partition(a,low,high);  
  22.         QSort(a,low,pivot);  
  23.         QSort(a,pivot+1,high);  
  24.     }  
  25. }  
  26.   
  27. void QucikSort(int *a,int n)//自己写的快排  
  28. {  
  29.     QSort(a,0,n-1);  
  30. }  
  31.   
  32. void PrintCombination(int *a,int n,int sum,vector<int>& vec)  
  33. {   //a为输入数组,n为数组长度,sum为待查找的和,vec用于保存查找到的组合  
  34.     if (sum==0)  
  35.     {  
  36.         vector<int>::iterator iter=vec.begin();  
  37.         for (;iter!=vec.end();iter++)  
  38.         {  
  39.             cout<<*iter<<" ";  
  40.         }  
  41.         cout<<endl;  
  42.         return;  
  43.     }  
  44.     else if(sum<0 || n<=0)  
  45.         return;  
  46.     vec.push_back(a[0]);//a[0]即*a,注指针a是变化的,每次指向后一个  
  47.     PrintCombination(a+1,n-1,sum-a[0],vec);  
  48.     vec.pop_back();  
  49.   
  50.     while(*a == *(a+1) && a < a+n) //【重要】跳过重复的数字    
  51.              a++;   
  52.     PrintCombination(a+1,n-1,sum,vec);  
  53. }  
  54.   
  55. void main()  
  56. {  
  57.     int a[8]={8,3,6,5,7,2,4,1};  
  58.     cout<<"原来的数组:";  
  59.    PrintArray(a,8);  
  60.    QucikSort(a,8);  
  61.    cout<<"排序后数组:";  
  62.    PrintArray(a,8);  
  63.    cout<<"-----------------------------"<<endl;  
  64.     vector<int> vec;  
  65.    int sum=10;  
  66.    cout<<"和为"<<sum<<"的组合如下:"<<endl;  
  67.    PrintCombination(a,8,sum,vec);  
  68. }  

 

【注】:感觉对数组“排序”的作用就是为了跳过重复的数字,如果没有重复数字,完全不需要对数组进行排序。

测试1:(排序情况)
给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试2:(不排序情况,前提是无重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试3:(不跳过重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合

 

测试4:(跳过重复数字)

给定一个数t,以及n个整数,在这n个数中找到加和为t的所有组合