首页 > 解决方案 > 在二维数组中查找子字符串(拼图)

问题描述

我一直在尝试制作一个单词拼图(不使用任何库函数),就像您在报纸上看到的那样:

15 rows 12 colums
X T Z M Q Y K C E C F H -->12 chars 
S H O U T E X O E A P I
X G T L Q B E L T N F K
'
'
'

正如您在第二行中看到的那样,有一个单词 SHOUT。现在拼图的设计使用户可以逐行输入他们想要的任何类型的字符集。

我想要做的是当一个词被搜索(如 SHOUT)时,我会返回它的起始索引。我想象的索引将从 0 开始并以 180 结束,因为 12*15=180 就像这样清楚:

X T Z M Q Y K C E C F H
0 1 2 3 4 5 6 7 8 9 10 11
S H O U T E X O E A P I
12 13 14 15 16 17 18 19 20 21 22 23
'
'
'
'''''''''''''''''''179

没有图片很难解释,希望你能理解。

现在棘手的是单词可以在各个方向(从上到下,从下到上,从左到右,从右到左)。我已经编写了大部分代码,但不断出错,它只能检查单词是否从左到右存在。

#include <stdio.h>

#define COLUNM 12
#define ROW 15

int computeLength (char str[50]) {
    int i;
    for (i = 0; str[i] != '\0'; ++i) {
    }
    return i;
}

int findString(char matrix[ROW][COLUNM], char string[], int length) {
    int i = 0, j, k = 0, searchlenght = 0;
    length = computeLength(string);

    for (j = 0; j < ROW; j++) {
        if (matrix[j][k] == string[k]) {
            searchlenght++;
        }
    }
    i++;
    if (searchlength == length) {
        return i;
    }
}

int main() {
    int i, j = 0;
    char matrix[ROW][COLUNM];
    char string[50];
    int b = 1;

    for (i = 0; i < ROW; i++) {
        printf("Enter line %d of the puzzle :\n", i + 1);       
        scanf("%s", &matrix[j][i]);
        j++;    
    }

    while (b > 0) {
        printf("Enter the string to be searched in the puzzle:\n");

        scanf("%s", &string[50]);
        if ((string[0] != 'q') || (string[0] != 'Q')) {
            b = 0;
        }
    }
    return 0;
}

我不认为这很难用 python 实现,但我对 C 非常不熟悉,以至于我不断收到错误和警告。

唯一需要工作的部分是 findString 函数。不要打扰输入,因为我会自己测试它。

能否请你帮忙?

**唯一不起作用的部分是length=computeLength(str1); thşs 当我输入 computeLength("Shout") 它返回 5 但在这段代码中它返回 2 这弄乱了结果**

int findString(char matrix[ROW][COLUNM],char str1[],int length){
int i,j,wordcounting;
int true=1;

length=computeLength(str1);
printf("%d",length);

for(j=0;j<ROW;j++){

if(matrix[i][j]==str1[0]){

    for(wordcounting=1;wordcounting<length;wordcounting++){

        if((matrix[i][j+wordcounting]!=str1[wordcounting])){
            true=0;
            break;

        }

    }
}
i++;}



if(true==1){return (i-length);}
}

当我说 printf("%d",computeLength(string)); 甚至在我输入一个字符串之前它变成了 2

标签: carraysmatrixsubstringpuzzle

解决方案


这是一个 loooooooog 的答案,我会在其中尽可能多地解释您的问题,如何解决它们,最后如何逐步实施搜索以达到最终解决方案。

好好读书!


你的代码有很多问题,首先它无法编译。

第29行无效,替换

