給出一組不同的正整數序列和一個目標值,求出所有可能的組合,使得組合里所有元素和為目標值。要求:
1)每個組合里的元素按照升序排列。
2)輸出組合里不含有重復的組合。
3)輸入序列中的整數可以多次使用。
舉例:
輸入{2,3,4,7},目標值為7
輸出{7},{2,2,3},{3,4}
為了讓輸出元素按升序排列,可對輸入序列進行排序。同這里我們使用遞歸的方法來解決這個組合問題,即典型的for語句內調用遞歸函數。需要注意以下幾點:
1)記錄剩余目標值和,只有當該值為0時,組合才是有效的。
2)記錄當前位置,因為序列中的數可以重復使用,所以下一次遞歸時,還可以從當前位置開始,這將體現在遞歸函數的參數里。
具體可參看代碼實現中的GetResultSet函數。
如果序列中可能有相同的元素,並且每個元素最多只能使用一次,那么又該怎么處理?相對於之前的問題,這里有兩個變化:1)每個元素最多只能使用一次,下次遞歸時是不能從當前位置開始的,而是從下一個開始。2)由於序列中含有相等的元素,哪怕每個元素最多只使用一次,也可能出現重復的組合,所以,為了避免重復,只取第一個相同元素。
具體可參看代碼實現中的GetResultSetEx函數。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef vector<int> IntArray;
//結果集
typedef vector<vector<int>> ResultSet;
ResultSet gResultSet;
//原始序列中不含相同的值
void GetResultSet( const IntArray& mSrcArray, int nTarget,
IntArray& mDstArray, int iStart )
{
if ( nTarget < 0 ) return;
if ( nTarget == 0 )
{
//找到一個結果
gResultSet.push_back( mDstArray );
}
else
{
for( int i = iStart; i < mSrcArray.size(); ++i )
{
//后面更大的數不可能滿足條件
if ( mSrcArray[i] > nTarget ) break;
//加入當前元素
mDstArray.push_back( mSrcArray[i] );
//遞歸處理,因為元素可以重復使用,所以從當前位置繼續遞歸
GetResultSet( mSrcArray, nTarget-mSrcArray[i], mDstArray, i );
//重置
mDstArray.pop_back();
}
}
}
//序列中可能有相同的元素,並且每個元素最多只能使用一次,不含重復組合
void GetResultSetEx( const IntArray& mSrcArray, int nTarget,
IntArray& mDstArray, int iStart )
{
if ( nTarget < 0 ) return;
if ( nTarget == 0 )
{
//找到一個結果
gResultSet.push_back( mDstArray );
}
else
{
for( int i = iStart; i < mSrcArray.size(); ++i )
{
//后面更大的數不可能滿足條件
if ( mSrcArray[i] > nTarget ) break;
//避免結果集重復,只取第一個相同值加入結果中
if ( i != iStart && mSrcArray[i] == mSrcArray[i-1] ) continue;
//加入當前元素
mDstArray.push_back( mSrcArray[i] );
////遞歸處理,因為元素可以重復使用,所以從當前位置繼續遞歸
//GetResultSet( mSrcArray, nTarget-mSrcArray[i], mDstArray, i );
//遞歸處理,因為元素不可以重復使用,所以從下一位置繼續遞歸
GetResultSetEx( mSrcArray, nTarget-mSrcArray[i], mDstArray, i+1 );
//重置
mDstArray.pop_back();
}
}
}
//輸出結果集
void OutPutResultSet()
{
if ( gResultSet.size() <= 20 )
{
for( ResultSet::iterator it = gResultSet.begin();
it != gResultSet.end(); ++it )
{
for( IntArray::iterator itTemp = it->begin();
itTemp != it->end(); ++itTemp )
{
cout << *itTemp << " ";
}
cout << endl;
}
}
cout << "總共結果數:" << gResultSet.size() << endl;
cout << "---------------------------------------" << endl;
}
int main()
{
IntArray mSrcArray;
IntArray mDstArrayTemp;
int nTarget = 0;
while( true )
{
//構造源數據
int nTemp = 0;
mSrcArray.clear();
while( cin >> nTemp )
{
if ( nTemp == 0 ) break;
mSrcArray.push_back( nTemp );
}
cin >> nTarget;
//從小到大排序
sort( mSrcArray.begin(), mSrcArray.end() );
mDstArrayTemp.clear();
gResultSet.clear();
//GetResultSet( mSrcArray, nTarget, mDstArrayTemp, 0 );
GetResultSetEx( mSrcArray, nTarget, mDstArrayTemp, 0 );
//輸出結果
OutPutResultSet();
}
return 0;
}
系列文章說明:
1.本系列文章[算法練習],僅僅是本人學習過程的一個記錄以及自我激勵,沒有什么說教的意思。如果能給讀者帶來些許知識及感悟,那是我的榮幸。
2.本系列文章是本人學習陳東鋒老師《進軍硅谷,程序員面試揭秘》一書而寫的一些心得體會,文章大多數觀點均來自此書,特此說明!
3.文章之中,難免有諸多的錯誤與不足,歡迎讀者批評指正,謝謝.
作者:山丘兒
轉載請標明出處,謝謝。原文地址:http://blog.csdn.net/s634772208/article/details/46710405
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。