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

以下各题均有时间复杂度为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)解决。但可以做到常量级的优化,减少扫描次数提高效率。注意字符串长度的变化,不变+变短可以直接从前往后处理,变长则需要从后往前处理避免覆盖原来的字符串中的元素。

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

时间: 2024-08-11 23:54:20

字符串元素重排高效算法集合的相关文章

集合框架(去除ArrayList集合中的重复字符串元素案例2)

package cn.itcast_04; import java.util.ArrayList; import java.util.Iterator; /* * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同) * 要求:不能创建新的集合,就在以前的集合上做. */ public class ArrayListDemo2 { public static void main(String[] args) { // 创建集合对象 ArrayList array = new Ar

Java基础知识强化之集合框架笔记27:ArrayList集合练习之去除ArrayList集合中的重复字符串元素

1. 去除ArrayList集合中的重复字符串元素(字符串内容相同) 分析: (1)创建集合对象 (2)添加多个字符串元素(包含重复的) (3)创建新的集合 (4)遍历旧集合,获取得到每一个元素 (5)拿着个元素到新集合中去找,看有没有   有:不搭理它 没有:添加到新集合      (6)遍历新集合 2. 案例代码: 1 package cn.itcast_04; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 6

Java基础知识强化之集合框架笔记28:ArrayList集合练习之去除ArrayList集合中的重复字符串元素(升级)

1. 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)     要求:不能创建新的集合,就在以前的集合上做. 2. 代码示例: 1 package cn.itcast_04; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 6 /* 7 * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同) 8 * 要求:不能创建新的集合,就在以前的集合上做. 9 */ 10 public cla

去除List集合中的重复元素? 如果没有Set集合,List集合是怎么去除重复元素的(字符串类型,自定义类型)?

 关键字: 如果没有Set集合,List集合是怎么去除重复元素的(字符串类型)?  *   *     思考: List就可以存储重复元素,那么需求中容器中的元素必须保证唯一性,该如何解决呢??  *      *   去除List集合中的重复元素?  * * 思路: * * 1.首先我需要另一个临时容器tempList,用来存放我认为应该保留的元素.(也就是不重复的元素) * 2.然后我们应该遍历原容器, 一个一个的取出元素, 放入tempList. * 当tempList里已经装有刚刚取出的

去除ArrayList集合中重复字符串元素方式_思路:创建新集合方式

import java.util.ArrayList; import java.util.Iterator; public class jh_01_去除ArrayList集合中重复字符串元素方式 { /* * /** * * A:案例演示 * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同) * 思路:创建新集合方式 */ public static void main(String[] args) { ArrayList list = new ArrayList(); li

java----数据结构与算法----集合元素的遍历:迭代器--------&gt;JavaAPI:java.util.Iterator+java.util.ListIterator

概述: 迭代器用于集合元素的遍历 迭代器有两种,分别是Iterator和ListIterator Iterator可以用于任何类型集合的遍历 ListIterator只能用于List集合的遍历 ListIterator接口继承了Iterator接口,所以前者拥有后者所定义的所有成员函数,同时,ListIterator还添加了一些具有List集合特性的操作函数,如按照索引访问集合元素.替换/添加集合元素等等 java.util.Iterator /** * @author chen * @date

Substring with Concatenation of All Words, 返回字符串中包含字符串数组所有字符串元素连接而成的字串的位置

问题描述:给定一个字符数组words,和字符串s,返回字符数组中所有字符元素组成的子串在字符串中的位置,要求所有的字符串数组里的元素只在字符串s中存在一次. 算法分析:这道题和strStr很类似.只不过strStr是子串,而这个题是字符串数组里的元素组成的子串,字符串数组里的元素是无序的,但是必须全部包含.所有考虑使用map集合.关键点在于几个临界值,字符串元素在s中重复了怎么做,找到一个符合的子串后怎么做,有字符串元素不匹配怎做. import java.util.ArrayList; imp

字符串非重复全排列算法

[题目描述] 输入一个字符串,打印出该字符串中字符的所有排列. 例如输入字符串abc,则输出由字符a.b.c 所能排列出来的所有字符串 abc.acb.bac.bca.cab 和 cba. [分析] 从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,从而得到所有元素的全排列.以对字符串abc进行全排列为例,我们可以这么做:以abc为例 固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac 固定b,求后面ac的排列:bac,bca,求好

c数据结构的字符串查找的Brute-Force算法

#include<stdio.h> #include<malloc.h> #include<string.h> //定义字符串的结构体 typedef struct { char *str;//字符串 int maxLength;//最大可以存放字符的长度 int length;//目前的字符长度 }DString; //1.初始化操作 //初始化操作用来建立和存储串的动态数组空间以及给相关的数据域赋值 void Initiate(DString *s,int max,