diff --git a/src/class32/Code01_IndexTree.java b/src/class32/Code01_IndexTree.java new file mode 100644 index 0000000..f7d5eca --- /dev/null +++ b/src/class32/Code01_IndexTree.java @@ -0,0 +1,77 @@ +package class32; + +public class Code01_IndexTree { + + public static class IndexTree { + + private int[] tree; + private int N; + + public IndexTree(int size) { + N = size; + tree = new int[N + 1]; + } + + public int sum(int index) { + int ret = 0; + while (index > 0) { + ret += tree[index]; + index -= index & -index; + } + return ret; + } + + public void add(int index, int d) { + while (index <= N) { + tree[index] += d; + index += index & -index; + } + } + } + + public static class Right { + private int[] nums; + private int N; + + public Right(int size) { + N = size + 1; + nums = new int[N + 1]; + } + + public int sum(int index) { + int ret = 0; + for (int i = 1; i <= index; i++) { + ret += nums[i]; + } + return ret; + } + + public void add(int index, int d) { + nums[index] += d; + } + + } + + public static void main(String[] args) { + int N = 100; + int V = 100; + int testTime = 2000000; + IndexTree tree = new IndexTree(N); + Right test = new Right(N); + System.out.println("test begin"); + for (int i = 0; i < testTime; i++) { + int index = (int) (Math.random() * N) + 1; + if (Math.random() <= 0.5) { + int add = (int) (Math.random() * V); + tree.add(index, add); + test.add(index, add); + } else { + if (tree.sum(index) != test.sum(index)) { + System.out.println("Oops!"); + } + } + } + System.out.println("test finish"); + } + +} diff --git a/src/class32/Code02_IndexTree2D.java b/src/class32/Code02_IndexTree2D.java new file mode 100644 index 0000000..12bb6e2 --- /dev/null +++ b/src/class32/Code02_IndexTree2D.java @@ -0,0 +1,57 @@ +package class32; + +// 测试链接:https://leetcode.com/problems/range-sum-query-2d-mutable +// 但这个题是付费题目 +// 提交时把类名、构造函数名从Code02_IndexTree2D改成NumMatrix +public class Code02_IndexTree2D { + private int[][] tree; + private int[][] nums; + private int N; + private int M; + + public Code02_IndexTree2D(int[][] matrix) { + if (matrix.length == 0 || matrix[0].length == 0) { + return; + } + N = matrix.length; + M = matrix[0].length; + tree = new int[N + 1][M + 1]; + nums = new int[N][M]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < M; j++) { + update(i, j, matrix[i][j]); + } + } + } + + private int sum(int row, int col) { + int sum = 0; + for (int i = row + 1; i > 0; i -= i & (-i)) { + for (int j = col + 1; j > 0; j -= j & (-j)) { + sum += tree[i][j]; + } + } + return sum; + } + + public void update(int row, int col, int val) { + if (N == 0 || M == 0) { + return; + } + int add = val - nums[row][col]; + nums[row][col] = val; + for (int i = row + 1; i <= N; i += i & (-i)) { + for (int j = col + 1; j <= M; j += j & (-j)) { + tree[i][j] += add; + } + } + } + + public int sumRegion(int row1, int col1, int row2, int col2) { + if (N == 0 || M == 0) { + return 0; + } + return sum(row2, col2) + sum(row1 - 1, col1 - 1) - sum(row1 - 1, col2) - sum(row2, col1 - 1); + } + +} diff --git a/src/class32/Code03_AC1.java b/src/class32/Code03_AC1.java new file mode 100644 index 0000000..a6874e5 --- /dev/null +++ b/src/class32/Code03_AC1.java @@ -0,0 +1,105 @@ +package class32; + +import java.util.LinkedList; +import java.util.Queue; + +public class Code03_AC1 { + + public static class Node { + public int end; // 有多少个字符串以该节点结尾 + public Node fail; + public Node[] nexts; + + public Node() { + end = 0; + fail = null; + nexts = new Node[26]; + } + } + + public static class ACAutomation { + private Node root; + + public ACAutomation() { + root = new Node(); + } + + // 你有多少个匹配串,就调用多少次insert + public void insert(String s) { + char[] str = s.toCharArray(); + Node cur = root; + int index = 0; + for (int i = 0; i < str.length; i++) { + index = str[i] - 'a'; + if (cur.nexts[index] == null) { + Node next = new Node(); + cur.nexts[index] = next; + } + cur = cur.nexts[index]; + } + cur.end++; + } + + public void build() { + Queue queue = new LinkedList<>(); + queue.add(root); + Node cur = null; + Node cfail = null; + while (!queue.isEmpty()) { + cur = queue.poll(); // 父 + for (int i = 0; i < 26; i++) { // 下级所有的路 + if (cur.nexts[i] != null) { // 该路下有子节点 + cur.nexts[i].fail = root; // 初始时先设置一个值 + cfail = cur.fail; + while (cfail != null) { // cur不是头节点 + if (cfail.nexts[i] != null) { + cur.nexts[i].fail = cfail.nexts[i]; + break; + } + cfail = cfail.fail; + } + queue.add(cur.nexts[i]); + } + } + } + } + + public int containNum(String content) { + char[] str = content.toCharArray(); + Node cur = root; + Node follow = null; + int index = 0; + int ans = 0; + for (int i = 0; i < str.length; i++) { + index = str[i] - 'a'; + while (cur.nexts[index] == null && cur != root) { + cur = cur.fail; + } + cur = cur.nexts[index] != null ? cur.nexts[index] : root; + follow = cur; + while (follow != root) { + if (follow.end == -1) { + break; + } + { // 不同的需求,在这一段{ }之间修改 + ans += follow.end; + follow.end = -1; + } // 不同的需求,在这一段{ }之间修改 + follow = follow.fail; + } + } + return ans; + } + + } + + public static void main(String[] args) { + ACAutomation ac = new ACAutomation(); + ac.insert("dhe"); + ac.insert("he"); + ac.insert("c"); + ac.build(); + System.out.println(ac.containNum("cdhe")); + } + +} diff --git a/src/class32/Code04_AC2.java b/src/class32/Code04_AC2.java new file mode 100644 index 0000000..fc915bc --- /dev/null +++ b/src/class32/Code04_AC2.java @@ -0,0 +1,126 @@ +package class32; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class Code04_AC2 { + + // 前缀树的节点 + public static class Node { + // 如果一个node,end为空,不是结尾 + // 如果end不为空,表示这个点是某个字符串的结尾,end的值就是这个字符串 + public String end; + // 只有在上面的end变量不为空的时候,endUse才有意义 + // 表示,这个字符串之前有没有加入过答案 + public boolean endUse; + public Node fail; + public Node[] nexts; + public Node() { + endUse = false; + end = null; + fail = null; + nexts = new Node[26]; + } + } + + public static class ACAutomation { + private Node root; + + public ACAutomation() { + root = new Node(); + } + + public void insert(String s) { + char[] str = s.toCharArray(); + Node cur = root; + int index = 0; + for (int i = 0; i < str.length; i++) { + index = str[i] - 'a'; + if (cur.nexts[index] == null) { + Node next = new Node(); + cur.nexts[index] = next; + } + cur = cur.nexts[index]; + } + cur.end = s; + } + + public void build() { + Queue queue = new LinkedList<>(); + queue.add(root); + Node cur = null; + Node cfail = null; + while (!queue.isEmpty()) { + // 当前节点弹出, + // 当前节点的所有后代加入到队列里去, + // 当前节点给它的子去设置fail指针 + // cur -> 父亲 + cur = queue.poll(); + for (int i = 0; i < 26; i++) { // 所有的路 + if (cur.nexts[i] != null) { // 找到所有有效的路 + cur.nexts[i].fail = root; // + cfail = cur.fail; + while (cfail != null) { + if (cfail.nexts[i] != null) { + cur.nexts[i].fail = cfail.nexts[i]; + break; + } + cfail = cfail.fail; + } + queue.add(cur.nexts[i]); + } + } + } + } + + public List containWords(String content) { + char[] str = content.toCharArray(); + Node cur = root; + Node follow = null; + int index = 0; + List ans = new ArrayList<>(); + for (int i = 0; i < str.length; i++) { + index = str[i] - 'a'; // 路 + // 如果当前字符在这条路上没配出来,就随着fail方向走向下条路径 + while (cur.nexts[index] == null && cur != root) { + cur = cur.fail; + } + // 1) 现在来到的路径,是可以继续匹配的 + // 2) 现在来到的节点,就是前缀树的根节点 + cur = cur.nexts[index] != null ? cur.nexts[index] : root; + follow = cur; + while (follow != root) { + if(follow.endUse) { + break; + } + // 不同的需求,在这一段之间修改 + if (follow.end != null) { + ans.add(follow.end); + follow.endUse = true; + } + // 不同的需求,在这一段之间修改 + follow = follow.fail; + } + } + return ans; + } + + } + + public static void main(String[] args) { + ACAutomation ac = new ACAutomation(); + ac.insert("dhe"); + ac.insert("he"); + ac.insert("abcdheks"); + // 设置fail指针 + ac.build(); + + List contains = ac.containWords("abcdhekskdjfafhasldkflskdjhwqaeruv"); + for (String word : contains) { + System.out.println(word); + } + } + +}