<think>我们正在讨论栈的操作。栈是一种后进先出(LIFO)的数据结构。将栈中某个元素置顶,意味着要将该元素移动到栈顶,而其他元素的相对顺序保持不变(除了被移动的元素外)。
通常,栈的基本操作包括:push(入栈)、pop(出栈)、peek(查看栈顶元素)等。但是,标准栈操作并不支持直接将中间元素置顶。
思路:
1. 我们需要找到目标元素,并将其从栈中移除,同时保持其他元素的顺序(即被移除元素上面的元素需要先弹出并保存,然后移除目标元素,再将之前弹出的元素按原顺序放回)。
2. 但是,由于栈只能从顶部操作,我们可以使用一个辅助栈来保存从原栈中弹出的元素,直到找到目标元素。然后,将目标元素弹出(不移入辅助栈),再将辅助栈中的元素依次压回原栈,最后将目标元素压入栈顶。这样目标元素就到了栈顶。
然而,这种方法会改变其他元素的相对顺序吗?注意:我们弹出目标元素上面的所有元素到辅助栈(这些元素在辅助栈中是逆序的),然后弹出目标元素,再将辅助栈中的元素依次压回原栈(此时这些元素又变回了原来的顺序),最后压入目标元素。因此,其他元素的相对顺序不变,只是目标元素被移到了栈顶。
但是,如果栈中有多个相同的元素,我们通常只移动第一个遇到的目标元素(即最靠近栈顶的目标元素)?或者移动所有目标元素?题目没有说明,一般我们移动最靠近栈顶的目标元素。如果要求移动所有目标元素,则我们需要多次操作,但这样会导致后面的目标元素被移动到栈顶,而前面的目标元素反而被压在下面。所以,题目应该明确是移动哪一个元素。这里我们假设移动第一个遇到的目标元素(即栈中从栈顶开始第一个等于目标值的元素)。
另一种情况:如果目标元素已经在栈顶,那么什么都不用做。
步骤:
1. 创建一个辅助栈。
2. 循环:当原栈不为空时,弹出栈顶元素。
如果该元素等于目标元素,则跳出循环(注意:我们只移动第一个遇到的目标元素)。
否则,将该元素压入辅助栈。
3. 此时,我们已经将目标元素弹出(但还没有放入辅助栈,而是暂时移除),并且目标元素上面的所有元素都在辅助栈中(顺序与原栈中这些元素的顺序相反)。
4. 将辅助栈中的所有元素依次弹出并压回原栈(这样辅助栈中元素的顺序又变回了原来的顺序,即恢复了目标元素下面的元素顺序)。
5. 将目标元素压入原栈的栈顶。
但是,上面的步骤在找到目标元素后,原栈中目标元素下面的元素并没有被弹出,所以它们还在原栈中。我们在步骤2中只弹出了目标元素和它上面的元素(实际上目标元素并没有被压入辅助栈,而是被暂时拿出,而它上面的元素都进入了辅助栈)。然后步骤4将辅助栈的元素(即目标元素上面的元素)放回原栈(此时原栈中只剩下目标元素下面的元素,然后我们放回了上面的元素,最后将目标元素放在栈顶)。这样,目标元素就被移到了栈顶。
然而,在步骤2中,我们实际上只找到了第一个目标元素,然后停止了。那么原栈中剩余的元素(目标元素下面的元素)并没有被弹出,所以它们仍然在栈底。因此,步骤4中我们将辅助栈的元素放回原栈后,原栈的当前状态是:底部是未被弹出的元素(目标元素下面的所有元素),然后是辅助栈放回的元素(目标元素上面的元素,顺序不变),再然后我们压入目标元素?不对,在步骤2中,我们弹出原栈直到找到目标元素,此时原栈中剩下的就是目标元素下面的所有元素(没有弹出)。然后步骤4我们是将辅助栈的元素全部放回原栈(这些元素在辅助栈中是逆序的,所以放回后顺序与原来相同),然后我们压入目标元素。所以最终栈的顺序是:
栈底:未被弹出的元素(目标元素下面的所有元素,顺序不变)
中间:原本在目标元素上面的所有元素(顺序不变)
栈顶:目标元素
因此,整个栈中,除了目标元素被移动到栈顶,其他元素的相对顺序都没有改变。
但是,如果栈中存在多个目标元素,我们只移动了最靠近栈顶的那一个。
另外,如果栈中不存在目标元素,那么我们的操作会怎么样?
在步骤2中,我们会弹出所有元素到辅助栈,然后发现没有找到目标元素,那么我们就应该将辅助栈中的所有元素再放回原栈,这样原栈不变。所以,在代码中,我们需要一个标志来记录是否找到了目标元素。如果没找到,则不要执行将目标元素压入栈顶的操作(因为根本没有目标元素)。
因此,我们可以这样设计:
方法:move_to_top(stack, target)
1. 初始化一个辅助栈auxiliary_stack。
2. 初始化一个变量found,标记是否找到目标,初始为False。
3. 循环,当原栈不为空时:
top = stack.pop()
if top == target and not found: # 找到第一个目标元素
found = True # 标记已找到
target_element = top # 保存目标元素,注意这里我们不需要保存,后面直接用target也可以,但是为了清晰可以保存
else:
auxiliary_stack.append(top) # 不是目标元素或者已经找到过了,就压入辅助栈
4. 现在,原栈为空,辅助栈中存放着除了目标元素之外的所有元素(注意:如果没找到,则辅助栈中有全部元素,且没有目标元素;如果找到了,辅助栈中有目标元素上面的元素和目标元素下面的元素(因为我们是按顺序弹出的,先弹出的是上面的,然后是目标元素(被拿出),然后再弹出下面的元素?不对,实际上在步骤3中,我们只弹出了目标元素上面的元素(在目标元素之上的都被弹到了辅助栈),然后当我们弹出目标元素后,循环还会继续,因为原栈非空(目标元素下面的元素还在),所以我们会继续弹出下面的元素并压入辅助栈。因此,辅助栈中存放了除了目标元素之外的所有元素(包括目标元素上面和下面的),而且是按弹出顺序(即反的顺序)存放的。
5. 接下来,我们需要将辅助栈中的元素全部放回原栈。由于辅助栈是后进先出,所以直接弹出并压回原栈即可。
while auxiliary_stack:
stack.append(auxiliary_stack.pop())
6. 如果找到了目标元素,则将其压入栈顶:stack.append(target_element) # 或者直接用target也可以
但是,步骤3中,当我们找到目标元素后,原栈中剩下的元素(即目标元素下面的元素)会继续被弹出并压入辅助栈。所以,辅助栈中包含了除目标元素外的所有元素(顺序是:先压入的是目标元素上面的元素,然后压入的是目标元素下面的元素,所以辅助栈的栈底是原来目标元素上面的元素,栈顶是原来栈底的元素)。然后步骤5,我们将辅助栈中的元素弹出压回原栈,此时辅助栈弹出顺序是:先弹出原来栈底的元素(即辅助栈的栈顶),再弹出原来栈顶的元素(即辅助栈的栈底)。这样放回原栈后,原栈的顺序变成:先进入的是原来栈底的元素(在栈底),然后依次是原来栈底上面的元素,最后是原来目标元素上面的元素(在栈顶下面)。然后我们再压入目标元素,目标元素就在栈顶。
因此,其他元素的相对顺序没有改变。
但是,这个算法需要遍历整个栈(直到找到目标元素后,还会继续弹出剩下的元素吗?是的,因为循环条件是原栈不为空,所以在找到目标元素后,我们还会继续将目标元素下面的元素全部弹出并放入辅助栈。这样,整个栈都被弹出过,然后又重新压入(除了目标元素最后单独压入)。所以,无论目标元素在栈的什么位置,我们都需要遍历整个栈。
另一种优化:如果我们只需要移动第一个目标元素,那么可以在找到目标元素后,不再继续弹出剩下的元素(即目标元素下面的元素不需要弹出,因为它们还在原栈中)。但是,为了保持其他元素的顺序,我们需要将目标元素上面的元素先放入辅助栈,然后将目标元素弹出,再把辅助栈中的元素放回原栈(此时,原栈中目标元素下面的元素并没有动,而目标元素上面的元素被弹出又放回,顺序不变),最后将目标元素压入栈顶。
修改后的步骤:
1. 创建一个辅助栈auxiliary_stack。
2. 创建一个变量found=False。
3. 循环:当原栈不为空且没有找到目标元素时:
top = stack.pop()
if top == target:
found = True
# 此时,我们已经移除了目标元素,并且循环结束
else:
auxiliary_stack.append(top)
4. 注意:此时,如果找到了目标元素,那么原栈中剩下的元素(目标元素下面的元素)并没有被弹出,而辅助栈中只有目标元素上面的元素(顺序是反的)。如果没找到,辅助栈中保存了所有元素(而且是反的)。
5. 现在,我们需要将辅助栈中的元素放回原栈:将辅助栈中的元素依次弹出并压回原栈(这样辅助栈中的元素又变回原来的顺序)。同时,如果找到了目标元素,我们最后将目标元素压入栈顶。
但是,这样我们只弹出了目标元素和它上面的元素,目标元素下面的元素还在原栈中。所以,在步骤3结束后,原栈中剩下的元素(即目标元素下面的元素)我们不需要动。然后我们将辅助栈中的元素(目标元素上面的元素)放回原栈:这样原栈中先有目标元素下面的元素(在栈底,顺序不变),然后上面是辅助栈放回的元素(即原来的目标元素上面的元素,顺序不变),最后我们压入目标元素(栈顶)。
因此,这个优化版本避免了不必要的弹出操作(只弹出到找到目标元素为止,而不弹出整个栈)。但是,如果目标元素在栈底,那么我们需要弹出整个栈(除了栈底,因为栈底就是目标元素,弹出栈底后循环结束,然后辅助栈存放了除栈底外的所有元素,再放回,最后压入目标元素(栈底元素变成了栈顶))。
所以,我们可以采用优化后的步骤:
步骤:
1. 初始化辅助栈auxiliary_stack = []。
2. 初始化found = False。
3. 当原栈非空且found为False:
top = stack.pop()
if top == target:
found = True
else:
auxiliary_stack.append(top)
4. 此时,如果找到了目标元素,那么原栈中剩下的部分就是目标元素下面的元素(如果有的话),而辅助栈中存放的是目标元素上面的元素(按弹出顺序是反的)。
5. 将辅助栈中的元素依次弹出并压回原栈:依次弹出辅助栈的元素(从栈顶到栈底)并压入原栈,这样辅助栈中的元素就按原来的顺序回到了原栈(位于原栈中剩余元素之上)。
6. 如果找到了目标元素,将目标元素压入原栈的栈顶:stack.append(target) # 注意:这里我们用的是target,因为top已经被弹出并且等于target,但是我们也可以直接用target,因为target是已知的。
注意:第5步中,我们是将辅助栈的元素全部弹出并压回原栈。辅助栈的元素存放顺序是:先弹出的是原来栈顶的元素,然后依次向下,直到目标元素上面的第一个元素。所以在辅助栈中,栈底是原来栈顶的元素,栈顶是目标元素下面的第一个元素(即紧挨着目标元素的上一个元素)。然后我们弹出辅助栈,先弹出的是辅助栈栈顶(即目标元素下面的第一个元素),最后弹出的是辅助栈栈底(即原来栈顶的元素)。所以这些元素压回原栈后,顺序与原来相同:原来栈顶的元素现在在栈顶的下面(因为最后压入的原来栈顶的元素会在栈的更上面?不对,我们重新梳理一下:
原栈初始状态(从栈底到栈顶):[a, b, c, target, d, e] 其中d在target上面,e在栈顶。
我们要将target移动到栈顶。
步骤3:
第一次弹出:e,不等于target,放入辅助栈 -> 辅助栈=[e]
第二次弹出:d,不等于target,放入辅助栈 -> 辅助栈=[e, d]
第三次弹出:target,等于target,标记found=True,停止循环。
此时原栈中还有[a, b, c](栈底到栈顶的顺序是a,b,c)。
步骤5:将辅助栈中的元素弹出并压回原栈:先弹出d(辅助栈栈顶),压入原栈,原栈变为[a,b,c,d];再弹出e(辅助栈栈顶),压入原栈,原栈变为[a,b,c,d,e]。
步骤6:压入target,原栈变为[a,b,c,d,e,target]。
这样,我们就将target移到了栈顶,其他元素的相对顺序不变。
但是,如果目标元素在栈底,例如原栈:[target, a, b, c](栈底target,栈顶c)。
步骤3:
第一次弹出:c,不等于target -> 辅助栈=[c]
第二次弹出:b,不等于target -> 辅助栈=[c,b]
第三次弹出:a,不等于target -> 辅助栈=[c,b,a]
此时栈为空,循环结束(因为原栈为空,即使没有找到,也会结束,但这里还没找到?不对,我们的循环条件是“原栈非空且found为False”。现在原栈非空(还有a,b,c),所以会一直弹出直到栈空。但是,我们在弹出a,b,c的过程中都没有找到target(因为target在栈底,还没有被弹出),所以循环结束后,found仍为False。然后进行步骤5:将辅助栈中的元素弹出并压回原栈:先弹出a,压入原栈;再弹出b,压入;再弹出c,压入。原栈恢复为[target,a,b,c](栈底到栈顶:target,a,b,c)。然后步骤6,由于found为False,我们不压入target(因为没找到),所以原栈不变。
但是,目标元素target实际上在栈底,而我们没有找到?因为我们在弹出过程中,直到栈空都没有弹出到target(因为栈底元素是最后被弹出的,而我们的循环条件在栈空时结束)。所以,我们需要修改:在循环结束后,如果还没有找到目标元素,那么我们需要继续弹出原栈(但实际上原栈已经空了)?所以,我们需要在循环结束后检查栈是否为空,并且还没有找到目标元素,那么就需要再弹出栈底元素(但此时栈已经空了,无法弹出)。因此,我们需要在循环中弹出所有元素,直到找到目标元素或者栈空。
在优化版本中,我们只弹出到找到目标元素为止,如果目标元素在栈底,那么我们需要弹出整个栈(直到栈空)才能找到它。所以,我们需要在循环中弹出所有元素吗?在优化版本中,我们的循环条件是“栈非空且没找到”,所以当栈空时循环结束。那么,如果目标元素在栈底,我们弹出到最后一个元素(即栈底)时,会弹出它然后判断:
top = stack.pop() # 最后一个元素
if top == target:
found = True # 找到了
else:
auxiliary_stack.append(top) # 没找到,放入辅助栈
所以,对于栈底是target的情况:
原栈:[target, a, b, c] 栈顶是c,栈底是target。
步骤3:
第一次:弹出c -> 辅助栈=[c]
第二次:弹出b -> 辅助栈=[c,b]
第三次:弹出a -> 辅助栈=[c,b,a]
第四次:栈非空(还有target),弹出target -> 等于target,found=True,循环结束。
然后步骤5:将辅助栈中的元素依次弹出并压回原栈:先弹出a,再b,再c -> 原栈变为[a,b,c](栈底到栈顶:a,b,c)?不对,压入顺序:先压入a,再b,再c,所以栈顶是c,栈底是a。顺序是a->b->c(栈底到栈顶)。
然后步骤6:将target压入栈顶:原栈变为[a,b,c,target](栈底a,栈顶target)。
这样,target从栈底变成了栈顶。
但是,我们注意到,在循环第三步中,我们弹出了整个栈,然后将辅助栈中的元素放回,最后将target压入栈顶。这样,其他元素的相对顺序发生了颠倒吗?原来栈中顺序(栈底到栈顶):target->a->b->c。我们弹出顺序:c, b, a, target。辅助栈中存放顺序:[c, b, a]。然后放回顺序:先压入a(此时栈为空,压入a后,栈底和栈顶都是a),再压入b(栈底a,栈顶b),再压入c(栈底a,栈顶c)。最后压入target,栈底a,栈顶target。所以栈中顺序:a->b->c->target(栈底到栈顶)。而原来的顺序是target->a->b->c(栈底到栈顶)。所以,除了target移动到栈顶,其他元素的相对顺序保持了原来的相反顺序?不对,我们希望其他元素的相对顺序保持不变,但实际上变成了逆序。
原因:当我们弹出整个栈时,栈中元素的弹出顺序是从栈顶到栈底(c,b,a),然后放入辅助栈(辅助栈中栈底是c,栈顶是a)。然后从辅助栈弹出时,先弹出a(辅助栈栈顶)压入原栈(此时原栈为空,所以a在栈底),然后弹出b压入(在a上面),然后弹出c压入(在b上面)。所以原栈的顺序是a->b->c(栈底到栈顶),而原本的顺序是target->a->b->c(栈底到栈顶),也就是说,a->b->c这部分在原来栈中是从栈底到栈顶的顺序,现在在新的栈中也是从栈底到栈顶,所以顺序没有变。但是,原来target在栈底,现在target在栈顶,而a->b->c这部分在新栈中仍然在target下面,且顺序不变(从栈底a到栈顶c,然后我们压入target后,target在栈顶)。所以,整个栈的顺序变为:a->b->c->target(栈底到栈顶)。而原来栈底是target,栈顶是c,现在栈底是a,栈顶是target。也就是说,除了target被移动,其他元素的相对顺序并没有颠倒,而是保持了原来的顺序(只是整个栈相对于原来的栈来说,除了target,其他元素的位置都向下移动了一格,而target从栈底移到了栈顶)。所以,其他元素的相对顺序没有改变。
但是,这里有一个细节:原来target在栈底,a在target上面(紧挨着),而在新栈中,a在栈底,b在a上面,c在b上面,target在c上面。所以,a,b,c的顺序没有变(都是a在b下面,b在c下面),而target从最下面移到了最上面。
因此,这个算法可以保证其他元素的相对顺序不变。
但是,如果目标元素在栈中间,比如原栈(栈底到栈顶):[a,target,b,c]。我们希望将target移动到栈顶,变成[a,b,c,target]。
步骤3:
弹出c -> 不是,辅助栈=[c]
弹出b -> 不是,辅助栈=[c,b]
弹出target -> 是,found=True,停止循环。
此时原栈中还有a(未被弹出)。
步骤5:将辅助栈弹出并压回原栈:弹出b,压入(此时原栈中有a,压入b后,栈底a,栈顶b);再弹出c,压入(栈底a,栈顶c)。所以原栈变为[a,b,c](栈底到栈顶:a,b,c?不对,压入顺序:先压入b(在栈a的上面,所以栈底a,栈顶b),然后压入c(在b的上面,所以栈底a,栈顶c)。
步骤6:压入target,变为[a,b,c,target](栈底a,栈顶target)。正确。
因此,算法是可行的。
代码实现:
注意:我们假设栈是用列表(list)表示的,且栈顶在列表末尾(即append()入栈,pop()出栈)。
函数原型:def move_to_top(stack, target)
代码如下:
```python
def move_to_top(stack, target):
if not stack: # 如果栈为空,直接返回
return
auxiliary_stack = []
found = False
# 查找目标元素,并将目标元素上面的元素弹出到辅助栈
while stack and not found:
top = stack.pop()
if top == target:
found = True
else:
auxiliary_stack.append(top)
# 将辅助栈中的元素放回原栈
while auxiliary_stack:
stack.append(auxiliary_stack.pop())
# 如果找到目标元素,则将其压入栈顶
if found:
stack.append(target)
```
测试一下:
情况1:目标元素在栈顶。原栈:[1,2,3](栈底1,栈顶3),目标target=3。
步骤3:弹出3,发现等于3,found=True,停止循环。此时原栈=[1,2](栈底1,栈顶2),辅助栈为空。
步骤5:辅助栈为空,所以不操作。
步骤6:将3压入,栈变为[1,2,3] -> 没有变化(因为3原本就在栈顶)。
情况2:目标元素在栈中间。原栈=[1,2,3,4](栈底1,栈顶4),target=2。
步骤3:
弹出4 -> 不等于2 -> 辅助栈=[4]
弹出3 -> 不等于2 -> 辅助栈=[4,3]
弹出2 -> 等于2,found=True,循环结束。此时原栈=[1](栈底1,栈顶1)。
步骤5:将辅助栈中的元素弹出并压回原栈:先弹出3(辅助栈栈顶)压入原栈 -> 原栈=[1,3];再弹出4压入 -> 原栈=[1,3,4]。
步骤6:将2压入 -> [1,3,4,2](栈底1,栈顶2)。此时,2在栈顶,其他元素相对顺序:1,3,4(原来是1,2,3,4,现在2被移走,剩下的1,3,4的顺序不变?但是原来2在3和4的下面,现在3和4在2的下面?是的,顺序变成了1,3,4,2。而原来的顺序是1,2,3,4,所以2后面的3和4在栈中的相对位置没有变(3在4下面),而2前面的1也没有变。所以相对顺序没有改变,只是2被移到了栈顶。
情况3:目标元素在栈底。原栈=[1,2,3,4](栈底1,栈顶4),target=1。
步骤3:
弹出4->辅助栈=[4]
弹出3->辅助栈=[4,3]
弹出2->辅助栈=[4,3,2]
弹出1->等于1,found=True,循环结束。原栈为空。
步骤5:将辅助栈中的元素弹出并压回原栈:弹出2 -> 压入[] -> [2];弹出3压入->[2,3];弹出4压入->[2,3,4]
步骤6:压入1 -> [2,3,4,1](栈底2,栈顶1)。我们希望的是将1从栈底移动到栈顶,且其他元素的相对顺序不变。原来栈中顺序(栈底到栈顶)是1,2,3,4。现在变成2,3,4,1。所以,其他元素的相对顺序保持不变(2,3,4的顺序没有变),1移动到了栈顶。
情况4:目标元素不在栈中。原栈=[1,2,3],target=4。
步骤3:弹出3->辅助栈=[3];弹出2->辅助栈=[3,2];弹出1->辅助栈=[3,2,1];栈空,循环结束,found=False。
步骤5:将辅助栈弹出:弹出1->压入[]->[1];弹出2->[1,2];弹出3->[1,2,3]。
步骤6:found=False,不压入。所以原栈恢复为[1,2,3]。
情况5:重复元素。原栈=[1,2,2,3](栈底1,栈顶3),target=2(我们希望移动第一个遇到的2,即栈顶方向最近的2,也就是第二个2(因为栈顶是3,然后第一个2在栈底方向,第二个2在栈顶方向))。
步骤3:
弹出3 -> 不等于2 -> 辅助栈=[3]
弹出2(栈顶的第一个2)-> 等于2,found=True,循环结束。此时原栈=[1,2](栈底1,栈顶2)。
步骤5:将辅助栈中的3弹出压回原栈:原栈=[1,2,3]。
步骤6:压入2 -> [1,2,3,2]。这样,我们将栈顶方向第一个2(即位置在3下面的那个2)移动到了栈顶,而栈底方向的2没有被移动。
因此,代码满足要求。
但是,如果我们想移动所有2,那么我们需要多次执行该操作?或者修改算法。不过题目没有要求,所以我们只移动第一个遇到的(即最靠近栈顶的目标元素)。
所以,我们可以提供这个函数作为答案。
注意:这个操作的时间复杂度为O(n),空间复杂度为O(n)(辅助栈)。
相关问题:
1. 如果不允许使用辅助栈,如何实现将栈中某个元素置顶?
2. 如何将栈中所有等于目标值的元素都移动到栈顶?
3. 栈的其他操作中,如何反转整个栈?
4. 如何在不使用额外空间的情况下反转栈?
我们将在回答中提供代码示例,并生成相关问题。
</think>以下是使用Python实现将栈中指定元素置顶的方法。栈是一种后进先出(LIFO)的数据结构,置顶操作需保持其他元素的相对顺序不变。核心思路是通过辅助栈临时存储元素,找到目标元素后重新入栈。
### 实现代码
```python
def move_to_top(stack, target):
"""
将栈中第一个匹配的目标元素移动到栈顶
:param stack: 栈(Python列表实现,栈顶在末尾)
:param target: 要置顶的目标元素
"""
if not stack: # 空栈直接返回
return
auxiliary = [] # 辅助栈
found = False # 标记是否找到目标
# 遍历原栈,查找目标元素
while stack:
item = stack.pop()
if item == target and not found:
found = True # 找到第一个目标,停止移除
else:
auxiliary.append(item) # 非目标元素存入辅助栈
# 将辅助栈元素按原顺序放回主栈
while auxiliary:
stack.append(auxiliary.pop())
# 如果找到目标,将其置于栈顶
if found:
stack.append(target)
# 示例用法
if __name__ == "__main__":
stack = [1, 2, 3, 4, 5] # 栈底->栈顶:1,2,3,4,5
print("原栈:", stack)
move_to_top(stack, 3) # 将3置顶
print("置顶后:", stack) # 输出: [1, 2, 4, 5, 3]
```
### 关键步骤说明
1. **初始化辅助栈**:`auxiliary` 暂存非目标元素。
2. **查找目标元素**:
- 循环弹出原栈元素,若遇到目标元素且是首次出现,标记为 `found = True`(不再存入辅助栈)。
- 其他元素压入辅助栈。
3. **恢复元素顺序**:
- 将辅助栈的元素按原顺序弹回原栈(保持非目标元素的相对位置)。
4. **置顶操作**:
- 若找到目标元素,最后将其压入栈顶。
### 时间复杂度分析
- **时间复杂度**:$O(n)$
所有元素最多经历两次出栈和两次入栈操作($n$ 为栈大小)。
- **空间复杂度**:$O(n)$
辅助栈在最坏情况下存储 $n-1$ 个元素。
### 示例结果
- 初始栈:`[1, 2, 3, 4, 5]`(栈顶为5)
- 将 `3` 置顶后:`[1, 2, 4, 5, 3]`(栈顶变为3,其他元素顺序不变)
此方法确保:
1. 仅移动第一个匹配的目标元素。
2. 非目标元素的相对顺序完全保留。
3. 目标不存在时栈保持不变[^1]。