2.算法之栈、队列、堆

STL stack(栈)

stack<int> s;
s.top();//取出栈顶
s.empty();//判断栈是否为空
s.push(x);//将x添加至栈
s.pop();//弹出栈顶
s.size();//栈的存储元素个数

225. 用队列实现栈

使用队列实现栈的下列操作:
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
注意:
你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

思路:适用另外临时双端队列来完成插在尾端,先插入临时双端队列,在将原来队列逆序插入,最后逆序移出,此时负负得正。

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        queue<int> temp_queue;
        temp_queue.push(x);
        while(!_data.empty())
        {
            temp_queue.push(_data.front());
            _data.pop();
        }
        while(!temp_queue.empty())
        {
            _data.push(temp_queue.front());
            temp_queue.pop();
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int x=_data.front();
        _data.pop();
        return x;
    }
    
    /** Get the top element. */
    int top() {
        return _data.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return _data.empty();
    }
    
private:
    queue<int> _data;
};

232. 用栈实现队列

使用栈实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
示例:
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:

你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        stack<int> temp_stack;
        while(!_data.empty())
        {
            temp_stack.push(_data.top());
            _data.pop();
        }
        _data.push(x);
        while(!temp_stack.empty())
        {
            _data.push(temp_stack.top());
            temp_stack.pop();
        }
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
       int x=_data.top();
        _data.pop();
        return x;
    }
    
    /** Get the front element. */
    int peek() {
        return _data.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return _data.empty();
    }
private:
    stack<int> _data;
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * bool param_4 = obj.empty();
 */

155. 最小栈

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
在这里插入图片描述
在这里插入图片描述

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        _data.push(x);
        if(_min.empty())
        {
            _min.push(x);
        }else
        {
            if(x>_min.top())
                x=_min.top();
            _min.push(x);
        }
    }
    
    void pop() {
        _data.pop();
        _min.pop();
    }
    
    int top() {
       return _data.top(); 
    }
    
    int getMin() {
        return _min.top();
    }
    
    stack<int> _data;
    stack<int> _min;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

02-线性结构4 Pop Sequence (25 分)

Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, …, N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.
Input Specification:
Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.
Output Specification:
For each pop sequence, print in one line “YES” if it is indeed a possible pop sequence of the stack, or “NO” if not.
Sample Input:
5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2
Sample Output:
YES
NO
NO
YES
NO

给定一个最多可以保留M个数字的堆栈。按1,2,3,…,N的顺序按N个数字并随机弹出。您应该判断给定的数字序列是否是堆栈的可能弹出序列。例如,如果M是5且N是7,我们可以从堆栈中获得1,2,3,4,5,6,7,但不能获得3,2,1,7,5,6,4。
输入规格:
每个输入文件包含一个测试用例。对于每种情况,第一行包含3个数字(全部不超过1000):M(堆栈的最大容量),N(推送序列的长度)和K(要检查的弹出序列的数量)。然后是K行,每行包含一个N个数字的弹出序列。一行中的所有数字都用空格分隔。

思路:入栈就是一段时间后就可以出栈了,所以出栈序列中的每个数后面的比它小的数,是按递减排列的。
判断标准:出栈序列中,元素i之后所有比i小的元素间必须是降序排列的
例如:126345是正确的,而126453是错误的,首先判断1,2是递增的序列,直到序列6,4,4<6且6-4>1,则需要判断6前面的序列中是否有6-4-1=1个在范围(4,6)的元素(即元素5),若有,则合法,若无,则不合法,显然126453是不合法的。
举个例子,124539867:
1,2:递增正确,由于1-2-1=-2<0,序列大小为0;
2,4:递增正确,由于2-4-1=-3<0,序列大小为0;
4,5:递增正确,由于4-5-1=-2<0,序列大小为0;
5,3:由于5-3-1=1>0,因此需要判断5前面的序列中是否存在5-3-1=1个在范围(3,5)的元素(即元素4),显然存在,正确,序列大小+2;
3,9:递增正确,且序列大小为0;
9,8:递减正确,由于9-8-1=0,不需要判断,序列大小+1;
8,6::减少,判断8前面的序列,是否存在8-6-1=1个在范围(6,8)即元素7,显然不存在,则该出栈序列不合法。

举一个例子:
栈的大小为5,出栈序列为654321,设栈的大小为n
6,5:正确,序列大小+1 (n=1)
5,4:正确,序列大小+1 (n=2)
4,3:正确,序列大小+1 (n=3)
3,2:正确,序列大小+1 (n=4)
2,1:正确,序列大小+1 (n=5)
1:正确,栈的大小+1 (n=6)
n>5,则说明该出栈序列是不合法的,超过了栈的大小。(该方法是由逐渐减少的元素个数判断,这些元素就是出栈的元素个数,一旦这些逐渐减少的元素个数超过栈的大小,说明原本存入栈内的元素的个数大于栈的大小,不合法)

#include <iostream>
using namespace std;

bool isCorrect[1000];
int stack[1000];
int seq[1000];