int findString(char matrix[ROW][COLUNM],char string[15],int computeLength(string[15])){

经过

int findString(char matrix[ROW][COLUNM], char string[15])

另请注意,大小 15 是无用的,您可以使用char string[]char * string作为参数字符串

第39行无效,替换

if(count==computeLength(string[15])){

经过

if(count==computeLength(string)){

现在您可以编译您的程序,但这还不够。


main中的一些问题。

您交换了行中的索引

scanf("%s",&matrix[j][i]);

它可以替换为

scanf("%s",&matrix[i][0]);

(我使用 0 而不是j,因为它更清楚,不要求我们检查j值 0)

但这还不够,如果输入无效, scanf可以读取超过COLUNM 个字符,甚至输入是 12 个字符,正如您所期望的那样,您忘记了scanf也会写入空字符来完成字符串,因此它写入 13 个字符。

一种方法是读取比COLUMN more 2 长的字符串并检查输入字符串的长度。所以你的for可以替换为:

for(i = 0 ; i < ROW ; i++)
{
  printf("Enter line %d of the puzzle :\n",i+1);       
  if ((scanf("%49s", string) != 1) ||
      (strlen(string) != COLUMN)) {
    puts("invalid line");
    return -1;
  }
  memcpy(&matrix[i][0], string, COLUMN);
  i++;    
}

还要注意最后i增加而不是j

while循环中

scanf("%s",&string[50]);

无效,因为它将结果放在string之后,索引必须为 0,实际上您可以只给出string

和以前一样,如果输入超过 49 个字符, scanf将写出字符串,所以这样做

scanf("%49s", string);

如果您想允许在不计算最后一个空字符的情况下搜索 50 个字符的字符串,则必须将其大小设置为 51 并将 49 替换为 50。

打印和读取while循环什么都不做,很可能您想在其中调用findString并写入返回值,直到第一个读取的字符是 q 或 Q。例如:

 for (;;) {
   puts("Enter the string to be searched in the puzzle:");
   if ((scanf("%49s", string) != 1) || (string[0] =='q') || (string[0] == 'Q'))
     break;
   printf("position in the puzzle: %d\n", findString(matrix, string));
 }

main的末尾,该行的兴趣是模糊的:

printf("%d",computeLength("küfür"));

printPuzzle中,您在打印PUZZLE后错过了引入换行符,您可以将printf替换为puts。请注意,当您知道没有 % 等时,要求printf搜索是没有用的。


查找字符串中

第一个问题是,如果count==computeLength(string)为真,您只返回一个值,您需要始终返回一个值。如果字符串不在拼图中,通常可以返回 -1,所以

return (count==computeLength(string)) ? i : -1;

但这也是错误的,有两个原因:

  • 当您到达测试时,总是将值设为 180,而不是字符串所在的位置
  • 这不是因为count==computeLength(string)是真的,因为您使用递增计数的方式和下一个错误找到了字符串:

您没有正确搜索拼图中的字符串,因为您在 i 上的第一个循环通过了字符串(string[i]),最糟糕的是会访问其中的 180 个字符,而它的长度只有 49 个(没有最后的空字符)。即使找到字符串,您也不会停止搜索。并且在您的算法中,您忘记了字符串的字符必须连续放置在矩阵中,每次您(错误地)在矩阵中的任何位置找到字符串的字符时都会增加count

考虑到您从左到右水平搜索字符串:

  • 字符串上的循环必须是更嵌入的循环,以检查其字符在矩阵中是否连续。

  • 您在行上有一个循环,在列上有一个循环,这是无用的,只会使工作变得复杂。因为matrix是一个数组,所以matrix[r][COLUMN]处的字符是matrix[r+1][0]处的字符,这意味着您可以通过矩阵,就像它是一串ROW*COLUMN字符一样。

  • 我让你重写findString,它就像strstr ,除了你返回索引或 -1 而不是子字符串的地址或 NULL


[编辑搜索功能的建议]

为了解释,我将使用更易于查看的小矩阵:

#define COLUMN 3
#define ROW 5

char Matrix[ROW][COLUMN] = { { 'a', 'b' , 'c' }, 
                             { 'd', 'e' , 'f' }, 
                             { 'g', 'h' , 'i' }, 
                             { 'j', 'k' , 'l' }, 
                             { 'm', 'n' , 'o' } };

让我们从从左到右搜索开始,这类似于经典的strstr函数,除了返回值和矩阵末尾有一个回滚。如果找不到字符串,则决定值为 -1,否则它的第一个字符的位置乘以它最后一个字符的位置的 1000 倍。定义可以是:

int search_left2right(char * matrix, char * word)
{
  int i;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    char * w = word;

    while (*w == matrix[j]) {
      if (!*++w)
        return i * 1000 + j;
      if (++j == ROW*COLUMN)
        j = 0;
    }
  }

  return -1;
}

使用该 main 编译和执行:

int main()
{
  printf("%d\n", search_left2right((char *) Matrix, "cde"));
  printf("%d\n", search_left2right((char *) Matrix, "noa"));
  printf("%d\n", search_left2right((char *) Matrix, "cdf"));
  return 0;
}

pi@raspberrypi:/tmp $ ./a.out
2004
13000
-1
pi@raspberrypi:/tmp $

2004 if for 2 and 4, 13000 if for 13 and 0, the string is not found in the last case, this ok

从右到左搜索。

第一个明显的方法是重用前一个函数并在搜索之前反转字符串。如果在结果中找到字符串,则第一个和最后一个字符的位置也会颠倒过来。

另一种方法是迭代字符串以反向搜索,让我们选择这种方式。

从右到左或从左到右搜索。

为了指示方向,添加了参数wstep,从左到右的值为 1,否则为 -1。定义可以是:

/* manual strlen, you want to define all string functions */
int strLen(char * s)
{
  char * p = s;

  while (*p)
    p += 1;
  return p - s;
}

int search_horiz(char * matrix, char * word, int wstep)
{
  int i;
  int wbegin = (wstep == 1) ? 0 : strLen(word) - 1;
  int wend = (wstep == 1) ? strLen(word) - 1 : 0;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    int k = wbegin;

    while (word[k] == matrix[j]) {
      if (k == wend)
        return (wstep == 1) ? i * 1000 + j : j * 1000 + i;
      k += wstep;
      if (++j == ROW*COLUMN)
        j = 0;
    }
  }

  return -1;
}

使用该 main 编译和执行:

int main()
{
  printf("%d\n", search_horiz((char *) Matrix, "cde", 1));
  printf("%d\n", search_horiz((char *) Matrix, "edc", -1));
  printf("%d\n", search_horiz((char *) Matrix, "noa", 1));
  printf("%d\n", search_horiz((char *) Matrix, "aon", -1));
  printf("%d\n", search_horiz((char *) Matrix, "cdf", 1));
  printf("%d\n", search_horiz((char *) Matrix, "fdc", -1));

  return 0;
}

pi@raspberrypi:/tmp $ gcc -g -Wall m.c
pi@raspberrypi:/tmp $ ./a.out
2004
4002
13000
13
-1
-1
pi@raspberrypi:/tmp $ 

从上到下搜索。

当我们从左到右搜索时,我们将字符 from 到 string 与矩阵中的连续字符(步长为 1)进行比较,更多的是回滚。

要从上到下搜索,我们不必查看矩阵中的连续字符,我们希望保持在同一垂直方向,因此步骤为COLUMN。当然,当我们在最后一行时,情况并非如此,在这种情况下,我们回到第一行并向右移动,除了从矩阵的最后一个字符开始,我们必须回滚到第一个字符。定义可以是:

int search_top2down(char * matrix, char * word)
{
  int i;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    char * w = word;

    while (*w == matrix[j]) {
      if (!*++w)
        return i * 1000 + j;
      if ((j += COLUMN) >= ROW*COLUMN)
        j = (j - ROW*COLUMN + 1) % COLUMN;
    }
  }

  return -1;
}

