实现一个Tire
实现一个Tire,用来求前缀和★★★
用栈实现队列
用队列实现栈
最小值栈
用栈实现括号匹配
数组中元素与下一个比它大的元素之间的距离★★
循环数组中比当前元素大的下一个元素
Tire : 又称前缀树或字典树,是用于快速检索的多叉树结构,利用字符串公共前缀来节约存储空间。
Tire树的基本性质:
1,根节点不包含字符,除根节点以外每个节点只包含一个字符
2,从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串
3,每个节点所有子节点包含的字符串不相同
简单实现:对每个节点开一个字母集大小的数组,下标是字母,内容是在数组中的索引
1. 实现一个Tire(208)
思路:
每个节点都定义一个大小为26的子节点指针数组,然后用一个标识符用来记录到当前位置位置是否一个词。初始化的时候将26个子节点都赋为空。那么insert操作只需要对于要插入的字符串的每一个字符算出位置,然后找是否存在这个子节点,若不存在则新建一个,然后再查找下一个。如果是查找前缀的话不需要看标识符有就true,查找完整词的话就需要标识符信息
1,
2,
代码
class Trie {
Trie *child[26];
bool isWord;
public:
/** Initialize your data structure here. */
Trie() {
isWord = false;
for(int i=0; i<26; ++i)
{
child[i] = nullptr;
}
}
/** Inserts a word into the trie. */
void insert(string word) {
//TireNode *p = new TireNode();
Trie *p = this;
for(auto &a:word)
{
int i = a-'a';
if(!p->child[i])
{
p->child[i] = new Trie();
}
p = p->child[i];
}
p->isWord = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie *p = this;
for(auto &a :word)
{
int i = a-'a';
if(!p->child[i]) return false;//这就返回了不会再走下面了
p = p->child[i];
}
return p->isWord;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie *p = this;
for(auto &a :prefix)
{
int i = a-'a';
if(!p->child[i]) return false;
p = p->child[i];
}
return true;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/
问题:
决定今天就开始把第一二季看完,每一个基础都不能落呀不然做题太纠结在基础语法上太浪费时间了
2. 实现一个Tire,用来求前缀和(677)
思路
再看吧……
代码
接下来是 栈和队列 的题目 第八天
3. 用栈实现队列(232)
思路:
用栈的先进后出特性来模拟队列的先进先出特性,只要将栈中元素按照队列中元素排列就ok,即在新push元素的时候把元素放到后面,这样其他的操作如取第一个元素之类的就正常取栈元素好了
要push元素的时候,先将原栈中的元素们放到一个临时栈中,将元素压入空栈中,再将寄放在临时栈中的元素放回去
代码
class MyQueue {
stack<int> st;
public:
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
stack<int> tmp;
while(!st.empty())
{
tmp.push(st.top());
st.pop();
}//先将原来的放到tmp中
st.push(x);//把要push进去的数放到空栈中,再tmp中的元素再放来,要push进去的数就变成最后一个了根队列一样了
while(!tmp.empty())
{
st.push(tmp.top());tmp.pop();
}
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
int val = st.top(); st.pop();
return val;
}
/** Get the front element. */
int peek() {
return st.top();
}
/** Returns whether the queue is empty. */
bool empty() {
return st.empty();
}
};
4. 用队列实现栈(225)
思路
和用栈实现队列一样思路,但是队列可以不用辅助队列,因为可以直接加到队尾
代码
class MyStack {
public:
queue<int> q;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
q.push(x);
for(int i = 0; i<(int)q.size()-1; ++i)
{
q.push(q.front());
q.pop();
}
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int x = q.front();
q.pop();
return x;
}
/** Get the top element. */
int top() {
return q.front();
}
/** Returns whether the stack is empty. */
bool empty() {
return q.empty();
}
};
5. 最小值栈(155)
对于实现最小值队列问题,可以先将队列使用栈来实现,然后将问题转换为最小值栈
思路
一个栈按顺序存储push进来的数据,另一个用来存出现过的最小值
主要是在出栈入栈的时候要注意对比辅助栈中栈顶元素和当前处理值得关系,如果压入一个更小的栈,就也压入辅助栈中,弹栈的时候如果弹出的是当前栈顶元素就也给弹出去
代码
class MinStack {
stack<int> s1, s2;
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
s1.push(x);
if(s2.empty() ||x<= s2.top())//为空这个情况不要忘了
{
s2.push(x);
}
}
void pop() {//弹出的时候看看是不是弹出的最小值
if(s1.top() == s2.top())
{
s2.pop();
}
s1.pop();
}
int top() {
return s1.top();
}
int getMin() {
return s2.top();
}
};
6. 用栈实现括号匹配(20)
思路
将左括号压栈,出现右括号时区看栈中有没有 栈顶元素是不是对应的左括号,没有 不是就直接返回false,否则就取出,注意边界条件,比如栈为空的情况
代码
class Solution {
stack<char> lp;
public:
bool isValid(string s) {
if(s.size()==0) return true;
for(char a : s)
{
if(a =='('|| a=='{'||a=='[')
{
lp.push(a);
}
else{
if(lp.empty()) return false;
if(a==')' && lp.top()!= '(') return false;
if(a=='}' && lp.top()!= '{') return false;
if(a==']' &&lp.top()!= '[') return false;
lp.pop();
}
}
return lp.empty();
}
};
7. 数组中元素与下一个比它大的元素之间的距离(739)![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/67581cf8c45c7aefe04189eb511206bc.png)
思路
递减栈,遍历数组,如果当前数字小于等于栈顶元素就将数字入栈,如果当前数字大于栈顶元素那就取出栈顶元素并且当前数字就是第一个大于栈顶元素的数,直接求两者下标就是两者距离
要解决的问题:下标,一个元素找到最近的较大值后就会被弹出,差值是等于现在点的坐标减去栈顶元素的坐标,并且差值要存入结果集中,那也不是顺序存入的呀,这个下标又是怎么解决的,当前的点就是循环的i然后……
===>栈中存入的不是值而是数组中的下标
代码
//1先定义一个结果, 初始化一个栈,开始递减栈的操作,当前值比栈顶元素小就压栈否则就取出值,差值就是结果存入结果集,压栈的是元素的下标
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
int n = T.size();
vector<int> res(n,0);
stack<int> st;
for(int i = 0; i<n;++i)
{
while(!st.empty() && T[i] > T[st.top()])
{
auto t = st.top();//取出这个值的下标
st.pop();
res[t] = i-t;//厉害
}
st.push(i);//是将索引存入
}
return res;
}
};
8. 循环数组中比当前元素大的下一个元素(503)
是上一题的follow up,next greater number是第一个比它大的数字,题中第二个1的结果是循环得到的,就是说某一个元素的下一个较大值可以是前面的值。那么对于循环数组的遍历,为了不超过数组的长度,我们需要对n取余
思路
1,暴力:遍历每一个数字,对每一个数字再次遍历所以其他数字,遇到较大值就存入res中
注意:避免越界,要对索引取余数,for(int j = i+1; j<i+n; ++j
、if(nums[j % n]>nums[i]) res[i] = nums[j % n]
2, 用栈优化:遍历两边数组
代码
//基础操作,定义一个结果集,获取元素个数,对每一个数字进行遍历
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> res(n,-1);//没有较大值就返回-1所以初始化为-1
for(int i = 0; i<n; ++i)
{
for(int j = i+1; j<i+n;++j)//下一个更大,所以遍历要从下一个开始,但是不是到尾就结束,而是要到当前数字的前一个,注意用取余用法
{
if(nums[j % n] > nums[i])
{
res[i] = nums[j%n];
break;//到下一个i
}
}
}
return res;
}
};
//遍历两遍元素
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> res(n,-1);
stack<int> st;
for(int i = 0; i<2*n; ++i)
{
int num = nums[i%n];
while(!st.empty() && nums[st.top()]<num)
{
res[st.top()] = num;
st.pop();
}
if(i<n) st.push(i);//压入栈的元素都是要有一个返回值的,所以已经压入栈的元素不能再入栈了,超过n的部分只是为了比较
}
return res;
}
};
随手笔记:今天结束有点早,把明天的力扣题整理好了,晚上决定看第一季(结束)第二季开始,有精力就把双指针看完。看完这第二季和双指针视频之后(不断往前复习like dfs bfs )再看看dp吧……可以先看起来……总是期待可以在家再待一个月啧啧,