[算法编程] 经典C语言面试题:求解最大公共子串

本文介绍了两种求解最长公共子串的方法:暴力解法和动态规划解法,并提供了详细的C语言实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天去面试,面试官出了一道题,求两个字符串的最大公共子串(Longest Common Substring),一听起来不是很难,但让我在纸上写着写着就迷糊了。回来特意网搜了一下。

下面通过两种方法来求两个字符串的最大连续公共子串。

方法1:暴力解法

将字符串s1和s2分别写在两把直尺上面,然后将s1固定,s2的头部和s1的尾部对齐,然后逐渐移动直尺s2,比较重叠部分的字符串中的公共子串的长度,直到直尺s2移动到s1的头部。在这个过程中求得的最大长度就是s1、s2最大子串的长度。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
char* longest_common_substring(char *str1,char *str2)
{
	int str1len = strlen(str1);
	int str2len = strlen(str2);
	int i,j,index,max=0,num=0; 
	int start;
    
	//将两个字符串看做两个直尺,固定一个直尺,另外一个从头到尾开始移动,逐一与固定的直尺比较值。
	for(i = 0; i < str1len; i++) 
	{
		for(j = 0; j < str2len; j++)
		{
			//这里的start1、start2是比较关键的
			int start1=i;
			int start2=j;
			while((start1 <= str1len-1) && (start2 <= str2len-1) && (str1[start1++] == str2[start2++]))
				num++;
			if(num > max)//如果num是当前最大匹配的个数,则赋给max,并且在start记下str1最长匹配开始的位置
			{
				max=num;
				start=i; 
			} 
			num=0;//如果num不是当前最大的,则赋为0值继续循环
		}
	}
	char *str=(char *)malloc(max + 1);
	strncpy(str,str1 + start,max);//从字符串str1的start位置开始,拷贝max个字符到str中,这就是我们找出的最大子串
	str[max] = '\0';
	printf("最长公共连续子串的长度为:%d\n",max);
	return str;
}
 
int main()
{ 
	char str1[1000],str2[1000];
	printf("请输入第一个字符串:");
	gets(str1);
	printf("请输入第二个字符串:");
	gets(str2);

	char *str= longest_common_substring(str1,str2);
	printf("%s\n",str);
	free(str);  //记得要free,否则造成内存泄露
	system("pause");
	return 0;    
}

 

方法2:动态规划解法

主要是定义了一个二维数组,这个数组c用来保存str1中每个字符向前能与str2中的字符匹配的个数。每次会将最大的匹配个数保存到max变量中,并且记录拥有max的字符在原字符串中的位置。

当str1[i] == str2[j]时,子序列长度c[i][j] = c[i - 1][j - 1] + 1;只是当str1[i] != str2[j]时,c[i][j]长度要为0,而不是max{c[i - 1][j], c[i][j - 1]}。

/** 
找出两个字符串的最长公共连续子串的长度
**/ 
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
 
int longest_common_substring(char *str1, char *str2)
{
	int i,j,k,len1,len2,max,x,y;
	len1 = strlen(str1);
	len2 = strlen(str2);
	int **c = new int*[len1+1];
	for(i = 0; i < len1+1; i++)
		c[i] = new int[len2+1];
	for(i = 0; i < len1+1; i++)
		c[i][0]=0;        //第0列都初始化为0
	for(j = 0; j < len2+1; j++)
		c[0][j]=0;        //第0行都初始化为0 
	max = -1;
	for(i = 1 ; i < len1+1 ; i++)
	{
		for(j = 1; j < len2+1; j++)
		{
			if(str1[i-1]==str2[j-1])     //只需要跟左上方的c[i-1][j-1]比较就可以了
				c[i][j]=c[i-1][j-1]+1;
			else                         //不连续的时候还要跟左边的c[i][j-1]、上边的c[i-1][j]值比较,这里不需要
				c[i][j]=0;
			if(c[i][j]>max)
			{
				max=c[i][j];
				x=i;
				y=j;
			}
		}
	}
 
	//输出公共子串
	char s[1000];
	k=max;
	i=x-1,j=y-1;
	s[k--]='\0';
	while(i>=0 && j>=0)
	{
		if(str1[i]==str2[j])
		{
			s[k--]=str1[i];
			i--;
			j--;
		}
		else       //只要有一个不相等,就说明相等的公共字符断了,不连续了
			break;
	}
	printf("最长公共子串为:");
	puts(s);
	for(i = 0; i < len1+1; i++)         //释放动态申请的二维数组
		delete[] c[i];
	delete[] c;
	return max;
}

int main(void)
{
	char str1[1000],str2[1000];
	printf("请输入第一个字符串:");
	gets(str1);
	printf("请输入第二个字符串:");
	gets(str2);
	int len = longest_common_substring(str1, str2);
	printf("最长公共连续子串的长度为:%d\n",len);
	system("pause");
	return 0;
}

 

内容概要:本文档为《2022年C语言操作题常考编程题库》,涵盖了一系列经典C语言编程题目及其解决方案。主要内容包括:个人所得税计算、统计一组数中正负数或奇偶数的数量和平均值、求二维数组的主次对角线之和、判断素数、级数有限项求和(如格里高利公式求π)、两个一维数组相加、求最大最小值、判断闰年、求水仙花数、解决百钱百鸡问题、求最大公约数和最小公倍数、识别回文数、排序算法(选择法、冒泡法、插入法)、二维数组转置、递归函数求阶乘、斐波那契数列、特殊整数求解(如特定条件下的平方数)、字符串加密以及统计字符串中字母和数字的个数。每个题目都附有完整的C语言代码示例,帮助读者理解和掌握相关算法。 适用人群:适合正在学习C语言编程的学生,尤其是计算机专业的大专院校学生和初学者,以及准备参加C语言编程考试或竞赛的考生。 使用场景及目标:①帮助读者巩固C语言基础知识,掌握常见的编程技巧和算法;②通过实际编程练习提高解决问题的能力;③为C语言编程考试、面试和竞赛做准备;④加深对C语言特性的理解,如函数调用、数组操作、条件判断、循环控制等。 其他说明:文档中的代码示例不仅展示了具体的算法实现,还提供了详细的注释,有助于读者理解每一步的操作逻辑。此外,部分题目提供了多种解法(如使用循环和函数调用),鼓励读者探索不同的编程思路,培养灵活运用C语言的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值