【问题标题】:Permutation of an array of strings字符串数组的排列
【发布时间】:2020-09-19 09:46:23
【问题描述】:

我正在解决这个挑战: https://www.hackerrank.com/challenges/permutations-of-strings/problem

我正在使用这个算法: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order

假设我输入的字符串数组为{"a", "b", "c"},那么输出应该是:

a b c 
a c b
b c a
c b a
b a c
c a b

因为有 3 个不同的字符串,所以有 3 个! = 6 个排列。

程序也是要处理重复的,所以如果我输入{"a", "b", "b"},就只有3个! /2! = 3 个排列。

无论如何,当我的程序到达c b a 时,它就会退出。为什么?我该如何解决?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(char** s1, char** s2) // to swap two strings
{
    char* temp = *s1;
    *s1 = *s2;
    *s2 = temp;
}
int next_permutation(int n, char **s)
{
    /**
    * Complete this method
    * Return 0 when there is no next permutation and 1 otherwise
    * Modify array s to its next permutation
    */
    int k, i, l;
    k = i = l = 0;

    for(i = n - 2; i >= 0; i--) // first step
        if(strcmp(s[i], s[i + 1]) < 0) {
            k = i;
            break;
        }


    if(i == -1)
        return 0;

    for(i = n - 1; i >= k + 1; i--) // second step
        if(strcmp(s[k], s[i]) < 0) {
            l = i;
            break;
        }


    swap(&s[k], &s[l]); // third step

    for(i = k + 1; i < n / 2; i++) // fourth step
        swap(&s[i], &s[n - i - 1]);

    return 1;
}

int main() // locked code
{
    char **s;
    int n;
    scanf("%d", &n);
    s = calloc(n, sizeof(char*));
    for (int i = 0; i < n; i++)
    {
        s[i] = calloc(11, sizeof(char));
        scanf("%s", s[i]);
    }
    do
    {
        for (int i = 0; i < n; i++)
            printf("%s%c", s[i], i == n - 1 ? '\n' : ' ');
    } while (next_permutation(n, s));
    for (int i = 0; i < n; i++)
        free(s[i]);
    free(s);
    return 0;
}

【问题讨论】:

  • 与你所说的相反,你的程序只是输出a b c 然后退出。这是因为你在完全错误的时间打破了这些循环。
  • 在 Xcode 上,当我输入 3、a、b、c 时,每个都在一个新行上,我得到输出,直到 c b a 然后它重复。无论如何我该怎么办?
  • edit 您的问题直接在此处提供附加信息,而不是将其隐藏在 cmets 中。一个好的minimal reproducible example 需要几对相关不同的样本输入以及结果输出。
  • 如果这是真的,那么“Xcode”就坏了。 strcmp(s[i], s[i + 1]) &lt; 0 对于a b c 的初始数组永远不应该为真,因此循环将一直持续到i == n - 1,这意味着您返回0。在进行任何排列之前。你认为我更信任谁,Xcode 还是你?
  • 我将为第一步提供以下提示:从最大索引开始并向后工作是否有意义,因为您希望最大索引匹配条件?这样,您可以更快地退出循环......如果您将k 初始化为一个它不可能最终的值,那么您可以检查k 是否仍然具有该值以确定条件是否曾经是的。

标签: c arrays string


【解决方案1】:

这是最终代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(char** s1, char** s2) // swaps two strings
{
    char* temp = *s1;
    *s1 = *s2;
    *s2 = temp;
}
int next_permutation(int n, char **s) // function to complete
{
    int k, i, l;
    k = i = l = 0;

    for(i = n - 2; i >= 0; i--) // step 1
        if(strcmp(s[i], s[i + 1]) < 0) {
            k = i;
            break;
        }


    if(i == -1)
        return 0;

    for(i = n - 1; i >= k + 1; i--) // step 2
        if(strcmp(s[k], s[i]) < 0) {
            l = i;
            break;
        }


    swap(&s[k], &s[l]); // step 3

    int inner = k + 1 + n - 1; // step 4
    int cond = inner / 2;
    for(i = n - 1; i > cond; i--)
        swap(&s[i], &s[inner - i]);

    return 1;
}

int main() // locked code
{
    char **s;
    int n;
    scanf("%d", &n);
    s = calloc(n, sizeof(char*));
    for (int i = 0; i < n; i++)
    {
        s[i] = calloc(11, sizeof(char));
        scanf("%s", s[i]);
    }
    do
    {
        for (int i = 0; i < n; i++)
            printf("%s%c", s[i], i == n - 1 ? '\n' : ' ');
    } while (next_permutation(n, s));
    for (int i = 0; i < n; i++)
        free(s[i]);
    free(s);
    return 0;
}

【讨论】:

  • 干得好。 My version. /// 我认为整个声明在顶部是不好的,声明的范围应该受到限制。 /// for (int i=n; i--; ) 是从 N-1 循环到 0 的常用习语(对于非负 N)。更重要的是,注意我是如何使用k = n 而不是k = -1 的?这是为了避免需要 neg nums。没有理由将有符号整数用于数组索引/大小! /// 在第 2 步中使用 i 没有意义;直接使用l 就可以了。 (在其他情况下,我会避免使用 l,因为它看起来像 1。)/// 我们在第 4 步中做的有点不同,但两者都很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-18
相关资源
最近更新 更多