算法 64式 10、队列算法整理

1 算法思想

队列

1.1含义

是操作受限的线性表,只允许在表的一端进行插入,另一端进行删除。

有顺序结构和链式结构两种实现形式。

队列的顺序存储:

分配连续存储单元存放队列中元素,设置两个指针front,read分别表示队头元素和队尾元素的位置。队尾指针指向队尾元素的下一个位置

类型描述如下:

# define Maxsize 50

typedef struct{

       ElemType data[Maxsize];

       Int front, rear;

}SqQueue;

 

队列的链式存储:

同时带有队头指针和队尾指针的单链表。头指针指向队头节点,尾指针指向队尾节点,即单链表的最后一个节点

类型描述如下:

typedef struct{

       ElemType data;

       Struct LinkNode* next;

}LinkNode;

typedef struct{

       LinkeNode *front, *rear;

}LinkQueue;

1.2特点

先进先出。

1.3适用

消息队列,生产者和消费者公用的数据队列等。

1.4通用解法

队列算法:

1 确保符合先进先出的性质

2 注意记录队头和队尾

3 优先级队列本质上是堆

 

1.5经典例题讲解

队列经典例题:

用两个队列实现一个栈

分析:

分析:设两个栈分别为栈1和栈2.栈1负责压入,栈2负责弹出。

一个例子:假设压入1,2,3,然后弹出1,压入4,。模拟过程:

栈1:

3

2

1

栈2:空

然后需要弹出1,此时需要将栈1所有元素压入栈2,

此时栈1为空,栈2为

1

2

3

然后弹出1,

栈2变为:

2

3

当需要压入4时,肯定不能直接压入到栈2,因为此时顺序不对,因此只能将栈2元素都压入栈1,然后将

4也压入栈1,变成

4

3

2

总结规律:

栈1用于压入,当需要压入元素时,判断此时如果栈1为空,需要将栈2的所有元素先压入栈1,然后再压入当前元素

栈2用于弹出,当需要弹出元素时,判断此时如果栈2为空,需要将栈1的所有元素压入栈2,然后弹出栈2的栈顶元素

 

代码如下:

class MyQueue

{

public:

       void push(int value)

       {

              //如果弹出栈不空,将该栈所有元素压入压入栈中,然后再执行压入

              if( !popStack.empty() )

              {

                     while( !popStack.empty() )

                     {

                            int num = popStack.top();

                            popStack.pop();

                            pushStack.push(num);

                     }

                     pushStack.push(value);

              }

              //如果弹出栈为空,直接压入元素

              else

              {

                     pushStack.push(value);

              }

       }

 

       void pop()

       {

              //如果压入栈不空,将压入栈中所有元素转移至弹出栈中,然后弹出

              if(!pushStack.empty())

              {

                     while(!pushStack.empty())

                     {

                            int num = pushStack.top();

                            pushStack.pop();

                            popStack.push(num);

                     }

                     popStack.pop();

              }

              else

              {

                     popStack.pop();

              }

       }

 

       //打印元素时,此时需要判断所有元素在哪个栈中。全部转移至弹出栈中,然后输出,就是正确顺序

       void print()

       {

              if(!pushStack.empty())

              {

                     while(!pushStack.empty())

                     {

                            int num = pushStack.top();

                            pushStack.pop();

                            popStack.push(num);

                     }

              }

              //弹出元素

              stack<int> tempStack( popStack );

              while(!tempStack.empty())

              {

                     int value = tempStack.top();

                     tempStack.pop();

                     cout << value << " ";

              }

              cout << endl;

       }

private:

       stack<int> pushStack;

       stack<int> popStack;

};

 

 

2 队列系列

类别-编号

题目

遁去的一

1

用两个栈实现队列

剑指offer

https://blog.csdn.net/qingyuanluofeng/article/details/102616547

参见经典例题解析

2

队列中取最大值操作问题:

假设有这样一个拥有3个操作的队列

1EnQueue(v):将v加入到队列中

2DeQueue():使队列中的队首元素删除并返回此元素

3MaxElement:返回队列中的最大元素

请设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低。

队列底层的数据结构不一定要用数组来实现,还可以使用其他特殊的数据结构来实现。

输入:

4

2 1 3 4

输出:

4

编程之美

https://blog.csdn.net/qingyuanluofeng/article/details/47187661

这道题目:

参见剑指。可以用两个栈来实现。(剑指上的题目是包含min功能的栈,这道题目是包含max功能的队列)

