LeetCode---遍历应用

本文详细介绍了如何使用C语言实现贪心算法和动态规划解决LeetCode中的子序列问题。通过贪心策略逐个匹配字符,以及动态规划构建查找表来判断一个字符串是否为另一个字符串的子序列。两种方法各有特点,动态规划尤其体现了减少重复计算的思想。
摘要由CSDN通过智能技术生成

LeetCode刷题笔记(C语言)

题一:给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。 (例如,"ace"是"abcde"的一个子序列,而"aec"不是)

• 0 <= s.length <= 100
• 0 <= t.length <= 10^4
• 两个字符串都只由小写字符组成。

方法一:使用贪心算法进行走一步算一步的层层递进、逐个击破的方法达成最终目标

贪心算法(Greedy Algorithm) 简介:
贪心算法,又名贪婪法,是寻找最优解问题的常用方法,这种方法模式一般将求解过程分成若干个步骤,但每个步骤都应用贪心原则,选取当前状态下最好/最优的选择(局部最有利的选择),并以此希望最后堆叠出的结果也是最好/最优的解。{看着这个名字,贪心,贪婪这两字的内在含义最为关键。这就好像一个贪婪的人,他事事都想要眼前看到最好的那个,看不到长远的东西,也不为最终的结果和将来着想,贪图眼前局部的利益最大化,有点走一步看一步的感觉。}

链接:推荐一篇关于贪心算法的博客

在这里插入图片描述
程序实现:

1.	bool isSubsequence(char * s, char * t){  
2.	    /* 
3.	     *  i:用于字符串t的遍历 
4.	     *  n:用于字符串s的当前字符位置 
5.	     */  
6.	    int i,n;  
7.	    i = n = 0;  //从0开始  
8.	    if(strlen(s) > strlen(t)) return false; //如果字符串s长度比字符串t长度要大的话,s肯定不是t的子序列  
9.	    if(strlen(s) == 0) return true;         //s字符串长度为0,说明字符串元素被删除完了,肯定是t的子序列  
10.	    /* 贪心算法,遍历整个字符串t,一个一个的比较字符串s内的字符不否符合字符串t的子序列字符之一 */  
11.	    while(i < strlen(t)) {         
12.	        /* 比较当前字符串t当前字符与字符串s当前字符相同 */             
13.	        if(*(s+n) == *(t+i)) {  
14.	            n += 1;       
15.	            /* 如果已经把字符串s的都对比完了,那么说明字符串s是字符串t的子序列,此时就可以停止遍历字符串t了 */  
16.	            if(strlen(s) == n) return true;   
17.	        }  
18.	        i += 1;  
19.	    }  
20.	    return false;  
21.	} 
方法二:动态规划

下图为力扣官方题解的对动态规划的描述。
在这里插入图片描述
动态规划简单来说好比做了一张模板卡,然后别的工艺品做出来后就直接那模板卡对比,省去了那些复杂的测量步骤,也就是说减少重复做的事情,把复杂的事情尽量简单化。具体的讲解,大家可以自行搜索百度。

步骤一:建表

在这里插入图片描述
建立边界,此边界除了作为表格的边界外,边界元素的值还是用于录表中标注字母在某顺序位置未出现或无。
程序实现:

8.	/* 1、建表 */  
9.	for(int i=0;i<26;i++) {  
10.	    table_str[m][i] = m;	//在表低添加无效元素值作为边界
11.	}  

步骤二:录表

在这里插入图片描述
按英文字母顺序和字符位置反顺序进行录表。字符串的当前字符与英文字母横坐标对应的位置(纵坐标字符位置)设置元素值为该位置是出现字符串t的第几(i)个字符,这目的是为了到时查表的时候就知道子序列s的当前字符是字符串t的第几个字符;而不符合的则标注为与之对应上下一个字符位置的元素值,这样可以证明该位置出现在第几个字符位置后或者无效元素。
程序实现:

13.	    /* 2、录表 */  
14.	    for(int i=m-1;i>=0;i--) {  			//字符串t反向顺序录入元素值
15.	        for(int j=0;j<26;j++) {  		//英文字母元素值对应坐标轮询
16.	            if(t[i]==(j+'a')) {  		//比较当前字符串t元素值是否与当前英文字符是对应关系
17.	                table_str[i][j] = i;  	//如果上面判断成立,标注表的当前位置元素值为当前字符串t元素的位置顺序
18.	            } else {  
19.	                table_str[i][j] = table_str[i+1][j];  //如不成立,标注为当前位置的纵向下一个位置的元素值,可能是字符串t某个元素出现的顺序值,也可能是边界元素值(无出现的元素)
20.	            }  
21.	        }  
22.	    } 

步骤三:查表

在这里插入图片描述

此图是我截取官方视频讲解的。
根据子序列s当前字符元素与横坐标英文字符相比较,找出与之对应的,然后判断该字符位置(纵坐标)的表格元素是否是字符串t的有效字符顺序(例如图示0->5,而6是无效顺序),然后读取子序列s当前字符在字符串t出现的位置顺序值,将此值加一,读取下一个与子序列s下一个元素相对应的表格元素,重复上面步骤,直至读取完毕。

程序实现:

24.	    /* 3、查表,对比 */  
25.	    for(int i=0;i<n;i++) {  
26.	        if (table_str[current_num][s[i]-'a']==m) {  	//判断与之对应的元素值是否为边界元素值
27.	            return false;  
28.	        }  
29.	        current_num = table_str[current_num][s[i]-'a'] + 1;  //下一个子序列s元素查询
30.	    } 

方法二的完整程序:

1.	bool isSubsequence(char* s, char* t) {  
2.	    int n = strlen(s), m = strlen(t); 	//n:子序列s长度, m:字符串t长度 
3.	    int current_num = 0;  				//轮询子序列s的当前元素位置
4.	    int table_str[m+1][26];  			//表格
5.	    memset(table_str,0,sizeof(table_str));  //清空表格
6.	    /* 使用动态规划方法解题 */  
7.	  
8.	    /* 1、建表 */  
9.	    for(int i=0;i<26;i++) {  
10.	        table_str[m][i] = m;	//在表低添加无效元素值作为边界  
11.	    }  
12.	  
13.	    /* 2、录表 */  
14.	    for(int i=m-1;i>=0;i--) {  			//字符串t反向顺序录入元素值  		
15.	        for(int j=0;j<26;j++) {  		//英文字母元素值对应坐标轮询  
16.	            if(t[i]==(j+'a')) {  		//比较当前字符串t元素值是否与当前英文字符是对应关系  
17.	                table_str[i][j] = i;  	//如果上面判断成立,标注表的当前位置元素值为当前字符串t元素的位置顺序  
18.	            } else {  
19.	                table_str[i][j] = table_str[i+1][j];  //如不成立,标注为当前位置的纵向下一个位置的元素值,可能是字符串t某个元素出现的顺序值,也可能是边界元素值(无出现的元素)  
20.	            }  
21.	        }  
22.	    }  
23.	  
24.	    /* 3、查表,对比 */  
25.	    for(int i=0;i<n;i++) {  
26.	        if (table_str[current_num][s[i]-'a']==m) {  	//判断与之对应的元素值是否为边界元素值  
27.	            return false;  
28.	        }  
29.	        current_num = table_str[current_num][s[i]-'a'] + 1;  //下一个子序列s元素查询  
30.	    }  
31.	  
32.	    return true;  
33.	} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓家文007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值