2020.2.20 大一寒假訓練十三(string)

Problem A:NEFU31 字符串合併

這題真水。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
string s1, s2;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>s1>>s2)
        cout<<s1+s2<<endl;
    return 0;
}

Problem B:NEFU194 迴文字符串

方法1:將字符串逆序後與原字符串比對。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
bool judge(string str)
{
    string tmp=str;
    reverse(str.begin(), str.begin()+str.size());
    return tmp==str;
}
int main()
{
    ios::sync_with_stdio(false);
    string s;
    int n;
    while(cin>>n)
    {
        while(n--)
        {
            cin>>s;
            if(judge(s)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}

方法2:兩個指針分別從首尾兩端一一比較。

#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
    ios::sync_with_stdio(false);
    while(~scanf("%d", &n))
    {
        while(n--)
        {
            char str[110];
            scanf("%s", str+1);
            int len=strlen(str+1);
            bool flag = 1;
            if(len%2)
            {
                for(int i=1,j=len; i<=len/2,j>=len/2+2; i++,j--)
                    if(str[i] != str[j])
                    {
                        flag = 0;
                        break;
                    }
            }
            else
            {
                for(int i=1,j=len; i<=len/2,j>=len/2+1; i++,j--)
                    if(str[i] != str[j])
                    {
                        flag = 0;
                        break;
                    }
            }
            if(flag) printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}

Problem C:NEFU549 氣球

這個題在之前的組隊賽中做過,當時採用的是結構體,這裏用string+map做一下。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<string, int> vis;
int main()
{
    ios::sync_with_stdio(false);
    int n;
    while(cin>>n)
    {
        if(!n) return 0;
        vis.clear();
        for(int i=1; i<=n; i++)
        {
            string str;
            cin>>str;
            vis[str]++;
        }
        string ans;
        int maxn = 0;
        for(map<string, int>::iterator it=vis.begin(); it!=vis.end(); it++)
        {
            string tmp = it->first;
            if(maxn<vis[tmp])
            {
                maxn = vis[tmp];
                ans = tmp;
            }
        }
        cout<<ans<<endl;
    }
}

Problem D:NEFU1001 取子字符串

方法1:比較原始的方法,從n輸出到m。

#include<bits/stdc++.h>
using namespace std;
string str;
int n, m;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>str)
    {
        cin>>n>>m;
        for(int i=n-1; i<=m-1; i++)
            cout<<str[i];
        cout<<endl;
    }
    return 0;
}

方法2:使用string自帶的substr直接返回對應位置。

#include<bits/stdc++.h>
using namespace std;
string str;
int n, m;
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>str)
    {
        cin>>n>>m;
        cout<<str.substr(n-1, m-n+1)<<endl;
    }
    return 0;
}

Problem E:NEFU1019 strange string

