0%

algorithm

算法学习

算法题

kmp算法

算法导论32.4

算法逻辑

关键点

当模式串的某个字符匹配不上时,就看前面的最长的公共前后缀是哪一段,没有就移动一格,有则前缀移动到后缀上,进而降低时间复杂度,因为这里是最长公共前后缀,所以不用担心中间会有匹配漏掉,这里可能要多想一下。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package chapter32;

/**
* @author zhangyu
* @date 2021/1/8
*/
public class Kmp {
private static char[] s;

private static char[] p;

private static int[] next;

public static void main(String[] args) {
input();
getNext();
printNext();
searchPatternStr();
}

// String str = "abababfefsaababafeffbaababfef";
// String pattern = "abab";
private static void searchPatternStr() {
int tar = 0; // 主串的每个对比的位置
int pos = 0; // 模式串的每个对比的位置
while (tar < s.length) {
if (s[tar] == p[pos]) { // 匹配上了一个字符
tar++;
pos++;
} else if (pos != 0) {
pos = next[pos - 1]; // 没匹配上,模式串回溯
} else {
tar++; // 整个模式串都没匹配上,主串位置加一
}
if (pos == p.length) {
System.out.println("find a match string, the index of position:"+ (tar - pos)); // 匹配到一个模式串
pos = next[pos - 1]; // 模式串移动最长公共前后缀
}
}
}

private static void printNext() {
System.out.print("next array:");
for (int i : next) {
System.out.printf(" %d", i );
}
System.out.println();
}

private static void getNext() {
int i = 1;
int now = 0;
while (i < p.length) {
if (p[i] == p[now]) { // 有公共前后缀
now++;
next[i] = now;
i++;
} else if (now != 0) {
now = next[now - 1]; // 回溯
} else {
next[i] = now; // now为0,无公共前后缀
i++;
}
}
}

private static void input() {
String str = "abababfefsaababafeffbaababfef";
String pattern = "abab";
s = str.toCharArray();
p = pattern.toCharArray();
next = new int[p.length];
}
}

370 区间加法

题目描述

假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k 个更新的操作。

其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndexendIndex](包括 startIndex 和 endIndex)增加 inc

请你返回 k 次操作后的数组。

示例:

输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
输出: [-2,0,3,5,3]
解释:

初始状态:
[0,0,0,0,0]

进行了操作 [1,3,2] 后的状态:
[0,2,2,2,0]

进行了操作 [2,4,3] 后的状态:
[0,2,5,5,3]

进行了操作 [0,2,-2] 后的状态:
[-2,0,3,5,3]

解题思路

差分数组
数组 a[0..n-1] 的差分数组 d[0..n-1],其定义为:

  • 当i=0时,d[0]=a[0]
  • 当i>0时,d[i] = a[i]-a[i-1]
    求差分数组的过程,就是求前缀和数组的逆过程。

差分数组的优势是,对原数组某个区间范围[L,R]内加减同一个数的更新操作,反映到差分数组上,只用更新区间两端(L和R+1位置)的值。
对中间部分的更新操作,由于相邻两项之间相减(求差分)而互相抵消。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int[] getModifiedArray(int length, int[][] updates) {
int[] originalArray = new int[length];
for(int i = 0; i < updates.length; i++) {
int startIndex = updates[i][0];
int endIndex = updates[i][1];
int inc = updates[i][2];
originalArray[startIndex] += inc;
if (endIndex < length - 1) {
originalArray[endIndex + 1] -= inc;
}
}
for(int i = 1; i < length; i++) {
originalArray[i] += originalArray[i -1];
}
return originalArray;
}
}