题目:先输入两个数n,m。然后接着输入m个数(每个数小于等于n)输出最小字典序。同时保证在输出结果中删去无关数字后可以得到输入的m个数的正确序列。
示例:
输入: 5 2
4 2
输出:1 3 4 2 5
解释:1 2 3 4 5是n为5时候最小的字典序,但是输出要4在2前面,所以这个输出才是最小的。
(先上代码,思路详述在下面)
public class Num2 {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int index = 0;
//mapIndex,key是输入的数的值,val是第几次输入的
HashMap <Integer,Integer> mapIndex = new HashMap <Integer,Integer>();
//mapRe,上面map的key和val相反的,这个map是要遍历的基准,因为最终序列必须包括这个顺序
HashMap <Integer,Integer> mapRe = new HashMap <Integer,Integer>();
while (index < m){
++index;
int tempVal = in.nextInt();
mapIndex.put(tempVal,index);
mapRe.put(index,tempVal);
}
int tempRe = 1;//从1开始递增理想情况当前应该输出的数
int outNum = 0;//已得到的正确序列的当前个数
int mapMax = 0;//当前遍历过的map中,输入的数最大值
StringBuffer resString = new StringBuffer();//存放结果
//对mapRe进行遍历,因为他的key从小到大对应的val是结果中必须成立的顺序
while (true){
//这个if是如果mapRe中的key没有现在递增的tempRe,说明我已经就m个数的出现顺序遍历完了,剩下只要把m个数中最大的到n之间顺序补全就行了
if(!mapRe.containsKey(tempRe)){
while (mapMax < n-1){
++mapMax;
resString.append(mapMax);
resString.append(" ");
}
resString.append(n);
break;
}
//取到输入时候第tempRe次输入的值
int indexMapNum = mapRe.get(tempRe);
++tempRe;
//如果当前遍历到顺序的indexMapNum比之前所有的值都大,那就要补全最大值到现在的这个次序
if (indexMapNum > mapMax){
int i = mapMax + 1;
while (i < indexMapNum){
//补全过程中,如果该值出现过(直接用key为值的map进行判断),就跳过,不出现才补全
if ( !mapIndex.containsKey(i)){
++outNum;
resString.append(i);
resString.append(" ");
}
++i;
}
}
++outNum;
resString.append(indexMapNum);
if(outNum < n)
resString.append(" ");
else
break;
mapMax = Math.max(mapMax, indexMapNum);
}
System.out.println(resString.toString());
}
}
思路详述:
输入的数n是要输出1-n,输入的m个数,是要让这m个数的序列在输出中存在。所以我先把输入放了两个map,mapIndex<inputVal,index>是用来判断输出当前数是不是在输入的范围中。mapRe是前一个key,val反过来,是用来遍历的,因为他的key值1-m对应的val就是输入的顺序。
当遍历到第k个时,首先要判断k在不在mapRe中(可以用k > m,或者map判定),如果不在,说明指定的排列顺序(m个数)已经存在于输出序列中了,那么只要把 k到n之间直接从小到大补全到输出序列中就可以了。
当k在mapRe中,这个数个要判断第k个val是否比之前k-1个都大,所以用mapMax进行存储临时最大值。如果比他大,那么就需要补全mapMax+1到第k-1个对应的val,同时要注意补全的时候判断该值是否是输入的m个数(如果是,那一定还不到他的出场时间,因为他比mapMax大,说明他还要在后面才出现),如果是就跳过,不是才输出。
刚刚之所以是补全到第k-1个是因为这样少写两行代码,因为不管当前遍历值比mpMax大还是小,都要在最后补上的。区别只是如果大于mapMax需要上面的操作,小于则不需要。
数字举例:5 2 4 2
过程:mapIndex有<4,1><2,2>mapRe中有<1,4><2,2>。遍历时候第一个值是4,且之前最大的mapMax是0(初始),从0+1开始输出第一个数1,第二数2发现在mapIndex的key中,就不输出,输出下一个3,补全当前4(暂时输出为1 3 4)。遍历到下一个mapRe,val是2,小于mapMax(4),就直接补在后面(输出为1 3 4 2)。这时候发现mapRe遍历完了,那就把mapMax到n直接补全(输出为 1 3 4 2 5)。