已知: n个数字序列,每个序列中包含m个数字,求这n个序列数字的所有可能的排列组合

今天做了一个算法题,题目大概是这样的:
已知: n个数字序列,每个序列中包含m个数字,求这n个序列数字的所有可能的排列组合

给出一个例子,这个例子n是3,要求n可以是任意的。
input = {{1,2,3},
         {4,5},
         {6,7,8}}
output = {
	{1,4,6},{1,4,7},{1,4,8},
	{1,5,6},{1,5,7},{1,5,8},
    {2,4,6},{2,4,7},{2,4,8},
	{2,5,6},{2,5,7},{2,5,8},
	{3,4,6},{3,4,7},{3,4,8},
	{3,5,6},{3,5,7},{3,5,8}}

不难看出
1.组合的总个数(total)为每一行数据个数的乘积。本题为3 × 2 × 3 = 18个(没剔除重复)。
2.每个组合内部数据的个数是输入数组的行数。本题是3行,一个组合内部是由3个数字组成。
3.每个组合内部的数据是每行取一个。
思路:
1.外循环控制组合的总个数,内循环控制每个组合内部数据的个数。
2.用vector< int> out 表示一个组合数据。
3.本题18个组合与其下标如下图所示:
在这里插入图片描述
可以看出第3行每遍历1个都会更换数字,第2行每3个更换数字,第1行每6个更换数字。我暂时把遍历x个后就更换数字,这个x叫做这一行的步长step。
步长step求法:

	// 计算步长
	int a = total;
	for (int i = 0; i <inputSize.size(); ++i) {
		a = a / inputSize[i];
		step.push_back(a);
	}

4.遍历数据,每一行各去一个数据,取该行某数据下标为:i / 该行的步长 % 该行的数据个数。其中i是组合总数的下标。

	for (int i = 0; i < total; ++i) {
		for (int j = 0; j < inputSize.size(); j++) {
			out.push_back(input.at(j).at(i / step[j] % inputSize[j]));
		}
		output->push_back(out); // 添加一个组合数据
		out.clear();
	}

5.这里没考虑重复的情况,也没考虑各种非正常数据的情况。
总代码如下:

// 创建输入数组
void CreateInputData(vector<vector<int>> &input)
{
	vector<int> n1;
    n1.push_back(1);
    n1.push_back(2);
    n1.push_back(3);
    input.push_back(n1);

    vector<int> n2;
    n2.push_back(4);
    n2.push_back(5);
    input.push_back(n2);

	vector<int> n3;
    n3.push_back(6);
    n3.push_back(7);
	n3.push_back(8);
    input.push_back(n3);
}

// 打印函数
void PrintResult(vector<vector<int> >& result, int s)
{

    int line = 0;
    cout << "{";
    for (auto i = result.begin(); i != result.end(); ++i) {
        if ( line++%s == 0) {
            cout << "\n  ";
        }
        cout << "{";
        for (auto j = i->begin(); j != i->end(); ++j) {
            cout << *j << ",";
        }
        cout << "},";
    }
    cout << "\n}\n";
}

// 组合数据
void Combine(const vector<vector<int>>& input, vector<vector<int> >* output)
{
	// 此处答题:
	vector<int> out; // 用于存放一个组合
	vector<int> inputSize;	// 存放每一组数据大小
	vector<int> step;
	int total; // 组合的个数

	// 计算每一组输入数据大小
	for (int i = 0; i < input.size(); ++i) {
		inputSize.push_back(input.at(i).size());
	}

	// 计算组合个数
	for (int i = 0; i < inputSize.size(); ++i) {
		total *= inputSize[i];
	}

	// 计算步长
	int a = total;
	for (int i = 0; i <inputSize.size(); ++i) {
		a = a / inputSize[i];
		step.push_back(a);
	}

	// 输出
	for (int i = 0; i < total; ++i) {
		for (int j = 0; j < inputSize.size(); j++) {
			out.push_back(input.at(j).at(i / step[j] % inputSize[j]));
		}
		output->push_back(out);
		out.clear();
	}
}

int main()
{
	vector<vector<int>> input;
    vector<vector<int>> output;
    CreateInputData(input);
    Combine(input, &output);
    PrintResult(output, input.size());

	system("pause");
	return 0;
}

总结:好久没做算法题了,突然一做简直要疯掉了,脑袋各种转不过来(本来就比较菜),在网上搜也搜不到,自己想也就只能想到这种方法了。如果哪位小伙伴有好方法可以分享出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值