面试官:来,用Golang设计并实现一个有getMin功能的栈~

​题目:在实现栈的基本功能基础上,再实现返回栈中最小元素的操作。

要求:

  1. pop、push、getMin操作的时间复杂度都是O(1)。

  2. 设计的栈类型可以使用现成的栈结构。

解答:维护两个栈,一个栈保存当前栈中的元素,其功能和正常的栈一样,记为stackData,另一个保存每一步操作的最小值,记为stackMin,调用getMin方法时,返回stackMin栈的栈顶元素即可。

具体实现方案有AB两种。

A压入数据规则:

  1. 假设当前数据为newNum,先将其压入stackData,然后判断stackMin是否为空。

  2. stackMin为空,则newNum也压入stackMin。

  3. stackMin不为空,则比较newNum和stackMin栈顶元素哪个更小。

  4. newNum更小或两者相等,则newNum也压入stackMin。

  5. stackMin栈顶元素更小,则stackMin不压入任何内容。

A举个栗子:依次压入3、4、5、1、2、1的过程,stackData和stackMin变化过程如下图:

A弹出数据规则:

  1. 先弹出stackData中栈顶元素记为value,与stackMin栈顶元素比较。

  2. 由【A压入数据规则】可知,stackMin中存在的元素是从栈顶到栈地逐渐变大的,stackMin栈顶元素即是stackMin中最小的元素,也是stackData中最小的元素,因此不会出现value比stackMin栈顶元素更小的情况,只可能大于或等于stackMin栈顶元素。

  3. 当value等于stackMin栈顶元素时,stackMin弹出栈顶元素,大于stackMin栈顶元素时,直接返回value。

A查询当前栈中最小值操作:

           由【A压入数据规则】和【A弹出数据规则】可知,stackMin始终记录着stackData中的最小值,所以stackMin栈顶元素始终是当前stackData中的最小值。

来看下方案A的Golang代码实现:

/* *                    .::::. *                  .::::::::. *                 ::::::::::: *             ..:::::::::::' *           '::::::::::::' *             .:::::::::: *        '::::::::::::::.. *             ..::::::::::::.    Utils:stack 栈和队列 *           ``::::::::::::::::    Author:崔金朋 *            ::::``:::::::::'        .:::. *           ::::'   ':::::'       .::::::::. *         .::::'      ::::     .:::::::'::::. *        .:::'       :::::  .:::::::::' ':::::. *       .::'        :::::.:::::::::'      ':::::. *      .::'         ::::::::::::::'         ``::::. *  ...:::           ::::::::::::'              ``::. * ```` ':.          ':::::::::'                  ::::.. *                 '.:::::'                ':'````.. */package mainimport ("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, nildefault:return 0, errors.New("数据类型错误")  }}

B压入数据规则:

  1. 假设当前数据为newNum,先将其压入stackData,然后判断stackMin是否为空。

  2. stackMin为空,则newNum也压入stackMin。

  3. stackMin不为空,则比较newNum和stackMin栈顶元素哪个更小。

  4. newNum更小或两者相等,则newNum也压入stackMin。

  5. stackMin栈顶元素更小,则把stackMin栈顶元素重复压入stackMin,也就是说在栈顶元素上再压入一个栈顶元素。

B举个栗子:依次压入3、4、5、1、2、1的过程,stackData和stackMin变化过程如下图:

B弹出数据规则:

  1. 先弹出stackData中栈顶元素记为value。

  2. 弹出stackMin栈顶元素。

  3. 返回value。

B查询当前栈中最小值操作:

           由【B压入数据规则】和【B弹出数据规则】可知,stackMin始终记录着stackData中的最小值,所以stackMin栈顶元素始终是当前stackData中的最小值。

来看下方案B的Golang代码实现:

/* *                    .::::. *                  .::::::::. *                 ::::::::::: *             ..:::::::::::' *           '::::::::::::' *             .:::::::::: *        '::::::::::::::.. *             ..::::::::::::.    Utils:stack 栈和队列 *           ``::::::::::::::::    Author:崔金朋 *            ::::``:::::::::'        .:::. *           ::::'   ':::::'       .::::::::. *         .::::'      ::::     .:::::::'::::. *        .:::'       :::::  .:::::::::' ':::::. *       .::'        :::::.:::::::::'      ':::::. *      .::'         ::::::::::::::'         ``::::. *  ...:::           ::::::::::::'              ``::. * ```` ':.          ':::::::::'                  ::::.. *                 '.:::::'                ':'````.. */package mainimport ("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, nildefault:return 0, errors.New("数据类型错误")  }}

上述AB都是使用stackMin栈保存着stackData每一次操作的最小值,操作的时间复杂度是都O(1)、空间复杂度都是O(n)。

上述AB的区别也很明显,A中stackMin压入时稍省空间,但是弹出操作稍费时间,B中stackMin压入时稍费空间,但是弹出操作稍省时间。

扫码关注公众号,获取更多优质内容。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

luyaran

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

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

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

打赏作者

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

抵扣说明:

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

余额充值