据说是google的一个面试题目

niu_a 2005-11-21 01:40:08
对现在的Stack(栈)数据结构进行改进,加一个min()功能,使之能在常数,即O(1),时间内给出栈中的最小值。可对push()和pop()函数进行修改,但要求其时间复杂度都只能是O(1)。

好象pop很难实现啊
...全文
6966 109 打赏 收藏 转发到动态 举报
写回复
用AI写文章
109 条回复
切换为时间正序
请发表友善的回复…
发表回复
swunstar 2006-04-29
  • 打赏
  • 举报
回复
mark
benlei999 2006-03-21
  • 打赏
  • 举报
回复
mark
cwsheng 2006-03-21
  • 打赏
  • 举报
回复
简单使用两个栈存在缺陷,如果两个相同的最小值呢?
C++荒废了,用C#写个粗糙的吧,可能看起来没C++那么优雅。

using System;
using System.Collections;

/// <summary>
/// 可以获知最小值的堆栈。
/// </summary>
/// <remarks>
/// 入栈的对象必须实现IComparable。
/// </remarks>
public class StackEx : Stack
{
private sealed class StackMateItem
{
private object _minValue;
private int _count;
private StackMateItem _nextRef;

/// <summary>
/// 最小值(特定事情)。
/// </summary>
public object MinValue
{
get { return _minValue; }
set { _minValue = value; }
}

/// <summary>
/// 该值计数。
/// </summary>
public int Count
{
get { return _count; }
}

public int AddCount()
{
return ++_count;
}

public int DecCount()
{
return --_count;
}

/// <summary>
/// 比它大一点的。
/// </summary>
public StackMateItem NextRef
{
get { return _nextRef; }
set { _nextRef = value; }
}

public StackMateItem()
{
_minValue = null;
_count = 0;
_nextRef = null;
}

public StackMateItem(object p_minValue, int p_count, StackMateItem p_nextRef)
{
_minValue = p_minValue;
_count = p_count;
_nextRef = p_nextRef;
}
}

private StackMateItem _currStackMateItem = null;

public StackEx() : base()
{
_currStackMateItem = new StackMateItem();
}

public override object Pop()
{
object obj = base.Pop();
if (obj != null && _currStackMateItem.MinValue != null)
{
if (obj == _currStackMateItem.MinValue)
{
int valueCount = _currStackMateItem.DecCount();
if (valueCount == 0)
{
_currStackMateItem = _currStackMateItem.NextRef;
}
}
}
return obj;
}

public override void Push(object obj)
{
if (!(obj is IComparable))
{
throw new InvalidCastException();
}
base.Push(obj);
if (_currStackMateItem.MinValue == null)
{
_currStackMateItem.MinValue = obj;
_currStackMateItem.AddCount();
}
else if (_currStackMateItem.MinValue == obj)
{
_currStackMateItem.AddCount();
}
else if ((_currStackMateItem.MinValue as IComparable).CompareTo(obj) > 0)
{
StackMateItem minItem = new StackMateItem();
minItem.MinValue = obj;
minItem.AddCount();
minItem.NextRef = _currStackMateItem;
_currStackMateItem = minItem;
}
}

/// <summary>
/// 堆栈最小值。
/// </summary>
public object Min
{
get
{
if (_currStackMateItem == null)
{
throw new NullReferenceException();
}
return _currStackMateItem.MinValue;
}
}

private static void TestStackEx()
{
StackEx myStackEx = new StackEx();
System.Random myRand = new System.Random();
Console.WriteLine("<<PUSH IN>>");
for (int k = 0; k < 11; k++)
{
myStackEx.Push(myRand.Next(1, 10));
PrintValues(myStackEx, ' ');
}
Console.WriteLine("<<POP OUT>>");
while (myStackEx.Count > 0)
{
myStackEx.Pop();
PrintValues(myStackEx, ' ');
}
}

public static void PrintValues( StackEx myStackEx, char mySeparator )
{
if (myStackEx == null || myStackEx.Count < 1)
{
return;
}
Array myArr = myStackEx.ToArray();
System.Collections.IEnumerator myEnumerator = myArr.GetEnumerator();
int i = 0;
int cols = myArr.GetLength( myArr.Rank - 1 );
Console.Write("Stack:");
while ( myEnumerator.MoveNext())
{
if ( i < cols )
{
i++;
}
else
{
Console.WriteLine();
i = 1;
}
Console.Write( "{0}{1}", mySeparator, myEnumerator.Current );
}
Console.WriteLine();
Console.Write("MinVal:" + myStackEx.Min);
Console.WriteLine();
}

public static void Main()
{
TestStackEx();
RL();
}

private static void WL(string text, params object[] args)
{
Console.WriteLine(text, args);
}

private static void RL()
{
Console.ReadLine();
}

private static void Break()
{
System.Diagnostics.Debugger.Break();
}
}

测试结果:
<<PUSH IN>>
Stack: 6
MinVal:6
Stack: 7 6
MinVal:6
Stack: 2 7 6
MinVal:2
Stack: 3 2 7 6
MinVal:2
Stack: 1 3 2 7 6
MinVal:1
Stack: 2 1 3 2 7 6
MinVal:1
Stack: 2 2 1 3 2 7 6
MinVal:1
Stack: 1 2 2 1 3 2 7 6
MinVal:1
Stack: 9 1 2 2 1 3 2 7 6
MinVal:1
Stack: 4 9 1 2 2 1 3 2 7 6
MinVal:1
Stack: 2 4 9 1 2 2 1 3 2 7 6
MinVal:1
<<POP OUT>>
Stack: 4 9 1 2 2 1 3 2 7 6
MinVal:1
Stack: 9 1 2 2 1 3 2 7 6
MinVal:1
Stack: 1 2 2 1 3 2 7 6
MinVal:1
Stack: 2 2 1 3 2 7 6
MinVal:1
Stack: 2 1 3 2 7 6
MinVal:1
Stack: 1 3 2 7 6
MinVal:1
Stack: 3 2 7 6
MinVal:2
Stack: 2 7 6
MinVal:2
Stack: 7 6
MinVal:6
Stack: 6
MinVal:6
buffet001 2006-03-20
  • 打赏
  • 举报
