20.有效的括号
检测一段字串序列中的有效括号
栈方法(C++)
-
创建一个栈结构,
- 若是左括号,则入栈
- 若是右括号,则检测栈顶是否是相应左括号
-
细节:
-
检测输入长度,若是0,直接返回true;若长度为奇数,返回false
if(!s.length()) return true; if(s.length%2=1) return false;
-
-
建立散列表(方便检测)
unordered_map<char, char> pairs = { {']','['}, {'}','{'}, {')','('} };
-
检测是否是右括号
if(pairs.count(c))
-
别忘了检测完出栈哦
-
最后检验栈是否为空
return stk.empty();
-
源码(map方法)
class Solution {
public:
bool isValid(string s) {
if(!s.length()) {
return true;
}
unordered_map<char, char> pairs = {
{']','['},
{'}','{'},
{')','('}
};
stack<char> stk;
for(char c: s) {
if(pairs.count(c)) {
if(stk.empty() || stk.top()!=pairs[c]) {
return false;
}
stk.pop();
}
else {
stk.push(c);
}
}
return stk.empty();
}
};
源码(switch方法)
class Solution {
public:
bool isValid(string s) {
if(s.empty()) return true;
if(s.size()%2==1) return false;
stack<char> paren;
for (char& c : s) {
switch (c) {
case '(':
case '{':
case '[': paren.push(c); break;
case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
default: ; // pass
}
}
return paren.empty() ;
}
};
155.最小栈
设计一个可以在 O ( 1 ) O(1) O(1) 时间复杂度内找到栈内最小元素的栈结构
双栈方法
- 再开一个栈,名为最小栈,与数据栈并行操作,不同:
- push时,最小栈只压入当前最小元素
- 两栈一起pop。
- getMin直接去最小栈查询。
-
细节
-
官方题解很憨,最小栈不管什么情况都压入,这样会多出很多重复最小元素,浪费空间
min_stack.push(min(min_stack.top(), x));
-
想节省空间,在push时做一个判断,利用getMin方法与待入元素做比较,节省最小栈的空间
void push(int x) { data_stack.push(x); if(min_stack.empty() || x<=getMin()) min_stack.push(x); }
-
最小栈pop时判断,不pop
void pop() { if(data_stack.top()==getMin()) min_stack.pop(); data_stack.pop(); }
-
双栈法源码
class MinStack {
public:
/** initialize your data structure here. */
// Two Stacks Method
stack<int> data_stack;
stack<int> min_stack;
MinStack() {
min_stack.push(INT_MAX);
}
void push(int x) {
data_stack.push(x);
if(min_stack.empty() || x<=getMin())
min_stack.push(x);
}
void pop() {
if(data_stack.top()==getMin())
min_stack.pop();
data_stack.pop();
}
int top() {
return data_stack.top();
}
int getMin() {
return min_stack.top();
}
};
Pair 法
本方法只用一个栈,但是扩大存入的元素大小
int ----> { int, min_int }
每个元素的second值记录当前最小值
题解来源:fuxuemingzhu
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
if (st.size() == 0) {
st.push({x, x});
} else {
st.push({x, min(x, st.top().second)});
}
}
void pop() {
st.pop();
}
int top() {
return st.top().first;
}
int getMin() {
return st.top().second;
}
private:
stack<pair<int, int>> st;
};
622.设计循环队列 & 641. 设计双向循环队列
循环队列,故名思义,就是头尾相接的数组/链表等基础数据结构 为基础实现的队列结构
链表方法
不如数组的下标可以利用复杂的数关系那样的 tricky
链表法在实现时,是比较容易思考的,因为链表的基本操作完全是是线性的
以下是我个人思考链表题时的过程:(分函数考虑)
细节:
-
注意边界的检查,即插入第一个元素时,控制首尾指针的行为
-
插入顺序:
newnode ->next = temp; rear -> next = head;
源码:
struct LinkedNode {
int val;
LinkedNode *next;
LinkedNode(int val){
val = val;
next = nullptr;
}
};
class MyCircularQueue {
// This implementation is based on Linked List
private:
int size,capacity;
ListNode* head,*rear;
public:
/** Initialize your data structure here. Set the size of the queue to be k. */
MyCircularQueue(int k) {
// the head as a dummy node
size = 0;
head =nullptr;
rear = nullptr;
capacity = k;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
bool enQueue(int value) {
if(!isFull()) {
ListNode* newnode =new ListNode(value),
*temp = head;
if(isEmpty()) {
rear = newnode;
}
head = newnode;
newnode ->next = temp;
rear -> next = head;
size++;
return true;
}
return false;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
bool deQueue() {
if(!isEmpty()) {
ListNode* temp = head;
while(temp->next !=rear) {
temp= temp->next;
}
//kill
temp ->next = head;
rear = temp;
size--;
return true;
}
return false;
}
/** Get the front item from the queue. */
int Front() {
return isEmpty()? -1 : this->rear->val;
}
/** Get the last item from the queue. */
int Rear() {
return isEmpty()? -1 : this->head->val;
}
/** Checks whether the circular queue is empty or not. */
bool isEmpty() {
return size == 0;
}
/** Checks whether the circular queue is full or not. */
bool isFull() {
return size == capacity;
}
};
用链表设计Deque
-
第一次想着:是不是把上面那道题的代码copy过来就行了,然而我过于天真,有以下几点问题:
- 插入第一个元素:要使得头尾指针同时指向一个元素。
if(isEmpty()) { head = newnode; rear = newnode; }
- 删除第一个元素:要恢复头尾指针到空指针:
if(rear == head) { rear = nullptr; head = nullptr; size--; return true; }
- 临时指针到判空(前后插入都要,这里只给出前插入)
bool insertFront(int value) { if(!isFull()) { LinkedNode* newnode = new LinkedNode(value), *temp = head; if(isEmpty()) { head = newnode; rear = newnode; } head = newnode; // 必须判空,不然前插入后插入会使得循环链表断开 if(temp) newnode ->next = temp; rear -> next = head; size++; return true; } }
源码
struct LinkedNode {
int val;
LinkedNode *next;
LinkedNode(int val){
this->val = val;
next = nullptr;
}
};
class MyCircularDeque {
private:
LinkedNode* head,*rear;
int size,capacity;
public:
/** Initialize your data structure here. Set the size of the deque to be k. */
MyCircularDeque(int k) {
head = nullptr;
rear = nullptr;
size = 0;
capacity = k;
}
/** Adds an item at the front of Deque. Return true if the operation is successful. */
bool insertFront(int value) {
if(!isFull()) {
LinkedNode* newnode = new LinkedNode(value),
*temp = head;
if(isEmpty()) {
head = newnode;
rear = newnode;
}
head = newnode;
// 必须判空,不然前插入后插入会使得循环链表断开
if(temp) newnode ->next = temp;
rear -> next = head;
size++;
return true;
}
return false;
}
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
bool insertLast(int value) {
if(!isFull()) {
LinkedNode* newnode =new LinkedNode(value),
*temp = rear;
if(isEmpty()) {
head = newnode;
rear = newnode;
}
rear = newnode;
// 必须判空,不然前插入后插入会使得循环链表断开
if(temp) temp->next = rear;
rear->next = head ;
size++;
return true;
}
return false;
}
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
bool deleteFront() {
if(!isEmpty()) {
if(rear == head) {
rear = nullptr;
head = nullptr;
size--;
return true;
}
head = head -> next;
rear -> next = head;
size--;
return true;
}
return false;
}
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
bool deleteLast() {
if(!isEmpty()) {
LinkedNode* temp = head;
// maintain_rear(rear);
if(rear == head) {
rear = nullptr;
head = nullptr;
size--;
return true;
}
while(temp->next != rear) {
temp = temp->next;
}
//kill
temp ->next = head;
rear = temp;
size--;
return true;
}
return false;
}
/** Get the front item from the deque. */
int getFront() {
return isEmpty()?-1:head->val;
}
/** Get the last item from the deque. */
int getRear() {
return isEmpty()?-1:rear->val;
}
/** Checks whether the circular deque is empty or not. */
bool isEmpty() {
return size == 0;
}
/** Checks whether the circular deque is full or not. */
bool isFull() {
return size == capacity ;
}
};
数组方法(只给出单向循环队列)
图解
源码
class MyCircularQueue {
/*
This is the implementation based on array
*/
private:
int size,head, rear;
int * queue;
public:
/** Initialize your data structure here. Set the size of the queue to be k. */
MyCircularQueue(int k) :size(k+1),head(0),rear(0){
// ***********detail***********
queue = new int[k+1];
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
bool enQueue(int value) {
if(!isFull()){
queue[rear]=value;
rear = (rear+1) % size;
return true;
}
return false;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
bool deQueue() {
if(!isEmpty()) {
head = (head + 1) % size;
return true;
}
return false;
}
/** Get the front item from the queue. */
int Front() {
return isEmpty()?-1:queue[head];
}
/** Get the last item from the queue. */
int Rear() {
// ***********detail***********
return isEmpty()?-1:queue[(rear-1+size)%size];
}
/** Checks whether the circular queue is empty or not. */
bool isEmpty() {
return rear == head;
}
/** Checks whether the circular queue is full or not. */
bool isFull() {
// ***********detail***********
return (rear+1)%size==head;
}
};