概述
题目描述
定义一个字符串的无序度为所有位置后面的字母比该位置的字母小的总数之和。比如"DAABEC’'这个字符串的无序度是5,因为D后面有4个位置比它小(AABC),E后面有1个比它小(C),其它位置后面没有比自己小的。" AACEDGG “的无序度为1(E后面有一个D比它小)。” ZWQM "的无序度为6,每个位置后面所有的字母都比它小。
现在你的任务是给定一些字符串(只由大写字母组成),把他们按照无序度从小到大排序,如果无序度一样,那么就按照输入的相对顺序排序。
输入
单组测试数据。
第一行有两个整数n(0 < n <= 50)和m (0 < m <= 100),分别表示输入的字符串的长度和字符串的个数。
接下来m行,每一行包含一个长度为n的字符串,只由大写字母组成。
输出
输出m行,表示排序之后的字符串。
输入样例
10 6
AACATGAAGG
TTTTGGCCAA
TTTGGCCAAA
GATCAGATTT
CCCGGGGGGA
ATCGATGCAT
输出样例
CCCGGGGGGA
AACATGAAGG
GATCAGATTT
ATCGATGCAT
TTTTGGCCAA
TTTGGCCAAA
题解:
给出一个字符串求逆序对数,然后放入到定义好的结构体中,根据逆序对数正序排下序(如果相等就按照加入的顺序编号排序),所以关键就是求逆序对数(三种方法:1.暴力枚举(字符串长度小,能过) 2.归并排序(我的这个方法有问题) 3.树状数组)。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <deque>
#include <list>
#include <utility>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <bitset>
#include <iterator>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double E = exp(1.0);
const int MOD = 1e9+7;
const int MAX = 1e5+5;
int n,m;
struct StrAndAngle
{
int num;
string str;
int angle;
}strAndAngle[MAX];
string str;
// 归并排序求逆序对
int tmp[MAX];
int cnt = 0;
void Merge(int left,int mid,int right,string str)
{
int i = left;
int j = mid + 1;
int x = left;
while(i <= mid && j <= right)
{
if(str[i] > str[j])
{
cnt += mid - i + 1;
tmp[x++] = str[j++];
}
else
{
tmp[x++] = str[i++];
}
}
while(i <= mid)
{
tmp[x++] = str[i++];
}
while(j <= right)
{
tmp[x++] = str[j++];
}
for(int k = left; k <= right; k++)
{
str[k] = tmp[k];
}
}
void MergeSort(int left,int right,string str)
{
if(left < right)
{
int mid = left + (right - left) / 2;
MergeSort(left,mid,str);
MergeSort(mid+1,right,str);
Merge(left,mid,right,str);
}
}
// 树状数组求逆序对
int c[MAX];
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,int k)
{
for(int i = pos; i <= MAX; i += lowbit(i))
{
c[i] += k;
}
}
int ask(int pos)
{
int res = 0;
for(int i = pos; i >= 1; i -= lowbit(i))
{
res += c[i];
}
return res;
}
int GetReverseNumByBIT(int n)
{
memset(c,0,sizeof(c));
int res = 0;
for(int i = 1; i <= n; i++)
{
/** 将数组的值依次放入树状数组 */
add(str[i-1],1);
/** 找出树状数组中小于等于该值的元素个数 */
res += i-ask(str[i-1]);
}
return res;
}
int CalStrNum()// 计算字符串的逆序对数(暴力枚举、归并排序、树状数组)
{
/* 方法1: 暴力枚举法 - O(n2)
int sum = 0;Z
int len = str.length();
for(int i = 0; i < len; i++)
{
for(int j = i + 1; j < len; j++)
{
if(str[i] > str[j])
{
sum++;
}
}
}
return sum;*/
/* 方法2: 归并排序 - O(nlogn)*/
cnt = 0;
int len = str.length();
MergeSort(0,len-1,str);
return cnt;
/* 方法3: 树状数组 - O(nlogn)
int len = str.length();
return GetReverseNumByBIT(len);*/
}
int cmp(StrAndAngle A,StrAndAngle B)
{
if(A.angle != B.angle)
{
return A.angle < B.angle;
}
else
{
return A.num < B.num;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while(cin >> str)
{
cout << CalStrNum() << endl;
}
while(cin >> n >> m)
{
for(int i = 0; i < m; i++)
{
cin >> str;
int strAngle = CalStrNum();
strAndAngle[i].num = i;
strAndAngle[i].str = str;
strAndAngle[i].angle = strAngle;
//cout << strAngle << endl;
}
sort(strAndAngle,strAndAngle+m,cmp);
for(int i = 0; i < m; i++)
{
cout << strAndAngle[i].str << endl;
}
}
return 0;
}
最后
以上就是俊逸仙人掌为你收集整理的51Nod 1874 字符串排序 c/c++题解的全部内容,希望文章能够帮你解决51Nod 1874 字符串排序 c/c++题解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复