数据结构与算法学习笔记字符串3

本文介绍三种高效的字符串操作算法,包括字符串旋转、字符串包含检测及字符串全排列。详细解析了每种算法的实现原理,提供了代码示例,并分析了时间与空间复杂度。

以下给出的均较为高效的算法
1.1字符串的旋转
题目描述:给出一个字符串,,将前面的若干个字符移到字符串的尾部,例如:“abcdef”的前3个字符‘a’、‘b’、‘c’移到字符串的尾部,那么原字符串将变成“defabc”。
算法描述:将原字符串分为X和Y两个部分,其中X为“abc”,Y为“def”,分别将X和Y进行翻转,X为“cba”。最后,将整个字符串进行翻转。得出结果。
参考代码如下:

void ReverseString(char* s,int from,int to){
	while(from<to){
		char t=s[from];
		s[from]=s[to];
		s[to]=t;
		from++;
		to--;
	}
}
void LeftRotateString(char* s,int n,int m){
	ReverseString(s,0,m-1);
	ReverseString(s,m,n-1);
	ReverseString(s,0,n-1);
}

时间复杂度:O(n),,空间复杂度:O(1)

1.2字符串的包含
题目描述:给定一长字符串a和一短字符串b,请问如何快速地判断出短字符串是否在长字符串中,例如字符串a是“ABCD”,字符串是“AA”,答案是true,否则为false。
算法描述:排序后轮询(很多算法进过排序都会降低时间复杂度)
代码如下:

bool StringContain(string &a,string &b){
	sort(a.begin(),a.end());
    sort(b.begin(),b.end());
	for(int pa=0,pb=0;pb<b.length();){
		while((pa<a.length())&&(a[pa]<b[pb])){
			++p;
		}
		if((pa>=a.length())||(a[pa]>b[pb]))
		{
			return false;
		}
		++pb;
	}
	return true;
}

算法时间复杂度:O(mlogm)+O(nlogn)+O(m+n)

方法二:素数相乘
算法描述:首先,让长字符串a中的每个字母与一个素数一一对应,如a对应2,b对应3,c对应5,以此类推,遍历a,把a中的每个字母对应的素数相乘,得到一个整数,,然后,让短字符串也对应一个整数,再用a除以b如果结果有余数,结果为false,如果没有余数,结果为true,b为a的子集。

bool StringContain(string &a,string &b)
{
	const int p[26]={2,3,5,7,11,13,17,19,23,29,31,37};  // 太多了,自己补吧
	int f=1;
	for(int i=0;i<a.length();i++){
		int x=p[a[i]-'A'];
		if(f%x){
			f=f*x;
		}
	}
	for(int i=0;i<b.length();i++){
		int x=p[b[i]-'A'];
		if(f%x){
			return false;
		}
	}
	return true;
}

这种算法的思想很好,实际上是不能运行的,因为素数的相乘的结果会很大,从而导致整数溢出,long long可以表示前16位。算法时间复杂度位O(m+n)。

1.3 字符串全排列-递归实现
算法思考
根据递归的特点,深度划分子逻辑-递归,标识出口。全排列一个思维:对待全排序的序列中从左选定一个数作为基数,然后对他右边的数进行全排列,以此递归。

算法描述
以字符串1234为例:

1 – 234

2 – 134

3 – 214

4 – 231

如何保证不遗漏: 每次递归前,保证1234的顺序不变。

算法演进
如1234序列,其中from和to指的是待全排序序列的首位置和尾位置。位置参考的是原序列长度

第一次就是from 0 to 3的全排列,选定1为基数,逐一的与后面序列每个数交换就得到以它为首的全部全排序序列,234就是进行 子全排列;然后在子全排列序列中就是from 1 to 3的全排列,选定2作为基数,34就是继续进行的 子全排列;然后在34中就是from 2 to 3的全排列,选定3为基数,4就是继续进行的 子全排列;…这时递归的深度会变大

当from == to相等时,自然不需要交换,全排序序列只有一个就是他自己,此时打印就好,此时return,递归就会往回走,然后根据循环走其他分支递归,直到没有分支递归,本层递归结束继续向上走。
在这里插入图片描述

void qpl(char* perm,int from,int to){
	if(to<=1){          // 第一个不用动的
		return;
	}
	if(from==to){
		for(int i=0;i<=to;i++){
			cout<<perm[i];
		}
		cout<<endl;
	}
	else{
		for(int j=from;j<=to;j++){
			swap(perm[j],perm[from]);
			qpl(perm,from+1,to);
			swap(perm[j],perm[from]);
		}
	}
}
下载代码方式:https://pan.quark.cn/s/e6c2e312b658 在苹果公司的Mac操作系统环境中,当用户尝试安装非原厂驱动程序时,可能会遭遇系统无法正常启动的困境。这种情况常常源于名为.kext的内核扩展驱动程序存在兼容性问题或安装过程中出现失误。这份指南介绍了一种无需重新安装操作系统且能够保护所有用户数据的修复方法,这一方案对于先前许多面临类似挑战的用户而言,曾是极为棘手的情况。文档中提及的“用户模式启动”实际是指单用户模式,这种启动方式仅加载核心系统功能,而忽略图形用户界面及常规应用程序的加载。在单用户模式下,用户能够访问命令行界面,进而执行一系列修复指令。解决此问题的首要环节是验证存储设备是否存在故障,因为这是导致系统无法启动的常见诱因。借助终端指令`/sbin/fsck -f`,可以诊断并纠正文件系统层面的错误。倘若系统在启动过程中检测到文件系统异常,通常会自动执行`fsck`命令,然而,如果系统卡在进度条100%无法继续,手动运行该命令则显得尤为必要。指令`mount -uw /`的功能是将根目录切换为可读写状态,由于系统默认是以只读模式启动的。这一操作的目的是为了在不重新进入正常模式的前提下,对系统进行必要的调整。随后,文档提供了一个关键操作:对存在问题的驱动程序文件进行修改或更名。在Mac系统中,第三方驱动程序一般安装在`/Library/Extensions/`目录下。每个驱动程序都包含一个以.kext为后缀名的文件夹,例如在此案例中的AX88772.kext。通过命令行将故障的.kext文件更名(例如改为.kext.bak),可以临时禁用该驱动程序。这一操作需在命令行环境中完成,首先使用`cd /Library/Exte...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值