回复
wingfiring(别逗了)(非典型秃子) ( ) 信誉:105


这个题目有点难度的。
其实可以这样:
设主要栈,和一个辅助栈。
push过程
对于主要栈的最小值,在辅助栈中保存其值,和他到栈底的距离,并且。当主要栈的push元素比辅助栈的顶元素更小时,把新的主要栈的栈顶数据和距离压入辅助栈。这是个O(1)复杂度的。
pop过程
如果主要栈pop后,其栈大小比辅助栈顶元素的距离小,则辅助栈的栈顶也弹出。
min()
返回辅助栈的栈顶元素即可。

//////////////////////////////////////


我觉得不要引入距离的概念。

建立主栈Z,和一个辅助栈F。

开始Z,F都为为空。Z push第一个数据时,F 也同样push进去。唯一的数据肯定是最小的。继续push Z,同时 if > F.top(),什么都不作,如果 <= 就push 到F。


现在讲pop,pop Z时,如果pop的数据大于 F.top(),什么都不作。如果 <= F.top(),F也pop.

例如:
1)push 1

Z F
1 1

2) push 2
Z F
2 1
1

3) push 1
Z F
1 1
2 1
1

4) push 3
Z F
3 1
1 1
2
1

5) pop
Z F
1 1
2 1
1

6) pop
Z F
2 1
1

7) pop
Z F
1 1


也就是说,F.top()是当前时刻Z的min
吃海的虾酱sa 2006-03-07
  • 打赏
  • 举报
回复
佩服,mark
lovememememe 2006-02-12
  • 打赏
  • 举报
回复
mark
yzx1983 2005-12-23
  • 打赏
  • 举报
回复
受教了,逛csdn这么久,难得看像这样一个有技术含量和讨论气氛的帖子(可惜看到的时间晚了点,错过了交流的机会)。
ThinkInDelphi 2005-12-22
  • 打赏
  • 举报
回复
好难,我做项目时不太考虑时间,空间复杂度的,只要过得去,合要求就好。
看来还是要加强理论学习!
SarahCla 2005-12-13
  • 打赏
  • 举报
回复
为stack增加一个int nMin,修改push将压栈数据和nMin比较,将小值放入nMin。在函数min()中直接返回nMin的值就可以了。
RainWindy 2005-12-12
  • 打赏
  • 举报
回复
请问楼主,你有答案吗?
我感觉是不可能的,除非这些数是可以全部列举出来的,比如
0-65535,则只有65535个元素就可以了。
sinall 2005-12-12
  • 打赏
  • 举报
回复
呵呵……,楼上开始收租子了,莫非楼上想新年之前升星……
x86 2005-12-12
  • 打赏
  • 举报
回复
楼主该结帖了。
yythinking 2005-11-29
  • 打赏
  • 举报
回复
需要另外加一个栈S2存储当前时刻的最小值,每次压入栈S1的数如果比S2栈顶小,同时要压入S2,出栈时,如果数和S2栈顶一样,同时S2也要pop一下

极端情况下:如果数列从大到小压入原始栈S1,S2的大小和S1一样大,
如果数列从小到大压入原始栈S1,S2的大小为1
一般情况下,S2会比S1小
ilovedudu 2005-11-29
  • 打赏
  • 举报
回复
xiaotianlyl(笑天)
如果你的PUSH操作是n/2的话,不需要看代码就可以知道处理上存在问题。
应该都是O(1)才对。
chengzhi81 2005-11-28
  • 打赏
  • 举报
回复
楼主好人啊,学习中...
baryjim 2005-11-28
  • 打赏
  • 举报
回复
每个元素增加一个字段,用来保存当前栈中最小元素的值。这样在pop最小一个元素后,就知道以前的栈中最小值的状态,因为最小值肯定是在当前栈中。
功夫熊猫kong 2005-11-28
  • 打赏
  • 举报
回复
看懂了, 同意x86(大雪)的归纳法思路来解释,这个方法使人想起当年汉洛塔的解法 :)
BackBad 2005-11-28
  • 打赏
  • 举报
回复
这是一个似易实难的问题,其问题的关键在于,必须使用一个辅助的数据结构S2使得栈内所有的元素有序。以上的这些办法只解决了Push的问题, 对于大雪的算法,当栈里的最小值被pop后,S2中乱序,此时无法以一个复杂度为O(1)的算法来解决这一问题。其他人的算法大致都是如此。
因此,就要求辅助数据结构S2有序,因此此问题就转化为一个在一个有序的数组中插入一个数,要求插入后依然有序,同时时间复杂度为O(1)。而满足这个要求的算法只有哈希算法。因此我想用哈希算法应该可以解决这一问题。 在此由于时间关系 未给出具体算法。
很佩服出题的人
narilee 2005-11-28
  • 打赏
  • 举报
回复
mark
功夫熊猫kong 2005-11-28
  • 打赏
  • 举报
回复
mark
加载更多回复(89)

64,682

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