每日一题-火星人
题目
人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回答。
火星人用一种非常简单的方式来表示数字——掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为 1,2,3……1,2,3……。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。
下表展示了只有 3 根手指时能够形成的 6 个 3 位数和它们代表的数字:
三位数 123,132,213,231,312,321
代表的数字 1,2,3,4,5,6
现在你有幸成为了第一个和火星人交流的地球人。
一个火星人会让你看他的手指,科学家会告诉你要加上去的很小的数。
你的任务是,把火星人用手指表示的数与科学家告诉你的数相加,并根据相加的结果改变火星人手指的排列顺序。输入数据保证这个结果不会超出火星人手指能表示的范围。
输入格式
输入包括三行,第一行有一个正整数 N,表示火星人手指的数目。
第二行是一个正整数 M,表示要加上去的小整数。
下一行是 1 到 N 这 N 个整数的一个排列,用空格隔开,表示火星人手指的排列顺序。
输出格式
输出只有一行,这一行含有 N 个整数,表示改变后的火星人手指的排列顺序。
每两个相邻的数中间用一个空格分开,不能有多余的空格。
数据范围
1≤N≤10000,
1≤M≤100
输入样例
5
3
1 2 3 4 5
输出样例
1 2 4 5 3
解题思路
前备知识
字典序:在数学中,字典或词典顺序(也称为词汇顺序,字典顺序,字母顺序或词典顺序)是基于字母顺序排列的单词按字母顺序排列的方法。 这种泛化主要在于定义有序完全有序集合(通常称为字母表)的元素的序列(通常称为计算机科学中的单词)的总顺序。
对于数字1、2、3…n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。
本题题面较长,其实简单来说就是:给定数字序列重新排列成字典序中下m个更大的排列(即,组合出下m个更大的整数)。
本题就此转化为经典问题求下一个排列,此题已有较多优秀的题解,在此给出链接,并贴代码,大家可以作为板子保存。下一个排列 ----下一个排列题解
AC代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
Solution s=new Solution();
int n=scan.nextInt();
int m=scan.nextInt();
int[] ans=new int[n];
for(int i=0;i<n;i++)//将现有排列读入数组
ans[i]=scan.nextInt();
for(int i=0;i<m;i++)//每执行一次nextPermutation(ans)函数 ans数组变为下一个更大的排列
s.nextPermutation(ans);
for(int i=0;i<n;i++)
System.out.print(ans[i]+" ");//输出
scan.close();
}
}
//下一个排列的板子
class Solution {
/*核心思想:寻找最靠右的需要变更的位数,使得变动幅度最小,选择该数右边与其相差最小的较大数交换,之后的数在按升序排列
*/
public void nextPermutation(int[] nums) {
int len=nums.length;
int left=len-2;
int right=len-1;
boolean flag=false;
while(left>=0)
{
if(nums[left]<nums[right])
{
int find=len-1;
for(;find>=right;find--)
{
if(nums[find]>nums[left]&&(find+1>len-1||nums[find+1]<=nums[left]))
{
int tmp=nums[left];
nums[left]=nums[find];
nums[find]=tmp;
flag=true;
break;
}
}
}
if(!flag){
left--;
right--;
}
else
break;
}
reverse(nums,right,len-1);
}
public void reverse(int[] nums,int start,int end)
{
while(start<end)
{
int tmp=nums[start];
nums[start]=nums[end];
nums[end]=tmp;
start++;
end--;
}
}
}