当前位置: 首页 > news >正文

算法打卡第10天

33 重复的子字符串

(力扣459题)

示例 1:

输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

示例 2:

输入: s = "aba"
输出: false

示例 3:

输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

示例 1:

输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

示例 2:

输入: s = "aba"
输出: false

示例 3:

输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)

提示:

  • 1 <= s.length <= 104
  • s 由小写英文字母组成

解题思路

题目要求判断一个字符串是否可以通过重复其子串来构造。核心思路是利用 KMP 算法中的前缀表(next 数组)来判断。

  1. 计算前缀表
    • 使用 KMP 算法的 getNext 函数计算字符串 s 的前缀表。前缀表的每个位置 next[i] 表示字符串 s 的前 i+1 个字符中,最长相同前后缀的长度。
    • 通过遍历字符串,利用已计算的前缀表值逐步构建完整的前缀表。
  2. 判断重复子串
    • 如果字符串长度 len 能被 (len - next[len - 1]) 整除,说明字符串可以由长度为 (len - next[len - 1]) 的子串重复构成。
    • next[len - 1] 表示整个字符串的最长相同前后缀长度,如果该长度不为零且满足上述条件,则返回 true,否则返回 false
  3. 特殊情况处理
    • 如果字符串为空,直接返回 false

代码

