リンク:https://ac.nowcoder.com/acm/problem/16644
出典:牛客网
#include<bits/stdc++.h>
using namespace std;
string solve(char b,char e,int p1,int p2,int p3)
{
if(e-b==1)return "";
if(!(isalpha(b)&&isalpha(e)&&b<e||isdigit(b)&&isdigit(e)&&b<e))
return "-";
string ans="";
for(char i=b+1;i<e;i++)
{
for(int j=1;j<=p2;j++)
{
ans+=i;
}
}
if(p1==2&&isalpha(b))
{
for(int i=0;i<ans.length();i++)
{
ans[i]=ans[i]-'a'+'A';
}
}
if(p1==3)
{
for(int i=0;i<ans.length();i++)
ans[i]='*';
}
if(p3==2){
reverse(ans.begin(),ans.end());
}
return ans;
}
int main()
{
int p1,p2,p3;
cin>>p1>>p2>>p3;
string a;
cin>>a;
string ans="";
for(int i=0;i<a.length();i++)
{
if(a[i]=='-')
{
ans+=solve(a[i-1],a[i+1],p1,p2,p3);
}
else
{
ans+=a[i];
}
}
cout<<ans<<endl;
return 0;
}
- ‘-’に出会うと文字列を展開する操作が繰り返されることがわかるので、関数を封装することを考える
- 文字列を走査する方法は、後ろに移動させることだが、明らかに面倒で、区間の長さを計算するため、複雑度が増す。最適な方法は、答えを格納するために新しい文字列 ans を作成すること
- もし a [i] が '-' でなければ ans に直接加える
- もしそうであれば、展開された文字列を加える
- どうやって展開するか?まず不正な場合を排除する
- 第一の不正な場合は "a-b"->"ab","2-3"->"23" のようなもので、この場合、文字でも数字でも、後ろの文字が前の文字よりも ASCII コードが 1 大きいと理解できる、つまり e-b == 1 の場合、この場合は空の文字列 "" を返す(e は '-' の前の文字、b は '-' の後の文字を表す。)
- "減号の両側が小文字のアルファベットまたは数字であり、ASCII コードの順序に従って、減号の右側の文字が左側の文字よりも厳密に大きい。" 逆の観点から入る、正面の状況は複雑で、前が文字で後が数字、前が数字で後が文字、ほぼ同じである
それからこの ans を書く
for(char i=b+1;i<e;i++) { for(int j=1;j<=p2;j++) { ans+=i; } }
このループは巧妙で、第一層はどれを解決するか、第二層はいくつあるかを解決する
そしてp1=2**かつ文字**の場合、埋められた小文字を大文字に変える。大文字は気にしなくてよい、ここでtoupper関数を呼び出すことができる(ここで注意、これは<mark class="hltr-orange">文字であることを必ず判断する</mark>、ここでwaしたことがある。)
p1=3は特に問題ない
最後に反転して直接reverse関数を呼び出す
上記のコードには誤りがある、1. 開始と終了の‘-’,例えば“-a-d-”
```c++
if(a[i]=='-'&&i-1>=0&&i+1<a.length())
{
ans+=solve(a[i-1],a[i+1],p1,p2,p3);
}
特殊な状況の考慮
- 開始と終了の‘-’,例えば “-a-d-”
- 連続する‘-’,例えば “---” この行のコードがこの問題を解決した
(isalpha(b)&&isalpha(e)&&b<e||isdigit(b)&&isdigit(e)&&b<e))
- 数字と文字の間の‘-’,例えば “1-a”
- ‘-’の左側の文字が右側の文字より大きい場合、例えば “d-a”