2019年华农19届大数据1班上学期第9周高程题解

这篇博客介绍了字符串处理的相关算法,包括如何定义存储字符串的字符数组,以及使用朴素算法进行字符串匹配。博主强调了算法时间复杂度的重要性,讨论了在面对特定数据量时朴素算法可能造成的时间超限问题,并提到了KMP算法作为优化方案。此外,还讲解了判断回文串和将十进制数转换为二进制数的方法。
摘要由CSDN通过智能技术生成

一、定义存储字符串的字符数组

这没啥好讲的,定义问题,语法就是下面这行,需要注意的是因为他字符串复制跟输出都是给s,所以可以判断要定义的字符数组名为s,还有数组不要开太小(会存不下"abcdefghijklmn",还有,记得因为字符串后面还会自动添加个'\0',这也占一个字符,得给这个字符留位置),也不要开太大(会导致内存溢出,不过随便开个几万几十万是没问题的)。

char s[100];

二、寻找字符串

这里采用的是朴素的二层循环算法

思路:采用二层循环,外层循环遍历主串用于定位主串匹配起点,内层循环遍历子串用于模拟匹配过程

step1:主串中从左到右,取出一个匹配起点

step2:子串从最左边对应主串匹配起点,进行逐一字符匹配

step3:若有不匹配的字符,跳出本次匹配,回到step1

step4:直到匹配到子串最右边都没检测到step3的情况,说明字符匹配成功,确定位置,跳出循环,输出答案

/*
	采用朴素的二层循环匹配算法
*/
#include<stdio.h>
#include<string.h>

int main()
{
	char str1[1000], str2[1000];
	scanf("%s%s", str1, str2);//%s会以空格跟回车作为分隔符,也就是说会跳过空格跟回车,所以这样粘着写是没问题的 
	
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	
	int pos = 0;
	int OK = 0;
	int i, j;
	for(i=0; i<len1 ;i++)
		for(j=0; j<len2 ;j++){
			if(i+j < len1 && str1[i+j] != str2[j]) break; //数组越界访问跟字符不匹配都直接跳出本次内层循环 
			
			if(j == len2 - 1){
				pos = i + 1;
				OK = 1;//表示匹配成功 
				i = len1; //直接外层循环也跳出了
			} 
		}
		
	if(OK) printf("%d", pos);
	
	return 0;
}

虽然知道题目中str2必定会在str1中出现,所以i+j < len1这一越界判断并不是必要的,但是出于程序的鲁棒性(你的程序在面对错误的数据时仍能做出正确处理,说白了就是可靠性)考虑 ,还是加个判断了,这里有个小细节,&&是短路运算符,i+j < len1在判断为假后,str1[i+j] != str2[j]这一条表达式就不会被执行了,所以不需要担心这个表达式会造成数组越界访问

扩展:

该字符串匹配算法的时间复杂度为O(n * m),n为主串长度,m为子串长度 

不了解什么是时间复杂度的,可以看下这个https://blog.csdn.net/qq_41523096/article/details/82142747

我们刷OJ的时候会看到有个时间限制,一般为1秒,也就是说,你程序运行时间要在1秒内出结果,否则就超时,我们有些同学已经遇到过超时的情况了,但这基本都是因为陷入了死循环,实际上,时间限制设置的本意并不是为了检测你是否陷入了死循环,而是为了检测你算法的优劣,一般来说,在OJ上O(1e7)的算法跑出来是几十毫秒,O(1e8)的算法跑出来是几百毫秒,超过O(1e8)的算法,在1秒的时间限制下基本都会超时。

对于一道正式的OJ题来说,是要给出数据量的,这道字符串匹配的题,正式来讲它要在题目下面跟你说明主串跟子串最长有多长,比如他这样限制:主串长度1<=n<=10^7,子串长度1=<m<=10^5,那我们这个朴素算法,最坏情况下时间复杂度就为O(n * m) = O(10^7 * 10^5) = O(10^12),远大于O(10^8),所以这种情况下这个算法就铁定超时,当然,由于这是面向初学者的题目,数据量肯定没有变态到这样去卡你们,所以就放心打你们的代码吧。

话说回来,对于上面所提到的数据量,有没有办法让它照样1秒内出结果呢?当然有!有一种字符串匹配算法叫做KMP算法,时间复杂度为O(n + m),所以在上面的数据量中用这个算法的话时间复杂度就是O(10^7),1秒内出结果是没有问题的。但是,我不建议你们现在就学KMP算法,因为这个算法琢磨起来快的话也得花个一两天才能弄清楚,对于你们现在来说,并不是很必要去花这个时间,这里就当科普一下算法在时间方面上的优化作用了。

三、回文串

其实就是直接从两端向中间,每次抓一对字符来判断,只要有其中一对有问题,就说明该字符串不是回文串,否则就是

#include<stdio.h>
#include<string.h>

int main()
{
	char s[10000];
	scanf("%s", s);
	int len = strlen(s);
	
	int OK = 1;
	for(int i=0; i<len/2 ;i++)
		if(s[i] != s[len-i-1]) OK = 0; //有不相等就说明不是回文串 
		
	if(OK) printf("Y");
	else printf("N"); 
	
	return 0;
}

四、十进制数转二进制数

从代码可判断我们需要定义一个名为binary的函数,其参数有一个,功能是把传入的参数转化成二进制并输出,函数无返回值

数x十进制转二进制步骤:

step1:检测数x是否为0,若为0,则退出循环

step2:数x取余2,得到一个二进制低位,加入ans[]字符数组

step3:数x除于2,然后返回step1

注意:对于数x原本就等于0的情况需要特判

void binary(int n)
{
	if(n == 0){//特判 
		printf("0");
		return;
	}
	
	char ans[10000];
	int cur = 0; //游标 
	while(n){ //只要n不为0,循环继续 
		ans[cur++] = (n % 2) + '0';
		n /= 2; //这里也可以写成n >>= 1,表示n向右移一位,从数学角度上思考,想想为什么可以这么做,然后也可以思考下n << 1在数学意义上又表示什么
	}
	
	//由于从最低位到最高位去获取二进制数字,所以在字符数组中,二进制是从低到高位存储的,然而我们输出时需要从高位到低位输出
	int i;
	for(i=cur-1; i>=0 ;i--)
		printf("%c", ans[i]); 
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值