剑指Offer :字符串的排列

## 1. 题目 1 >输入一个字符串,打印出该字符串中字符的所有排列。例如,输入字符串 abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。 ### 1.1 示例 输入: ```c abc ``` 输出: ```c abc acb bac bca cba cab ``` ### 1.2 解题思路 >可以把一个字符串看成由两部分组成:第一部分是它的第一个字符;第二部分是后面的所有字符。求整个字符串的排列,可以看成两步。 1.求所有可能出现在第一个位置的字符。 2.固定第一个字符,求后面所有字符的排列。这时仍把后面所有字符分成两部分:后面字符的第一个字符,以及这个字符之后的所有字符。 ### 1.3 代码实现 ```c #include 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. 题目 2 >如果不是求字符的所有排列,而是求字符的所有组合,应该怎么办呢?还是输入三个字符 a、b、c,则它们的组合有 a、b、c、ab、ac、bc、abc。当交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是同一个组合。比如 ab 和 ba 是不同的排列,但只算一个组合。 ### 2.1 示例 输入: ```c abc ``` 输出: ```c a b c ab ac bc abc ``` ### 2.2 解题思路 >可以把这 n 个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取 m-1个字 符:如果组合里不包含第一个字符,则下一步在剩余的 n-1 个字符里选取 m 个字符。也就是说,我们可以把求 n 个字符组成长度为 m 的组合的问题分解成两个子问题。 1.求 n-1 个字符串中长度为 m-1 的组合。 2.求 n-1 个字符的长度为 m 的组合。 ### 2.3 代码实现 ```c #include #include #include void Combination(char* string, int number, std::vector & result); void Combination(char* string) { if (string == nullptr) { return; } std::vector result; for (int i = 1; i <= strlen(string); ++i) { Combination(string, i, result); } } void Combination(char* string, int number, std::vector & result) { if (number == 0) { std::vector ::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. 题目 3 >输入一个含有 8 个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。 ### 3.1 解题思路 >相当于先得到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。 ### 3.2 代码实现 ```c #include #include 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! */ ``` --- 个人博客: [www.codeapes.cn](https://www.codeapes.cn)

你可能感兴趣的:(剑指Offer :字符串的排列)