剑指offer-38

输入一个字符串,打印该字符串中字符的所有排列

解法一:

递归得遍历所有位数,每一位替换所有数值(备用的不算,用数组tag记录数字被使用情况),用list记录要打印的结果,空间复杂度O(N),时间复杂度O(N^N),不划算

解法二:

分为两组,当前位和剩下位,用当前位于剩下的位数一一进行替换,可避免重复,即可导出全排列,空间O(1),时间O(N^2)

解法1
void Permutation(char* pStr, bool* tag, int pos, std::list<char>& plist)//diy
{
	if (pStr[pos]=='\0')
	{
		for (auto& it : plist)
			printf("%c,", it);
		printf("\n");
		return;
	}
	int i = 0;
	while (pStr[i]!='\0')
	{
		if (tag[i] != true)
		{
			plist.push_back(pStr[i]);
			tag[i] = true;
			Permutation(pStr, tag, pos + 1, plist);
			tag[i] = false;
			plist.pop_back();
		}
		i++;
	}
	return;
}

void Permutation(char* pStr)//diy,space O(n),time O(n^n)
{
	if (pStr == nullptr) return;
	int len = 0;
	for (int i = 0;;i++)
	{
		if (pStr[i]=='\0') break;
		len++;
	}
	
	bool* tag = new bool[len]();
	std::list<char> pList;
	Permutation(pStr, tag, 0, pList);
}

解2:
void Permutation(char* pStr, char* pCurr)//diy
{
	if (*pCurr=='\0')
	{
		for (int i=0;;i++)
		{
			if (*(pStr + i) != '\0')
				printf("%c,", *(pStr + i));
			else
			{
				printf("\n");
				return;
			}
		}
	}

	int addnum = 1;
	char ctemp = *pCurr;
	while (true)
	{
		if (*(pCurr + addnum) == '\0')
		{
			Permutation(pStr, pCurr + 1);
			return;
		}
		*pCurr = *(pCurr + addnum);
		*(pCurr + addnum) = ctemp;
		Permutation(pStr, pCurr + 1);
		*(pCurr + addnum) = *pCurr;
		*pCurr = ctemp;
		addnum++;
	}
}
void Permutation(char* pStr) //diy
{
	if (pStr == nullptr) return;
	Permutation(pStr, pStr);
}

38.2

求字符的所有组合

给定N个字符,组合的位数有1-N种

针对一种长度为M的组合,分为两部分,第1位,剩下m-1位

第1位要么选择某个符号,从剩下符号中选M-1位,要么不选,从剩下符号中选M位

void Combinations(char* pStr, int len, int m, int currPos, bool* tag)//diy
{
	if (m == 0)
	{
		for (int i = 0;i<len;i++)//不够简洁
		{
			if (tag[i]==true)
				printf("%c,", *(pStr + i));
		}
		printf("\n");
		return;
	}
	if (len - currPos >= m)//边界条件,保证有足够的字符可以选
	{
		tag[currPos] = true;
		Combinations(pStr, len, m - 1, currPos + 1,tag);
		tag[currPos] = false;
	}
	if (len - currPos - 1 >= m)
		Combinations(pStr, len, m, currPos + 1,tag);
	return;
}

void Combinations(char* pStr)//diy
{
	if (pStr == nullptr) return;
	int len = 0;
	while (*(pStr + len) != '\0')//cautions for non-existent of '\0'
		len++;
	
	bool* tag = new bool[len]();//额外空间O(N)
	for (int m = 0;;m++)
	{
		if (*(pStr+m)=='\0') break;
		Combinations(pStr, len, m + 1, 0,tag);
	}
}

38.3输入一个含有8个数字的数组,把数字放到正方体的8个顶点,使得正方体三组相对面的四个顶点的和都相等

8个顶点分别为a1~a8,分于八个顶点上,三个相对的面组成三个等式,把八个顶点进行全排列,每次排列结果用三个等式检测即可

 

38.4皇后问题,8*8的棋盘摆8个皇后,使其互相不能攻击,皇后只能攻击同一行,同一列,同一对角线,判断共有多少种符合条件的摆法

用数组对每个皇后进行全排列,然后根据下标判断是否有同行或同对角线的情况,时间复杂度很高,具体来说,1-64个数里,抽取8个数字,做法就是抽取8位的所有组合,再进行判断即可

 

说白了,要是问题抽象涉及摆放数字问题,先求出所有排列,然后一一判断排列是否满足

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值