試題 基礎練習 完美的代價
阿新 • • 發佈:2021-01-24
資源限制
時間限制:1.0s 記憶體限制:512.0MB
問題描述
迴文串,是一種特殊的字串,它從左往右讀和從右往左讀是一樣的。小龍龍認為迴文串才是完美的。現在給你一個串,它不一定是迴文的,請你計算最少的交換次數使得該串變成一個完美的迴文串。
交換的定義是:交換兩個相鄰的字元
例如mamad
第一次交換 ad : mamda
第二次交換 md : madma
第三次交換 ma : madam (迴文!完美!)
輸入格式
第一行是一個整數N,表示接下來的字串的長度(N <= 8000)
第二行是一個字串,長度為N.只包含小寫字母
輸出格式
否則輸出Impossible
樣例輸入
5
mamad
樣例輸出
3
思路解析:
- 首先要判斷是否滿足迴文,即沒有“物件”的字元的個數要小於等於一
我在判斷的時候使用了兩種容器:set和multiset容器。
s.begin() // 返回指向第一個元素的迭代器 s.clear() // 清除所有元素 s.count() // 返回某個值元素的個數 s.empty() // 如果集合為空,返回true(真) s.end() // 返回指向最後一個元素之後的迭代器,不是最後一個元素 s.equal_range
() // 返回集合中與給定值相等的上下限的兩個迭代器 s.erase() // 刪除集合中的元素 s.find() // 返回一個指向被查詢到元素的迭代器 s.get_allocator() // 返回集合的分配器 s.insert() // 在集合中插入元素 s.lower_bound() // 返回指向大於(或等於)某值的第一個元素的迭代器 s.key_comp() // 返回一個用於元素間值比較的函式 s.max_size() // 返回集合能容納的元素的最大限值 s.rbegin() // 返回指向集合中最後一個元素的反向迭代器 s.rend() // 返回指向集合中第一個元素的反向迭代器 s.size() // 集合中元素的數目 s.swap() // 交換兩個集合變數 s.upper_bound() // 返回大於某個值元素的迭代器 s.value_comp() // 返回一個用於比較元素間的值的函式轉載於:
(https://blog.csdn.net/love20165104027/article/details/81510406)
- 還要滿足交換次數最少(貪心,此處不做詳解),即當遇到沒有“物件”的字元時,不需要真正的去把它交換到中間,只需要計算出該過程中需要的交換次數即可,加到count上即可。
程式碼如下:
#include<iostream>
#include<string>
#include<set>
using namespace std;
string s;//全域性變數,獲取使用者輸入的字串
bool judge(int n)
{
multiset<char>m1;//兩種容器,set容器不能出現重複的,multiset容器可以出現重複值,
set<char>m2;//都是定義的char型別的,不能定義成string型的,要將s中的字母以單個字元的形式存入容器。
int flag = 0;//單個奇數字符的個數。
for (int i = 0; i < n; i++)//利用迴圈將s中的單個字元存入容器中。
{
m1.insert(s[i]);
m2.insert(s[i]);
}
multiset<char>::iterator p1 = m1.begin();
set<char>::iterator p2 = m2.begin();
for (p2; p2 != m2.end(); p2++)
{
if (m1.count(*p2) % 2 != 0)//count的作用是返回*p2這個字元的個數。
flag++;//若是奇數個flag++。
}
if (flag > 1)//當大於一個時肯定不能構成迴文字串!
return false;
else
return true;
}
void show(int x)
{
if (!judge(x))
cout << "Impossible" << endl;
if(judge(x))
{
int count = 0;//交換的次數。
int end = x-1;//字串s的末尾。
int i, j;
for (i = 0; i < end; i++)//頭開始
{
for (j = end; j > i; j--)//尾開始
{
if (s[i] == s[j])
{
for (int k = j; k <= end-1; k++)
{
swap(s[k], s[k + 1]);//將找到的對應的字元交換到尾巴。
count++;//次數對應增加。
}
end--;//交換完畢後,end--,就是尾巴向前一位
break;//此時跳出第二個迴圈,結果就是頭和尾巴都向著中間移了一位。
}
}
if (i == j)//此時就是代表著那個沒有“物件”的那個字元。
{
count = count + (x - 1) / 2 - i;//算出他移到中間位置的交換次數,但此時並不需要真正的進行交換,
}//顯然此處就是單純的是count增加了,並沒有使用swap進行交換,目的就是為了滿足最小次數。
}
cout<<count<<endl;
}
}
int main()
{
int n;
cin >> n;
cin >> s;
show(n);
}
評測資料(可自行驗證):
- 58
fkgikmvqufokkuuiwqbfugwwwukigsvobbsygkokyuwgbmuqgkoqfjuiwj - 214