栈题目:用栈操作构建数组

题目

标题和出处

标题:用栈操作构建数组

出处:1441. 用栈操作构建数组

难度

3 级

题目描述

要求

给你一个目标数组 target \texttt{target} target 和一个整数 n \texttt{n} n。每次迭代,需要从 list   =   {1,2,3, … ,n} \texttt{list = \{1,2,3,\ldots,n\}} list = {1,2,3,,n} 中依序读取一个数字。

请使用下述操作来构建目标数组 target \texttt{target} target

  • Push \texttt{Push} Push:从 list \texttt{list} list 中读取一个新元素, 并将其推入数组中。
  • Pop \texttt{Pop} Pop:删除数组中的最后一个元素。
  • 如果目标数组构建完成,就停止读取更多元素。

请返回构建目标数组所用的操作序列。如果有多种可能的答案,返回任意一种答案。

示例

示例 1:

输入: target   =   [1,3],   n   =   3 \texttt{target = [1,3], n = 3} target = [1,3], n = 3
输出: ["Push","Push","Pop","Push"] \texttt{["Push","Push","Pop","Push"]} ["Push","Push","Pop","Push"]
解释:
读取 1 \texttt{1} 1 并自动推入数组 → [1] \rightarrow \texttt{[1]} [1]
读取 2 \texttt{2} 2 并自动推入数组,然后删除它 → [1] \rightarrow \texttt{[1]} [1]
读取 3 \texttt{3} 3 并自动推入数组 → [1,3] \rightarrow \texttt{[1,3]} [1,3]

示例 2:

输入: target   =   [1,2,3],   n   =   3 \texttt{target = [1,2,3], n = 3} target = [1,2,3], n = 3
输出: ["Push","Push","Push"] \texttt{["Push","Push","Push"]} ["Push","Push","Push"]

示例 3:

输入: target   =   [1,2],   n   =   4 \texttt{target = [1,2], n = 4} target = [1,2], n = 4
输出: ["Push","Push"] \texttt{["Push","Push"]} ["Push","Push"]
解释:只需要读取前 2 \texttt{2} 2 个数字就可以停止。

示例 4:

输入: target   =   [2,3,4],   n   =   4 \texttt{target = [2,3,4], n = 4} target = [2,3,4], n = 4
输出: ["Push","Pop","Push","Push","Push"] \texttt{["Push","Pop","Push","Push","Push"]} ["Push","Pop","Push","Push","Push"]

数据范围

  • 1 ≤ target.length ≤ 100 \texttt{1} \le \texttt{target.length} \le \texttt{100} 1target.length100
  • 1 ≤ target[i] ≤ n \texttt{1} \le \texttt{target[i]} \le \texttt{n} 1target[i]n
  • 1 ≤ n ≤ 100 \texttt{1} \le \texttt{n} \le \texttt{100} 1n100
  • target \texttt{target} target 是严格递增的

解法

思路和算法

由于目标数组 target \textit{target} target 中的元素都不超过 n n n,因此构建目标数组时需要读取的数字都不会超过 n n n,而是由目标数组中的最大值决定。用 m m m 表示目标数组中的最大值,则遍历从 1 1 1 m m m 的每个数字即可构建目标数组。由于 m ≤ n m \le n mn,因此构建目标数组时不需要考虑 n n n

对于从 1 1 1 m m m 的每个数字,如果该数字在目标数组中,则需要将其推入数组中,如果该数字不在目标数组中,则需要将其推入数组中然后删除。

为了得到每个数字是否在目标数组中,需要遍历目标数组中的每个元素。由于目标数组中的元素严格递增,因此遍历目标数组中的元素顺序一定是从小到大。

num \textit{num} num 表示在 [ 1 , m ] [1, m] [1,m] 范围内遍历到的数字,初始时 num = 1 \textit{num} = 1 num=1。遍历目标数组,假设当前遍历到的目标数组中的数字是 targetNum \textit{targetNum} targetNum,进行如下操作:

  1. num < targetNum \textit{num} < \textit{targetNum} num<targetNum 时, num \textit{num} num 不在目标数组中,因此需要将 num \textit{num} num 推入数组中然后删除,需要一次 Push \text{Push} Push 操作和一次 Pop \text{Pop} Pop 操作,然后将 num \textit{num} num 的值加 1 1 1 表示遍历下一个数字;

  2. num \textit{num} num 的值加 1 1 1 之后,如果仍有 num < targetNum \textit{num} < \textit{targetNum} num<targetNum,则重复上一步操作,直到 num = targetNum \textit{num} = \textit{targetNum} num=targetNum

  3. num = targetNum \textit{num} = \textit{targetNum} num=targetNum 时, num \textit{num} num 在目标数组中,因此需要将 num \textit{num} num 推入数组,需要一次 Push \text{Push} Push 操作,然后将 num \textit{num} num 的值加 1 1 1 表示遍历下一个数字。

遍历目标数组结束之后,从 1 1 1 m m m 的每个数字都遍历过,遍历过程中可以知道每个数字是否在目标数组中,并得到操作序列。

代码

class Solution {
    public List<String> buildArray(int[] target, int n) {
        List<String> operations = new ArrayList<String>();
        int length = target.length;
        int num = 1;
        for (int i = 0; i < length; i++) {
            int targetNum = target[i];
            while (num < targetNum) {
                operations.add("Push");
                operations.add("Pop");
                num++;
            }
            operations.add("Push");
            num++;
        }
        return operations;
    }
}

复杂度分析

  • 时间复杂度: O ( m ) O(m) O(m),其中 m m m 是数组 target \textit{target} target 的最大元素。构建目标数组时,到达目标数组中的最大值 m m m 即停止构建,因此需要遍历从 1 1 1 m m m 的每个数字,对于每个数字,可能有一次 Push \text{Push} Push 操作,或者一次 Push \text{Push} Push 操作和一次 Pop \text{Pop} Pop 操作,因此每个数字的操作时间都是 O ( 1 ) O(1) O(1),总时间复杂度是 O ( m ) O(m) O(m)。题目满足 m ≤ n m \le n mn

  • 空间复杂度: O ( 1 ) O(1) O(1)。除了返回值以外,使用的空间复杂度是常数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值