C++ 删除任何“;配对;字符串中具有相同值的相邻字母的
比如说- aaabccddd->abd aaacccbbcccd->accd->ad 阿巴->空刺 我首先尝试了下面的方法。调用splitString函数直到字符串无法进一步缩减(即,我们提供的字符串长度(a)=执行操作后获得的字符串长度)。 对于10^5左右的值,此代码给出超出内存限制(MLE)错误,但是对于小于10^5的值运行正常。C++ 删除任何“;配对;字符串中具有相同值的相邻字母的,c++,string,optimization,micro-optimization,C++,String,Optimization,Micro Optimization,比如说- aaabccddd->abd aaacccbbcccd->accd->ad 阿巴->空刺 我首先尝试了下面的方法。调用splitString函数直到字符串无法进一步缩减(即,我们提供的字符串长度(a)=执行操作后获得的字符串长度)。 对于10^5左右的值,此代码给出超出内存限制(MLE)错误,但是对于小于10^5的值运行正常。 #include<bits/stdc++.h> using namespace std; void splitString(string str)
#include<bits/stdc++.h>
using namespace std;
void splitString(string str)
{
int a=str.length();
for(int i=0; i<str.length()-1; i++)
{
if(str[i]==str[i+1]){str[i]=1; str[i+1]=1;}
}
string alpha="";
for (int i=0; i<str.length(); i++)
{
if(str[i] >= 'a' && str[i] <= 'z')
alpha.push_back(str[i]);
}
int b=alpha.length();
if(a==b)
{cout <<b<<"\n"<<alpha; return;}
else
{splitString(alpha);}
}
int main()
{
int n; string str; cin>>n>>str;
splitString(str);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define size 100005
void foo(char *s){
int len = strlen(s);
int i, j;
j = 0;
for(i = 0; i < len; i++)
{
if(s[i] != '$')
{
s[j] = s[i]; j++;
}
}
s[j] = '\0';
}
char* super_reduced_string(char* s){
int len = strlen(s);
int i;
for(i = 1; i < len; i++){
if(s[i] == s[i-1])
{
s[i] = s[i-1] = '$';
foo(s);
len = strlen(s);
i = 0;
}
}
return s;
}
int main() {
int n; scanf("%d", &n);
char s[size]={0};
scanf("%s", s);
char* result = super_reduced_string(s);
printf("%d", strlen(result));
printf("\n");
printf("%s\n", result);
return 0;
}
#包括
使用名称空间std;
空拆分字符串(字符串str)
{
int a=str.length();
对于(int i=0;i您可以对当前算法进行一些改进,例如直接删除字符而不将'$'
存储为填充符。例如,执行一次就地对删除过程(如第二个版本,但在第一对之后不停止),然后重复,直到长度停止更改。(在循环中而不是尾部递归中)
但实际上,不同的算法更有意义
这可能是就地(O(1)存储,在单次(O(n)时间内,常数因子较低,在为现代x86编译时,每个字节可能有几个到几个时钟周期。分支预测失误可能是最大的变量
这看起来像是一个现有的在线问题。
。您可以查看现有的解决方案,如(并且可以看到,许多解决方案都像垃圾一样编码,带有全局变量和1个字母的变量名,并且i
,每次迭代都会重新运行strlen
),但我查看的2的实际算法是好的(除了循环中的strlen使其成为O(n^2),并证实了我的想法,即如果你能够在折叠一系列对之后继续回溯,那么就有可能在间隔前后的奇数字母之间创建一个新的对。也就是说,你可以回溯并再次查看将成为输出一部分的字母
我的版本针对可能有3个或更多相同字符的输入进行了优化,不仅仅是分散的对,但在这种情况下也可以
为了对回溯字符串开头的检查进行微优化,实际字符串数据位于一个具有前导0
字节('\0'
字符)的缓冲区中。这意味着我们不需要在buf[wpos-1]==c
之前检查wpos!=0
黑客竞赛/练习网站将此列在“堆栈”练习下。您可以将写入位置视为堆栈。
#include<bits/stdc++.h>
using namespace std;
void splitString(string str)
{
int a=str.length();
for(int i=0; i<str.length()-1; i++)
{
if(str[i]==str[i+1]){str[i]=1; str[i+1]=1;}
}
string alpha="";
for (int i=0; i<str.length(); i++)
{
if(str[i] >= 'a' && str[i] <= 'z')
alpha.push_back(str[i]);
}
int b=alpha.length();
if(a==b)
{cout <<b<<"\n"<<alpha; return;}
else
{splitString(alpha);}
}
int main()
{
int n; string str; cin>>n>>str;
splitString(str);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define size 100005
void foo(char *s){
int len = strlen(s);
int i, j;
j = 0;
for(i = 0; i < len; i++)
{
if(s[i] != '$')
{
s[j] = s[i]; j++;
}
}
s[j] = '\0';
}
char* super_reduced_string(char* s){
int len = strlen(s);
int i;
for(i = 1; i < len; i++){
if(s[i] == s[i-1])
{
s[i] = s[i-1] = '$';
foo(s);
len = strlen(s);
i = 0;
}
}
return s;
}
int main() {
int n; scanf("%d", &n);
char s[size]={0};
scanf("%s", s);
char* result = super_reduced_string(s);
printf("%d", strlen(result));
printf("\n");
printf("%s\n", result);
return 0;
}
//这是我的版本。不要在在线比赛中作为你的版本提交。
//但是可以在其他任何地方使用它。对于这个答案的代码部分,license=公共域。
#包括
#包括
#包括
#包括
#包括
//第一次不匹配=一次跑步结束后一次
内联大小查找不到(常量字符*基数、大小位置、字符指针){
while(基[pos]==针){
pos++;
}
返回pos;
}
静态字符static_buf[10000002];
int main(int argc,char*argv[])
{
char*buf=static_buf+1;
int infd=0;
如果(argc>1)infd=open(argv[1],Ordonly);
//尺寸长度=
read(infd,buf,sizeof(static_buf)-4);//修复:不处理短读
//1字节的开头填充不能出现在字符串中的值可以简化回溯
//我认为我们的读数不会超过结尾;c!=0,所以检查该值的运行不会走得太远。
//static_buf[0]=0;//str[-1]
//str[len]=0;
大小\u t RPO=0;
while(buf[rpos]&&buf[rpos]!=buf[rpos+1])//std::nexting\u find
rpos++;
//只读,直到第一对或字符串结束。是否可以使用类似palignr的字节移位来SIMD它以馈送pcmpeqb
如果(buf[RPO]){
//我们很早就停了下来,一对一对
size\u t wpos=rpos;//下一个写入位置。prev char=字符串前的0,或最后一个非对
rpos+=2;//从对后读取
//rpos=find_not(buf,rpos+2,buf[rpos]);//运行后读取
//wpos+=(RPO-(wpos+1))%2;//奇数运行长度->保留一个,否则为0
字符c;
而((c=buf[RPO])!=0){
大小\u t运行\u结束=查找\u未(基本单位,RPO+1,c);
如果((运行结束-RPO)%2){
//读端留下一个字符,写端是否取消。
if(buf[wpos-1]==c)//字符串开头之前的0总是比较false
--WPO;
其他的
buf[wpos++]=c;
}
rpos=运行结束;
}
buf[wpos]=0;
}//否则我们将命中一个终止的0,但找不到一对
puts(buf[0]?buf:“空字符串”);
如果(infd==0)
lseek(infd,0,SEEK_SET);//倒带stdin,以便在perf stat下重新读取另一次运行
}
假设一个read
将读取所有可用的输入不是一个好主意。它可能不会,例如从管道中。我使用POSIXread
而不是stdiofread
,因为我想我将使用长度而不是调用strlen
。stdio行输入函数大多是哑的,不会返回他们刚刚找到的线路长度
GCC的另一个微观优化是将(run_end-rpos)%2
编写为(run_end+rpos)%2
。GCC知道未签名的%2
只取低位,但它没有意识到当您只需要低位时,可以添加、SUB和XOR(添加而不带进位)它们都是等价的,只是在高位不同,进位/借位/无从低位传播。+
是可交换的,可以在x86上使用LEA指令进行复制和添加。在这种特殊情况下,它恰好在子
周围保存2条mov
指令,而只是