使用该 main 编译和执行:

int main()
{
  printf("%d\n", search_top2down((char *) Matrix, "dgj"));
  printf("%d\n", search_top2down((char *) Matrix, "knc"));
  printf("%d\n", search_top2down((char *) Matrix, "oad"));

  return 0;
}

pi@raspberrypi:/tmp $ gcc -g -Wall m.c
pi@raspberrypi:/tmp $ ./a.out
3009
10002
14003
pi@raspberrypi:/tmp $ 

从左到右或从上到下搜索

但是比较search_left2rightsearch_top2down可以看到它们的定义几乎相同,唯一的变化是矩阵中步长的值以及步长不能单独应用时的校正。所以可以有:

int search_left2right_top2down(char * matrix, char * word, int step, int correct)
{
  int i;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    char * w = word;

    while (*w == matrix[j]) {
      if (!*++w)
        return i*100 + j;
      if ((j += step) >= ROW*COLUMN)
        j = (j - ROW*COLUMN + correct) % COLUMN;
    }
  }

  return -1;
}

做从左到右的步骤是1,正确的是0,做从上到下的步骤是COLUMN,正确的是1。

搜索所有四个方向

从下到上从上到下搜索所需的修改就像从左到右从右到左搜索一样。

这意味着我们可以很容易地只使用一个搜索功能来管理从左到右、从右到左、从上到下和从下到上。例如 :

int search(char * matrix, char * word, int wstep, int step, int correct)
{
  int i;
  int wbegin = (wstep == 1) ? 0 : strLen(word) - 1;
  int wend = (wstep == 1) ? strLen(word) - 1 : 0;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    int k = wbegin;

    while (word[k] == matrix[j]) {
      if (k == wend)
        return (wstep == 1) ? i * 1000 + j : j * 1000 + i;
      k += wstep;
      if ((j += step) >= ROW*COLUMN)
        j = (j - ROW*COLUMN + correct) % COLUMN;
    }
  }

  return -1;
}

通过该主要编译和执行:

int main()
{
  printf("%d\n", search((char *) Matrix, "cde", 1, 1, 0));
  printf("%d\n", search((char *) Matrix, "noa", 1, 1, 0));
  printf("%d\n", search((char *) Matrix, "cdf", 1, 1, 0));

  putchar('\n');

  printf("%d\n", search((char *) Matrix, "edc", -1, 1, 0));
  printf("%d\n", search((char *) Matrix, "aon", -1, 1, 0));
  printf("%d\n", search((char *) Matrix, "fdc", -1, 1, 0));

  putchar('\n');

  printf("%d\n", search((char *) Matrix, "dgj", 1, COLUMN, 1));
  printf("%d\n", search((char *) Matrix, "knc", 1, COLUMN, 1));
  printf("%d\n", search((char *) Matrix, "oad", 1, COLUMN, 1));

  putchar('\n');

  printf("%d\n", search((char *) Matrix, "jgd", -1, COLUMN, 1));
  printf("%d\n", search((char *) Matrix, "cnk", -1, COLUMN, 1));
  printf("%d\n", search((char *) Matrix, "dao", -1, COLUMN, 1));

  return 0;
}

