码迷,mamicode.com
首页 > 其他好文 > 详细

字符串元素重排高效算法集合

时间:2014-06-20 10:49:56      阅读:296      评论:0      收藏:0      [点我收藏+]

标签:style   class   blog   code   strong   2014   

         以下各题均有时间复杂度为O(n*n)或以空间换取时间使得时间空间复杂度为O(n)的算法,在此均不考虑。


问题一、字符串移动

      字符串为*号和26个字母的任意组合,把*号都移动到最左侧,把字母移到最右侧并保持相对顺序不变,要求时间和空间复杂度最小 。如“afdg**fa**hjfkdsl”变换成“****afdgfahjfkdsl”

         此题前后字符串的长度不变,由于最终一边只有‘*’,另一边为字母,可以设置两个指针fast和slow,当str[fast]不为‘*’时,赋值给str[slow];否则直接移到下一个。不需额外空间,只需扫描一次字符串,时间复杂度为O(n),空间复杂度为O(1)。

#include<iostream>
using namespace std;

const int MAXN=100;

void removeString(char *pStr)
{
	if(NULL==pStr)
		return ;
	int fast,slow;
	fast=slow=strlen(pStr)-1;
	while(fast>=0)
	{
		if(pStr[fast]!='*')
		{
			pStr[slow]=pStr[fast];
			--slow;
		}
		--fast;
	}

	while(slow>=0)
	{
		pStr[slow]='*';
		--slow;
	}
}

int main()
{
	char str[MAXN];
	while(scanf("%s",str)!=EOF)
	{
		printf("%s\n",str);
		removeString(str);
		printf("%s\n",str);
	}
	return 0;
}


问题二、字符串连续‘*’合并

       字符串为‘*‘和字母的任意组合,把多个连续‘*‘合成一个,要求时间复杂度O(n)和空间复杂度O(1) 。如“afh***hd**”变换成“afh*hd*”.

       这是2014阿里武汉二面写代码的题,当时我先扫描一遍统计变换后字符串的长度,然后从后往前依次处理,达到了题目要求,共两次扫描字符串,但面试官说有更好的做法,当时他也没让我再想,放我过了。

       后来之后感觉可以一次扫描字符串,将直接从前往后处理,同样设置两个指针fast和slow,当str[fast]为连续‘*’中的非第一个时,fast后移,slow不变;否则str[fast]赋值给str[slow],然后二者都后移一个位置。

#include<iostream>
#include<cstring>
using namespace std;

const int MAXN=100;

int removeBlack(char *pStr)
{
	if(NULL==pStr)
		return -1;
	int len=strlen(pStr);
	int fast,slow;
	for(fast=1,slow=1;fast<len;fast++)
	{
		if(pStr[fast]==pStr[fast-1]&&pStr[fast]=='*')
			continue;
		else if(fast!=slow)pStr[slow++]=pStr[fast];
		else slow++;
	}
	pStr[slow]='\0';
	return slow;
}

int main()
{
	char str[MAXN];
	while(scanf("%s",str)!=EOF)
	{
		printf("%s\n",str);
		removeBlack(str);
		printf("%s\n",str);
	}
	system("pause");
	return 0;
}

问题三、字符串‘*‘变’%20‘

        字符串为‘*‘和字母的任意组合,把‘*‘变换成‘%20‘,要求时间、空间复杂度尽可能小 。如“*hjaf**hjafj*”变换成“%20hjaf%20%20hjafj%20”.

       先扫描一遍统计’*‘个数得出变换后字符串的长度,然后从后往前依次处理,共两次扫描字符串,时间复杂度为O(n),空间复杂度为O(1)。由于字符串长度增加了,从后往前处理是为了避免覆盖原来的字符串中的元素,这点很重要。

#include<iostream>
#include<cstring>
using namespace std;

const int MAXN=100;

int replace(char *pStr)
{
	if(NULL==pStr)
		return -1;
	int i=0,j,num=0,len=strlen(pStr);
	while(pStr[i]!='\0')
	{
		if(pStr[i]=='*')
			++num;
		++i;
	}

	i=len-1;
	j=len+2*num-1;
	while(i>=0)
	{
		if(pStr[i]=='*')
		{
			pStr[j]='0';
			--j;
			pStr[j]='2';
			--j;
			pStr[j]='%';
			--j;
		}
		else 
		{
			pStr[j]=pStr[i];
			--j;
		}
		--i;
	}
	pStr[len+2*num]='\0';
	return len+2*num-1;;
}

int main()
{
	char str[MAXN];
	while(scanf("%s",str)!=EOF)
	{
		printf("%s\n",str);
		replace(str);
		printf("%s\n",str);
	}
	system("pause");
	return 0;
}
    上述代码在实际应用时还需考虑字符串数组下标越界等,同时加上提前退出条件可以做到常量级的优化。


总结

    此类问题都可以在时间复杂度为O(n),空间复杂度为O(1)解决。但可以做到常量级的优化,减少扫描次数提高效率。注意字符串长度的变化,不变+变短可以直接从前往后处理,变长则需要从后往前处理避免覆盖原来的字符串中的元素





字符串元素重排高效算法集合,布布扣,bubuko.com

字符串元素重排高效算法集合

标签:style   class   blog   code   strong   2014   

原文地址:http://blog.csdn.net/xiaofengcanyuexj/article/details/28168225

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!