一个用作数据栈,一个用作存储最大值的栈。存储最大值的栈中,我们这样设计,如果最大栈为空,那么将当前元素直接压入最大栈中;如果已经有了元素,

那么我们将当前值与栈顶比较,如果栈顶>=当前值,再向栈中压入栈顶;如果栈顶<当前值,将当前值压入;

弹出的时候,我们就将最大栈里面的值弹出即可。

而数据栈则是存放所有数据。

解法三:

由于栈是和队列相似的数据结构,先看看栈。

这里,维护一个最大值的序列(link2NextMaxItem)来保证Max操作的时间复杂度为O(1),相当于用空间复杂度换取时间复杂度。

 

 

关键:

1 这里,维护一个最大值的序列(link2NextMaxItem)来保证Max操作的时间复杂度为O(1),相当于用空间复杂度换取时间复杂度。

2 stack():_iStackTop(-1),_iMaxIndex(-1){}//设置栈顶为-1,最大值下标元素为-1

3           if(_iMaxIndex >= 0)//如果最大值下标>=0,表示可以返回栈数组中对应最大值下标的元素,否则返回负无穷大

              {

                     return _itemArr[_iMaxIndex];

4    void push(T x)//压入算法:首先使栈顶累加,然后判断栈顶是否超过最大值;放入元素,将放入的元素与栈中的最大值进行比较,如果大于最大值,那么

              //使最大值序列中的栈顶存放最大值下标,同时使最大值下标为栈;                                                       小于      ,那么

              //使最大值序列栈顶元素对应的值为-1

       {

              _iStackTop++;

5                  if(_iStackTop == _iMaxIndex)//记住,返回栈顶最大值元素之后,要重新修改链表,更新最大值下标为链表中下一个元素,并使栈顶减减

                     {

                            _iMaxIndex = _iLinkNextMaxItem[_iStackTop];

                     }

                     _iStackTop--;

6           if(x > max())

              {

                     _iLinkNextMaxItem[_iStackTop] = _iMaxIndex;//采用类似头插法的方式来保存最大元素,使_iLinkNextMaxItem[_iStackTop]中始终保存的是最大值下标

                     _iMaxIndex = _iStackTop;

              }

              else

              {

                     _iLinkNextMaxItem[_iStackTop] = -1;//如果不是最大值,就始终维持最大值下标为-1

              }

7    Stack<T> stackA;//注意标准是stack,queue,小写

       Stack<T> stackB;//注意,这里调用的是我们自己写的栈

8    void EnQueue(T x)

       {

              stackB.push(x);

       }

       T DeQueue()

       {

              if(stackA.empty())//如果队列A空了,就将B中的元素全部放入A中

              {

                     while(!stackB.empty())//每个元素被移动的次数最多3次:从B堆栈进入,当A堆栈为空时,从B堆栈弹出并压入A堆栈,从A堆栈弹出

                     {

                            stackA.push(stackB.pop());

                     }

              }

              return stackA.pop();//返回A中弹出的栈顶元素

9    T max()

       {

              return maxValue(stackA.max(),stackB.max());//牛逼,用递归来做

             

代码:

 

const int INT_MAX1 = 0x7fffffff;//靠名字冲突了

const int INT_MIN1 = -INT_MAX1;

const int MAXSIZE = 10000;

 

using namespace std;

 

template<typename T>

class Stack

{

public:

       Stack():_iStackTop(-1),_iMaxIndex(-1){}//设置栈顶为-1,最大值下标元素为-1

       bool empty()

       {

              if(_iStackTop < 0)

              {

                     return true;

              }

              else

              {

                     return false;

              }

       }

       T max()

       {

              if(_iMaxIndex >= 0)//如果最大值下标>=0,表示可以返回栈数组中对应最大值下标的元素,否则返回负无穷大

              {

                     return _itemArr[_iMaxIndex];

              }

              else

              {

                     return INT_MIN1;

              }

       }

       void push(T x)//压入算法:首先使栈顶累加,然后判断栈顶是否超过最大值;放入元素,将放入的元素与栈中的最大值进行比较,如果大于最大值,那么

              //使最大值序列中的栈顶存放最大值下标,同时使最大值下标为栈;                                                       小于      ,那么

              //使最大值序列栈顶元素对应的值为-1

       {

              _iStackTop++;

              if(_iStackTop >= MAXSIZE)

              {

                     return;

              }

              else

              {

                     _itemArr[_iStackTop] = x;

              }

              if(x > max())

              {

                     _iLinkNextMaxItem[_iStackTop] = _iMaxIndex;//采用类似头插法的方式来保存最大元素,使_iLinkNextMaxItem[_iStackTop]中始终保存的是最大值下标

                     _iMaxIndex = _iStackTop;

              }

              else

              {

                     _iLinkNextMaxItem[_iStackTop] = -1;//如果不是最大值,就始终维持最大值下标为-1

              }

       }

       T pop()

       {

              T ret;

              if(_iStackTop < 0)

              {

                     printf("Stack is Empty!");

                     return NULL;

                     //throw new exception("Stack is Empty!");

              }

              else

              {

                     ret = _itemArr[_iStackTop];

                     if(_iStackTop == _iMaxIndex)//记住,返回栈顶最大值元素之后,要重新修改链表,更新最大值下标为链表中下一个元素,并使栈顶减减

                     {

                            _iMaxIndex = _iLinkNextMaxItem[_iStackTop];

                     }

                     _iStackTop--;

              }

              return ret;

       }

private:

       int _iStackTop;

       int _iMaxIndex;

       int _iLinkNextMaxItem[MAXSIZE];//维护最大值的序列

       T _itemArr[MAXSIZE];//存放数据

};

 

//用两个栈来实现一个队列

template<typename T>

class Queue

{

public:

       T maxValue(T a,T b)

       {

              return a > b ? a : b;

       }

       bool empty()

       {

              if(stackA.empty() && stackB.empty())

              {

                     return true;

              }

              else

              {

                     return false;

              }

       }

       T max()

       {

              return maxValue(stackA.max(),stackB.max());//牛逼,用递归来做

       }

       void EnQueue(T x)

       {

              stackB.push(x);

       }

       T DeQueue()

       {

              if(stackA.empty())//如果队列A空了,就将B中的元素全部放入A中

              {

                     while(!stackB.empty())//每个元素被移动的次数最多3次:从B堆栈进入,当A堆栈为空时,从B堆栈弹出并压入A堆栈,从A堆栈弹出

                     {

                            stackA.push(stackB.pop());

                     }

              }

              return stackA.pop();//返回A中弹出的栈顶元素

       }

private:

       Stack<T> stackA;//注意标准是stack,queue,小写

       Stack<T> stackB;//注意,这里调用的是我们自己写的栈

};

 

void queueMax_queue(int* pArr,int iLen)

{

       Queue<int> que;

       for(int i = 0 ; i < iLen ; i++)

       {

              que.EnQueue(pArr[i]);

       }

       while(!que.empty())

       {

              printf("%d\n",que.max());//关键这里只能返回最大值,对于2 1 3 4这种,只会返回4 3 2, 但是1不会返回是因为已经到达最后的      

              que.DeQueue();

       }

}

 

void process()

{

       int n;

       while(EOF != scanf("%d",&n))

       {

              int iArr[MAXSIZE];

              for(int i = 0 ; i < n ; i++)

              {

                     scanf("%d",&iArr[i]);

              }

              queueMax_queue(iArr,n);

       }

}

3

实现一个MyQueue类,该类用两个栈来实现一个队列

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53839880

参见经典例题解析

4

猫狗动物队列

有家动物收容所只收容狗与猫,并且严格遵守“先进先出”原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(根据进入收容所的时间长短)的动物,或者,可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueue,dequeueAny,dequeueDog和dequeueCat等。允许使用Java内置的LinkedList数据结构。

输入:

5(猫狗个数之和)

d(表示狗) c(表示猫) c d c

3(指令个数)

dequeueAny

dequeueCat

dequeueDog

输出:

d(该操作返回的动物名称) 0(动物序号)

c 1

d 3

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53858060

分析:所谓的挑选猫或狗,就是直接提取出任何动物,但是必须收养最老的动物。一种暴力破解方法就是直接遍历,从头到尾遍历,直接去获取最老的

      动物,或者是挑选某个指定位置的猫,并要找出最老的猫一起返回;或者挑选某个狗以及最老的狗。

         如果采用队列,那么就是先进先出。

         一种实现队列的方法就是:采用链表来实现,并且采用尾插法,遍历的时候从头部开始。

         挑选其实就是所谓的删除。

书上解法:只维护一个队列,找猫或狗需要遍历整个队列,增加复杂度。

          简单方法:猫和狗各创建一个队列,将两个队列放入包裹类AnimalQueue,存储时间戳作为入队时间。

                当调用dequeueAny时,查看狗队列和猫队列的时间戳即可。

                我之所以没想到,是因为我想用一个队列来做。像类似的猫狗不同对象队列,小于x大于x进行划分,最好都用两个队列或两个链表来做。

                另外想错了一个地方,dequeueDog就只能获取最老的狗而不是某个狗+最老的狗

 

关键:

1 猫和狗各创建一个队列,将两个队列放入包裹类AnimalQueue,存储时间戳作为入队时间。

       当调用dequeueAny时,查看狗队列和猫队列的时间戳即可。

       我之所以没想到,是因为我想用一个队列来做。像类似的猫狗不同对象队列,小于x大于x进行划分,最好都用两个队列或两个链表来做。

       另外想错了一个地方,dequeueDog就只能获取最老的狗而不是某个狗+最老的狗

 

 

class Animal

{

public:

       Animal(string& name) : _name(name){}

       void setName(string& name)

       {

              _name = name;

       }

       virtual string getName()

       {

              return _name;

       }

       void setOrder(int order)

       {

              _order = order;

       }

       bool isOlderThan (Animal& other)

       {

              return _order < other._order;

       }

       int getOrder()

       {

              return _order;

       }

protected:

       string _name;

       int _order;//用于记录顺序,数值越小,比较的时候越应该弹出

};

 

class Dog : public Animal

{

public:

       //构造函数需要直接对父类构造函数进行赋值

       Dog(string& name) : Animal(name){}

       string getName()

       {

              return _name;

       }

};

 

class Cat : public Animal

{

public:

       //构造函数需要直接对父类构造函数进行赋值

       Cat(string& name) : Animal(name){}

       string getName()

       {

              return _name;

       }

};

 

class AnimalQueue : public queue<Animal>

{

public:

       AnimalQueue()

       {

              order = 0;

       }

       void enqueue(Animal& animal)

       {

              string name = animal.getName();

              if(name == "c")

              {

                     //使用引用转换dynamic_cast<Cat&> (animal),注意转换必须加括号

                     Cat cat = dynamic_cast<Cat&> (animal);

                     cat.setOrder(order++);

                     queueCat.push(cat);

              }

              else if(name == "d")

              {

                     Dog dog = dynamic_cast<Dog&> (animal);

                     dog.setOrder(order++);

                     queueDog.push(dog);

              }

       }

 

       //弹出队列中最老的元素,注意每次弹入元素时,需要设置顺序

       Animal dequeueAny()

       {

              if(queueDog.empty() && queueCat.empty())

              {

                     Animal animal(string("animal"));

                     return animal;

              }

              else if(queueCat.empty())

              {

                     Dog dog = queueDog.front();

                     queueDog.pop();

                     return dog;

              }

              else if(queueDog.empty())

              {

                     Cat cat = queueCat.front();

                     queueCat.pop();

                     return cat;

              }

              else

              {

                     //根据顺序来找到最老的元素

                     Dog dog = queueDog.front();

                     Cat cat = queueCat.front();

                     bool isOlder = dog.isOlderThan(cat);

                     if(isOlder)

                     {

                            queueDog.pop();

                            return dog;

                     }

                     else

                     {

                            queueCat.pop();

                            return cat;

                     }

              }

       }

 

       Animal dequeDog()

       {

              if(queueDog.empty())

              {

                     Dog dog(string("dog"));

                     return dog;

              }

              else

              {

                     Dog dog = queueDog.front();

                     queueDog.pop();

                     return dog;

              }

       }

 

       Animal dequeCat()

       {

              if(queueCat.empty())

              {

                     Cat cat(string("cat"));

                     return cat;

              }

              else

              {

                     Cat cat = queueCat.front();

                     queueCat.pop();

                     return cat;

              }

       }

private:

       queue<Dog> queueDog;

       queue<Cat> queueCat;

       int order;

};

5

Implement Queue using Stacks

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56685862

参见经典例题解析

6

如何实现队列

实现一个队列的数据结构,使其具有入队列、出队列、查看队列首尾元素、查看队列大小等功能

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/90115956

分析:

队列的特点就是先进先出。

这里最关键的一点就是查看队列首尾元素。

栈和队列实际都是链表的变体。

这里可以考虑用双向链表。

采用尾插法,设置一个头结点,头结点存储队列长度信息。

记录当前节点的前一个节点,即为prev, 每次待插入的节点记为curr,

初始令:

prev = head

tail = head

进队操作:

prev.nextNode = curr

curr.prevNode = prev

prev = curr

tail = prev

那么查看队列的首元素就是获取: head.nextNode

查看队列的尾元素就是获取: tail

出队操作,则需要将链表的第一个节点删除:

head.nextNode = head.nextNode.nextNode

关键:

1 可以用单向链表实现

只是要查看队尾元素,可以记录一个尾指针

2 可以用数组实现

设置front指向第一个元素,设置rear初始为front后面的一个元素,

进队: list[rear] = newData, read += 1

出队: front += 1

后面可以用循环数组实现

两种方法更推荐用单向链表

 

 

class Node(object):

    def __init__(self, data=None, nextNode=None, prevNode=None):

        self.data = data

        self.nextNode = nextNode

        self.prevNode = prevNode

 

 

class MyQueue(object):

    def __init__(self):

        self.head = Node()

        self.prev = self.head

        self.tail = None

        self.len = 0

 

    def getLen(self):

        return self.len

 

    def isEmpty(self):

        if self.len <= 0:

            return True

        else:

            return False

 

    def push(self, data):

        curr = Node(data)

        self.prev.nextNode = curr

        curr.prevNode = self.prev

        self.prev = curr

        self.tail = self.prev

        self.len += 1

 

    def pop(self):

        if self.isEmpty():

            print "queue is empty, it can not pop"

            return

        temp = self.head.nextNode

        self.len -= 1

        self.head.nextNode = self.head.nextNode.nextNode if self.head.nextNode else None

        return temp.data

 

    def getHead(self):

        if self.isEmpty():

            print "queue is empty, it can not get head"

            return None

        return self.head.nextNode.data

 

    def getTail(self):

        if self.isEmpty():

            print "queue is empty, it can not get head"

            return None

        else:

            return self.tail.data

7

如何用两个栈模拟队列操作

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/91127045

关键:

1 书上解法

栈A入队,栈B用于出队,

如果B为空,则将A中元素压入B中,最后弹出B的top元素;

否则直接弹出B中的top元素

 

 

class Stack(object):

    def __init__(self):

        self.data = list()

 

    def empty(self):

        result = False if self.data else True

        return result

 

    def push(self, data):

        self.data.append(data)

 

    def pop(self):

        if not self.empty():

            self.data.pop()

        else:

            print "stack is empty, it can not pop"

 

    def top(self):

        if not self.empty():

            data = self.data[-1]

            return data

        else:

            print "stack is empty, it can not get top"

 

 

class SimulatedQueue(object):

    def __init__(self):

        self.stack1 = Stack()

        self.stack2 = Stack()

 

    def push(self, data):

        self.stack1.push(data)

 

    def pop(self):

        if self.stack2.empty():

            while not self.stack1.empty():

                value = self.stack1.top()

                if value is not None:

                    self.stack2.push(value)

                self.stack1.pop()

        if not self.stack2.empty():

            front = self.stack2.top()

            self.stack2.pop()

            return front

        else:

            return None

 

    def empty(self):

        result = True if self.stack2.empty() and self.stack1.empty() else False

        return result

8

如何设计一个排序系统
请设计一个排队系统,能够让每个进入队伍的用户都能看到自己在队列中所处的位置和变化,队伍可能

随时有人加入和退出;当有人退出影响到用户的位置的排名时需要及时反馈到用户。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/91350337

关键:

1 书上解法:

1.1 使用使用python中collections.deque

deque是双端队列,在list基础上增加了移动,旋转,增删。

1.2 设定一个User类,并设置seq这个属性,

实现equals方法,比较两个对象的id是否相同(应该是队列

删除元素时需要)

当将User对象放入队列时,设置seq的序号;

当出队的时候,都需要更新seq

2 deque方法

append(value): 在最右边添加元素

appendleft(value): 最左边添加元素

extend(aList): 在最右边添加所有元素

extendleft(aList): 在最左边添加所有元素

pop():将最右边元素取出

popleft():将最左边元素取出

rotate(intValue): 旋转位置,负数为向左旋转

count(value):获取队列中值为value的元素个数

remove(value): 将队列中的元素value删除

reverse():将队列逆置

 

from collections import deque

 

class User(object):

    def __init__(self, id, name, seq=None):

        self.id = id

        self.name = name

        self.seq = seq

 

    def equals(self, other):

        return other.id == self.id

 

    def __str__(self):

        info = "id: {id}, name: {name}, sequence: {seq}".format(

            id=self.id,

            name=self.name,

            seq=self.seq

        )

        return info

 

 

class UserQueue(object):

    def __init__(self):

        self.queue = deque()

 

    def enQueue(self, user):

        user.seq = len(self.queue) + 1

        self.queue.append(user)

 

    def deQueue(self):

        self.queue.popleft()

        self.updateSeq()

 

    # 有用户随机离开

    def deQueueRemove(self, user):

        self.queue.remove(user)

        self.updateSeq()

 

    def updateSeq(self):

        for i, user in enumerate(self.queue):

            user.seq = i + 1

 

    def printQueue(self):

        for user in self.queue:

            print user

9

如何实现LRU缓存方案
LRU就是最近最少使用,请实现。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/91350970

分析:

最近最少使用实际就是在缓存不够的时候将最先进入的删除掉,那么这就可以使用队列完成。

将需要删除的最前面的n个元素删除即可。

使用双向链表来实现队列,队列最大容量为缓存大小。把最近使用的页面移动到队列头,

最近没有使用的放在队列尾部。

使用哈希表,建立: <页号,队列中该页面对应节点地址>的节点字典。

当引用页面在队列中,则将页面对应节点移动到队列头部,

否则,将一个新节点添加到队列前面,并更新节点字典。

若队列已经满了,那么就从队列尾部移除一个节点,并将新节点添加到队列前面

关键:

1  缓存有大小

最近访问的页面需要放置到队列头部;

队列满,需要移除队尾元素;

需要建立字典保存<页号,队列中页面对应节点地址>

 

 

from collections import deque

 

class LRU(object):

    def __init__(self, cacheSize):

        self.cacheSize = cacheSize

        self.queue = deque()

        self.hashSet = set()

 

    def full(self):

        return len(self.queue) >= self.cacheSize

 

    def enQueue(self, data):

        # 如果待入队元素在队列中,则移动到队头

        if data in self.hashSet:

            self.queue.remove(data)

            self.queue.appendleft(data)

        else:

            self.hashSet.add(data)

            # 如果队列已经满了,则先移除队尾的元素,然后将待入队元素放入队头

            if self.full():

                self.queue.pop()

            self.queue.appendleft(data)

 

    def deQueue(self):

        self.queue.pop()

 

    def deQueueRemove(self, data):

        self.queue.remove(data)

 

    def printLRU(self):

        info = ""

        for value in self.queue:

            if info:

                info += " " + str(value)

            else:

                info += str(value)

        print info

10

如何从给定的车票中找出旅程

给定一趟旅途旅程中所有的车票信息,根据这个车票信息找出这趟旅程的路线。例如:

给定下面的车票: 西安到成都,北京到上海,大连到西安,上海到大连。

那么可以得到旅程的路线为: 北京->上海,上海->大连,大连->西安,西安->成都。

假定给定的车票不会有环,也就是说有一个城市之作为终点而不会作为起点。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/91351720

关键:

1 我的方法是可行的

书上解法:

同时设置input和reverseInput,遍历input中的每个key,如果某个key不在reverseInput中,

则该key就是起点。

 

from collections import deque

 

 

class OptimizedRoute(object):

    def __init__(self):

        self.queue = deque()

        self.dict = dict()

        self.reverseDict = dict()

 

    def addTicket(self, key, value):

        self.dict[key] = value

        self.reverseDict[value] = key

 

    def findRoute(self):

        # 寻找起点

        start = None

        for key, value in self.dict.iteritems():

            if key not in self.reverseDict:

                start = key

                break

        if start is None:

            print "start is None, it it not correct"

            return

        result = start

        while start in self.dict:

            start = self.dict[start]

            result += '->' + start

        return result

11

卡片游戏

桌上有一叠拍,从第一张牌(位于顶面的牌)开始从上往下依次编号为1~n。当至少还剩两张牌时进行以下操作:把第一张牌扔掉,然后把新的第一张放到整叠牌

的最后。输入n,输出每次扔掉的牌,以及最后剩下的牌

算法竞赛入门经典

https://blog.csdn.net/qingyuanluofeng/article/details/47730663

思路:

设置剪枝数组,凡是扔掉的牌,置剪枝标记为真,循环结束条件为还剩一张牌,有两个循环:报数循环,每次报到的删除,大循环,每次超过7进入下一次循环

关键:如何解决放在末尾的问题?用循环链表,每次放在后面。凡是放在后面,再为它开辟一个数组元素

用链表,找到末尾位置之后,从前向后遍历,如果是新1,则在末尾后加上新1,一直到只剩一个元素位置,采用尾插法

首先建立单链表n

用队列也可以做,前面弹出元素,后面末尾追加元素

 

 

void cardGame(int n,int i)

{

       int m_queue[MAXSIZE];

       int front = 0,rear = n;//关键,模拟队列,设置队首和队尾

       for(int i = 0; i < n;i++)

       {

              m_queue[i] = i+1;

       }

       while(front < rear)

       {

              printf("%d ",m_queue[front++]);

              m_queue[rear++] = m_queue[front++];//这个经典,将队尾累加队守元素,不需要设置剪枝数组

       }

}

12

实现一个优先级队列,支持插入元素和返回最小元素操作

输入:

12(数组元素个数)

19 51 26 40 35 22 17 23 29 15 20 12

输出:

12(最小元素)

编程珠玑

https://blog.csdn.net/qingyuanluofeng/article/details/54670021

分析:优先级队列保证插入和返回最小值元素的时间复杂度都是O(logN),假设有n个元素,每个元素插入在堆中的时间复杂度为O(logN)

      所以堆排序的总时间复杂度为O(NlogN)

优先级队列:说白了就是小顶堆的变体。

 

关键:

1 优先级队列注意使用模板

//优先级队列:包含最大元素个数,支持插入和提起最小元素

template<class T>

class MyPriorityQueue

{

public:

       MyPriorityQueue(int maxSize)

       {

              //需要new出maxSize+1个元素

              _maxSize = maxSize;

              x = new T[_maxSize + 1];

              n = 0;

       }

2 优先级队列保证插入和返回最小值元素的时间复杂度都是O(logN),假设有n个元素,每个元素插入在堆中的时间复杂度为O(logN)

      所以堆排序的总时间复杂度为O(NlogN)

优先级队列:说白了就是小顶堆的变体。

 

 

//优先级队列:包含最大元素个数,支持插入和提起最小元素

template<class T>

class MyPriorityQueue

{

public:

       MyPriorityQueue(int maxSize)

       {

              //需要new出maxSize+1个元素

              _maxSize = maxSize;

              x = new T[_maxSize + 1];

              n = 0;

       }

 

       //析构必须删除指针

       ~MyPriorityQueue()

       {

              delete[] x;

       }

       //插入:先判断元素个数是否已经

       void insert(T t)

       {

              if( n + 1 > _maxSize )

              {

                     cout << "element size greater than " << _maxSize << endl;

                     return;

              }

              x[++n] = t;//留了x[0]不做处理

              int i = n ;

              int p = i / 2;;

              //注意插入元素,是向上调整,如果父节点 > 子节点

              for( ; i > 1 && x[p] >  x[i] ; )

              {

                     swap(p ,i);

                     i = p;

                     p = i/2;

              }

       }

 

       //提取最小元素,只需要获取堆顶元素,然后交换堆顶和最末端元素,然后重新调整除最末端的元素,使其再次成为堆

       T extractMin()

       {

              //如果当前队列为空

              if(isEmpty())

              {

                     throw("PrioorityQueue is empty!");

              }

              T min = x[1];

              x[1] = x[n--];

              int i = 1;

              int c;

              for(i = 1 ; (c = 2 * i) <= n ; i = c)

              {

                     if(c + 1 <= n && x[c+1] < x[c])

                     {

                            c++;

                     }

                     if(x[i] > x[c])

                     {

                            swap(i , c);

                     }

                     else

                     {

                            break;

                     }

              }

              return min;

       }

 

       bool isEmpty()

       {

              return n <= 0 ? true : false;

       }

 

       void swap(int i , int j)

       {

              T temp = x[i];

              x[i] = x[j];

              x[j] = temp;

       }

 

 

private:

       int _maxSize;

       int n;

       T* x;

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考:
[1]计算机考研--机试指南,王道论坛 组编
[2]剑指offer
[3]算法设计与分析
[4]编程之美
[5]程序员面试金典
[6]leecode
[7]Python
程序员面试算法宝典
[8]刘汝佳算法竞赛入门经典
[9]算法导论
[10]编程珠玑

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值