pi@raspberrypi:/tmp $ gcc -Wall m.c
pi@raspberrypi:/tmp $ ./a.out
2004
13000
-1

4002
13
-1

3009
10002
14003

9003
2010
3014
pi@raspberrypi:/tmp $ 

让我们注意给出 3 个参数来指示如何处理不是一个漂亮的方式,我使用它们是因为我认为最好让它们来解释,但是因为总是相同的所以很容易改进:

#include <stdio.h>

#define COLUMN 3
#define ROW 5

/* manual strlen, you want to define all string functions */
int strLen(const char * s)
{
  const char * p = s;

  while (*p)
    p += 1;
  return p - s;
}

typedef struct SearchParameters {
  int wstep;
  int step;
  int correct;
} SearchParameters;

const SearchParameters Left2Right = { 1, 1, 0 };
const SearchParameters Right2Left = { -1, 1, 0 };
const SearchParameters Top2Bottom = { 1, COLUMN, 1 };
const SearchParameters Bottom2Top = { -1, COLUMN, 1 };

int search(const char * matrix, const char * word, SearchParameters how)
{
  int i;
  int wbegin = (how.wstep == 1) ? 0 : strLen(word) - 1;
  int wend = (how.wstep == 1) ? strLen(word) - 1 : 0;

  for (i = 0; i != ROW*COLUMN; ++i) {
    int j = i;
    int k = wbegin;

    while (word[k] == matrix[j]) {
      if (k == wend)
        return (how.wstep == 1) ? i * 1000 + j : j * 1000 + i;
      k += how.wstep;
      if ((j += how.step) >= ROW*COLUMN)
        j = (j - ROW*COLUMN + how.correct) % COLUMN;
    }
  }

  return -1;
}

/* */

typedef struct TestCase {
  const char * str;
  const SearchParameters * how;
  const char * strHow;
} TestCase;

void test(const char (*m)[3], const TestCase * tc)
{
  int r = search((char *) m, tc->str, *(tc->how));

  if (r == -1)
    printf("cannot found '%s' in '%s'\n", tc->str, tc->strHow);
  else
    printf("'%s' found in '%s', start at %d, end at %d\n",
           tc->str, tc->strHow, r / 1000, r % 1000);
}

int main()
{
  static const char matrix[ROW][COLUMN] = { { 'a', 'b' , 'c' }, 
                                            { 'd', 'e' , 'f' }, 
                                            { 'g', 'h' , 'i' }, 
                                            { 'j', 'k' , 'l' }, 
                                            { 'm', 'n' , 'o' } };
  static const TestCase tests[] = {
    { "cde", &Left2Right, "Left2Right" },
    { "noa", &Left2Right, "Left2Right" },
    { "cdf", &Left2Right, "Left2Right" },
    { "edc", &Right2Left, "Right2Left" },
    { "aon", &Right2Left, "Right2Left" },
    { "fdc", &Right2Left, "Right2Left" },
    { "dgj", &Top2Bottom, "Top2Bottom" },
    { "knc", &Top2Bottom, "Top2Bottom" },
    { "oad", &Top2Bottom, "Top2Bottom" },
    { "jgd", &Bottom2Top, "Bottom2Top" },
    { "cnk", &Bottom2Top, "Bottom2Top" },
    { "dao", &Bottom2Top, "Bottom2Top" }
  };

  int t;

  for (t = 0; t != sizeof(tests) / sizeof(TestCase); t += 1)
    test(matrix, &tests[t]);

  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall mm.c
pi@raspberrypi:/tmp $ ./a.out
'cde' found in 'Left2Right', start at 2, end at 4
'noa' found in 'Left2Right', start at 13, end at 0
cannot found 'cdf' in 'Left2Right'
'edc' found in 'Right2Left', start at 4, end at 2
'aon' found in 'Right2Left', start at 0, end at 13
cannot found 'fdc' in 'Right2Left'
'dgj' found in 'Top2Bottom', start at 3, end at 9
'knc' found in 'Top2Bottom', start at 10, end at 2
'oad' found in 'Top2Bottom', start at 14, end at 3
'jgd' found in 'Bottom2Top', start at 9, end at 3
'cnk' found in 'Bottom2Top', start at 2, end at 10
'dao' found in 'Bottom2Top', start at 3, end at 14
pi@raspberrypi:/tmp $ 

推荐阅读