diff --git a/src/class24/Code01_SlidingWindowMaxArray.java b/src/class24/Code01_SlidingWindowMaxArray.java index 071eba7..d115951 100644 --- a/src/class24/Code01_SlidingWindowMaxArray.java +++ b/src/class24/Code01_SlidingWindowMaxArray.java @@ -9,11 +9,12 @@ public class Code01_SlidingWindowMaxArray { if (arr == null || w < 1 || arr.length < w) { return null; } - int[] res = new int[arr.length - w + 1]; + int N = arr.length; + int[] res = new int[N - w + 1]; int index = 0; int L = 0; int R = w - 1; - while (R < arr.length) { + while (R < N) { int max = arr[L]; for (int i = L + 1; i <= R; i++) { max = Math.max(max, arr[i]); @@ -30,6 +31,8 @@ public class Code01_SlidingWindowMaxArray { if (arr == null || w < 1 || arr.length < w) { return null; } + // qmax 窗口最大值的更新结构 + // 放下标 LinkedList qmax = new LinkedList(); int[] res = new int[arr.length - w + 1]; int index = 0; diff --git a/src/class24/Code04_MinCoinsOnePaper.java b/src/class24/Code04_MinCoinsOnePaper.java index a0a73b8..cfda95a 100644 --- a/src/class24/Code04_MinCoinsOnePaper.java +++ b/src/class24/Code04_MinCoinsOnePaper.java @@ -110,10 +110,8 @@ public class Code04_MinCoinsOnePaper { return dp[0][aim]; } - // 这种解法课上不讲 - // 因为需要理解窗口内最小值的更新结构 - // 后面的课会讲 // dp3时间复杂度为:O(arr长度) + O(货币种数 * aim) + // 优化需要用到窗口内最小值的更新结构 public static int dp3(int[] arr, int aim) { if (aim == 0) { return 0; @@ -132,6 +130,8 @@ public class Code04_MinCoinsOnePaper { // 因为用了窗口内最小值的更新结构 for (int i = N - 1; i >= 0; i--) { for (int mod = 0; mod < Math.min(aim + 1, c[i]); mod++) { + // 当前面值 X + // mod mod + x mod + 2*x mod + 3 * x LinkedList w = new LinkedList<>(); w.add(mod); dp[i][mod] = dp[i + 1][mod]; @@ -244,7 +244,7 @@ public class Code04_MinCoinsOnePaper { System.out.println("当货币很少出现重复,dp2比dp3有常数时间优势"); System.out.println("当货币大量出现重复,dp3时间复杂度明显优于dp2"); - System.out.println("dp3的讲解放在窗口内最大值或最小值的更新结构里"); + System.out.println("dp3的优化用到了窗口内最小值的更新结构"); } } diff --git a/src/class26/Code01_FibonacciProblem.java b/src/class26/Code01_FibonacciProblem.java new file mode 100644 index 0000000..e2376e5 --- /dev/null +++ b/src/class26/Code01_FibonacciProblem.java @@ -0,0 +1,186 @@ +package class26; + +public class Code01_FibonacciProblem { + + public static int f1(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return 1; + } + return f1(n - 1) + f1(n - 2); + } + + public static int f2(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return 1; + } + int res = 1; + int pre = 1; + int tmp = 0; + for (int i = 3; i <= n; i++) { + tmp = res; + res = res + pre; + pre = tmp; + } + return res; + } + + public static int f3(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return 1; + } + // [ 1 ,1 ] + // [ 1, 0 ] + int[][] base = { + { 1, 1 }, + { 1, 0 } + }; + int[][] res = matrixPower(base, n - 2); + return res[0][0] + res[1][0]; + } + + public static int[][] matrixPower(int[][] m, int p) { + int[][] res = new int[m.length][m[0].length]; + for (int i = 0; i < res.length; i++) { + res[i][i] = 1; + } + + // res = 矩阵中的1 + int[][] tmp = m;// 矩阵1次方 + for (; p != 0; p >>= 1) { + if ((p & 1) != 0) { + res = muliMatrix(res, tmp); + } + tmp = muliMatrix(tmp, tmp); + } + return res; + } + + // 两个矩阵乘完之后的结果返回 + public static int[][] muliMatrix(int[][] m1, int[][] m2) { + int[][] res = new int[m1.length][m2[0].length]; + for (int i = 0; i < m1.length; i++) { + for (int j = 0; j < m2[0].length; j++) { + for (int k = 0; k < m2.length; k++) { + res[i][j] += m1[i][k] * m2[k][j]; + } + } + } + return res; + } + + public static int s1(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return n; + } + return s1(n - 1) + s1(n - 2); + } + + public static int s2(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return n; + } + int res = 2; + int pre = 1; + int tmp = 0; + for (int i = 3; i <= n; i++) { + tmp = res; + res = res + pre; + pre = tmp; + } + return res; + } + + public static int s3(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return n; + } + int[][] base = { { 1, 1 }, { 1, 0 } }; + int[][] res = matrixPower(base, n - 2); + return 2 * res[0][0] + res[1][0]; + } + + public static int c1(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2 || n == 3) { + return n; + } + return c1(n - 1) + c1(n - 3); + } + + public static int c2(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2 || n == 3) { + return n; + } + int res = 3; + int pre = 2; + int prepre = 1; + int tmp1 = 0; + int tmp2 = 0; + for (int i = 4; i <= n; i++) { + tmp1 = res; + tmp2 = pre; + res = res + prepre; + pre = tmp1; + prepre = tmp2; + } + return res; + } + + public static int c3(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2 || n == 3) { + return n; + } + int[][] base = { + { 1, 1, 0 }, + { 0, 0, 1 }, + { 1, 0, 0 } }; + int[][] res = matrixPower(base, n - 3); + return 3 * res[0][0] + 2 * res[1][0] + res[2][0]; + } + + public static void main(String[] args) { + int n = 19; + System.out.println(f1(n)); + System.out.println(f2(n)); + System.out.println(f3(n)); + System.out.println("==="); + + System.out.println(s1(n)); + System.out.println(s2(n)); + System.out.println(s3(n)); + System.out.println("==="); + + System.out.println(c1(n)); + System.out.println(c2(n)); + System.out.println(c3(n)); + System.out.println("==="); + + } + +} diff --git a/src/class26/Code02_ZeroLeftOneStringNumber.java b/src/class26/Code02_ZeroLeftOneStringNumber.java new file mode 100644 index 0000000..00ca6fc --- /dev/null +++ b/src/class26/Code02_ZeroLeftOneStringNumber.java @@ -0,0 +1,109 @@ +package class26; + +public class Code02_ZeroLeftOneStringNumber { + + public static int getNum1(int n) { + if (n < 1) { + return 0; + } + return process(1, n); + } + + public static int process(int i, int n) { + if (i == n - 1) { + return 2; + } + if (i == n) { + return 1; + } + return process(i + 1, n) + process(i + 2, n); + } + + public static int getNum2(int n) { + if (n < 1) { + return 0; + } + if (n == 1) { + return 1; + } + int pre = 1; + int cur = 1; + int tmp = 0; + for (int i = 2; i < n + 1; i++) { + tmp = cur; + cur += pre; + pre = tmp; + } + return cur; + } + + public static int getNum3(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return n; + } + int[][] base = { { 1, 1 }, { 1, 0 } }; + int[][] res = matrixPower(base, n - 2); + return 2 * res[0][0] + res[1][0]; + } + + + + + + + public static int fi(int n) { + if (n < 1) { + return 0; + } + if (n == 1 || n == 2) { + return 1; + } + int[][] base = { { 1, 1 }, + { 1, 0 } }; + int[][] res = matrixPower(base, n - 2); + return res[0][0] + res[1][0]; + } + + + + + public static int[][] matrixPower(int[][] m, int p) { + int[][] res = new int[m.length][m[0].length]; + for (int i = 0; i < res.length; i++) { + res[i][i] = 1; + } + int[][] tmp = m; + for (; p != 0; p >>= 1) { + if ((p & 1) != 0) { + res = muliMatrix(res, tmp); + } + tmp = muliMatrix(tmp, tmp); + } + return res; + } + + public static int[][] muliMatrix(int[][] m1, int[][] m2) { + int[][] res = new int[m1.length][m2[0].length]; + for (int i = 0; i < m1.length; i++) { + for (int j = 0; j < m2[0].length; j++) { + for (int k = 0; k < m2.length; k++) { + res[i][j] += m1[i][k] * m2[k][j]; + } + } + } + return res; + } + + public static void main(String[] args) { + for (int i = 0; i != 20; i++) { + System.out.println(getNum1(i)); + System.out.println(getNum2(i)); + System.out.println(getNum3(i)); + System.out.println("==================="); + } + + } +} diff --git a/src/class27/Code01_FindMinKth.java b/src/class27/Code01_FindMinKth.java new file mode 100644 index 0000000..2ca14b7 --- /dev/null +++ b/src/class27/Code01_FindMinKth.java @@ -0,0 +1,174 @@ +package class27; + +import java.util.Comparator; +import java.util.PriorityQueue; + +public class Code01_FindMinKth { + + public static class MaxHeapComparator implements Comparator { + + @Override + public int compare(Integer o1, Integer o2) { + return o2 - o1; + } + + } + + // 利用大根堆,时间复杂度O(N*logK) + public static int minKth1(int[] arr, int k) { + PriorityQueue maxHeap = new PriorityQueue<>(new MaxHeapComparator()); + for (int i = 0; i < k; i++) { + maxHeap.add(arr[i]); + } + for (int i = k; i < arr.length; i++) { + if (arr[i] < maxHeap.peek()) { + maxHeap.poll(); + maxHeap.add(arr[i]); + } + } + return maxHeap.peek(); + } + + // 改写快排,时间复杂度O(N) + public static int minKth2(int[] array, int k) { + int[] arr = copyArray(array); + return process2(arr, 0, arr.length - 1, k - 1); + } + + public static int[] copyArray(int[] arr) { + int[] ans = new int[arr.length]; + for (int i = 0; i != ans.length; i++) { + ans[i] = arr[i]; + } + return ans; + } + + // arr 第k小的数 + // process2(arr, 0, N-1, k-1) + // arr[L..R] 范围上,如果排序的话(不是真的去排序),找位于index的数 + // index [L..R] + public static int process2(int[] arr, int L, int R, int index) { + if (L == R) { // L = =R ==INDEX + return arr[L]; + } + // 不止一个数 L + [0, R -L] + int pivot = arr[L + (int) (Math.random() * (R - L + 1))]; + + // range[0] range[1] + // L ..... R pivot + // 0 1000 70...800 + int[] range = partition(arr, L, R, pivot); + if (index >= range[0] && index <= range[1]) { + return arr[index]; + } else if (index < range[0]) { + return process2(arr, L, range[0] - 1, index); + } else { + return process2(arr, range[1] + 1, R, index); + } + } + + public static int[] partition(int[] arr, int L, int R, int pivot) { + int less = L - 1; + int more = R + 1; + int cur = L; + while (cur < more) { + if (arr[cur] < pivot) { + swap(arr, ++less, cur++); + } else if (arr[cur] > pivot) { + swap(arr, cur, --more); + } else { + cur++; + } + } + return new int[] { less + 1, more - 1 }; + } + + public static void swap(int[] arr, int i1, int i2) { + int tmp = arr[i1]; + arr[i1] = arr[i2]; + arr[i2] = tmp; + } + + // 利用bfprt算法,时间复杂度O(N) + public static int minKth3(int[] array, int k) { + int[] arr = copyArray(array); + return bfprt(arr, 0, arr.length - 1, k - 1); + } + + // arr[L..R] 如果排序的话,位于index位置的数,是什么,返回 + public static int bfprt(int[] arr, int L, int R, int index) { + if (L == R) { + return arr[L]; + } + int pivot = medianOfMedians(arr, L, R); + int[] range = partition(arr, L, R, pivot); + if (index >= range[0] && index <= range[1]) { + return arr[index]; + } else if (index < range[0]) { + return bfprt(arr, L, range[0] - 1, index); + } else { + return bfprt(arr, range[1] + 1, R, index); + } + } + + // arr[L...R] 五个数一组 + // 每个小组内部排序 + // 每个小组中位数领出来,组成marr + // marr中的中位数,返回 + public static int medianOfMedians(int[] arr, int L, int R) { + int size = R - L + 1; + int offset = size % 5 == 0 ? 0 : 1; + int[] mArr = new int[size / 5 + offset]; + for (int team = 0; team < mArr.length; team++) { + int teamFirst = L + team * 5; + // L ... L + 4 + // L +5 ... L +9 + // L +10....L+14 + mArr[team] = getMedian(arr, teamFirst, Math.min(R, teamFirst + 4)); + } + // marr中,找到中位数 + // marr(0, marr.len - 1, mArr.length / 2 ) + return bfprt(mArr, 0, mArr.length - 1, mArr.length / 2); + } + + public static int getMedian(int[] arr, int L, int R) { + insertionSort(arr, L, R); + return arr[(L + R) / 2]; + } + + public static void insertionSort(int[] arr, int L, int R) { + for (int i = L + 1; i <= R; i++) { + for (int j = i - 1; j >= L && arr[j] > arr[j + 1]; j--) { + swap(arr, j, j + 1); + } + } + } + + // for test + public static int[] generateRandomArray(int maxSize, int maxValue) { + int[] arr = new int[(int) (Math.random() * maxSize) + 1]; + for (int i = 0; i < arr.length; i++) { + arr[i] = (int) (Math.random() * (maxValue + 1)); + } + return arr; + } + + public static void main(String[] args) { + int testTime = 1000000; + int maxSize = 100; + int maxValue = 100; + System.out.println("test begin"); + for (int i = 0; i < testTime; i++) { + int[] arr = generateRandomArray(maxSize, maxValue); + int k = (int) (Math.random() * arr.length) + 1; + int ans1 = minKth1(arr, k); + int ans2 = minKth2(arr, k); + int ans3 = minKth3(arr, k); + if (ans1 != ans2 || ans2 != ans3) { + System.out.println("Oops!"); + } + } + System.out.println("test finish"); + } + +} diff --git a/src/class27/Code02_MaxTopK.java b/src/class27/Code02_MaxTopK.java new file mode 100644 index 0000000..87746c8 --- /dev/null +++ b/src/class27/Code02_MaxTopK.java @@ -0,0 +1,223 @@ +package class27; + +import java.util.Arrays; + +public class Code02_MaxTopK { + + // 时间复杂度O(N*logN) + // 排序+收集 + public static int[] maxTopK1(int[] arr, int k) { + if (arr == null || arr.length == 0) { + return new int[0]; + } + int N = arr.length; + k = Math.min(N, k); + Arrays.sort(arr); + int[] ans = new int[k]; + for (int i = N - 1, j = 0; j < k; i--, j++) { + ans[j] = arr[i]; + } + return ans; + } + + // 方法二,时间复杂度O(N + K*logN) + // 解释:堆 + public static int[] maxTopK2(int[] arr, int k) { + if (arr == null || arr.length == 0) { + return new int[0]; + } + int N = arr.length; + k = Math.min(N, k); + // 从底向上建堆,时间复杂度O(N) + for (int i = N - 1; i >= 0; i--) { + heapify(arr, i, N); + } + // 只把前K个数放在arr末尾,然后收集,O(K*logN) + int heapSize = N; + swap(arr, 0, --heapSize); + int count = 1; + while (heapSize > 0 && count < k) { + heapify(arr, 0, heapSize); + swap(arr, 0, --heapSize); + count++; + } + int[] ans = new int[k]; + for (int i = N - 1, j = 0; j < k; i--, j++) { + ans[j] = arr[i]; + } + return ans; + } + + public static void heapInsert(int[] arr, int index) { + while (arr[index] > arr[(index - 1) / 2]) { + swap(arr, index, (index - 1) / 2); + index = (index - 1) / 2; + } + } + + public static void heapify(int[] arr, int index, int heapSize) { + int left = index * 2 + 1; + while (left < heapSize) { + int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left; + largest = arr[largest] > arr[index] ? largest : index; + if (largest == index) { + break; + } + swap(arr, largest, index); + index = largest; + left = index * 2 + 1; + } + } + + public static void swap(int[] arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + // 方法三,时间复杂度O(n + k * logk) + public static int[] maxTopK3(int[] arr, int k) { + if (arr == null || arr.length == 0) { + return new int[0]; + } + int N = arr.length; + k = Math.min(N, k); + // O(N) + int num = minKth(arr, N - k); + int[] ans = new int[k]; + int index = 0; + for (int i = 0; i < N; i++) { + if (arr[i] > num) { + ans[index++] = arr[i]; + } + } + for (; index < k; index++) { + ans[index] = num; + } + // O(k*logk) + Arrays.sort(ans); + for (int L = 0, R = k - 1; L < R; L++, R--) { + swap(ans, L, R); + } + return ans; + } + + // 时间复杂度O(N) + public static int minKth(int[] arr, int index) { + int L = 0; + int R = arr.length - 1; + int pivot = 0; + int[] range = null; + while (L < R) { + pivot = arr[L + (int) (Math.random() * (R - L + 1))]; + range = partition(arr, L, R, pivot); + if (index < range[0]) { + R = range[0] - 1; + } else if (index > range[1]) { + L = range[1] + 1; + } else { + return pivot; + } + } + return arr[L]; + } + + public static int[] partition(int[] arr, int L, int R, int pivot) { + int less = L - 1; + int more = R + 1; + int cur = L; + while (cur < more) { + if (arr[cur] < pivot) { + swap(arr, ++less, cur++); + } else if (arr[cur] > pivot) { + swap(arr, cur, --more); + } else { + cur++; + } + } + return new int[] { less + 1, more - 1 }; + } + + // for test + public static int[] generateRandomArray(int maxSize, int maxValue) { + int[] arr = new int[(int) ((maxSize + 1) * Math.random())]; + for (int i = 0; i < arr.length; i++) { + // [-? , +?] + arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random()); + } + return arr; + } + + // for test + public static int[] copyArray(int[] arr) { + if (arr == null) { + return null; + } + int[] res = new int[arr.length]; + for (int i = 0; i < arr.length; i++) { + res[i] = arr[i]; + } + return res; + } + + // for test + public static boolean isEqual(int[] arr1, int[] arr2) { + if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) { + return false; + } + if (arr1 == null && arr2 == null) { + return true; + } + if (arr1.length != arr2.length) { + return false; + } + for (int i = 0; i < arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + // for test + public static void printArray(int[] arr) { + if (arr == null) { + return; + } + for (int i = 0; i < arr.length; i++) { + System.out.print(arr[i] + " "); + } + System.out.println(); + } + + // 生成随机数组测试 + public static void main(String[] args) { + int testTime = 500000; + int maxSize = 100; + int maxValue = 100; + boolean pass = true; + System.out.println("测试开始,没有打印出错信息说明测试通过"); + for (int i = 0; i < testTime; i++) { + int k = (int) (Math.random() * maxSize) + 1; + int[] arr = generateRandomArray(maxSize, maxValue); + + int[] arr1 = copyArray(arr); + int[] arr2 = copyArray(arr); + int[] arr3 = copyArray(arr); + + int[] ans1 = maxTopK1(arr1, k); + int[] ans2 = maxTopK2(arr2, k); + int[] ans3 = maxTopK3(arr3, k); + if (!isEqual(ans1, ans2) || !isEqual(ans1, ans3)) { + pass = false; + System.out.println("出错了!"); + printArray(ans1); + printArray(ans2); + printArray(ans3); + break; + } + } + System.out.println("测试结束了,测试了" + testTime + "组,是否所有测试用例都通过?" + (pass ? "是" : "否")); + } + +} diff --git a/src/class27/Code03_ReservoirSampling.java b/src/class27/Code03_ReservoirSampling.java new file mode 100644 index 0000000..b187659 --- /dev/null +++ b/src/class27/Code03_ReservoirSampling.java @@ -0,0 +1,63 @@ +package class27; + +public class Code03_ReservoirSampling { + + public static class RandomBox { + private int[] bag; + private int N; + private int count; + + public RandomBox(int capacity) { + bag = new int[capacity]; + N = capacity; + count = 0; + } + + private int rand(int max) { + return (int) (Math.random() * max) + 1; + } + + public void add(int num) { + count++; + if (count <= N) { + bag[count - 1] = num; + } else { + if (rand(count) <= N) { + bag[rand(N) - 1] = num; + } + } + } + + public int[] choices() { + int[] ans = new int[N]; + for (int i = 0; i < N; i++) { + ans[i] = bag[i]; + } + return ans; + } + + } + + public static void main(String[] args) { + System.out.println("hello"); + int all = 100; + int choose = 10; + int testTimes = 50000; + int[] counts = new int[all + 1]; + for (int i = 0; i < testTimes; i++) { + RandomBox box = new RandomBox(choose); + for (int num = 1; num <= all; num++) { + box.add(num); + } + int[] ans = box.choices(); + for (int j = 0; j < ans.length; j++) { + counts[ans[j]]++; + } + } + + for (int i = 0; i < counts.length; i++) { + System.out.println(i + " times : " + counts[i]); + } + + } +} diff --git a/src/class28/Code01_KMP.java b/src/class28/Code01_KMP.java new file mode 100644 index 0000000..400cf5b --- /dev/null +++ b/src/class28/Code01_KMP.java @@ -0,0 +1,77 @@ +package class28; + +public class Code01_KMP { + // O(N) + public static int getIndexOf(String s, String m) { + if (s == null || m == null || m.length() < 1 || s.length() < m.length()) { + return -1; + } + char[] str = s.toCharArray(); + char[] match = m.toCharArray(); + int x = 0; // str中当前比对到的位置 + int y = 0; // match中当前比对到的位置 + // M M <= N O(M) + int[] next = getNextArray(match); // next[i] match中i之前的字符串match[0..i-1] + // O(N) + while (x < str.length && y < match.length) { + if (str[x] == match[y]) { + x++; + y++; + } else if (next[y] == -1) { // y == 0 + x++; + } else { + y = next[y]; + } + } + return y == match.length ? x - y : -1; + } + + // M O(M) + public static int[] getNextArray(char[] match) { + if (match.length == 1) { + return new int[] { -1 }; + } + int[] next = new int[match.length]; + next[0] = -1; + next[1] = 0; + int i = 2; + // cn代表,cn位置的字符,是当前和i-1位置比较的字符 + int cn = 0; + while (i < next.length) { + if (match[i - 1] == match[cn]) { // 跳出来的时候 + next[i++] = ++cn; + } else if (cn > 0) { + cn = next[cn]; + } else { + next[i++] = 0; + } + } + return next; + } + + // for test + public static String getRandomString(int possibilities, int size) { + char[] ans = new char[(int) (Math.random() * size) + 1]; + for (int i = 0; i < ans.length; i++) { + ans[i] = (char) ((int) (Math.random() * possibilities) + 'a'); + } + return String.valueOf(ans); + } + + public static void main(String[] args) { + int possibilities = 5; + int strSize = 20; + int matchSize = 5; + int testTimes = 5000000; + System.out.println("test begin"); + for (int i = 0; i < testTimes; i++) { + String str = getRandomString(possibilities, strSize); + String match = getRandomString(possibilities, matchSize); + if (getIndexOf(str, match) != str.indexOf(match)) { + System.out.println("Oops!"); + } + } + System.out.println("test finish"); + } + +} diff --git a/src/class28/Code02_TreeEqual.java b/src/class28/Code02_TreeEqual.java new file mode 100644 index 0000000..e03d696 --- /dev/null +++ b/src/class28/Code02_TreeEqual.java @@ -0,0 +1,177 @@ +package class28; + +import java.util.ArrayList; + +public class Code02_TreeEqual { + + public static class Node { + public int value; + public Node left; + public Node right; + + public Node(int v) { + value = v; + } + } + + // big做头节点的树,其中是否有某棵子树的结构,是和small为头的树,完全一样的 + public static boolean containsTree1(Node big, Node small) { + if (small == null) { + return true; + } + // small != null + if (big == null) { + return false; + } + // big!=null small!=null + if (isSameValueStructure(big, small)) { + return true; + } + return containsTree1(big.left, small) || containsTree1(big.right, small); + } + + // head1为头的树,是否在结构对应上,完全和head2一样 + public static boolean isSameValueStructure(Node head1, Node head2) { + if (head1 == null && head2 != null) { + return false; + } + if (head1 != null && head2 == null) { + return false; + } + if (head1 == null && head2 == null) { + return true; + } + if (head1.value != head2.value) { + return false; + } + // head1.value == head2.value + return isSameValueStructure(head1.left, head2.left) + && isSameValueStructure(head1.right, head2.right); + } + + public static boolean containsTree2(Node big, Node small) { + if (small == null) { + return true; + } + if (big == null) { + return false; + } + ArrayList b = preSerial(big); + ArrayList s = preSerial(small); + String[] str = new String[b.size()]; + for (int i = 0; i < str.length; i++) { + str[i] = b.get(i); + } + + String[] match = new String[s.size()]; + for (int i = 0; i < match.length; i++) { + match[i] = s.get(i); + } + return getIndexOf(str, match) != -1; + } + + public static ArrayList preSerial(Node head) { + ArrayList ans = new ArrayList<>(); + pres(head, ans); + return ans; + } + + public static void pres(Node head, ArrayList ans) { + if (head == null) { + ans.add(null); + } else { + ans.add(String.valueOf(head.value)); + pres(head.left, ans); + pres(head.right, ans); + } + } + + public static int getIndexOf(String[] str1, String[] str2) { + if (str1 == null || str2 == null || str1.length < 1 || str1.length < str2.length) { + return -1; + } + int x = 0; + int y = 0; + int[] next = getNextArray(str2); + while (x < str1.length && y < str2.length) { + if (isEqual(str1[x], str2[y])) { + x++; + y++; + } else if (next[y] == -1) { + x++; + } else { + y = next[y]; + } + } + return y == str2.length ? x - y : -1; + } + + public static int[] getNextArray(String[] ms) { + if (ms.length == 1) { + return new int[] { -1 }; + } + int[] next = new int[ms.length]; + next[0] = -1; + next[1] = 0; + int i = 2; + int cn = 0; + while (i < next.length) { + if (isEqual(ms[i - 1], ms[cn])) { + next[i++] = ++cn; + } else if (cn > 0) { + cn = next[cn]; + } else { + next[i++] = 0; + } + } + return next; + } + + public static boolean isEqual(String a, String b) { + if (a == null && b == null) { + return true; + } else { + if (a == null || b == null) { + return false; + } else { + return a.equals(b); + } + } + } + + // for test + public static Node generateRandomBST(int maxLevel, int maxValue) { + return generate(1, maxLevel, maxValue); + } + + // for test + public static Node generate(int level, int maxLevel, int maxValue) { + if (level > maxLevel || Math.random() < 0.5) { + return null; + } + Node head = new Node((int) (Math.random() * maxValue)); + head.left = generate(level + 1, maxLevel, maxValue); + head.right = generate(level + 1, maxLevel, maxValue); + return head; + } + + public static void main(String[] args) { + int bigTreeLevel = 7; + int smallTreeLevel = 4; + int nodeMaxValue = 5; + int testTimes = 100000; + System.out.println("test begin"); + for (int i = 0; i < testTimes; i++) { + Node big = generateRandomBST(bigTreeLevel, nodeMaxValue); + Node small = generateRandomBST(smallTreeLevel, nodeMaxValue); + boolean ans1 = containsTree1(big, small); + boolean ans2 = containsTree2(big, small); + if (ans1 != ans2) { + System.out.println("Oops!"); + } + } + System.out.println("test finish!"); + + } + +} diff --git a/src/class28/Code03_IsRotation.java b/src/class28/Code03_IsRotation.java new file mode 100644 index 0000000..f11fd28 --- /dev/null +++ b/src/class28/Code03_IsRotation.java @@ -0,0 +1,64 @@ +package class28; + +public class Code03_IsRotation { + + public static boolean isRotation(String a, String b) { + if (a == null || b == null || a.length() != b.length()) { + return false; + } + String b2 = b + b; + return getIndexOf(b2, a) != -1; + } + + // KMP Algorithm + public static int getIndexOf(String s, String m) { + if (s.length() < m.length()) { + return -1; + } + char[] ss = s.toCharArray(); + char[] ms = m.toCharArray(); + int si = 0; + int mi = 0; + int[] next = getNextArray(ms); + while (si < ss.length && mi < ms.length) { + if (ss[si] == ms[mi]) { + si++; + mi++; + } else if (next[mi] == -1) { + si++; + } else { + mi = next[mi]; + } + } + return mi == ms.length ? si - mi : -1; + } + + public static int[] getNextArray(char[] ms) { + if (ms.length == 1) { + return new int[] { -1 }; + } + int[] next = new int[ms.length]; + next[0] = -1; + next[1] = 0; + int pos = 2; + int cn = 0; + while (pos < next.length) { + if (ms[pos - 1] == ms[cn]) { + next[pos++] = ++cn; + } else if (cn > 0) { + cn = next[cn]; + } else { + next[pos++] = 0; + } + } + return next; + } + + public static void main(String[] args) { + String str1 = "yunzuocheng"; + String str2 = "zuochengyun"; + System.out.println(isRotation(str1, str2)); + + } + +} diff --git a/src/class29/Code01_Manacher.java b/src/class29/Code01_Manacher.java new file mode 100644 index 0000000..74c8d42 --- /dev/null +++ b/src/class29/Code01_Manacher.java @@ -0,0 +1,89 @@ +package class29; + +public class Code01_Manacher { + + public static int manacher(String s) { + if (s == null || s.length() == 0) { + return 0; + } + // "12132" -> "#1#2#1#3#2#" + char[] str = manacherString(s); + // 回文半径的大小 + int[] pArr = new int[str.length]; + int C = -1; + // 讲述中:R代表最右的扩成功的位置。coding:最右的扩成功位置的,再下一个位置 + int R = -1; + int max = Integer.MIN_VALUE; + for (int i = 0; i < str.length; i++) { + // R第一个违规的位置,i>= R + // i位置扩出来的答案,i位置扩的区域,至少是多大。 + pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1; + while (i + pArr[i] < str.length && i - pArr[i] > -1) { + if (str[i + pArr[i]] == str[i - pArr[i]]) + pArr[i]++; + else { + break; + } + } + if (i + pArr[i] > R) { + R = i + pArr[i]; + C = i; + } + max = Math.max(max, pArr[i]); + } + return max - 1; + } + + public static char[] manacherString(String str) { + char[] charArr = str.toCharArray(); + char[] res = new char[str.length() * 2 + 1]; + int index = 0; + for (int i = 0; i != res.length; i++) { + res[i] = (i & 1) == 0 ? '#' : charArr[index++]; + } + return res; + } + + // for test + public static int right(String s) { + if (s == null || s.length() == 0) { + return 0; + } + char[] str = manacherString(s); + int max = 0; + for (int i = 0; i < str.length; i++) { + int L = i - 1; + int R = i + 1; + while (L >= 0 && R < str.length && str[L] == str[R]) { + L--; + R++; + } + max = Math.max(max, R - L - 1); + } + return max / 2; + } + + // for test + public static String getRandomString(int possibilities, int size) { + char[] ans = new char[(int) (Math.random() * size) + 1]; + for (int i = 0; i < ans.length; i++) { + ans[i] = (char) ((int) (Math.random() * possibilities) + 'a'); + } + return String.valueOf(ans); + } + + public static void main(String[] args) { + int possibilities = 5; + int strSize = 20; + int testTimes = 5000000; + System.out.println("test begin"); + for (int i = 0; i < testTimes; i++) { + String str = getRandomString(possibilities, strSize); + if (manacher(str) != right(str)) { + System.out.println("Oops!"); + } + } + System.out.println("test finish"); + } + +} diff --git a/src/class29/Code02_AddShortestEnd.java b/src/class29/Code02_AddShortestEnd.java new file mode 100644 index 0000000..81f3e20 --- /dev/null +++ b/src/class29/Code02_AddShortestEnd.java @@ -0,0 +1,54 @@ +package class29; + +public class Code02_AddShortestEnd { + + public static String shortestEnd(String s) { + if (s == null || s.length() == 0) { + return null; + } + char[] str = manacherString(s); + int[] pArr = new int[str.length]; + int C = -1; + int R = -1; + int maxContainsEnd = -1; + for (int i = 0; i != str.length; i++) { + pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1; + while (i + pArr[i] < str.length && i - pArr[i] > -1) { + if (str[i + pArr[i]] == str[i - pArr[i]]) + pArr[i]++; + else { + break; + } + } + if (i + pArr[i] > R) { + R = i + pArr[i]; + C = i; + } + if (R == str.length) { + maxContainsEnd = pArr[i]; + break; + } + } + char[] res = new char[s.length() - maxContainsEnd + 1]; + for (int i = 0; i < res.length; i++) { + res[res.length - 1 - i] = str[i * 2 + 1]; + } + return String.valueOf(res); + } + + public static char[] manacherString(String str) { + char[] charArr = str.toCharArray(); + char[] res = new char[str.length() * 2 + 1]; + int index = 0; + for (int i = 0; i != res.length; i++) { + res[i] = (i & 1) == 0 ? '#' : charArr[index++]; + } + return res; + } + + public static void main(String[] args) { + String str1 = "abcd123321"; + System.out.println(shortestEnd(str1)); + } + +} diff --git a/src/class30/Code01_MorrisTraversal.java b/src/class30/Code01_MorrisTraversal.java new file mode 100644 index 0000000..7206332 --- /dev/null +++ b/src/class30/Code01_MorrisTraversal.java @@ -0,0 +1,223 @@ +package class30; + +public class Code01_MorrisTraversal { + + public static class Node { + public int value; + Node left; + Node right; + + public Node(int data) { + this.value = data; + } + } + + public static void morris(Node head) { + if (head == null) { + return; + } + Node cur = head; + Node mostRight = null; + while (cur != null) { + // cur有没有左树 + mostRight = cur.left; + if (mostRight != null) { // 有左树的情况下 + // 找到cur左树上,真实的最右 + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; + } + // 从while中出来,mostRight一定是cur左树上的最右节点 + // mostRight + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; + continue; + } else { // mostRight.right != null -> mostRight.right == cur + mostRight.right = null; + } + } + cur = cur.right; + } + } + + public static void morrisIn(Node head) { + if (head == null) { + return; + } + Node cur = head; + Node mostRight = null; + while (cur != null) { + mostRight = cur.left; + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; + } + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; + continue; + } else { + mostRight.right = null; + } + } + System.out.print(cur.value + " "); + cur = cur.right; + } + System.out.println(); + } + + public static void morrisPre(Node head) { + if (head == null) { + return; + } + Node cur1 = head; + Node cur2 = null; + while (cur1 != null) { + cur2 = cur1.left; + if (cur2 != null) { + while (cur2.right != null && cur2.right != cur1) { + cur2 = cur2.right; + } + if (cur2.right == null) { + cur2.right = cur1; + System.out.print(cur1.value + " "); + cur1 = cur1.left; + continue; + } else { + cur2.right = null; + } + } else { + System.out.print(cur1.value + " "); + } + cur1 = cur1.right; + } + System.out.println(); + } + + public static void morrisPos(Node head) { + if (head == null) { + return; + } + Node cur = head; + Node mostRight = null; + while (cur != null) { + mostRight = cur.left; + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; + } + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; + continue; + } else { + mostRight.right = null; + printEdge(cur.left); + } + } + cur = cur.right; + } + printEdge(head); + System.out.println(); + } + + public static void printEdge(Node head) { + Node tail = reverseEdge(head); + Node cur = tail; + while (cur != null) { + System.out.print(cur.value + " "); + cur = cur.right; + } + reverseEdge(tail); + } + + public static Node reverseEdge(Node from) { + Node pre = null; + Node next = null; + while (from != null) { + next = from.right; + from.right = pre; + pre = from; + from = next; + } + return pre; + } + + // for test -- print tree + public static void printTree(Node head) { + System.out.println("Binary Tree:"); + printInOrder(head, 0, "H", 17); + System.out.println(); + } + + public static void printInOrder(Node head, int height, String to, int len) { + if (head == null) { + return; + } + printInOrder(head.right, height + 1, "v", len); + String val = to + head.value + to; + int lenM = val.length(); + int lenL = (len - lenM) / 2; + int lenR = len - lenM - lenL; + val = getSpace(lenL) + val + getSpace(lenR); + System.out.println(getSpace(height * len) + val); + printInOrder(head.left, height + 1, "^", len); + } + + public static String getSpace(int num) { + String space = " "; + StringBuffer buf = new StringBuffer(""); + for (int i = 0; i < num; i++) { + buf.append(space); + } + return buf.toString(); + } + + public static boolean isBST(Node head) { + if (head == null) { + return true; + } + Node cur = head; + Node mostRight = null; + Integer pre = null; + boolean ans = true; + while (cur != null) { + mostRight = cur.left; + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; + } + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; + continue; + } else { + mostRight.right = null; + } + } + if (pre != null && pre >= cur.value) { + ans = false; + } + pre = cur.value; + cur = cur.right; + } + return ans; + } + + public static void main(String[] args) { + Node head = new Node(4); + head.left = new Node(2); + head.right = new Node(6); + head.left.left = new Node(1); + head.left.right = new Node(3); + head.right.left = new Node(5); + head.right.right = new Node(7); + printTree(head); + morrisIn(head); + morrisPre(head); + morrisPos(head); + printTree(head); + + } + +} diff --git a/src/class30/Code05_MinHeight.java b/src/class30/Code05_MinHeight.java new file mode 100644 index 0000000..c328760 --- /dev/null +++ b/src/class30/Code05_MinHeight.java @@ -0,0 +1,117 @@ +package class30; + +public class Code05_MinHeight { + + public static class Node { + public int val; + public Node left; + public Node right; + + public Node(int x) { + val = x; + } + } + + public static int minHeight1(Node head) { + if (head == null) { + return 0; + } + return p(head); + } + + public static int p(Node x) { + if (x.left == null && x.right == null) { + return 1; + } + // 左右子树起码有一个不为空 + int leftH = Integer.MAX_VALUE; + if (x.left != null) { + leftH = p(x.left); + } + int rightH = Integer.MAX_VALUE; + if (x.right != null) { + rightH = p(x.right); + } + return 1 + Math.min(leftH, rightH); + } + + // 根据morris遍历改写 + public static int minHeight2(Node head) { + if (head == null) { + return 0; + } + Node cur = head; + Node mostRight = null; + int curLevel = 0; + int minHeight = Integer.MAX_VALUE; + while (cur != null) { + mostRight = cur.left; + if (mostRight != null) { + int rightBoardSize = 1; + while (mostRight.right != null && mostRight.right != cur) { + rightBoardSize++; + mostRight = mostRight.right; + } + if (mostRight.right == null) { // 第一次到达 + curLevel++; + mostRight.right = cur; + cur = cur.left; + continue; + } else { // 第二次到达 + if (mostRight.left == null) { + minHeight = Math.min(minHeight, curLevel); + } + curLevel -= rightBoardSize; + mostRight.right = null; + } + } else { // 只有一次到达 + curLevel++; + } + cur = cur.right; + } + int finalRight = 1; + cur = head; + while (cur.right != null) { + finalRight++; + cur = cur.right; + } + if (cur.left == null && cur.right == null) { + minHeight = Math.min(minHeight, finalRight); + } + return minHeight; + } + + // for test + public static Node generateRandomBST(int maxLevel, int maxValue) { + return generate(1, maxLevel, maxValue); + } + + // for test + public static Node generate(int level, int maxLevel, int maxValue) { + if (level > maxLevel || Math.random() < 0.5) { + return null; + } + Node head = new Node((int) (Math.random() * maxValue)); + head.left = generate(level + 1, maxLevel, maxValue); + head.right = generate(level + 1, maxLevel, maxValue); + return head; + } + + public static void main(String[] args) { + int treeLevel = 7; + int nodeMaxValue = 5; + int testTimes = 100000; + System.out.println("test begin"); + for (int i = 0; i < testTimes; i++) { + Node head = generateRandomBST(treeLevel, nodeMaxValue); + int ans1 = minHeight1(head); + int ans2 = minHeight2(head); + if (ans1 != ans2) { + System.out.println("Oops!"); + } + } + System.out.println("test finish!"); + + } + +} diff --git a/src/class31/Code01_SegmentTree.java b/src/class31/Code01_SegmentTree.java new file mode 100644 index 0000000..80e1b26 --- /dev/null +++ b/src/class31/Code01_SegmentTree.java @@ -0,0 +1,251 @@ +package class31; + +public class Code01_SegmentTree { + + public static class SegmentTree { + // arr[]为原序列的信息从0开始,但在arr里是从1开始的 + // sum[]模拟线段树维护区间和 + // lazy[]为累加懒惰标记 + // change[]为更新的值 + // update[]为更新慵懒标记 + private int MAXN; + private int[] arr; + private int[] sum; + private int[] lazy; + private int[] change; + private boolean[] update; + + public SegmentTree(int[] origin) { + MAXN = origin.length + 1; + arr = new int[MAXN]; // arr[0] 不用 从1开始使用 + for (int i = 1; i < MAXN; i++) { + arr[i] = origin[i - 1]; + } + sum = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围的累加和信息 + + lazy = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围沒有往下傳遞的纍加任務 + change = new int[MAXN << 2]; // 用来支持脑补概念中,某一个范围有没有更新操作的任务 + update = new boolean[MAXN << 2]; // 用来支持脑补概念中,某一个范围更新任务,更新成了什么 + } + + private void pushUp(int rt) { + sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; + } + + // 之前的,所有懒增加,和懒更新,从父范围,发给左右两个子范围 + // 分发策略是什么 + // ln表示左子树元素结点个数,rn表示右子树结点个数 + private void pushDown(int rt, int ln, int rn) { + if (update[rt]) { + update[rt << 1] = true; + update[rt << 1 | 1] = true; + change[rt << 1] = change[rt]; + change[rt << 1 | 1] = change[rt]; + lazy[rt << 1] = 0; + lazy[rt << 1 | 1] = 0; + sum[rt << 1] = change[rt] * ln; + sum[rt << 1 | 1] = change[rt] * rn; + update[rt] = false; + } + if (lazy[rt] != 0) { + lazy[rt << 1] += lazy[rt]; + sum[rt << 1] += lazy[rt] * ln; + lazy[rt << 1 | 1] += lazy[rt]; + sum[rt << 1 | 1] += lazy[rt] * rn; + lazy[rt] = 0; + } + } + + // 在初始化阶段,先把sum数组,填好 + // 在arr[l~r]范围上,去build,1~N, + // rt : 这个范围在sum中的下标 + public void build(int l, int r, int rt) { + if (l == r) { + sum[rt] = arr[l]; + return; + } + int mid = (l + r) >> 1; + build(l, mid, rt << 1); + build(mid + 1, r, rt << 1 | 1); + pushUp(rt); + } + + public void update(int L, int R, int C, int l, int r, int rt) { + if (L <= l && r <= R) { + update[rt] = true; + change[rt] = C; + sum[rt] = C * (r - l + 1); + lazy[rt] = 0; + return; + } + // 当前任务躲不掉,无法懒更新,要往下发 + int mid = (l + r) >> 1; + pushDown(rt, mid - l + 1, r - mid); + if (L <= mid) { + update(L, R, C, l, mid, rt << 1); + } + if (R > mid) { + update(L, R, C, mid + 1, r, rt << 1 | 1); + } + pushUp(rt); + } + + // L..R -> 任务范围 ,所有的值累加上C + // l,r -> 表达的范围 + // rt 去哪找l,r范围上的信息 + public void add( + int L, int R, int C, + int l, int r, + int rt) { + // 任务的范围彻底覆盖了,当前表达的范围 + if (L <= l && r <= R) { + sum[rt] += C * (r - l + 1); + lazy[rt] += C; + return; + } + // 任务并没有把l...r全包住 + // 要把当前任务往下发 + // 任务 L, R 没有把本身表达范围 l,r 彻底包住 + int mid = (l + r) >> 1; // l..mid (rt << 1) mid+1...r(rt << 1 | 1) + // 下发之前所有攒的懒任务 + pushDown(rt, mid - l + 1, r - mid); + // 左孩子是否需要接到任务 + if (L <= mid) { + add(L, R, C, l, mid, rt << 1); + } + // 右孩子是否需要接到任务 + if (R > mid) { + add(L, R, C, mid + 1, r, rt << 1 | 1); + } + // 左右孩子做完任务后,我更新我的sum信息 + pushUp(rt); + } + + // 1~6 累加和是多少? 1~8 rt + public long query(int L, int R, int l, int r, int rt) { + if (L <= l && r <= R) { + return sum[rt]; + } + int mid = (l + r) >> 1; + pushDown(rt, mid - l + 1, r - mid); + long ans = 0; + if (L <= mid) { + ans += query(L, R, l, mid, rt << 1); + } + if (R > mid) { + ans += query(L, R, mid + 1, r, rt << 1 | 1); + } + return ans; + } + + } + + public static class Right { + public int[] arr; + + public Right(int[] origin) { + arr = new int[origin.length + 1]; + for (int i = 0; i < origin.length; i++) { + arr[i + 1] = origin[i]; + } + } + + public void update(int L, int R, int C) { + for (int i = L; i <= R; i++) { + arr[i] = C; + } + } + + public void add(int L, int R, int C) { + for (int i = L; i <= R; i++) { + arr[i] += C; + } + } + + public long query(int L, int R) { + long ans = 0; + for (int i = L; i <= R; i++) { + ans += arr[i]; + } + return ans; + } + + } + + public static int[] genarateRandomArray(int len, int max) { + int size = (int) (Math.random() * len) + 1; + int[] origin = new int[size]; + for (int i = 0; i < size; i++) { + origin[i] = (int) (Math.random() * max) - (int) (Math.random() * max); + } + return origin; + } + + public static boolean test() { + int len = 100; + int max = 1000; + int testTimes = 5000; + int addOrUpdateTimes = 1000; + int queryTimes = 500; + for (int i = 0; i < testTimes; i++) { + int[] origin = genarateRandomArray(len, max); + SegmentTree seg = new SegmentTree(origin); + int S = 1; + int N = origin.length; + int root = 1; + seg.build(S, N, root); + Right rig = new Right(origin); + for (int j = 0; j < addOrUpdateTimes; j++) { + int num1 = (int) (Math.random() * N) + 1; + int num2 = (int) (Math.random() * N) + 1; + int L = Math.min(num1, num2); + int R = Math.max(num1, num2); + int C = (int) (Math.random() * max) - (int) (Math.random() * max); + if (Math.random() < 0.5) { + seg.add(L, R, C, S, N, root); + rig.add(L, R, C); + } else { + seg.update(L, R, C, S, N, root); + rig.update(L, R, C); + } + } + for (int k = 0; k < queryTimes; k++) { + int num1 = (int) (Math.random() * N) + 1; + int num2 = (int) (Math.random() * N) + 1; + int L = Math.min(num1, num2); + int R = Math.max(num1, num2); + long ans1 = seg.query(L, R, S, N, root); + long ans2 = rig.query(L, R); + if (ans1 != ans2) { + return false; + } + } + } + return true; + } + + public static void main(String[] args) { + int[] origin = { 2, 1, 1, 2, 3, 4, 5 }; + SegmentTree seg = new SegmentTree(origin); + int S = 1; // 整个区间的开始位置,规定从1开始,不从0开始 -> 固定 + int N = origin.length; // 整个区间的结束位置,规定能到N,不是N-1 -> 固定 + int root = 1; // 整棵树的头节点位置,规定是1,不是0 -> 固定 + int L = 2; // 操作区间的开始位置 -> 可变 + int R = 5; // 操作区间的结束位置 -> 可变 + int C = 4; // 要加的数字或者要更新的数字 -> 可变 + // 区间生成,必须在[S,N]整个范围上build + seg.build(S, N, root); + // 区间修改,可以改变L、R和C的值,其他值不可改变 + seg.add(L, R, C, S, N, root); + // 区间更新,可以改变L、R和C的值,其他值不可改变 + seg.update(L, R, C, S, N, root); + // 区间查询,可以改变L和R的值,其他值不可改变 + long sum = seg.query(L, R, S, N, root); + System.out.println(sum); + + System.out.println("对数器测试开始..."); + System.out.println("测试结果 : " + (test() ? "通过" : "未通过")); + + } + +} diff --git a/src/class31/Code02_FallingSquares.java b/src/class31/Code02_FallingSquares.java new file mode 100644 index 0000000..fb85a67 --- /dev/null +++ b/src/class31/Code02_FallingSquares.java @@ -0,0 +1,116 @@ +package class31; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.TreeSet; + +public class Code02_FallingSquares { + + public static class SegmentTree { + private int[] max; + private int[] change; + private boolean[] update; + + public SegmentTree(int size) { + int N = size + 1; + max = new int[N << 2]; + + change = new int[N << 2]; + update = new boolean[N << 2]; + } + + private void pushUp(int rt) { + max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]); + } + + // ln表示左子树元素结点个数,rn表示右子树结点个数 + private void pushDown(int rt, int ln, int rn) { + if (update[rt]) { + update[rt << 1] = true; + update[rt << 1 | 1] = true; + change[rt << 1] = change[rt]; + change[rt << 1 | 1] = change[rt]; + max[rt << 1] = change[rt]; + max[rt << 1 | 1] = change[rt]; + update[rt] = false; + } + } + + public void update(int L, int R, int C, int l, int r, int rt) { + if (L <= l && r <= R) { + update[rt] = true; + change[rt] = C; + max[rt] = C; + return; + } + int mid = (l + r) >> 1; + pushDown(rt, mid - l + 1, r - mid); + if (L <= mid) { + update(L, R, C, l, mid, rt << 1); + } + if (R > mid) { + update(L, R, C, mid + 1, r, rt << 1 | 1); + } + pushUp(rt); + } + + public int query(int L, int R, int l, int r, int rt) { + if (L <= l && r <= R) { + return max[rt]; + } + int mid = (l + r) >> 1; + pushDown(rt, mid - l + 1, r - mid); + int left = 0; + int right = 0; + if (L <= mid) { + left = query(L, R, l, mid, rt << 1); + } + if (R > mid) { + right = query(L, R, mid + 1, r, rt << 1 | 1); + } + return Math.max(left, right); + } + + } + + // positions + // [2,7] -> 2 , 8 + // [3, 10] -> 3, 12 + // + // + public HashMap index(int[][] positions) { + TreeSet pos = new TreeSet<>(); + for (int[] arr : positions) { + pos.add(arr[0]); + pos.add(arr[0] + arr[1] - 1); + } + HashMap map = new HashMap<>(); + int count = 0; + for (Integer index : pos) { + map.put(index, ++count); + } + return map; + } + + public List fallingSquares(int[][] positions) { + HashMap map = index(positions); + // 100 -> 1 306 -> 2 403 -> 3 + // [100,403] 1~3 + int N = map.size(); // 1 ~ N + SegmentTree segmentTree = new SegmentTree(N); + int max = 0; + List res = new ArrayList<>(); + // 每落一个正方形,收集一下,所有东西组成的图像,最高高度是什么 + for (int[] arr : positions) { + int L = map.get(arr[0]); + int R = map.get(arr[0] + arr[1] - 1); + int height = segmentTree.query(L, R, 1, N, 1) + arr[1]; + max = Math.max(max, height); + res.add(max); + segmentTree.update(L, R, height, 1, N, 1); + } + return res; + } + +}