问题描述
小F拿到了一个长度为n的排列 aa,她希望你帮她构造一个长度相等的排列 bb,使得 ai≠biai=bi 并且 bb 的字典序尽可能小。排列的定义是,长度为n的数组,包含从1到n的所有正整数,每个数字恰好出现一次。
测试样例
样例1:
输入:
n = 3 ,a = [1, 2, 3]
输出:[2, 3, 1]
样例2:
输入:
n = 4 ,a = [3, 1, 2, 4]
输出:[1, 2, 4, 3]
样例3:
输入:
n = 5 ,a = [5, 3, 1, 4, 2]
输出:[1, 2, 3, 5, 4]
问题理解:
我们需要构造一个长度为 n 的排列 b,使得 b 中的每个元素都与 a 中的对应元素不同,并且 b 的字典序尽可能小。因此我们首先需要建立一个新的排列b,将b初始化为a的副本,为了使得b的字典序列尽可能地小,可以首先按照递增的顺序对b进行排列,这样得到的排列就是目前数字集合的最小排列。
但是初次之外,我们观察题目,尽管题目并没有清楚的说明,从样例中依旧可以分析出新的排列b需要和a完全不同。即每个索引上的数字都需要与a不一样,这就带来了一定的复杂度。
我对于这个问题的处理是,需要将b与a相同的索引收集起来,并打乱这部分相同的地方,例如在样例1中a与b的索引相同的有0,1,2,首先观察样例1可以如何对b进行打乱操作,且仍使得字典序尽可能地小。对于索引为0的位置,可以发现,他们的元素是相同的,且在排列元素互不相同的情况下,从任意一个位置的元素取出来与索引0进行交换都不会导致这两个位置上的元素出现相同的情况。同时为了尽可能的使字典序最低,就可以与当前位置的下一条元素进行交换。样例1中,就可以先将1和2交换,得到新的b[2,1,3]。同理,对于样例2和样例3,从头到尾遍历a和b的元素,发现相等就可以对数组b,将其位置上的元素与下一个索引位置的元素交换,得到[1,2,3,4]和[1,2,3,5,4].
但是注意,到了这里我们会发现最后一位的数据还没有处理,这就属于边界处理的问题,对于数组的边界情况,我的处理是直接与倒数第二位的元素交换,得到样例1,2,3的结果依次为[2,3,1]、[1,2,4,3]、[1,2,3,5,4]结果符合样例输出,具体的java代码实现如下
import java.util.Arrays;
public class Main {
public static int[] solution(int n, int[] a) {
// write code here
int[] b;
b = a.clone();
Arrays.sort(b);
int c = b.length-1;
for (int i = 0; i < b.length-1; i++) {
if (a[i] == b[i]) {
swap(b, i, i+1);
}
}
if (a[c] == b[c]) {
swap(b, c, b.length - 2);
}
return b;
}
public static void swap(int[] b, int i, int j) {
int temp = b[i];
b[i] = b[j];
b[j] = temp;
}
public static void main(String[] args) {
System.out.println(Arrays.equals(solution(3, new int[] { 1, 2, 3 }), new int[] { 2, 3, 1 }));
System.out.println(Arrays.equals(solution(4, new int[] { 3, 1, 2, 4 }), new int[] { 1, 2, 4, 3 }));
System.out.println(Arrays.equals(solution(5, new int[] { 5, 3, 1, 4, 2 }), new int[] { 1, 2, 3, 5, 4 }));
}
}