leetcode
leetcode 1501 ~ 1550
构建字典序最大的可行序列

构建字典序最大的可行序列

难度:

标签:

题目描述

代码结果

运行时间: 28 ms, 内存: 16.4 MB


/*
 * 给定一个整数 n,找到满足以下条件的一个序列:
 * 1. 整数 1 在序列中只出现一次。
 * 2. 2 到 n 之间每个整数都恰好出现两次。
 * 3. 对于每个 2 到 n 之间的整数 i,两个 i 之间出现的距离恰好为 i。
 * 4. 返回满足上述条件中字典序最大的序列。
 * 思路:
 * 从 n 开始向下放置数字。优先放置大的数字,这样可以确保字典序最大。
 */
import java.util.Arrays;
import java.util.stream.IntStream;

public class Solution {
    public int[] constructSequence(int n) {
        int[] result = new int[2 * n - 1];
        Arrays.fill(result, -1);  // 使用 -1 作为占位符
        IntStream.rangeClosed(2, n).map(i -> n - i + 2).forEach(i -> {
            IntStream.range(0, 2 * n - 1 - i).filter(j -> result[j] == -1 && result[j + i + 1] == -1).findFirst().ifPresent(j -> {
                result[j] = i;
                result[j + i + 1] = i;
            });
        });
        IntStream.range(0, 2 * n - 1).filter(i -> result[i] == -1).findFirst().ifPresent(i -> result[i] = 1);
        return result;
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        int n = 3;
        System.out.println(Arrays.toString(sol.constructSequence(n)));  // 输出: [3, 1, 2, 3, 2]
    }
}

解释

方法:

此题解基于回溯算法。首先,初始化一个长度为2n-1的数组res,用于存放最终的序列。数组中的每个位置初始值为None,表示尚未放置任何数字。使用一个集合visited来记录当前已经被放置在序列中的数字。回溯函数recurse通过递归的方式尝试在序列res中放置数字,从n开始尝试到1,以确保字典序最大。对于每个数字i,如果i未被访问过,并且位置上的放置是可行的(对于大于1的i,需要确保res[idx + i]也未被占用),则将i放入当前位置和对应的间隔位置(如果i大于1)。然后,继续递归尝试填充下一个位置。如果递归成功,返回True;否则,撤销当前放置,尝试下一个数字。通过这种方式,算法尝试构建字典序最大的序列。

时间复杂度:

O(n!)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在递归函数中从数字n开始递减尝试放置,而不是从1开始放置?
在递归函数中从数字n开始递减尝试放置而不是从1开始,是因为我们需要构建一个字典序最大的序列。字典序比较是从左到右比较数字的大小,因此首先尝试放置较大的数可以更有可能在序列的前面放置大数字,从而确保生成的序列在字典序上尽可能大。
🦆
在回溯算法中,如果放置了数字i但未能成功构建整个序列,为什么需要撤销当前位置和间隔位置的放置?
在回溯算法中,如果试图放置数字i后未能成功构建整个序列,需要撤销当前位置和间隔位置的放置是因为这样的放置可能阻碍了其他可能的数字放置,导致无法找到一个成功的完整序列。撤销放置允许算法回退到前一个状态,尝试其他数字的放置,从而找到正确的序列配置。
🦆
在寻找下一个空位置时,是否存在更高效的方法来确定下一个未被占用的位置,而不是通过逐个检查?
确实存在更高效的方法来确定下一个未被占用的位置,比如使用一个辅助数据结构(如队列或链表)来跟踪还未被填充的位置。每次填充位置后,可以从这个数据结构中移除相应的位置,从而快速获取下一个空位置。这种方法可以减少不必要的遍历,提高算法的效率。
🦆
题解中没有详细解释如何确保构建的是字典序最大的序列,能否进一步解释这一点?
构建字典序最大的序列的关键在于优先放置较大的数字,并尽可能地将这些数字放在序列的前面位置。算法从n开始递减尝试放置数字,确保一旦较大的数字可以放置,它们会立即被放置在可用的最前端位置。这样,较大的数字较早出现在序列中,从而确保整个序列的字典序尽可能大。此外,通过正确管理数字的放置和撤销(回溯),算法能够探索所有可能的配置,从而找到字典序最大的序列。

相关问题