小C的排列构造问题 | 豆包MarsCode AI 刷题

101 阅读3分钟

问题描述

小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 }));
    }
}