(力扣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
数组)来判断。
getNext
函数计算字符串 s
的前缀表。前缀表的每个位置 next[i]
表示字符串 s
的前 i+1
个字符中,最长相同前后缀的长度。len
能被 (len - next[len - 1])
整除,说明字符串可以由长度为 (len - next[len - 1])
的子串重复构成。next[len - 1]
表示整个字符串的最长相同前后缀长度,如果该长度不为零且满足上述条件,则返回 true
,否则返回 false
。false
。代码
#include
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++;
}
// 更新next
next[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;
}
};
(力扣232题)
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回 true
;否则,返回 false
说明:
push to top
, peek/pop from top
, size
, 和 is empty
操作是合法的。示例 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
100
次 push
、pop
、peek
和 empty
pop
或者 peek
操作)进阶:
O(1)
的队列?换句话说,执行 n
个操作的总时间复杂度为 O(n)
,即使其中一个操作可能花费较长时间。解题思路
使用栈来模拟队列的行为,如果仅仅用一个栈,是一定不行的,需要两个栈一个输入栈,一个输出栈,这里要注意输入栈和输出栈的关系
push
操作:直接将元素压入 stIN
栈。pop
操作:如果 stOut
栈为空,将 stIN
栈的所有元素依次弹出并压入 stOut
栈。这样,stOut
栈的栈顶元素就是队列的首元素。然后弹出并返回该元素。peek
操作:与 pop
类似,但需要将弹出的元素重新压入 stOut
栈,以保持队列状态不变。empty
操作:判断两个栈是否都为空,如果都为空,则队列为空。class MyQueue
{
public:
stack stIN;
stack 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();
}
};
(力扣255题)
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回 true
;否则,返回 false
。注意:
push to back
、peek/pop from front
、size
和 is empty
这些操作。示例:
输入:
["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
push
操作:
push
方法一致。pop
和 top
操作:
pop
和 top
操作,需要将队列的最后一个元素(即栈顶元素)移到队列的前面。size-1
个元素依次弹出并重新添加到队列尾部,使得最后一个元素移到队列的前面。pop
操作,弹出并返回队列的队首元素。top
操作,获取队首元素后,再将其重新加回到队列尾部,以保持队列的原始状态。empty
操作:
true
;否则返回 false
。push
操作:
push
方法一致。pop
和 top
操作:
pop
和 top
操作,需要将队列的最后一个元素(即栈顶元素)移到队列的前面。size-1
个元素依次弹出并重新添加到队列尾部,使得最后一个元素移到队列的前面。pop
操作,弹出并返回队列的队首元素。top
操作,获取队首元素后,再将其重新加回到队列尾部,以保持队列的原始状态。empty
操作:
true
;否则返回 false
。代码
#include
#include
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 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();
*/