下一个排列(Next Permutation)

题目原型:

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

基本思想:
本着一条,尽量不动前面的元素,要找到下一个序列,我们最希望的是动低位上的数。

比如:123454->123445.那么我们就要从最后一个元素(其次是倒数第二个,第三个、、、)开始从后往前比较,

找到比其小的数的位置(假设为i),经过相应的判断后进行交换,然后从i+1开始对其进行从小到大的排序即可。

如:1,0,2,3,1那么从最后一个数1开始,首先和3比较,比3小,继续和2,也小,然后和0比较,比0大,那么就把0和1

交换,此时数组变为1,1,2,3,0.最后对2,3,0进行排序得到0,2,3。最后得到的数组为1,1,0,2,3。

public void nextPermutation(int[] num)
	{
		boolean isMax = true;
		int len = num.length;
		int tempMin = num[0];//判断num数组是否是递减时用到
		int start = 0;//快速排序的起始位置
		int last;//记录待对比的元素
		int besti = 0,bestj = 0;//待交换元素的位置
		for (int i = 1; i < len; i++)
		{
			if (num[i] > tempMin)
			{
				isMax = false;
				break;
			} else
				tempMin = num[i];
		}
		// 如果是逆序
		if (isMax)
		{
			for (int i = 0, j = len - 1; i < j; i++, j--)
			{
				int temp = num[i];
				num[i] = num[j];
				num[j] = temp;
			}
		} else
		{
			//注意,记录待交换元素的位置分别为besti和bestj
			
			for(int j = len-1;j>=0;j--)
			{
				last = num[j];
				//从j的前一个位置开始扫描,遇到比num[j]小的元素就开始判断
				for (int i = j-1; i >= 0; i--)
				{
					if (last > num[i])
					{
						//besti肯定是越大越好,即越靠后越好,比如说数组num为72685假如没有此判断的话,那么进行结果就应该是5和2交换,然后对5后面的6,8,2进行从小到大排序,结果为:75268
						//而75268并非答案,答案是72856,即交换8和6,然后排序8后面的6,5即可。
						if(besti<i)
						{
							besti = i;
							bestj = j;
						}
						//当besti相同的情况下,我们要比较bestj和j,bestj尽可能靠后,例如:num为265,结果是526(交换5和2,再对6和2排序)而不是625(交换6和2)
						else if(besti==i)
						{
							if(bestj<j)
								bestj = j;
						}
						break;
					}
				}
			}
			//交换
			System.out.println(besti+":"+bestj);
			start = besti + 1;
			int temp = num[bestj];
			num[bestj] = num[besti];
			num[besti] = temp;
			
			System.out.println(start);
			// 从小到大排序剩下的元素
			if (start != len - 1)
			{
				// 采用快速排序
				quick(num, start);
			}
		}

	}

	// 快速排序
	public int[] quick(int[] numbers,int start)
	{
		if (numbers.length > 0)
		{ // 查看数组是否为空
			_quickSort(numbers, start, numbers.length-1);
		}
		return numbers;
	}

	public void _quickSort(int[] numbers, int low, int high)
	{
		if (low < high)
		{
			int middle = getMiddle(numbers, low, high); // 将list数组进行一分为二
			_quickSort(numbers, low, middle - 1); // 对低字表进行递归排序
			_quickSort(numbers, middle + 1, high); // 对高字表进行递归排序
		}
	}

	public int getMiddle(int[] numbers, int low, int high)
	{
		int tmp = numbers[low]; // 数组的第一个作为中轴
		while (low < high)
		{
			while (low < high && numbers[high] > tmp)
			{
				high--;
			}
			numbers[low] = numbers[high]; // 比中轴小的记录移到低端
			while (low < high && numbers[low] <= tmp)
			{
				low++;
			}
			numbers[high] = numbers[low]; // 比中轴大的记录移到高端
		}
		numbers[low] = tmp; // 中轴记录到尾
		return low; // 返回中轴的位置
	}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值