又是排列组合问题,记得5年前遇到过一次,结果用了个很挫的方法 勉强凑出功能。
//todo:未完待续
1.问题:有一个字符集具有n个字符,需要从这字符集中取出字符元素来构成一个长度为m的字符串(m<=n),允许字符串中的字符有重复的,求解这样的字符串列表。
ex. 从字符集 {a, b, c}中取出元素构成一个长度为2的字符串,并且允许字符串中的字符重复
根据数学上的排列组合可以知道,在构成的长度为2的字符串中,每个位置都有3中可能,所有共有3 * 3=9种组合,分别是
aa
ab
ac
ba
bb
bc
ca
cb
cc
解决方案:
采用回溯法来实现该问题,然后选择非递归的方式来完成
从新字符串尾部开始,往首部尝试遍历。当一个位置尝试完所有位置的时候,回溯一个,然后再重新列举组合。
具体逻辑见代码。
type
TOnAStringSequenceBuilded = procedure (ANewStringSequence: string) of object;
{-----------------------------------------------------------------------------
作者:zyan 2011.08.05
参数: ASrcSet - 源字符集
nDstSetSize - 目标串大小
AResultList - 提供返回的组合列表
ACallback - 回调函数,当找到一组组合的时候,会尝试调用一次回调
返回:
功能:
-----------------------------------------------------------------------------}
function BuildSequence(const ASrcSet: string; nDstSetSize: Integer;
AResultList: TStrings; ACallback: TOnAStringSequenceBuilded): Integer;
var
//里面存储的索引是从0开始的,记得最后在输出需要把索引值+1 来取得字符
AResultIndexArray: array of Integer;
nSrcSetSize: Integer;
I: Integer;
ANewSequence: string;
begin
Result := 0;
nSrcSetSize := Length(ASrcSet);
if (nDstSetSize < 0) or (nSrcSetSize < 0)
or (nDstSetSize > nSrcSetSize) then
Exit;
SetLength(AResultIndexArray, nDstSetSize);
SetLength(ANewSequence, nDstSetSize);
for I := 0 to nDstSetSize - 1 do
begin
AResultIndexArray[I] := 0;
ANewSequence[I+1] := ASrcSet[AResultIndexArray[I] + 1];
end;
I := nDstSetSize - 1;
repeat
while (I < nDstSetSize - 1) and (AResultIndexArray[I] < nSrcSetSize) do
Inc(I);
if (I >= nDstSetSize - 1) and (AResultIndexArray[I] < nSrcSetSize) then
begin
//当I >= nDstSetSize-1,则可以输出一组数据,然后把AResultIndexArray[I]的值+1
ANewSequence[I + 1] := ASrcSet[AResultIndexArray[I] + 1];
if Assigned(ACallback) then
begin
ACallback(ANewSequence);
end;
AResultList.Add(ANewSequence);
Inc(Result);
Inc(AResultIndexArray[I]);
end
else
begin
//such as: if I < nDstSetSize or AResultIndexArray[I] >= nSrcSetSize then
//backtrack
AResultIndexArray[I] := 0;
Dec(I);
if I >= 0 then
begin
Inc(AResultIndexArray[I]);
if AResultIndexArray[I] < nSrcSetSize then
ANewSequence[I + 1] := ASrcSet[AResultIndexArray[I] + 1];
end;
end;
until I < 0;
end;