28. 找出字符串中第一个匹配项的下标(KMP算法)
文章链接:代码随想录 (programmercarl.com)
思路:KMP算法
(1)需要注意的是在定义next数组函数时,cn有两种含义,其一表示哪个位置的字符与i - 1 位置的字符相比较,其二表示最长公共前后缀
(2)要获取i位置的最长公共前后缀就需要看i - 1位置
Java代码:(看注释!!!)
class Solution {
public int strStr(String haystack, String needle) {
char[] hay = haystack.toCharArray();
char[] nee = needle.toCharArray();
//获取要匹配字符串的next数组
int[] next = getNextArr(nee);
//开始使用KMP算法进行匹配
int i = 0;
int j = 0;
while(i < hay.length && j < nee.length){
//两个字符匹配的上
if(hay[i] == nee[j]){
i++;
j++;
}
//没有匹配的上,此时就要开始通过next数组跳位置了
else if(next[j] == -1){//表示此时j指针已经跳不了,匹配不上,i要动一动了
i++;
}
else{//j指针可以跳
j = next[j];
}
}
//当j越界时,说明nee已经匹配好了,此时一开始的索引位置就是i位置减去长度
return j == nee.length ? i - j: -1;
}
//定义求得next数组的函数
private int[] getNextArr(char[] ch){
//先判断特殊情况
if(ch.length == 1){
return new int[] {-1};
}
int[] next = new int[ch.length];
//人为规定
next[0] = -1;
next[1] = 0;
//此时开始计算i的最长公共前后缀长度,i从2开始
int i = 2;
//cn表示从哪个位置跟i - 1开始比较,要想获取next[i],就要看i - 1 和 cn
//此外cn还表示最长公共前后缀的长度
int cn = 0;
while(i < ch.length){
if(ch[i - 1] == ch[cn]){
next[i] = cn + 1;
i++;
//此处cn也要++,因为比较完成后,接下来就要求i + 1了,此时就要看i位置
cn++;
}
//没对的上,那么让cn继续往前跳,继续比较
else if(cn > 0){
cn = next[cn];
}
//没对的上,并且cn不能跳了
else{
next[i] = 0;
i++;
}
}
return next;
}
}
459.重复的子字符串
文章链接:代码随想录 (programmercarl.com)
思路:
(1)思路一,使用移动匹配,如果一个非空字符串s可以通过由它的一个子串重复多次构成,那么 s + s 组成的新字符串的中间位置一定能找到s,注意遍历s + s 时,要去除首尾位置,然后开始遍历
(2)思路二,使用KMP,题目转换为在s + s 中 是否能找到 s
巩固的知识:
(1)string.indexOf(str):返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
Java代码:使用移动匹配
class Solution {
public boolean repeatedSubstringPattern(String s) {
if(s.length() == 0 || s.equals("")){
return false;
}
String ns = s + s;
StringBuilder sb = new StringBuilder();
//去除首尾位置
for(int i = 1; i < ns.length() - 1;i++){
sb.append(ns.charAt(i));
}
//去除了首尾字符的字符串
String news = new String(sb);
//找是否有s
return news.indexOf(s) != -1 ? true : false;
}
}
232.用栈实现队列(二刷仍然卡顿)
文章链接:代码随想录 (programmercarl.com)
思路:
(1)栈是先入后出,队列是先入先出,因此要想用栈实现队列,需要两个栈(in栈和out栈),in栈负责将元素压入到栈然后弹出顶部元素给out栈;out栈负责弹出,此时out栈弹出元素的顺序就跟队列是一致的了
(2)此时in栈和out栈两个整体相当于就是队列
实现代码遇到的问题:
(1)在定义empty()时,应该是in和out均为空的时候才是true,因为n栈和out栈两个整体相当于就是队列
(2)在push函数部分,想复杂了,直接push到in栈就行了
Java代码:
class MyQueue {
Stack<Integer> in;
Stack<Integer> out;
public MyQueue() {
//在构造器里先初始化栈,in栈负责将元素压入in栈然后弹出顶部元素给out栈,out栈负责将元素弹出(out栈相当于是队列)
in = new Stack<>();
out = new Stack<>();
}
public void push(int x) {
//out栈相当于就是队列
//相当于是向队列添加元素
in.push(x);
}
public int pop() {
//out栈相当于就是队列
//相当于是返回队列的开头元素
if(out.isEmpty()){
inToOut();
}
return out.pop();
}
public int peek() {
if(out.isEmpty()) inToOut();
return out.peek();
}
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
//用来将in栈里的全部元素移动到out栈里面
private void inToOut(){
if(in.isEmpty()) return;
while(!in.isEmpty()){
out.push(in.pop());
}
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
225.用队列实现栈(二刷仍然卡顿)
文章链接:代码随想录 (programmercarl.com)
思路:也是需要两个队列来实现栈,唯一不同的地方在于
(1)队列用的是offer和poll,分别是加入和弹出元素的方法
(2)push()函数里,在que2每次添加完元素后,都要将que1的元素加入到que2,然后再俩俩交换que1和que2
(3)当时就思考为什么在实现pop()函数时不判断是否为空,理由如下:队列接口的poll()方法返回并移除容器前面的元素。它删除容器中的元素。当Queue为空时,该方法不会引发异常,而是返回null
(4)单个队列思路就是在push时,每次都重新对队列里的数进行排序,确保新加入的数永远在队列首
Java代码:(两个队列)(看代码注释!!!)
class MyStack {
//栈是先入后出
Queue<Integer> queue1;//和栈中保持一致的队列
Queue<Integer> queue2;//辅助的队列
public MyStack() {
//在构造器里初始化两个队列
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
public void push(int x) {
queue2.offer(x);
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
public int pop() {
//不需要判断是否为空,poll()会返回null,不会报错
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.isEmpty();
}
}
/**
* 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();
* boolean param_4 = obj.empty();
*/
Java代码:单个队列
class MyStack {
Queue<Integer> que;
public MyStack() {
que = new LinkedList<>();
}
public void push(int x) {
que.offer(x);
int size = que.size();
while(size > 1){
que.offer(que.poll());
size--;
}
}
public int pop() {
return que.poll();
}
public int top() {
return que.peek();
}
public boolean empty() {
return que.isEmpty();
}
}
/**
* 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();
* boolean param_4 = obj.empty();
*/