题目描述:设数组的每个元素只储存0~9的数,把数组的n个整数的排列看作是一个n位长整数的一种表示。现编写程序将数组中元素重新排列,使新排列表示的长整数比调整前的大(如果可能的话),但又是所有更大的表示中最小的。例如
输入:
6
3 2 6 5 4 1
要求输出:
Origin:
3 2 6 5 4 1
Reorder:
3 4 1 2 5 6
注:若没有更大的排列,直接输出原数组。
我们可以先将元素较少,或者是元素已经按从大到小排列的情况排出来。剩下的是可以重新排列的情况,就应该是元素并未按从大到小排列,即在某个数之后还有更大者,这是“关键数”。
现在想要得到更大的排列中的最小者,即要使排列做出幅度最小的变化,思路就是从后往前找出第一个关键数,再从它往后找出更大的元素。这时还要找出这些元素中的最小者,接着将它放到关键数的位置。最后就只需要将关键数之后的元素连同它本身从小到大排序,这就是更大而最小的表示,完整代码如下:
#include<stdio.h>
#define MAX_SIZE 100
int main()
{ //a是原数组,b用以存放更大的数
int a[MAX_SIZE],b[MAX_SIZE], i, j, k=0, n, flag = 0, x=0,temp;
//x用以标记关键数,temp用以交换排序
scanf("%d", &n); //元素个数
for (i = 0; i < n; i++) //n个元素
scanf("%d", &a[i]);
if (n == 1) //n为1,直接输出
{
printf("Origin:\n");
printf("%d\n", a[0]);
}
if (n == 2) //n为2,只需进行一次大小判断
{
if (a[0] >= a[1])
{
printf("Origin:\n");
printf("%d %d\n", a[0], a[1]);
}
else {
printf("Origin:\n");
printf("%d %d\n", a[0], a[1]);
printf("Reorder:\n");
printf("%d %d\n", a[1], a[0]);
}
}
if (n > 2)
{
for (i = 0; i <= n - 2; i++) //对每个数检查是否其后有更大的数
for (j = i + 1; j <= n - 1; j++)
if (a[i] < a[j])
{
flag = 1;
break;
}
if (flag == 0) //若没有,可以直接输出
{
printf("Origin:\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d ", a[i]);
if (i == n - 1)
printf("\n");
}
}
if(flag==1) //若有,可以重新排列
{
printf("Origin:\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d ", a[i]);
if (i == n - 1)
printf("\n");
}
flag = 0; //先将flag归0,用作标记
for (i = n - 2; i >= 0; i--) //从后往前看是否其后有更大的数
{
if (i < x)
break;
for (j = n - 1; j >= i + 1; j--)
if (a[i] < a[j]) //当其后有更大的数,存入数组b
{
b[k] = a[j];
k++;
x = i; //记录该位置,这是需要开始重新排列的数,同时需要将循环停止
}
}
for(i=0;i<k-1;i++) //对数组b冒泡排序
{
for (j = k - 1;j>i;j--)
if(b[j]<b[j-1])
{
temp = b[j]; b[j] = b[j - 1]; b[j - 1] = temp;
flag = 1;
}
if (flag == 0)
break;
}
flag = 0; //此时需要用到b中最小的数
for (i = x + 1; i <= n - 1; i++) //在原数组中找到该最小数的位置
if (a[i] == b[0])
{
a[i] = a[x]; //将其替换为a[x]
break;
}
a[x] = b[0]; //将a[x]替换为b组中最小数
for(i=x+1;i<n-1;i++) //再将x之后的数进行冒泡排序
{
for (j = n - 1;j>i;j--)
if(a[j]<a[j-1])
{
temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp;
flag = 1;
}
if (flag == 0)
break;
}
printf("Reorder:\n");
for (i = 0; i <= n - 1; i++)
{
printf("%d ", a[i]);
if (i == n - 1)
printf("\n");
}
}
}
return 0;
}
我的方法过程较长,尽可能使每一步操作更为清晰,如有更优解,欢迎分享。