void Judge(int* seq, int stack_num, int seq_len, int seq_index)
{
	int stack_cur=0;
	int pre = seq[0];
	for (int i = 1; i < seq_len; i++)
	{
		if (pre<seq[i])
		{
			pre = seq[i];
			stack_cur = 0;
		}
		else
		{
			if (pre-seq[i]==1)
			{
				pre = seq[i];
				stack_cur++;//栈中的元素加1
			}
			else
			{
				stack_cur++;
				int flag = pre - seq[i]-1;
				for (int j = 0; j < i; j++)
				{
					if (seq[j]<pre&&seq[j]>seq[i])
					{
						flag--;
					}
				}
				if (flag!=0)
				{
					isCorrect[seq_index] = false;
					return;
				}
				pre = seq[i];
			}
		}

		if (seq_len!=stack_num&&stack_cur >= stack_num)
		{
			isCorrect[seq_index] = false;
			return;
		}
	}
	if (seq_len != stack_num && stack_cur >= stack_num)
	{
		isCorrect[seq_index] = false;
		return;
	}
	isCorrect[seq_index] = true;
}

int main()
{
	int stack_num, seq_len, seq_num;
	cin >> stack_num >> seq_len >> seq_num;

	for (int i = 0; i < seq_num; i++)
	{
		for (int j = 0; j < seq_len; j++)
		{
			cin >> seq[j];
		}
		Judge(seq, stack_num, seq_len, i);
	}

	for (int i = 0; i < seq_num; i++)
	{
		switch (isCorrect[i])
		{
		case true:
			cout << "YES";
			break;
		case false:
			cout << "NO" ;
			break;
		}
		
		if (i<seq_num-1)
		{
			cout << endl;
		}
	}
}

224. 基本计算器

实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
示例 1:
输入: “1 + 1”
输出: 2
示例 2:
输入: " 2-1 + 2 "
输出: 3
示例 3:
输入: “(1+(4+5+2)-3)+(6+8)”
输出: 23
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
在这里插入图片描述
栈可以去掉括号,可以处理优先级
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

二叉堆

最大堆的堆顶最大,最小堆的堆顶最小。
在这里插入图片描述

std::priority_queue<int> big_heap;//默认构造最大堆
std::priority_queue<int,std::vector<int>,std::greater<int>> small_heap;//构造最小堆
std::priority_queue<int,std::vector<int>,std::less<int>> big_heap2;//构造最大堆

215. 数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
在这里插入图片描述

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int> > Q;
        for(int i=0;i<nums.size();i++)
        {
            if(Q.size()<k)
                Q.push(nums[i]);
            else if(Q.size()>=k&&nums[i]>Q.top())
            {
                Q.pop();
                Q.push(nums[i]);
            }
        }
        return Q.top();
    }
};

295. 数据流的中位数

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:
如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
在这里插入图片描述巧用堆的性质:动态维护一个最大堆和一个最小堆,最大堆存储一半数据,最小堆存储一半数据,并且最大堆的堆顶比最小堆的堆顶小。维持两个堆的元素个数的差的绝对值小于等于1,最大堆的堆顶小于等于最小堆的堆顶(即最小堆的所有元素比最大堆的所有元素要大)

情况1:最大堆和最小堆的元素个数相同时,判断最大堆和最小堆的堆顶元素与新元素,并push。
情况2:最大堆比最小堆多一个元素,
①新元素小于最大堆堆顶,将最大堆的堆顶push进入最小堆,然后pop移除最大堆堆顶,将新元素添加至最大堆。
②新元素大于最大堆堆顶,将新元素直接push进入最小堆。
在这里插入图片描述
情况3:最小堆比最大堆多一个元素,
①新元素小于最小堆堆顶,直接push最小堆
②新元素大于最小堆堆顶,将最小堆堆顶push最大堆,pop最小堆移出堆顶,将新元素添加至最小堆

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        if(big_queue.empty())
        {
            big_queue.push(num);
            return;
        }
        if(big_queue.size()==small_queue.size())
        {
            if(num< big_queue.top())
                big_queue.push(num);
            else{
                small_queue.push(num);
            }
        }
        else if(big_queue.size()>small_queue.size())
        {
            if(num>big_queue.top())
            {
                small_queue.push(num);
            }
            else{
                small_queue.push(big_queue.top());
                big_queue.pop();
                big_queue.push(num);
                
            }
        }else if(big_queue.size()<small_queue.size())
        {
             if(num<small_queue.top())
            {
                big_queue.push(num);
            }
            else{
                big_queue.push(small_queue.top());
                small_queue.pop();
                small_queue.push(num);
            }
        }
    }
    
    double findMedian() {
        if(small_queue.size()==big_queue.size())
        {
            return (big_queue.top()+small_queue.top())/2;
        }
        else if(big_queue.size()>small_queue.size()){            
            return big_queue.top();
        }
            return small_queue.top();
    }
    priority_queue<double,vector<double>,greater<double> > small_queue;
    priority_queue<double,vector<double>,less<double> > big_queue;
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值