用栈操作构建数组-LeetCode
1441. 用栈操作构建数组
🎯 问题描述
描述:
给你一个数组 target 和一个整数 n。每次迭代,需要从列表 list = {1, 2, 3, ..., n} 中依序读取一个数字。
请使用下述操作来构建目标数组 target:
- “Push”:从
list中读取一个新元素,并将其推入数组中。 - “Pop”:删除数组中的最后一个元素。
如果目标数组构建完成,就停止读取更多元素。题目数据保证目标数组严格递增。请返回构建目标数组所用的操作序列。
说明:
-
这是一个模拟类问题。
-
核心策略:
- 我们需要按顺序遍历
1到n的数字。 - 对于每个数字
i,它要么是我们需要的(存在于target中),要么是不需要的。 - 如果是需要的,执行 “Push”。
- 如果是不需要的,执行 “Push” 紧接着执行 “Pop”(相当于读取后丢弃)。
- 一旦
target构建完成,立即停止。
- 我们需要按顺序遍历
-
示例:
-
示例 1:
1 | 输入:target = [1,3], n = 3 |
💻 解题思路
思路1:模拟 + 双指针
核心逻辑
- 初始化:
ans:用于存储操作序列。x:指向target数组的当前下标,表示我们正在等待匹配target[x]。
- 遍历数据流:
- 使用循环变量
i从1遍历到n。 - 终止条件:如果
x已经等于target的长度,说明目标数组已构建完成,直接break。
- 使用循环变量
- 判断与操作:
- 情况 A:匹配 (
i == target[x])- 当前数字
i正是我们需要的。 - 执行 “Push”。
- 指针
x向后移动 (x++),准备匹配下一个目标数字。
- 当前数字
- 情况 B:不匹配 (
i != target[x])- 当前数字
i不是我们需要的(因为target是递增的,且i小于当前目标值,或者i根本不在target中)。 - 执行 “Push”(读入),紧接着执行 “Pop”(丢弃)。
- 指针
x不动,继续等待下一个目标。
- 当前数字
- 情况 A:匹配 (
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 最坏情况下,我们需要遍历完
1到n的所有数字(例如target的最后一个元素是n)。 - 但在很多情况下会提前结束,实际运行时间通常小于 。
- 最坏情况下,我们需要遍历完
- 空间复杂度:
- 除了存储结果的
ans列表外,只使用了常数级别的额外变量 (m,x,i)。 - 注意:结果列表本身的空间不计入额外空间复杂度。
- 除了存储结果的
思考
-
为什么不需要显式的栈?
- 虽然题目描述涉及栈操作,但我们实际上只需要记录操作序列(“Push”/“Pop”),并不需要真正维护一个栈来存储数字。因为我们是从
1到n顺序读取的,逻辑上很清楚哪些数字被保留了。
- 虽然题目描述涉及栈操作,但我们实际上只需要记录操作序列(“Push”/“Pop”),并不需要真正维护一个栈来存储数字。因为我们是从
-
target的严格递增性质:- 题目保证
target是严格递增的,这非常关键。这意味着我们只需要按顺序匹配即可。如果i小于target[x],说明i不在目标中;如果i等于target[x],说明匹配成功。不会出现i大于target[x]的情况(除非已经匹配完了)。
- 题目保证
-
提前终止的重要性:
- 代码中的
if x == m: break是必须的。 - 例如
target = [1, 2],n = 4。当我们匹配完2之后,就不需要再处理3和4了,直接停止可以节省时间。
- 代码中的
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






