类型:栈 难度 困难
思路:对于(1+(4+5+2)-3)+(6+8)这样一个式子,只有加减两种,所以借鉴了大神的思路,判断扫描到的字符,如果是左括号,则表示开启新的一波计算,将之前的计算结果和左括号前的运算度也入栈,如果是右括号,则表示这一波的计算结束了,这时候需要将之前存的运算符出栈,把之前的结果也出栈,和当前的结果进行计算,
res*=stack.top(); stack.pop(); res+=stack.top();stack.pop();
类型:堆,优先队列 难度 困难
思路:用c++中的priority_queue 创建两个优先队列去模拟堆,一个小顶堆small_queue用来存储数据中较大的一半,一个大顶堆big_queue用来存储数据中较大的一半,然后 small_queue.top() > big_queue.top(),但是还需要保证一点,由于求的是中位数,所以small_queue.size() 和 big_queue.size() 要么相等,要么相差一
如果相等的话,直接输出 两个队列 top 的平均值,否则的话,哪个队列的size更大就输出谁的 top ,在 插入 过程中,需要调整两个队列的size,让尺寸保持上面的标准
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
small_queue.push(num);
big_queue.push(small_queue.top());
small_queue.pop();
if (small_queue.size() < big_queue.size()) {
small_queue.push(big_queue.top());
big_queue.pop();
}
}
double findMedian() {
int size = big_queue.size() + small_queue.size();
return size % 2 == 1 ? small_queue.top() : (small_queue.top() + big_queue.top()) / 2.0;
}
private:
//保证小顶堆的堆顶>大顶堆堆顶,且两个堆size一样或者小.size() = 大.size()+1
priority_queue<int, vector<int>, greater<int>> big_queue; //小顶堆
priority_queue<int, vector<int>, less<int>> small_queue;//大顶堆
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
类型:栈 队列 难度 简单
思路:两个栈 s1 s2,用s1模拟入队,出队的时候,进行判断,如果两个栈都为空,返回-1,如果s2为空,则把s1的元素都出栈然后入栈到s2中,如果s2不为空,则直接输出s2.top()
类型:栈 难度 中等 88.62% 100%
思路:计算函数的独占时间,思路类似于最简答的括号匹配,不过需要对时间进行简单的计算,设计两个数据结构,一个vectorres存储最后结果,一个stack
class Solution {
public:
vector<int> exclusiveTime(int n, vector<string>& logs) {
vector<int> res(n,0);
for(auto &log:logs)
{
int index1 = log.find(':',0);
int index2 = log.rfind(':');
int fun_id = atoi(log.substr(0,index1).c_str());
string status = log.substr(index1+1, index2-index1-1);
int time = atoi(log.substr(index2+1).c_str());
if(status == "start")
{
s.push(make_pair(fun_id, time));
}else if(status == "end")
{
int st_time = s.top().second;
int index = s.top().first;
s.pop();
int run_time = time - st_time + 1;
res[index] += run_time;
if(!s.empty())
{
res[s.top().first] -= run_time;
}
}
}
return res;
}
private:
stack<pair<int, int>> s;
};
类型:栈 难度 中等
思路:要求 i 类型:栈 难度 中等 思路:首先不可能把解码后的字符串都展开,因为可能会特别长,所以我们需要计算每一步展开后的长度 long long curLength,比如 lee2code3 ,如果当前扫描到是字母的话,就把curLength++,如果是数字的话,就把当前长度乘上这个数字,如果当前长度 >= K,就结束遍历,后面的字符我们就没必要关注了 然后开始计算最后结果,如果最后是因为乘了数字导致的>=K,则首先curLength要除以这个数字,也就是去掉复印件,得到原件,然后K也需要对curLength取模,因为比如说 3*2>5, 相当于是把3复制了两倍,比5大,实际对应的就是原件的第二个, 如果最后不是因为乘了数字,就需要一步一步往前退,知道退到了上面K取模之后的值 类型:堆 难度 中等 82.72% 33.33% 思路:进行分情况讨论,如果是当前栈顶和扫描到的数字符号相同,则直接把扫描到的数字入栈,如果栈顶是负数,扫描到的是正数,则也是直接入栈,上述两种情况均不会发生碰撞 可能发生碰撞的情况是,栈顶是一个正数,扫描到的是一个负号,这时候需要判断如果负数的绝对值大则需要出栈,继续重复上述流程,如果正数绝对值更大,则直接扫描下一个数字 这里附上耗时最短的大佬的想法,处理思路一致,用数组代替栈,思路更加巧妙 类型:栈 难度 中等 100% 100% (我也不知道为什么有点繁琐的代码能双百,挺离谱的,应该是正常的波动范围?) 思路:见代码注释 另一种递归范例,处理思路一致 类型:小顶堆 难度 中等 类型 队列 难度 中等 说实话,这个简单题我没搞懂题目是什么意思,虽然它很简单 类型: 队列 难度:中等 99.85% 36ms 100% 15.5MB 双指针法,一个正常遍历,一个标记非0元素该插入的位置 思路与上一题类似,两个指针 中等class Solution {
public:
bool find132pattern(vector<int>& nums) {
if(nums.size()<3) return false;
stack<int> max;
int n=nums.size();
int third=INT_MIN;//初始化不能为0,因为要进行比较,初始化为0会出错。
for(int i=n-1;i>=0;i--)
{
if(nums[i]<third) return true;
while(!max.empty() && nums[i]>max.top())//若找到比栈中还大的元素,则更新
{
third=max.top();
max.pop();
}
max.push(nums[i]);
}
return false;
}
};
880 索引处的解码字符串
class Solution {
public:
string decodeAtIndex(string S, int K) {
long long curLength=0;
int index=0;
for(auto s:S)
{
if(isdigit(s))
{
curLength *=(s-'0');
}
else
{
curLength++;
}
if(curLength >= K)
break;
index++;
}
for(int i=index;i>=0;i--)
{
if(isdigit(S[i]))
{
curLength/=(S[i]-'0');
K%=curLength;
}
else
{
if(K%curLength == 0)
{
string res(1,S[i]);
return res;
}
curLength--;
}
}
return "";
}
};
735 行星碰撞
class Solution {
public:
bool sameAbs(int a, int b)
{
if(a<0 && b<0)
return true;
else if(a>0 && b>0)
return true;
else
return false;
}
vector<int> asteroidCollision(vector<int>& asteroids) {
for(auto asteroid:asteroids)
{
M:if(st.empty())
st.push(asteroid);
else if(sameAbs(asteroid, st.top())) //同号
st.push(asteroid);
else if(asteroid > 0 && st.top() < 0) //- +
st.push(asteroid);
else // +-
{
if(abs(asteroid) > abs(st.top())) // - > +
{
st.pop();
goto M;
}
else if(abs(asteroid) == abs(st.top())) //- = +
{
st.pop();
continue;
}
else
continue;
}
}
vector<int> res(st.size(), 0);
int size = st.size()-1;
for(int i=size;i>=0;i--)
{
res[i] = st.top();
st.pop();
}
return res;
}
private:
stack<int> st;
};
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asteroids) {
int len = asteroids.size();
int stack[len];
int top = 0;
int i = 0;
while(i < len){
if (top == 0){
stack[top] = asteroids[i];
top++;
i++;
}else if(asteroids[i] * stack[top-1] >0 || (asteroids[i]>0&&stack[top-1]<0)){
stack[top] = asteroids[i];
top++;
i++;
}else{
if(abs(stack[top-1]) > abs(asteroids[i])){
i++;
continue;
}else if (abs(stack[top-1]) == abs(asteroids[i])){{
top--;
i++;
}
}else if (abs(stack[top-1]) < abs(asteroids[i])){
top--;
}
}
}
vector<int>res;
for (int i = 0; i < top; i++){
res.push_back(stack[i]);
}
return res;
}
};
394 字符串解码
class Solution {
public:
string decodeString(string s) {
int i=0,num=0;
bool noNum=true;
for(;i<s.size();i++)
{
//遇到数字需要确定到底需要重复几次,如果是100[a]这种,不能直接把1入栈,而应该一直扫描到左括号才行
if(isdigit(s[i]))
{
if(s[i+1] == '[')
{ num=num*10 + (s[i]-'0');
stNum.push(num);
num=0;
}
else
num=num*10 + (s[i]-'0');
noNum=false;
}
//之前没有数字或数字被处理完了
if(noNum)
{
res+=s[i];
}
//有数字说明 之后会出现字母和括号
else if(!noNum)
{
if(s[i] == '[')
stBor.push(s[i]);
else if(s[i] == ']')
{
/*
有右括号的话,需要把左括号之前的元素出栈,存入temp
由于是栈,所以实际的顺序需要反过来,这里借用了temp_2进行翻转
翻转过后根据数字进行重复,再入栈
再入栈是为了处理 3[a2[bc]] 这种情况
如果不再入栈,而是直接加入结果,最后的结果就成了 bcbcaaa
所以需要把bcbc再入栈,栈中为 [abcbc,再扫描到右括号就继续上面相同的操作
结束的依据是,如果数字栈为空,表示当前扫描到的数字都处理完了
此时出栈并加入结果字符串中
扫描过程中遇到了字母,直接入栈就行
*/
while(stBor.top()!='[')
{
temp+=stBor.top();
stBor.pop();
}
stBor.pop();
temp_2 = string(temp.rbegin(), temp.rend());
int time = stNum.top();
stNum.pop();
for(int j=0;j<time;j++) //根据数字进行重复
{
for(int k=0;k<temp_2.size();k++)
{
stBor.push(temp_2[k]); //在入栈主要是为了处理括号套括号的情况
}
}
temp = string();
temp_2 = string();
//数字栈为空,表示目前扫描到的数字都处理完毕了,拼入结果字符串中
if(stNum.empty())
{
noNum=true;
int size = stBor.size();
for(int j=0;j<size;j++)
{
temp+=stBor.top();
stBor.pop();
}
temp_2 = string(temp.rbegin(), temp.rend());
res+=temp_2;
}
temp = string();
temp_2 = string();
}
else if(isalpha(s[i]))
{
stBor.push(s[i]);
}
}
}
return res;
}
private:
string temp;
string temp_2;
string res;
stack<int> stNum;
stack<char> stBor;
};
class Solution {
public:
// 递归实现
string dfs(const string &s, int &i) {
string res = "";
int num = 0;
for (; i < s.size(); i++) {
char c = s[i];
if (c >= '0' && c <= '9') {
num = num * 10 + (c - '0');
} else if (c == '[') {
string tmp1 = "";
string tmp2 = dfs(s, ++i);
while (num > 0) {
tmp1 += tmp2;
num--;
}
res += tmp1;
} else if (c == ']') {
return res;
} else {
res += c;
}
}
return res;
}
string decodeString(string s) {
int i = 0;
return dfs(s, i);
}
};
215 TOP K
思路:维护一个size为K的小顶堆class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
for(int i=0;i<nums.size();i++)
{
if(myQue.size() < k)
myQue.push(nums[i]);
else if(myQue.top() < nums[i]){
myQue.pop();
myQue.push(nums[i]);
}
}
return myQue.top();
}
private:
priority_queue<int, vector<int>, greater<int>> myQue;
};
641 设计循环双端队列
思路:我觉得这应该是个简单题,用双向循环链表去模拟一下,链表增删这不是基本功吗我寻思class MyCircularDeque {
public:
/** Initialize your data structure here. Set the size of the deque to be k. */
int size=0,maxsize=0;
struct LNode{
int data;
LNode *next;
LNode *pre;
LNode() : data(-1), next(NULL), pre(NULL) {}
LNode(int v) : data(v), next(NULL), pre(NULL) {}
};
LNode *head;
LNode *tail;
MyCircularDeque(int k) {
maxsize=k;
head = new LNode();
tail = new LNode();
head->next = tail;
head->pre = tail;
tail->next = head;
tail->pre = head;
}
/** Adds an item at the front of Deque. Return true if the operation is successful. */
bool insertFront(int value) {
if(isFull())
return false;
struct LNode * node = new LNode(value);
node->pre = head;
head->next->pre = node;
node->next = head->next;
head->next = node;
++size;
return true;
}
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
bool insertLast(int value) {
if(isFull())
return false;
struct LNode *node = new LNode(value);
node->pre = tail->pre;
tail->pre = node;
node->pre->next = node;
node->next = tail;
++size;
return true;
}
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
bool deleteFront() {
if(isEmpty())
return false;
struct LNode * node = head->next;
struct LNode * node2 = head->next->next;
head->next = node2;
node2->pre = head;
delete(node);
--size;
return true;
}
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
bool deleteLast() {
if(isEmpty())
return false;
struct LNode* node = tail->pre;
struct LNode * node_2 = tail->pre->pre;
tail->pre = node_2;
node_2->next = tail;
delete(node);
--size;
return true;
}
/** Get the front item from the deque. */
int getFront() {
if(isEmpty())
return -1;
return head->next->data;
}
/** Get the last item from the deque. */
int getRear() {
if(isEmpty())
return -1;
return tail->pre->data;
}
/** 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==maxsize;
}
};
/**
* Your MyCircularDeque object will be instantiated and called as such:
* MyCircularDeque* obj = new MyCircularDeque(k);
* bool param_1 = obj->insertFront(value);
* bool param_2 = obj->insertLast(value);
* bool param_3 = obj->deleteFront();
* bool param_4 = obj->deleteLast();
* int param_5 = obj->getFront();
* int param_6 = obj->getRear();
* bool param_7 = obj->isEmpty();
* bool param_8 = obj->isFull();
*/
933最近的请求次数
class RecentCounter {
public:
RecentCounter() {}
int ping(int t) {
que.push(t);
while (que.front() < t - 3000)
que.pop();
return que.size();
}
private:
queue<int>que;
};
622 设计循环队列
思路:用数组模拟一个循环队列,牺牲一个存储单元作为判断队满的条件,(rear+1)%maxsize==front
然后获取队尾元素时需要注意一点,因为rear比实际的最后一个元素更靠后,所以需要判断一下,如果rear为0,则rear-1就越界了,所以需要判断一下,如不不越界,直接输出rear-1处的值,否则输出maxsize-1处的class MyCircularQueue {
public:
/** Initialize your data structure here. Set the size of the queue to be k. */
int *que;
int rear=0,front=0;
int maxsize=0;
MyCircularQueue(int k) {
que = new int[k+1];
maxsize=k+1;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
bool enQueue(int value) {
if(isFull())
return false;
que[rear] = value;
rear=(rear+1)%maxsize;
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
bool deQueue() {
if(isEmpty())
return false;
front=(front+1)%maxsize;
return true;
}
/** Get the front item from the queue. */
int Front() {
if(isEmpty())
return -1;
return que[front];
}
/** Get the last item from the queue. */
int Rear() {
if(isEmpty())
return -1;
int index = rear-1;
if(index<0)
index = maxsize-1;
return que[index];
}
/** Checks whether the circular queue is empty or not. */
bool isEmpty() {
return rear==front;
}
/** Checks whether the circular queue is full or not. */
bool isFull() {
return (rear+1)%maxsize==front;
}
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue* obj = new MyCircularQueue(k);
* bool param_1 = obj->enQueue(value);
* bool param_2 = obj->deQueue();
* int param_3 = obj->Front();
* int param_4 = obj->Rear();
* bool param_5 = obj->isEmpty();
* bool param_6 = obj->isFull();
*/
26 删除排序树组中的重复项
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int j = 0;
if(nums.empty()) return 0;
for(int i = 1;i<nums.size();i++)
{
if(nums[j] != nums[i])
{
nums[++j] = nums[i];
}
}
return j+1;
}
};
283移动0问题
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j=0;
for(int i=0;i<nums.size();i++)
{
if(nums[i] != 0)
{
nums[j] = nums[i];
if(i!=j) //avoid nums.size() == 0
nums[i]=0;
j++;
}
}
}
};
11 盛最多水的容器
首先会选取数组的边界,然后如果把两边中较低的一边往中间挪动,容器的宽度减少,但是容器的高度可能会增加,如果把两边中较高的一边往中间挪动,容器的宽度减少,但是容器的高度最起码不会增加,因为容器的高度取决于较低的一边class Solution {
public:
int maxArea(vector<int>& height) {
int left=0, right=height.size()-1, maxsize = 0;
while(left < right)
{
maxsize = max(maxsize, min(height[left], height[right]) * (right - left));
if(height[left] < height[right])
left++;
else
right--;
}
return maxsize;
}
};