C语言数组实现最大公共字符串
关于最大公共字符串真的难为我这0基础的同学了,花了整整5个小时,爬了好几个帖子。
可是帖子里面的技术含量太高,看不懂的居多,有用指针的,有用strstr这个没有学过的函数的。指针变量虽然说能看懂一部分,但是还是有点吃力,后来看到一个帖子说用二维数组来计数,就看了一下,只可惜他并没有用纯数组来做。所以我就根据学过的C语言,花了近3个小时,写出了下面的这些代码。
//10、 找出多个字符串中的最大公共子字符串,如“nbitheimanb”和“itheia”的最大子串是:”ithei”。(C语言)
#include <stdio.h>
#include <string.h>
int main()
{
//1.定义字符串数组
char s1[100], s2[100];
//2.定义一个二维数组存放指定变量(两个字母相等,值为1,不相等,值为0)
int a[100][100];
//3.定义变量记录公共字符串长度
int MaxLenth = 0;
//4.定义变量记录相等字符的最后的地址
int adds = 0;
//5.提示用户输入第一个字符串
printf("请输入第一个字符串:\n");
//6.接收用户输入的第一个字符串数组
scanf("%s", s1);
//7.提示用户输入第二个字符串
printf("请输入第二个字符串\n");
//8.接收用户输入的第二个字符串数组
scanf("%s", s2);
//9.遍历字符串s1
for(int i = 0; i < strlen(s1); i++)
{
//10.遍历字符串s2
for(int j = 0; j < strlen(s2); j++)
{
//11.判断相应字符是否相等
if(s1[i] == s2[j])
{
//12.如果对应字符相等,则在二维数组对应坐标赋值为1
a[i][j] = 1;
}
//13.如果对应字符不相等,则在二维数组对应坐标赋值为0
else
a[i][j] = 0;
}
}
//14.打印说明
printf("------------上方为输入数据-----------\n");
printf("----------下方为二维数组数据-----------\n");
//15.遍历输出二维数组(此处作为查看使用)
for(int i = 0; i < strlen(s1); i++)
{
for(int j = 0; j < strlen(s2); j++)
{
printf("%d ",a[i][j]);
}
//16.每打印完一行,换行
printf("\n");
}
//17.打印说明(分隔符)
printf("----------下方为结果数据-----------\n");
//18.遍历二维数组的行元素
for(int i = 0; i < strlen(s1); i++)
{
//19.遍历二维数组的列元素
for(int j = 0; j < strlen(s2); j++)
{
//20.判断该坐标处值是否为1,值为1代表是两个字符串开始字符开始相等的位置
if(a[i][j] == 1)
{
//21.定义并初始化临时变量,记录存放公共字符串长度
int temp = 0;
//22.定义新的变量,存放i值,避免更改i值
int i1 = i;
//23.定义新的变量,存放j值,避免更改j值
int j1 = j;
//24.当该坐标的值为1时,进入循环,判断该坐标右下角坐标是否为1,如果为1,代表两个字符串下一个字符也相等
while(a[i1][j1] == 1)
{
//25.自增1,为下次判断做准备
i1++;
//26.自增1,为下次判断做准备
j1++;
//27.记录公共字符串的长度
temp++;
}
//28.判断新的公共字符串长度是否大于上一次公共字符串长度,如果不大于,则互换值。保证所取公共字符串的长度是最大。
if(temp > MaxLenth)
{
MaxLenth = temp;
//29.把最长公共字符串地址赋值给adds
adds = j1;
}
}
}
}
//30.输出最大公共字符串长度值
printf("最大公共字符串长度:%d\n",MaxLenth);
//31.输出标题
printf("最大公共字符串是:");
//32.循环输出公共字符串
for(int i = 0 ; i < MaxLenth; i++)
{
//33.因为所取地址值是最后的地址,所以要提取公共字符串的首字符地址,为 adds - MaxLenth
printf("%c",s2[adds - MaxLenth +i]);
}
//34.输入换行符
printf("\n");
return 0;
}
试运行:
请输入第一个字符串:
nbitheimanb
请输入第二个字符串
itheia
------------上方为输入数据-----------
----------下方为二维数组数据-----------
0 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
1 0 0 0 1 0
0 0 0 0 0 0
0 0 0 0 0 1
0 0 0 0 0 0
0 0 0 0 0 0
----------下方为结果数据-----------
最大公共字符串长度:5
最大公共字符串是:ithei
此理论是根据,使用二维数组存放0,1,对应字符串中的某个字符,把它s1位置作为横坐标,把它s2的位置作为纵坐标,在二维数组里面赋值。如果相等,赋值为1,如果不相等,赋值为0。在例子中可以看到,二维数组输出的结果。然后用for循环遍历二维数组,找出值为1的元素,当找到这个元素时,接着判断该元素的右下角的元素是否为1,如果为1,则计数,直到不为1退出。这步的作用,就是判断公共字符串的个数,至于怎么来判断的,大家可以看数组,顺序必须得时由左上角到右下角的斜线上相同为1,不能是其它的方向。看数组可以看到2、3、4、5、6行(首行为0行)对应的0、1、2、3、4列,值为1。那么在数组s1中的2、3、4、5、6号元素,和s2的0、1、2、3、4号元素就是公共字符串。如此判断,找出最长的一个,用adds记录最后一位元素的横坐标或者是纵坐标,在这里我记录的是纵坐标也就是s2数组元素序号。输出的时候注意,记录的时最后一位元素序号,所以要减去该字符长度,才是公共字符串首元素的序号,然后循环输出。
思路解析:
1、把两个字符串里面相等的字符和不相等的字符,转化为更好理解的数字形式,存放到二维数组。
2、建立一个二维数组,用来存放0和1,0代表该坐标处两个字符不相等,1代表该坐标出两个字符相等。
3、把其中一个字符串作为行元素,另外一个字符串作为列元素。在这里s1是行元素,s2是列元素。
4、用for循环遍历两个字符串,找出相等的元素,并按照行列坐标对应放到二维数组里面。
5、用for循环遍历二维数组,找出等于1的元素,当找到等于1的元素之后,重新定义两个变量,对应提取坐标(为了不改变for循环中i,j的值)。
6、定义全局变量MaxLenth,然后定义中间变量temp存放临时的公共字符串长度,用while循环判断横纵坐标同时增1,即从左上角到右下角的斜线上的元素是否相等,如果相等,中间变量自增1。把中间变量赋值给全局变量MaxLenth。
7、定义一个整型变量adds,存放找到的最后一个1的二维坐标中的纵坐标或者横坐标(代码中存放的时纵坐标)。
8、用if语句判断,新找到的公共字符串(斜线上连续为1的个数)长度是否大于上一个的长度,如果大于,把新值赋给全局变量MaxLenth,并把最新的纵坐标赋值给整形变量adds。如果不大于,继续循环寻找。
9、输出找到的最长的字符串个数即MaxLenth的值。
10、输出字符串:要输出的字符串的长度是MaxLenth,该字符串的末地址是adds,找出该字符串的首地址为adds – MaxLenth,用for循环输出该字符串。
补充:为什么只能在方向是左上角到右下角的斜线上寻找连续的1,因为如果是其它方向会导致寻找的1(相等字符)的顺序是反着的。
举例:如果是左下到右上,那么它的顺序是按照s1字符串的首字符开始与s2的末字符开始比较,然后s1增加,s2减少,那么得出的公共字符串是逆向的。
左上角到右下角和右下角到左上角是一条斜线,只不过是输出形式变化。读者可自行斟酌。