题目:在实现栈的基本功能基础上,再实现返回栈中最小元素的操作。
要求:
-
pop、push、getMin操作的时间复杂度都是O(1)。
-
设计的栈类型可以使用现成的栈结构。
解答:维护两个栈,一个栈保存当前栈中的元素,其功能和正常的栈一样,记为stackData,另一个保存每一步操作的最小值,记为stackMin,调用getMin方法时,返回stackMin栈的栈顶元素即可。
具体实现方案有AB两种。
A压入数据规则:
-
假设当前数据为newNum,先将其压入stackData,然后判断stackMin是否为空。
-
stackMin为空,则newNum也压入stackMin。
-
stackMin不为空,则比较newNum和stackMin栈顶元素哪个更小。
-
newNum更小或两者相等,则newNum也压入stackMin。
-
stackMin栈顶元素更小,则stackMin不压入任何内容。
A举个栗子:依次压入3、4、5、1、2、1的过程,stackData和stackMin变化过程如下图:
A弹出数据规则:
-
先弹出stackData中栈顶元素记为value,与stackMin栈顶元素比较。
-
由【A压入数据规则】可知,stackMin中存在的元素是从栈顶到栈地逐渐变大的,stackMin栈顶元素即是stackMin中最小的元素,也是stackData中最小的元素,因此不会出现value比stackMin栈顶元素更小的情况,只可能大于或等于stackMin栈顶元素。
-
当value等于stackMin栈顶元素时,stackMin弹出栈顶元素,大于stackMin栈顶元素时,直接返回value。
A查询当前栈中最小值操作:
由【A压入数据规则】和【A弹出数据规则】可知,stackMin始终记录着stackData中的最小值,所以stackMin栈顶元素始终是当前stackData中的最小值。
来看下方案A的Golang代码实现:
/*
* .::::.
* .::::::::.
* :::::::::::
* ..:::::::::::'
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::. Utils:stack 栈和队列
* ``:::::::::::::::: Author:崔金朋
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
*/
package main
import (
"errors"
)
type Stack struct {
stackData []interface{}
stackMin []interface{}
}
func (s *Stack) Push(item interface{}) (bool, error) {
if item == nil {
return false, errors.New("数据不能为空")
}
var newNum int
newNum, numErr := CheckNum(item)
if numErr != nil || newNum == 0 {
return false, numErr
}
s.stackData = append(s.stackData, newNum)
if len(s.stackMin) == 0 {
s.stackMin = append(s.stackMin, newNum)
} else {
minNum, minErr := s.GetMin()
if minNum == 0 || minErr != nil {
s.stackMin = append(s.stackMin, newNum)
} else if newNum <= minNum {
s.stackMin = append(s.stackMin, newNum)
}
}
return true, nil
}
func (s *Stack) Pop() (interface{}, error) {
length := len(s.stackData)
var item interface{}
if length == 0 {
return item, errors.New("数据不存在")
} else if length == 1 {
item = s.stackData[0]
s.stackData = nil
} else {
item = s.stackData[length-1]
s.stackData = s.stackData[0 : length-1]
}
num, numErr := CheckNum(item)
if numErr != nil || num == 0 {
return num, numErr
}
minNum, minErr := s.GetMin()
if minNum == 0 || minErr != nil {
return minNum, minErr
}
if num == minNum {
val, valErr := s.PopMin()
return val, valErr
}
return num, nil
}
func (s *Stack) PopMin() (int, error) {
length := len(s.stackMin)
var item interface{}
if length == 0 {
return 0, errors.New("数据不存在")
} else if length == 1 {
item = s.stackMin[0]
s.stackMin = nil
} else {
item = s.stackMin[length-1]
s.stackMin = s.stackMin[0 : length-1]
}
num, numErr := CheckNum(item)
if numErr != nil || num == 0 {
return num, numErr
}
return num, errors.New("Min")
}
func (s *Stack) GetMin() (int, error) {
length := len(s.stackMin)
var item interface{}
if length == 0 {
return 0, errors.New("数据不存在")
}
if length == 1 {
item = s.stackMin[0]
} else {
item = s.stackMin[length-1]
}
num, numErr := CheckNum(item)
if numErr != nil || num == 0 {
return num, numErr
}
return num, nil
}
func CheckNum(item interface{}) (int, error) {
switch item := item.(type) {
case int:
return item, nil
default:
return 0, errors.New("数据类型错误")
}
}
B压入数据规则:
-
假设当前数据为newNum,先将其压入stackData,然后判断stackMin是否为空。
-
stackMin为空,则newNum也压入stackMin。
-
stackMin不为空,则比较newNum和stackMin栈顶元素哪个更小。
-
newNum更小或两者相等,则newNum也压入stackMin。
-
stackMin栈顶元素更小,则把stackMin栈顶元素重复压入stackMin,也就是说在栈顶元素上再压入一个栈顶元素。
B举个栗子:依次压入3、4、5、1、2、1的过程,stackData和stackMin变化过程如下图:
B弹出数据规则:
-
先弹出stackData中栈顶元素记为value。
-
弹出stackMin栈顶元素。
-
返回value。
B查询当前栈中最小值操作:
由【B压入数据规则】和【B弹出数据规则】可知,stackMin始终记录着stackData中的最小值,所以stackMin栈顶元素始终是当前stackData中的最小值。
来看下方案B的Golang代码实现:
/*
* .::::.
* .::::::::.
* :::::::::::
* ..:::::::::::'
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::. Utils:stack 栈和队列
* ``:::::::::::::::: Author:崔金朋
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ```` ':. ':::::::::' ::::..
* '.:::::' ':'````..
*/
package main
import (
"errors"
)
type Stack2 struct {
stackData []interface{}
stackMin []interface{}
}
func (s *Stack2) Push2(item interface{}) (bool, error) {
if item == nil {
return false, errors.New("数据不能为空")
}
var newNum int
newNum, numErr := CheckNum2(item)
if numErr != nil || newNum == 0 {
return false, numErr
}
s.stackData = append(s.stackData, newNum)
if len(s.stackMin) == 0 {
s.stackMin = append(s.stackMin, newNum)
} else {
minNum, minErr := s.GetMin2()
if minNum == 0 || minErr != nil {
s.stackMin = append(s.stackMin, newNum)
} else if newNum < minNum {
s.stackMin = append(s.stackMin, newNum)
} else if newNum == minNum {
s.stackMin = append(s.stackMin, newNum)
} else {
s.stackMin = append(s.stackMin, minNum)
}
}
return true, nil
}
func (s *Stack2) Pop2() (interface{}, error) {
length := len(s.stackData)
var item interface{}
if length == 0 {
return item, errors.New("数据不存在")
} else if length == 1 {
item = s.stackData[0]
s.stackData = nil
} else {
item = s.stackData[length-1]
s.stackData = s.stackData[0 : length-1]
}
num, numErr := CheckNum2(item)
if numErr != nil || num == 0 {
return num, numErr
}
s.PopMin2()
return num, nil
}
func (s *Stack2) PopMin2() (int, error) {
length := len(s.stackMin)
var item interface{}
if length == 0 {
return 0, errors.New("数据不存在")
} else if length == 1 {
item = s.stackMin[0]
s.stackMin = nil
} else {
item = s.stackMin[length-1]
s.stackMin = s.stackMin[0 : length-1]
}
num, numErr := CheckNum2(item)
if numErr != nil || num == 0 {
return num, numErr
}
return num, errors.New("Min")
}
func (s *Stack2) GetMin2() (int, error) {
length := len(s.stackMin)
var item interface{}
if length == 0 {
return 0, errors.New("数据不存在")
}
if length == 1 {
item = s.stackMin[0]
} else {
item = s.stackMin[length-1]
}
num, numErr := CheckNum2(item)
if numErr != nil || num == 0 {
return num, numErr
}
return num, nil
}
func CheckNum2(item interface{}) (int, error) {
switch item := item.(type) {
case int:
return item, nil
default:
return 0, errors.New("数据类型错误")
}
}
上述AB都是使用stackMin栈保存着stackData每一次操作的最小值,操作的时间复杂度是都O(1)、空间复杂度都是O(n)。
上述AB的区别也很明显,A中stackMin压入时稍省空间,但是弹出操作稍费时间,B中stackMin压入时稍费空间,但是弹出操作稍省时间。
扫码关注公众号,获取更多优质内容。