剑指Offer :字符串的排列
题目 1
输入一个字符串,打印出该字符串中字符的所有排列。例如,输入字符串 abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
示例
输入:
abc
输出:
abc
acb
bac
bca
cba
cab
解题思路
可以把一个字符串看成由两部分组成:第一部分是它的第一个字符;第二部分是后面的所有字符。求整个字符串的排列,可以看成两步。
1.求所有可能出现在第一个位置的字符。
2.固定第一个字符,求后面所有字符的排列。这时仍把后面所有字符分成两部分:后面字符的第一个字符,以及这个字符之后的所有字符。
代码实现
#include <stdio.h>
void Permutation(char* string, char* strBegin);
void Permutation(char* string)
{
if (string == NULL) {
return;
}
Permutation(string, string);
}
void swap(char* strA, char* strB)
{
char temp = *strA;
*strA = *strB;
*strB = temp;
}
void Permutation(char* string, char* strBegin)
{
if (*strBegin == '\0') {
printf("%s\n", string);
} else {
for (char* strCh = strBegin; *strCh != '\0'; ++strCh) {
// 有重复字符时,跳过
if ((*strCh == *strBegin) && (strCh != strBegin)) {
continue;
}
swap(strCh, strBegin);
Permutation(string, strBegin + 1);
swap(strCh, strBegin);
}
}
}
int main(void)
{
char string[] = "abc";
Permutation(string);
return 0;
}
题目 2
如果不是求字符的所有排列,而是求字符的所有组合,应该怎么办呢?还是输入三个字符 a、b、c,则它们的组合有 a、b、c、ab、ac、bc、abc。当交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是同一个组合。比如 ab 和 ba 是不同的排列,但只算一个组合。
示例
输入:
abc
输出:
a
b
c
ab
ac
bc
abc
解题思路
可以把这 n 个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取 m-1个字 符:如果组合里不包含第一个字符,则下一步在剩余的 n-1 个字符里选取 m 个字符。也就是说,我们可以把求 n 个字符组成长度为 m 的组合的问题分解成两个子问题。
1.求 n-1 个字符串中长度为 m-1 的组合。
2.求 n-1 个字符的长度为 m 的组合。
代码实现
#include <cstdio>
#include <cstring>
#include <vector>
void Combination(char* string, int number, std::vector<char>& result);
void Combination(char* string)
{
if (string == nullptr) {
return;
}
std::vector<char> result;
for (int i = 1; i <= strlen(string); ++i) {
Combination(string, i, result);
}
}
void Combination(char* string, int number, std::vector<char>& result)
{
if (number == 0) {
std::vector<char>::iterator iter = result.begin();
for (; iter < result.end(); ++iter) {
printf("%c", *iter);
}
printf("\n");
return;
}
if (*string == '\0') {
return;
}
result.push_back(*string);
Combination(string + 1, number - 1, result);
result.pop_back();
Combination(string + 1, number, result);
}
int main(void)
{
char string[] = "abc";
Combination(string);
return 0;
}
题目 3
输入一个含有 8 个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。
解题思路
相当于先得到a1、a2、a3、a4、a5、a6、a7和a8这 8 个数字的排列,然后判断有没有某一个排列符合题目给定的条件,即 a1+a2+a3+a4 == a5+a6+a7+a8,a1+a3+a5+a7 == a2+a4+a6+a8,并且a1+a2+a5+a6 == a3+a4+a7+a8。
代码实现
#include <stdio.h>
#include <stdbool.h>
void swap(int* a, int*b)
{
int temp = *a;
*a = *b;
*b = temp;
}
bool CubVertex(int* A, int length, int begin)
{
if ((A == NULL) || (length != 8)) {
return false;
}
bool result = false;
int i = 0;
if (begin == length - 1) {
if ((A[0] + A[1] + A[2] + A[3] ==A[4] + A[5] + A[6] + A[7]) &&
(A[0] + A[2] + A[4] + A[6] == A[1] + A[3] + A[5] + A[7]) &&
(A[0] + A[1] + A[4] + A[5] == A[2] + A[3] + A[6] + A[7])) {
for (i = 0; i < length; ++i) {
printf("%d ", A[i]);
}
printf("\n");
result = true;
}
} else {
for (i = begin; i < length; ++i) {
swap(&A[begin], &A[i]);
result = CubVertex(A, length, begin + 1);
if (result) {
break;
}
swap(&A[begin], &A[i]);
}
}
return result;
}
int main(void)
{
int A[8] = {1, 2, 3, 1, 2, 3, 2, 2};
int B[8] = {1, 2, 3, 1, 8, 3, 2, 2};
if (CubVertex(A, 8, 0)) {
printf("Yes!\n");
} else {
printf("No!\n");
}
if (CubVertex(B, 8, 0)) {
printf("Yes!\n");
} else {
printf("No!\n");
}
return 0;
}
/* 运行结果
* 1 2 3 2 3 2 1 2
* Yes!
* No!
*/
个人博客: