最长公共子序列 -- C语言

需求

 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。
 
 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
 
 若这两个字符串没有公共子序列,则返回 0。
 
 示例 1: 
 输入:text1 = "abcde", text2 = "ace" 
 输出:3  
 解释:最长公共子序列是 "ace",它的长度为 3。

 示例 2: 
 输入:text1 = "abc", text2 = "abc"
 输出:3
 解释:最长公共子序列是 "abc",它的长度为 3。

 示例 3: 
 输入:text1 = "abc", text2 = "def"
 输出:0
 解释:两个字符串没有公共子序列,返回 0。
   
 提示: 
 1 <= text1.length <= 1000
 1 <= text2.length <= 1000
 输入的字符串只含有小写英文字符。

 

思路

使用动态规划法,建立dp;dp[i][j] 表示 s1[0....i-1]和s[0...j-1]的公共子串大小,如果 s1[i-1] 和 s2 [j -1] 相同,那么又找到了一个公共字符,所以 dp[i][j] = dp[i - 1][j - 1] + 1; 如果不相同,从最长的两个子串(“s1[i-1] 和 s2 [j] ” 或 “s1[i] 和 s2 [j -1] ”)中,选出LCS较大的那个作为 dp[i][j] ,  dp[i][j] = MAX(dp[i - 1][j], dp[i][j - 1]);  注意,下标是从0开始标记的,所以这里应该变为 i - 1 和 j - 1

思路是很清楚,但是有个难点,我一直没有想明白,初始值是多少啊,因为我也不知道两个串的第一个字符是否相同,这就太恶心了。我承认,这个初始化我看了解答中的提示,这的太巧妙了。解答中,让dp[xxxx][0] 和 dp[0][xxxx] 这两行代表 "" 空串和任意字符串的 LCS,这样,我们直接可以在左上角初始化出一行0和一列0,然后利用这个初始值就可以初始化了。

最终,相当于返回dp[len1][len2],也就是s1[len1-1] 和 s2 [len2 -1] 的LCS值,这个就是需求要的最大值。从二位数组来看,相当于从左上角开始,一直推算到右下角

代码实现

/*
 * 需求
 
 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。
 
 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
 
 若这两个字符串没有公共子序列,则返回 0。
 
  
 示例 1: 
 输入:text1 = "abcde", text2 = "ace" 
 输出:3  
 解释:最长公共子序列是 "ace",它的长度为 3。

 示例 2: 
 输入:text1 = "abc", text2 = "abc"
 输出:3
 解释:最长公共子序列是 "abc",它的长度为 3。

 示例 3: 
 输入:text1 = "abc", text2 = "def"
 输出:0
 解释:两个字符串没有公共子序列,返回 0。
   
 提示: 
 1 <= text1.length <= 1000
 1 <= text2.length <= 1000
 输入的字符串只含有小写英文字符。
      
 gcc longestCommonSubsequence.c -g -o a.exe -DDEBUG

 */
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#ifdef DEBUG
#define LOG(fmt, args...) fprintf(stdout, fmt, ##args)
#else
#define LOG(fmt,...)
#endif

#define TRUE        1
#define FALSE       0

#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) > (b) ? (b) : (a))


int longestCommonSubsequence(char * text1, char * text2){

	if(NULL == text1 || NULL == text2){
		return 0;
	}

	int len1 = 0, len2 = 0, i = 0, j = 0, ret = 0;
	int ** dp = NULL;
	
	len1 = strlen(text1);
	len2 = strlen(text2);

	/*构建 dp*/
	dp = (int **)malloc((len1 + 1) * sizeof(int *));
	for(i = 0; i <= len1; i++){
		dp[i] = (int *) malloc((len2 + 1) * sizeof(int));
	}
	
	/*初始化dp*/
	for(i = 0; i <= len1; i++){
		for(j = 0; j <= len2; j++){
			dp[i][j] = 0;
		}
	}

	/*
	 * 0的那列和那行,代表一个字符串是“”,公共子串为为0,
	 * dp[i][j] 表示 s1[0....i-1]和s[0...j-1]的公共子串大小
	 * 注意,下标是从0开始标记的,所以这里应该变为 i - 1 和 j - 1
	 */
	for(i = 1; i <=len1; i++){
		for(j = 1; j <= len2; j++){
			if(text1[i - 1] == text2[j - 1]){
				/* 又发现一个相同的字符,在原有基础上加1*/
				dp[i][j] = dp[i - 1][j - 1] + 1; 
			} else {
				/* 两个新的字符不同,从他们最长的两个子串中,选出LCS较大的数量*/
				dp[i][j] = MAX(dp[i - 1][j], dp[i][j - 1]);
			}
		}
	}

	ret = dp[len1][len2];

	/*释放已用完的dp*/
	for(i = 0; i <= len1; i++){
		free(dp[i]);
		dp[i] = NULL;
	}
	free(dp);
	dp = NULL;

	return ret;
	
}


void testlongestCommonSubsequence(void){
	
	printf("\n************  testlongestCommonSubsequence ************ \n");
	int ret = 0;
	
	char * str1 = "abcde";
	char * str2 = "ace";
	ret = longestCommonSubsequence(str1, str2);
	printf("The Longest commen subseq of \"%s\" and  \"%s\" is %d\n", str1, str2, ret);

	char * str3 = "abc";
	char * str4 = "abc";
	ret = longestCommonSubsequence(str3, str4);
	printf("The Longest commen subseq of  \"%s\" and  \"%s\" is %d\n", str3, str4, ret);


	char * str5 = "abc";
	char * str6 = "def";
	ret = longestCommonSubsequence(str5, str6);
	printf("The Longest commen subseq of \"%s\" and \"%s\" is %d\n", str5, str6, ret);

	return; 
 
 }


 int main(int argc, char ** argv){
	testlongestCommonSubsequence();
 }

代码编译

gcc longestCommonSubsequence.c -g -o a.exe -DDEBUG

调试输出


liufeng@Feng-Ubuntu:~/workspace/src/study/interview/LeetCode/C/longestCommonSubsequence$ ./a.exe

************  testlongestCommonSubsequence ************
The Longest commen subseq of "abcde" and  "ace" is 3
The Longest commen subseq of  "abc" and  "abc" is 3
The Longest commen subseq of "abc" and "def" is 0

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值