1.有一组无序的数,只能两两相邻交换,最少交换几次可以使数组有序
由两两相邻交换考虑到逆序数,这个问题就转化到了逆序数一共有几对。
对于逆序数对数的计算,普通的有O(n*n)的算法,当然可以通过树状数组优化N*log(N)
2.有一组无序的数(数字两两不相等:如3 1 1 1就不行),可以任意相互交换,最少交换几次可以使数组有序
问题其实可以转化到选择排序,比如 6 2 1 3 4,第一次将最小的取出放到第一位,如果最小的本来就在第一位,步数就不变,反之加1后交换位置 1 2 6 3 4,后面依次进行
O(n*n)的方法
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int s[100999]; int s2[100999]; int main(){ int n; while(scanf("%d",&n)!=EOF){ int i,j; for(i=1;i<=n;i++){ scanf("%d",&s[i]); s2[i]=s[i]; } sort(&s2[1],&s2[n+1]); int add=0; for(i=1;i<=n;i++){ if(s2[i]==s[i])continue; for(j=i+1;j<=n;j++){ if(s2[i]==s[j]){ add++; swap(s[i],s[j]); break; } } } printf("%d ",add); } return 0; }
还可以继续优化到N*log(N)
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int s[100999]; struct data{ int no; int newno; int v; }node[100999]; int cmp(data x,data y){ return x.v<y.v; } int cmp2(data x,data y){ return x.no<y.no; } int main(){ int n; while(scanf("%d",&n)!=EOF){ int i,j; for(i=1;i<=n;i++){ scanf("%d",&s[i]); node[i].no=i; node[i].v=s[i]; } sort(&node[1],&node[1+n],cmp); for(i=1;i<=n;i++){ node[i].newno=i; s[i]=node[i].no; } sort(&node[1],&node[1+n],cmp2);//离散化 int add=0; for(i=1;i<=n;i++){ if(node[i].newno==i)continue; add++; int no=s[i]; s[node[i].newno]=no; swap(node[i].newno,node[no].newno); } printf("%d ",add); } return 0; }
3.有一组无序的数(数字两两可以相等:如3 1 1 1),可以任意相互交换,最少交换几次可以使数组有序
先预处理,快排原数组 1 1 1 3,将排序后数组中与原数组同位置数字不相同的生成新数组3 1再按第二题的方法处理
发现这样有问题!考虑3 2 1 1,按我的方法是3次,实际是两次,暂时没有想到好的方法,不知博友有什么好的想法?