剑指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!
 */

个人博客:

www.codeapes.cn

posted @ 2020-06-26 23:19  Codeapes  阅读(155)  评论(0编辑  收藏  举报