純模擬,菜雞蒟蒻專用做法。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int a[26];
int main()
{
    ios::sync_with_stdio(false);
    string str;
    while(cin>>str)
    {
        bool flag = 0;
        fill(a, a+26, 0);
        if(str.size()==3)
        {
            if(str[0]!=str[1] && str[1]!=str[2] && str[0]!=str[2])
                flag = 1;
        }
        else if(str.size()==6)
        {
            if(str[0]==str[1] && str[2]==str[3] && str[4]==str[5])
                if(str[1]!=str[2] && str[3]!=str[4] && str[1]!=str[4])
                    flag = 1;
        }
        else if(str.size()==9)
        {
            if((str[0]==str[1]&&str[1]==str[2])&&(str[3]==str[4]&&str[4]==str[5])&&(str[6]==str[7]&&str[7]==str[8]))
                if(str[0]!=str[3] && str[3]!=str[6] && str[0]!=str[6])
                    flag = 1;
        }
        else flag = 0;
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

Problem F:NEFU2132 字符串處理

樣例解釋aba的迴文子串爲a, b, a, aba

思路:先篩選首尾相同字母的字符串,如aa,bcb。然後對篩選出來的字符串判斷,依次比較前後對應兩個字符是否相同,相同則繼續判斷,不相同則結束當前字符串的判斷。比較到最後會有兩種情況:

  1. 只剩一個字符,計數器+1;
  2. 只剩兩個字符,若相等。計數器+1。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int cnt = 0;
void find(int n, int m, string str)
{
    if(n-m==1 || n==m) cnt++;
    else
    {
        if(str[m]==str[n])
            find(n+1, m-1, str);
        else return;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    string s;
    while(cin>>s)
    {
        cnt = 0;
        for(int i=0; i<s.size(); i++)
            for(int j=i+1; j<s.size(); j++)
                if(s[i]==s[j])
                    find(i, j, s);
        cout<<cnt+s.size()<<endl;
    }
    return 0;
}

Problem G:NEFU2131 字符串乘方

類似於KMP算法中next數組的求解。直接從字符串匹配那篇博客裏套用了,就不多做解釋了。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int Next[1000010];
void getNEXT(string str)
{
    Next[0] = -1;
    int i=-1, j=0;
    while(j < str.size())
    {
        if(i==-1 || str[j]==str[i])
        {
            i++;
            j++;
            Next[j] = i;
            if(str[j] != str[i]) Next[j] = i;
            else Next[j] = Next[i];
        }
        else i = Next[i];
    }
}
int main()
{
    ios::sync_with_stdio(false);
    string s;
    while(cin>>s)
    {
        if(s[0] == '.') return 0;
        getNEXT(s);
        int len = s.size();
        if(len%(len-Next[len])==0)
            cout<<len/(len-Next[len])<<endl;
        else cout<<1<<endl;
    }
}

Problem H:NEFU2130 字符串匹配

說實話一看到這題激動壞了,什麼BF、RK、KMP、Sunday算法啥的我都寫過博客了,可以直接拿來用了吧?
但是一看題,,好像不是這麼一回事。。。

其實這題AC率慘不忍睹是樣例的鍋。NEFU1683的樣例就好多了。

首先看一下對匹配程度的定義,定義中包括兩個名詞:對齊,匹配程度。

  1. 對齊:將某一字符串的首字符與另一字符串的某一字符對齊,然後後面的字符也一一對齊,直至某一字符串的串尾爲止。
    注意:“某一字符串”暗示着兩個字符串都要做一次對齊。
  2. 匹配程度:對於每一組對齊的兩個字符,若這兩個字符相等,則計數。匹配程度爲每種對齊方法的計數的最大值

設有輸入數據:abdfbdefgh:答案應爲appx(abdf,bdefgh) = 2/5

假定我們將其中的一個字符串叫做主串,另一個則稱爲模式串。那麼我們首先固定主串,讓模式串來與主串匹配,同時使用一個cnt計數器和最大值maxn來記錄。

按照大多數人的思路,我們先將長度小abdf的串定爲模式串,長度大bdefgh的定爲主串。
初始cnt和maxn值爲0。

第一輪,首位對齊:
step1
cnt=1,maxn=1;

第二輪,模式串後移:
step2
cnt=0,maxn=1;

第三輪,模式串繼續後移:
step3
cnt=0,maxn=1;

第n輪,模式串首後移至主串尾,本輪結束後匹配結束:stepn
cnt=0,maxn=1。

很多人的處理到這裏就結束了,然後就WA了。其實題中“某一字符串”已經暗示兩個字符串都分別要做一次主串和一次模式串。接下來主串和模式串交換。

第一輪,首位對齊:step1cnt=1,maxn=1;

第二輪,模式串後移:
step2
cnt=2,maxn=2;

第三輪,模式串繼續後移:
step3
cnt=0,maxn=2;

第四輪,模式串繼續後移:
step4
cnt=0,maxn=2。

所以匹配程度應該是2,而不是1。

這組數據也很好的解釋了爲什麼兩個字符串都分別要進行匹配。

接下來就是處理細枝末節了:求一下兩串總長,用最大公約數來約分等等。

注意,以下兩種情況需要特判:

  • [ 1 ] maxn爲0(即沒有匹配)時應單獨輸出0;
  • [ 2 ] 匹配程度的二倍和兩串總長度相等時應單獨輸出1。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int comp(string str1, string str2) // str1固定,str2移動
{
    int len1=str1.size(), len2=str2.size();
    int maxn = -1;
    for(int i=0; i<len1; i++) // 定位str2首位
    {
        int cnt=0;
        for(int j=0; j<len2; j++) // 逐位比較
        {
            if(str1[i+j] == str2[j]) cnt++;
            if(i+j >= len1) break; // 直至某一字符串的串尾爲止
        }
        maxn = max(maxn, cnt);
    }
    return maxn;
}
int main()
{
    ios::sync_with_stdio(false);
    string s1, s2;
    while(cin>>s1 && s1[0]!='-')
    {
        cin>>s2;
        int num1 = 2*max(comp(s1, s2), comp(s2, s1)); // 取二者最大值
        int num2 = s1.size()+s2.size();
        int ans = __gcd(num1, num2);
        int ans1=num1/ans, ans2=num2/ans;
        /* 因爲樣例問題這裏就錯了
        if(num1==0) 
            cout<<"appx("<<s1<<","<<s2<<") = 0"<<endl;
        else if(num1==num2)
            cout<<"appx("<<s1<<","<<s2<<") = 1"<<endl;
        else cout<<"appx("<<s1<<","<<s2<<") = "<<ans1<<"/"<<ans2<<endl;
        */
       if(num1==0) 
            cout<<"appx("<<s1<<","<<s2<<") = 0"<<endl;
        else if(num1==num2)
            cout<<"appx("<<s1<<","<<s2<<") = 1"<<endl;
        else cout<<"appx("<<s1<<","<<s2<<") = "<<ans1<<"/"<<ans2<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章