#include <iostream>
using namespace std;class Solution
{
public:// KMP算法void getNext(int *next, const string &s){    // 前缀表next[0] = 0;// 前缀表末尾int j = 0;for(int i = 1; i < s.size(); i++){//前后缀不同while(j > 0 && s[i] != s[j]){// 回退j =  next[j - 1];   }//前后缀相同if(s[i] == s[j]){j++;}//  更新nextnext[i] = j;}}bool   repeatedSubstringPattern(string s){if(s.size() == 0){return 0;}int next[s.size()];getNext(next, s);int len = s.size();if(next[len - 1] != 0 && len % (len - (next[len - 1])) == 0){return true;}return false;}
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

34.用栈实现队列

(力扣232题)

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

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

示例 1:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

解题思路

使用栈来模拟队列的行为,如果仅仅用一个栈,是一定不行的,需要两个栈一个输入栈,一个输出栈,这里要注意输入栈和输出栈的关系

  1. push 操作:直接将元素压入 stIN 栈。
  2. pop 操作:如果 stOut 栈为空,将 stIN 栈的所有元素依次弹出并压入 stOut 栈。这样,stOut 栈的栈顶元素就是队列的首元素。然后弹出并返回该元素。
  3. peek 操作:与 pop 类似,但需要将弹出的元素重新压入 stOut 栈,以保持队列状态不变。
  4. empty 操作:判断两个栈是否都为空,如果都为空,则队列为空。
class MyQueue
{
public:stack<int> stIN;stack<int> stOut;MyQueue(){}// 元素压入stIn栈void push(int x){stIN.push(x);}// 队列前面移除元素并返回该元素int pop(){// 如果输出栈为空if (stOut.empty()){// 将输入栈中的所有元素转移到输出栈while (!stIN.empty()){// 将输入栈的栈顶元素压入输出栈stOut.push(stIN.top());// 弹出输入栈的栈顶元素stIN.pop();}}// 获取输出栈的栈顶元素(即队列的首元素)int result = stOut.top();// 弹出输出栈的栈顶元素stOut.pop();// 返回队列的首元素return result;}int peek(){// 获取队列前面的元素,但不移除他int res = this->pop();//  因为pop函数弹出了元素res,所以再添加回输出栈stOut.push(res);// 返回队列的首元素return res;}// 判断队列是否为空bool empty(){// 当输入栈和输出栈都为空时,队列为空return stIN.empty() && stOut.empty();} 
};
  • 时间复杂度: 都为O(1)。pop和peek看起来像O(n),实际上一个循环n会被使用n次,最后还是O(1)。
  • 空间复杂度: O(n)

35.用队列实现栈

(力扣255题)

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
  • 解题思路

    1. push 操作
      • 直接将元素压入队列的末尾。这个操作与队列的 push 方法一致。
    2. poptop 操作
      • 为了模拟栈的 poptop 操作,需要将队列的最后一个元素(即栈顶元素)移到队列的前面。
      • 通过将队列的前 size-1 个元素依次弹出并重新添加到队列尾部,使得最后一个元素移到队列的前面。
      • 对于 pop 操作,弹出并返回队列的队首元素。
      • 对于 top 操作,获取队首元素后,再将其重新加回到队列尾部,以保持队列的原始状态。
    3. empty 操作
      • 直接检查队列是否为空。如果队列为空,返回 true;否则返回 false
  1. push 操作
    • 直接将元素压入队列的末尾。这个操作与队列的 push 方法一致。
  2. poptop 操作
    • 为了模拟栈的 poptop 操作,需要将队列的最后一个元素(即栈顶元素)移到队列的前面。
    • 通过将队列的前 size-1 个元素依次弹出并重新添加到队列尾部,使得最后一个元素移到队列的前面。
    • 对于 pop 操作,弹出并返回队列的队首元素。
    • 对于 top 操作,获取队首元素后,再将其重新加回到队列尾部,以保持队列的原始状态。
  3. empty 操作
    • 直接检查队列是否为空。如果队列为空,返回 true;否则返回 false

代码

#include <iostream>
#include <queue>
using namespace std;
/*请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。*/
class MyStack
{
public:queue<int> que;MyStack(){}// 将元素 x 推到队列的末尾void push(int x){que.push(x);}// 移除并返回栈顶元素int pop(){int size = que.size();size--;// 将队列头部的元素(除了最后一个元素外) 弹出再重新添加到队列尾部while (size--){que.push(que.front());que.pop();}// 此时弹出的元素顺序就是栈的顺序了int result = que.front();que.pop();return result;}// 返回栈顶元素。int top(){int size = que.size();size--;// 将队列头部的元素(除了最后一个元素外) 弹出再重新添加到队列尾部while(size--){que.push(que.front());que.pop();}// 此时弹出的元素顺序就是栈的顺序了int result = que.front();//将获取完的元素也重新添加到队列尾部,保证数据结构没有变化que.push(que.front());que.pop();return result;}//如果栈是空的,返回 true ;否则,返回 false bool empty(){return que.empty();}
};/*** Your MyStack object will be instantiated and called as such:* MyStack* obj = new MyStack();* obj->push(x);* int param_2 = obj->pop();* int param_3 = obj->top();* bool param_4 = obj->empty();*/
  • 时间复杂度: pop为O(n),top为O(n),其他为O(1)
  • 空间复杂度: O(n)
http://www.xdnf.cn/news/705565.html

相关文章:

  • Linux `cp` 命令深度解析与高阶应用指南
  • dify 配置访问前缀
  • WPF 按钮点击音效实现
  • 性能优化深度实践:突破vue应用性能
  • C# 打印PDF的常用方法
  • JS入门——JS引入方式
  • Qt Creator调用Python代码
  • 微信小程序(uniapp)实现腾讯云 IM 消息撤回
  • 本地部署消息代理软件 RabbitMQ 并实现外部访问( Windows 版本 )
  • stm32cube ide如何生成LL库工程
  • 云原生时代 Kafka 深度实践:02快速上手与环境搭建
  • 公司数据不泄露,DeepSeek R1本地化部署+web端访问+个人知识库搭建与使用
  • Git的三种合并方式
  • LVS+Keepalived 高可用群集
  • 第二章 1.7 数据采集安全风险防范之数据质量管理
  • 一文清晰理解目标检测指标计算
  • 无人机桥梁3D建模的拍摄频率
  • 异步上传石墨文件进度条前端展示记录(采用Redis中List数据结构实现)
  • 俄罗斯无人机自主任务规划!UAV-CodeAgents:基于多智能体ReAct和视觉语言推理的可扩展无人机任务规划
  • Flink
  • 云原生与DevOps融合实践:加速企业数字化转型的加速器
  • 2024长春全国邀请赛CCPC
  • Next.js路由导航完全指南
  • TCP/IP四层模型
  • 如何用AI设计海报,DeepSeek+即梦免费批量生成
  • 通义灵码2.5——基于MCP打造我的12306火车票智能查询小助手
  • LVS+Keepalived 高可用
  • 【前端】Hexo一键生成目录插件推荐_放入Hexo博客
  • lesson04-简单回归案例实战(理论+代码)
  • C#·常用快捷键