将数组看作一个n位长整数,重新排列使新排列的长整数比之前大,但又是所有更大的表示中最小的

题目描述:设数组的每个元素只储存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;
}

我的方法过程较长,尽可能使每一步操作更为清晰,如有更优解,欢迎分享。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值