检查排列而不修改原始字符串C.

时间:2015-07-13 03:21:05

标签: c pass-by-reference permutation

我正在检查2个字符串是否是排列。我对字符串进行排序,然后将每个字符相互比较。但是,我认为我的排序过程也改变了原始字符串(我用指针和通过引用传递非常糟糕)。

有没有办法在不修改原始字符串的情况下进行检查?

我也试过使用strcpy,但我真的不知道如何使用它。 我在check()函数中试过这个:

void check(char *word, struct Entry *en) { 
   if (areAnagram(en->word, word) == 1) {
        //printf("EW:%s W:%s\n", en->word, word);
        //For example, this should return something like
        // EW:silent W:listen
        //But I got
        // EW:eilnst W:eilnst
   }
}

以下是我的代码。我从另一个函数调用areAnagram函数:

typedef struct Entry {
   char *word;
   int len;
   struct Entry *next;
} Entry;

参赛作品结构:

void quickSort(char *arr, int si, int ei);

int areAnagram(char *str1, char *str2)
{
   // Get lenghts of both strings
   int n1 = strlen(str1);
   int n2 = strlen(str2);

   // If lenght of both strings is not same, then they cannot be anagram

   if (n1 != n2) {
      return 0;
   }

   // Sort both strings
   quickSort (str1, 0, n1 - 1);
   quickSort (str2, 0, n2 - 1);

   int i;
   // Compare sorted strings
   for (i = 0; i < n1;  i++) {
      if (str1[i] != str2[i]) {
         return 0;
      }
   }

   return 1;
}

void exchange(char *a, char *b)
{
   char temp;
   temp = *a;
   *a   = *b;
   *b   = temp;
}

int partition(char A[], int si, int ei)
{
   char x = A[ei];
   int i = (si - 1);
   int j;

   for (j = si; j <= ei - 1; j++) {
      if(A[j] <= x) {
         i++;
         exchange(&A[i], &A[j]);
      }
   }

   exchange (&A[i + 1], &A[ei]);
   return (i + 1);
}

void quickSort(char A[], int si, int ei)
{
   int pi;    /* Partitioning index */
   if(si < ei) {
      pi = partition(A, si, ei);
      quickSort(A, si, pi - 1);
      quickSort(A, pi + 1, ei);
   }
}

这是anagram检查过程:

{{1}}

3 个答案:

答案 0 :(得分:3)

有一种更好的方法可以检查两个字符串是否为字谜。您可以创建一个数组来存储第一个字符串中每个字符的计数(增加数组中的ASCII值索引)。然后遍历第二个字符串并减少每个字符的计数(数组中的ASCII值索引)。现在检查数组的所有元素是否为零,如果是,则这些是anagrams,否则不是。

int arr [123]; 假设两个字符串是s1 =&#34; abba&#34;和s2 =&#34; baba&#34;

在遍历第一个字符串arr [97] = 2时,arr [98] = 2;

遍历第二个数组arr [97] = 0,arr [98] = 0;

现在,如果遍历整个数组,那么所有元素都将为零。

但如果两个字符串s1 =&#34; abba&#34;和s2 =&#34; abac&#34;

在遍历第一个字符串arr [97] = 2时,arr [98] = 2;

遍历第二个字符串arr [97] = 0时,

,arr [98] = 1,arr [99] = - 1;

由于数组的所有元素都不为零,因此这些不是字谜。

上述算法的复杂性为O(n)。

希望它有所帮助。

答案 1 :(得分:0)

使用strcpy制作副本:

char *copy = malloc(strlen(word) + 1); // can use a temporary buffer, but this     allows variable length inputs
strcpy(copy, word);
// use copy as your temporary string

free(copy);

答案 2 :(得分:0)

您的标题声明您不想修改原始字符串,但是您的解决方案使用Quicksort修改字符串。此外,排序 - 即使是快速优化的排序 - 也是一项昂贵的操作,并且不是您要解决的问题所必需的。您可以使用查找表来获得速度,但不会修改原始字符串。您只需为每个字母创建一个唯一编号,然后对这些值求和。等额将构成一个字谜。

/* OPTION 1: let the compiler build your table */
static const int A=0x0000001;
static const int B=0x0000002;
static const int C=0x0000004;
/* continue to double for other letters until ... */
static const int Z=0x4000000;

/* OPTION 2: calculate a cheap hash for each letter */
/* Returns 0 for anagram similar to strcmp */
int anagram (const char* word1, const char* word2)
{
    /* strings must be equal length */
    if (strlen(word1) != strlen(word2))
        return -1;

    unsigned long sum1 = 0;
    unsigned long sum2 = 0;
    char c;
    for (int i = 0 ; word1[i] != '\0' ; i++)
    {
        /* use toupper() function here if case insensitive */
        c = toupper(word1[i]);
        sum1 += 1 << (c - 'A');
    }
    for (int i = 0 ; word2[i] != '\0' ; i++)
    {
        /* use toupper() function here if case insensitive */
        c = toupper(word2[i]);
        sum2 += 1 << (c - 'A');
    }
    return (int)(sum1 - sum2); /* ignore overflow */
}

上面的anagram函数未经测试,为清楚起见而编写。您需要包含ctype.h才能使用toupper()转换案例。

最后,您可以复制其中一个字符串,遍历每个字符上调用strchr()的另一个字符串,以查找副本中的匹配字符。如果strchr()返回NULL,则没有anagram,否则如果strchr()返回有效指针,则使用它来修改副本,例如设置为char值为0x01,以便您可以对修改后的副本中的字符求和。在这种情况下,如果修改后的副本中所有字符的总和等于比较字符串的整数长度,则字符串将是字谜。