└── src ├── class01 ├── Problem01_ScrambleString.java ├── Problem02_MinWindowLength.java ├── Problem03_LFU.java └── Problem04_GasStations.java ├── class02 ├── Code01_PathsToNums.java ├── Code02_CandyProblem.java ├── Code03_MinCameraCover.java └── Code04_MaximumSumof3NonOverlappingSubarrays.java ├── class03 ├── Code01_NiuNiuSplitField.java ├── Code02_BricksFallingWhenHit1.java ├── Code02_BricksFallingWhenHit2.java ├── Code03_TallestBillboard.java ├── Code04_DistinctSubseq.java └── Main.java ├── class04 ├── Code01_SplitArrayLargestSum.java ├── Code02_ThrowChessPiecesProblem.java ├── Code03_PostOfficeProblem.java ├── Code04_MergeRecord.java └── Code05_FactorialProblem.java ├── class05 ├── Code01_PalindromePairs.java ├── Code02_LongestConsecutive.java ├── Code03_TarjanAndDisjointSetsForLCA.java └── Code04_MaximalRectangle.java ├── class06 ├── Code01_RemoveBoxes.java ├── Code02_StrangePrinter.java ├── Code03_SmallestRangeCoveringElementsfromKLists.java └── Code04_RestoreWays.java ├── class07 ├── Code01_TSP.java └── Code02_PavingTile.java └── class08 ├── Code01_CreateMaximumNumber.java ├── Code02_LastSubstringInLexicographicalOrder.java ├── Code03_InsertS2MakeMostAlphabeticalOrder.java ├── DC3.java └── DC3_Algorithm.pdf /src/class01/Problem01_ScrambleString.java: -------------------------------------------------------------------------------- 1 | package class01; 2 | 3 | public class Problem01_ScrambleString { 4 | 5 | public static boolean sameTypeSameNumber(char[] str1, char[] str2) { 6 | if (str1.length != str2.length) { 7 | return false; 8 | } 9 | int[] map = new int[256]; 10 | for (int i = 0; i < str1.length; i++) { 11 | map[str1[i]]++; 12 | } 13 | for (int i = 0; i < str2.length; i++) { 14 | if (--map[str2[i]] < 0) { 15 | return false; 16 | } 17 | } 18 | return true; 19 | } 20 | 21 | public static boolean isScramble1(String s1, String s2) { 22 | if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) { 23 | return false; 24 | } 25 | if (s1 == null && s2 == null) { 26 | return true; 27 | } 28 | if (s1.equals(s2)) { 29 | return true; 30 | } 31 | char[] str1 = s1.toCharArray(); 32 | char[] str2 = s2.toCharArray(); 33 | if (!sameTypeSameNumber(str1, str2)) { 34 | return false; 35 | } 36 | int N = s1.length(); 37 | return process(str1, str2, 0, 0, N); 38 | } 39 | 40 | // 返回str1[从L1开始往右长度为size的子串]和str2[从L2开始往右长度为size的子串]是否互为旋变字符串 41 | // 在str1中的这一段和str2中的这一段一定是等长的,所以只用一个参数size 42 | public static boolean process(char[] str1, char[] str2, int L1, int L2, int size) { 43 | if (size == 1) { 44 | return str1[L1] == str2[L2]; 45 | } 46 | // 枚举每一种情况,有一个计算出互为旋变就返回true。都算不出来最后返回false 47 | for (int leftPart = 1; leftPart < size; leftPart++) { 48 | if ( 49 | // 如果1左对2左,并且1右对2右 50 | (process(str1, str2, L1, L2, leftPart) 51 | && process(str1, str2, L1 + leftPart, L2 + leftPart, size - leftPart)) 52 | 53 | || 54 | // 如果1左对2右,并且1右对2左 55 | (process(str1, str2, L1, L2 + size - leftPart, leftPart) 56 | && process(str1, str2, L1 + leftPart, L2, size - leftPart))) { 57 | return true; 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | public static boolean isScramble2(String s1, String s2) { 64 | if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) { 65 | return false; 66 | } 67 | if (s1 == null && s2 == null) { 68 | return true; 69 | } 70 | if (s1.equals(s2)) { 71 | return true; 72 | } 73 | char[] str1 = s1.toCharArray(); 74 | char[] str2 = s2.toCharArray(); 75 | if (!sameTypeSameNumber(str1, str2)) { 76 | return false; 77 | } 78 | int N = s1.length(); 79 | boolean[][][] dp = new boolean[N][N][N + 1]; 80 | for (int L1 = 0; L1 < N; L1++) { 81 | for (int L2 = 0; L2 < N; L2++) { 82 | dp[L1][L2][1] = str1[L1] == str2[L2]; 83 | } 84 | } 85 | // 第一层for循环含义是:依次填size=2层、size=3层..size=N层,每一层都是一个二维平面 86 | // 第二、三层for循环含义是:在具体的一层,整个面都要填写,所以用两个for循环去填一个二维面 87 | // L1的取值氛围是[0,N-size],因为从L1出发往右长度为size的子串,L1是不能从N-size+1出发的,这样往右就不够size个字符了 88 | // L2的取值范围同理 89 | // 第4层for循环完全是递归函数怎么写,这里就怎么改的 90 | for (int size = 2; size <= N; size++) { 91 | for (int L1 = 0; L1 <= N - size; L1++) { 92 | for (int L2 = 0; L2 <= N - size; L2++) { 93 | for (int leftPart = 1; leftPart < size; leftPart++) { 94 | if ((dp[L1][L2][leftPart] && dp[L1 + leftPart][L2 + leftPart][size - leftPart]) 95 | || (dp[L1][L2 + size - leftPart][leftPart] && dp[L1 + leftPart][L2][size - leftPart])) { 96 | dp[L1][L2][size] = true; 97 | break; 98 | } 99 | } 100 | } 101 | } 102 | } 103 | return dp[0][0][N]; 104 | } 105 | 106 | public static boolean dp(String s1, String s2) { 107 | if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) { 108 | return false; 109 | } 110 | if (s1 == null && s2 == null) { 111 | return true; 112 | } 113 | if (s1.equals(s2)) { 114 | return true; 115 | } 116 | char[] str1 = s1.toCharArray(); 117 | char[] str2 = s2.toCharArray(); 118 | if (!sameTypeSameNumber(str1, str2)) { 119 | return false; 120 | } 121 | int N = s1.length(); 122 | 123 | boolean[][][] dp = new boolean[N][N][N + 1]; 124 | 125 | for (int L1 = 0; L1 < N; L1++) { 126 | for (int L2 = 0; L2 < N; L2++) { 127 | dp[L1][L2][1] = str1[L1] == str2[L2]; 128 | } 129 | } 130 | 131 | for (int size = 2; size <= N; size++) { // 面所在的层数为size 132 | for (int L1 = 0; L1 <= N - size; L1++) { 133 | for (int L2 = 0; L2 <= N - size; L2++) { 134 | 135 | dp[L1][L2][size] = false; 136 | for (int leftPart = 1; leftPart < size; leftPart++) { 137 | if ( 138 | // 如果左1对左2,并且右1对右2 139 | (dp[L1][L2][leftPart] && dp[L1 + leftPart][L2 + leftPart][size - leftPart]) || 140 | // 如果左1对右2,并且右1对左2 141 | (dp[L1][L2 + size - leftPart][leftPart] && dp[L1 + leftPart][L2][size - leftPart])) { 142 | dp[L1][L2][size] = true; 143 | break; 144 | } 145 | } 146 | } 147 | } 148 | 149 | } 150 | 151 | return dp[0][0][N]; 152 | 153 | } 154 | 155 | public static boolean isScramble3(String s1, String s2) { 156 | if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) { 157 | return false; 158 | } 159 | if (s1 == null && s2 == null) { 160 | return true; 161 | } 162 | if (s1.equals(s2)) { 163 | return true; 164 | } 165 | char[] str1 = s1.toCharArray(); 166 | char[] str2 = s2.toCharArray(); 167 | if (!sameTypeSameNumber(str1, str2)) { 168 | return false; 169 | } 170 | int N = s1.length(); 171 | int[][][] dp = new int[N][N][N+1]; 172 | // dp[i][j][k] = 0 processDP(i,j,k)状态之前没有算过的 173 | // dp[i][j][k] = -1 processDP(i,j,k)状态之前算过的,返回值是false 174 | // dp[i][j][k] = 1 processDP(i,j,k)状态之前算过的,返回值是true 175 | return processDP(str1, str2, 0, 0, N, dp); 176 | } 177 | 178 | public static boolean processDP(char[] str1, char[] str2, int L1, int L2, int size, int[][][] dp) { 179 | if (dp[L1][L2][size] != 0) { 180 | return dp[L1][L2][size] == 1; 181 | } 182 | boolean ans = false; 183 | if (size == 1) { 184 | ans = str1[L1] == str2[L2]; 185 | } else { 186 | // 枚举每一种情况,有一个计算出互为旋变就返回true。都算不出来最后返回false 187 | for (int leftPart = 1; leftPart < size; leftPart++) { 188 | if ( 189 | // 如果1左对2左,并且1右对2右 190 | (processDP(str1, str2, L1, L2, leftPart, dp) 191 | && processDP(str1, str2, L1 + leftPart, L2 + leftPart, size - leftPart, dp)) 192 | 193 | || 194 | // 如果1左对2右,并且1右对2左 195 | (processDP(str1, str2, L1, L2 + size - leftPart, leftPart, dp) 196 | && processDP(str1, str2, L1 + leftPart, L2, size - leftPart, dp))) { 197 | ans = true; 198 | break; 199 | } 200 | } 201 | } 202 | dp[L1][L2][size] = ans ? 1 : -1; 203 | return ans; 204 | } 205 | 206 | public static void main(String[] args) { 207 | String test1 = "abcd"; 208 | String test2 = "cdab"; 209 | System.out.println(isScramble1(test1, test2)); 210 | System.out.println(isScramble2(test1, test2)); 211 | System.out.println(isScramble3(test1, test2)); 212 | 213 | test1 = "abcd"; 214 | test2 = "cadb"; 215 | System.out.println(isScramble1(test1, test2)); 216 | System.out.println(isScramble2(test1, test2)); 217 | System.out.println(isScramble3(test1, test2)); 218 | 219 | test1 = "bcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcdebcde"; 220 | test2 = "ebcdeebcdebebcdebcdebcdecdebcbcdcdebcddebcbdebbbcdcdebcdeebcdebcdeebcddeebccdebcdbcdebcd"; 221 | // System.out.println(isScramble1(test1, test2)); 222 | System.out.println(isScramble2(test1, test2)); 223 | System.out.println(isScramble2(test1, test2)); 224 | //System.out.println(dp(test1, test2)); 225 | System.out.println(isScramble3(test1, test2)); 226 | } 227 | 228 | } 229 | -------------------------------------------------------------------------------- /src/class01/Problem02_MinWindowLength.java: -------------------------------------------------------------------------------- 1 | package class01; 2 | 3 | public class Problem02_MinWindowLength { 4 | 5 | public static int minLength(String s1, String s2) { 6 | if (s1 == null || s2 == null || s1.length() < s2.length()) { 7 | return Integer.MAX_VALUE; 8 | } 9 | char[] str1 = s1.toCharArray(); 10 | char[] str2 = s2.toCharArray(); 11 | int[] map = new int[256]; // map[37] = 4 37 4次 12 | for (int i = 0; i != str2.length; i++) { 13 | map[str2[i]]++; 14 | } 15 | int left = 0; 16 | int right = 0; 17 | int all = str2.length; 18 | int minLen = Integer.MAX_VALUE; 19 | // [left, right) [left, right-1] [0,0) 20 | // R右扩 L ==0 R 21 | while (right != str1.length) { 22 | map[str1[right]]--; 23 | if (map[str1[right]] >= 0) { 24 | all--; 25 | } 26 | if (all == 0) { // 还完了 27 | while (map[str1[left]] < 0) { 28 | map[str1[left++]]++; 29 | } 30 | // [L..R] 31 | minLen = Math.min(minLen, right - left + 1); 32 | all++; 33 | map[str1[left++]]++; 34 | } 35 | right++; 36 | } 37 | return minLen == Integer.MAX_VALUE ? 0 : minLen; 38 | } 39 | 40 | public static void main(String[] args) { 41 | String str1 = "adabbca"; 42 | String str2 = "acb"; 43 | System.out.println(minLength(str1, str2)); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/class01/Problem03_LFU.java: -------------------------------------------------------------------------------- 1 | package class01; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Problem03_LFU { 6 | 7 | // 节点的数据结构 8 | public static class Node { 9 | public Integer key; 10 | public Integer value; 11 | public Integer times; // 这个节点发生get或者set的次数总和 12 | public Node up; // 节点之间是双向链表所以有上一个节点 13 | public Node down;// 节点之间是双向链表所以有下一个节点 14 | 15 | public Node(int key, int value, int times) { 16 | this.key = key; 17 | this.value = value; 18 | this.times = times; 19 | } 20 | } 21 | 22 | // 桶结构 23 | public static class NodeList { 24 | public Node head; // 桶的头节点 25 | public Node tail; // 桶的尾节点 26 | public NodeList last; // 桶之间是双向链表所以有前一个桶 27 | public NodeList next; // 桶之间是双向链表所以有后一个桶 28 | 29 | public NodeList(Node node) { 30 | head = node; 31 | tail = node; 32 | } 33 | 34 | // 把一个新的节点加入这个桶,新的节点都放在顶端变成新的头部 35 | public void addNodeFromHead(Node newHead) { 36 | newHead.down = head; 37 | head.up = newHead; 38 | head = newHead; 39 | } 40 | 41 | // 判断这个桶是不是空的 42 | public boolean isEmpty() { 43 | return head == null; 44 | } 45 | 46 | // 删除node节点并保证node的上下环境重新连接 47 | public void deleteNode(Node node) { 48 | if (head == tail) { 49 | head = null; 50 | tail = null; 51 | } else { 52 | if (node == head) { 53 | head = node.down; 54 | head.up = null; 55 | } else if (node == tail) { 56 | tail = node.up; 57 | tail.down = null; 58 | } else { 59 | node.up.down = node.down; 60 | node.down.up = node.up; 61 | } 62 | } 63 | node.up = null; 64 | node.down = null; 65 | } 66 | } 67 | 68 | // 总的缓存结构 69 | public static class LFUCache { 70 | private int capacity; // 缓存的大小限制,即K 71 | private int size; // 缓存目前有多少个节点 72 | private HashMap records;// 表示key(Integer)由哪个节点(Node)代表 73 | private HashMap heads; // 表示节点(Node)在哪个桶(NodeList)里 74 | private NodeList headList; // 整个结构中位于最左的桶 75 | 76 | public LFUCache(int K) { 77 | this.capacity = K; 78 | this.size = 0; 79 | this.records = new HashMap<>(); 80 | this.heads = new HashMap<>(); 81 | headList = null; 82 | } 83 | 84 | // removeNodeList:刚刚减少了一个节点的桶 85 | // 这个函数的功能是,判断刚刚减少了一个节点的桶是不是已经空了。 86 | // 1)如果不空,什么也不做 87 | // 88 | // 2)如果空了,removeNodeList还是整个缓存结构最左的桶(headList)。 89 | // 删掉这个桶的同时也要让最左的桶变成removeNodeList的下一个。 90 | // 91 | // 3)如果空了,removeNodeList不是整个缓存结构最左的桶(headList)。 92 | // 把这个桶删除,并保证上一个的桶和下一个桶之间还是双向链表的连接方式 93 | // 94 | // 函数的返回值表示刚刚减少了一个节点的桶是不是已经空了,空了返回true;不空返回false 95 | private boolean modifyHeadList(NodeList removeNodeList) { 96 | if (removeNodeList.isEmpty()) { 97 | if (headList == removeNodeList) { 98 | headList = removeNodeList.next; 99 | if (headList != null) { 100 | headList.last = null; 101 | } 102 | } else { 103 | removeNodeList.last.next = removeNodeList.next; 104 | if (removeNodeList.next != null) { 105 | removeNodeList.next.last = removeNodeList.last; 106 | } 107 | } 108 | return true; 109 | } 110 | return false; 111 | } 112 | 113 | // 函数的功能 114 | // node这个节点的次数+1了,这个节点原来在oldNodeList里。 115 | // 把node从oldNodeList删掉,然后放到次数+1的桶中 116 | // 整个过程既要保证桶之间仍然是双向链表,也要保证节点之间仍然是双向链表 117 | private void move(Node node, NodeList oldNodeList) { 118 | oldNodeList.deleteNode(node); 119 | // preList表示次数+1的桶的前一个桶是谁 120 | // 如果oldNodeList删掉node之后还有节点,oldNodeList就是次数+1的桶的前一个桶 121 | // 如果oldNodeList删掉node之后空了,oldNodeList是需要删除的,所以次数+1的桶的前一个桶,是oldNodeList的前一个 122 | NodeList preList = modifyHeadList(oldNodeList) ? oldNodeList.last 123 | : oldNodeList; 124 | // nextList表示次数+1的桶的后一个桶是谁 125 | NodeList nextList = oldNodeList.next; 126 | if (nextList == null) { 127 | NodeList newList = new NodeList(node); 128 | if (preList != null) { 129 | preList.next = newList; 130 | } 131 | newList.last = preList; 132 | if (headList == null) { 133 | headList = newList; 134 | } 135 | heads.put(node, newList); 136 | } else { 137 | if (nextList.head.times.equals(node.times)) { 138 | nextList.addNodeFromHead(node); 139 | heads.put(node, nextList); 140 | } else { 141 | NodeList newList = new NodeList(node); 142 | if (preList != null) { 143 | preList.next = newList; 144 | } 145 | newList.last = preList; 146 | newList.next = nextList; 147 | nextList.last = newList; 148 | if (headList == nextList) { 149 | headList = newList; 150 | } 151 | heads.put(node, newList); 152 | } 153 | } 154 | } 155 | 156 | public void put(int key, int value) { 157 | if(capacity == 0) { 158 | return; 159 | } 160 | if (records.containsKey(key)) { 161 | Node node = records.get(key); 162 | node.value = value; 163 | node.times++; 164 | NodeList curNodeList = heads.get(node); 165 | move(node, curNodeList); 166 | } else { 167 | if (size == capacity) { 168 | Node node = headList.tail; 169 | headList.deleteNode(node); 170 | modifyHeadList(headList); 171 | records.remove(node.key); 172 | heads.remove(node); 173 | size--; 174 | } 175 | Node node = new Node(key, value, 1); 176 | if (headList == null) { 177 | headList = new NodeList(node); 178 | } else { 179 | if (headList.head.times.equals(node.times)) { 180 | headList.addNodeFromHead(node); 181 | } else { 182 | NodeList newList = new NodeList(node); 183 | newList.next = headList; 184 | headList.last = newList; 185 | headList = newList; 186 | } 187 | } 188 | records.put(key, node); 189 | heads.put(node, headList); 190 | size++; 191 | } 192 | } 193 | 194 | public Integer get(int key) { 195 | if (!records.containsKey(key)) { 196 | return null; 197 | } 198 | Node node = records.get(key); 199 | node.times++; 200 | NodeList curNodeList = heads.get(node); 201 | move(node, curNodeList); 202 | return node.value; 203 | } 204 | 205 | } 206 | } -------------------------------------------------------------------------------- /src/class01/Problem04_GasStations.java: -------------------------------------------------------------------------------- 1 | package class01; 2 | 3 | public class Problem04_GasStations { 4 | 5 | public static boolean[] stations(int[] dis, int[] oil) { 6 | if (dis == null || oil == null || dis.length < 2 7 | || dis.length != oil.length) { 8 | return null; 9 | } 10 | int init = changeDisArrayGetInit(dis, oil); 11 | return init == -1 ? new boolean[dis.length] : enlargeArea(dis, init); 12 | } 13 | 14 | public static int changeDisArrayGetInit(int[] dis, int[] oil) { 15 | int init = -1; 16 | for (int i = 0; i < dis.length; i++) { 17 | dis[i] = oil[i] - dis[i]; 18 | if (dis[i] >= 0) { 19 | init = i; 20 | } 21 | } 22 | return init; 23 | } 24 | 25 | public static boolean[] enlargeArea(int[] dis, int init) { 26 | boolean[] res = new boolean[dis.length]; 27 | int start = init; 28 | int end = nextIndex(init, dis.length); 29 | int need = 0; 30 | int rest = 0; 31 | do { 32 | // 当前来到的start已经在连通区域中,可以确定后续的开始点一定无法转完一圈 33 | if (start != init && start == lastIndex(end, dis.length)) { 34 | break; 35 | } 36 | // 当前来到的start不在连通区域中,就扩充连通区域 37 | if (dis[start] < need) { // 当前start无法接到连通区的头部 38 | need -= dis[start]; 39 | } else { // 当前start可以接到连通区的头部,开始扩充连通区域的尾巴 40 | rest += dis[start] - need; 41 | need = 0; 42 | while (rest >= 0 && end != start) { 43 | rest += dis[end]; 44 | end = nextIndex(end, dis.length); 45 | } 46 | // 如果连通区域已经覆盖整个环,当前的start是良好出发点,进入2阶段 47 | if (rest >= 0) { 48 | res[start] = true; 49 | connectGood(dis, lastIndex(start, dis.length), init, res); 50 | break; 51 | } 52 | } 53 | start = lastIndex(start, dis.length); 54 | } while (start != init); 55 | return res; 56 | } 57 | 58 | // 已知start的next方向上有一个良好出发点 59 | // start如果可以达到这个良好出发点,那么从start出发一定可以转一圈 60 | public static void connectGood(int[] dis, int start, int init, boolean[] res) { 61 | int need = 0; 62 | while (start != init) { 63 | if (dis[start] < need) { 64 | need -= dis[start]; 65 | } else { 66 | res[start] = true; 67 | need = 0; 68 | } 69 | start = lastIndex(start, dis.length); 70 | } 71 | } 72 | 73 | public static int lastIndex(int index, int size) { 74 | return index == 0 ? (size - 1) : index - 1; 75 | } 76 | 77 | public static int nextIndex(int index, int size) { 78 | return index == size - 1 ? 0 : (index + 1); 79 | } 80 | 81 | // for test 82 | public static boolean[] test(int[] dis, int[] oil) { 83 | if (dis == null || oil == null || dis.length < 2 84 | || dis.length != oil.length) { 85 | return null; 86 | } 87 | boolean[] res = new boolean[dis.length]; 88 | for (int i = 0; i < dis.length; i++) { 89 | dis[i] = oil[i] - dis[i]; 90 | } 91 | for (int i = 0; i < dis.length; i++) { 92 | res[i] = canWalkThrough(dis, i); 93 | } 94 | return res; 95 | } 96 | 97 | // for test 98 | public static boolean canWalkThrough(int[] arr, int index) { 99 | int sum = 0; 100 | for (int i = 0; i < arr.length; i++) { 101 | sum += arr[index]; 102 | if (sum < 0) { 103 | return false; 104 | } 105 | index = nextIndex(index, arr.length); 106 | } 107 | return true; 108 | } 109 | 110 | // for test 111 | public static void printArray(int[] dis, int[] oil) { 112 | for (int i = 0; i < dis.length; i++) { 113 | System.out.print(oil[i] - dis[i] + " "); 114 | } 115 | System.out.println(); 116 | } 117 | 118 | // for test 119 | public static void printBooleanArray(boolean[] arr) { 120 | for (int i = 0; i < arr.length; i++) { 121 | System.out.print(arr[i] + " "); 122 | } 123 | System.out.println(); 124 | } 125 | 126 | // for test 127 | public static int[] generateArray(int size, int max) { 128 | int[] res = new int[size]; 129 | for (int i = 0; i < res.length; i++) { 130 | res[i] = (int) (Math.random() * max); 131 | } 132 | return res; 133 | } 134 | 135 | // for test 136 | public static int[] copyArray(int[] arr) { 137 | int[] res = new int[arr.length]; 138 | for (int i = 0; i < res.length; i++) { 139 | res[i] = arr[i]; 140 | } 141 | return res; 142 | } 143 | 144 | // for test 145 | public static boolean isEqual(boolean[] res1, boolean[] res2) { 146 | for (int i = 0; i < res1.length; i++) { 147 | if (res1[i] != res2[i]) { 148 | return false; 149 | } 150 | } 151 | return true; 152 | } 153 | 154 | public static void main(String[] args) { 155 | System.out.println("JJJ"); 156 | int max = 20; 157 | for (int i = 0; i < 5000000; i++) { 158 | int size = (int) (Math.random() * 20) + 2; 159 | int[] dis = generateArray(size, max); 160 | int[] oil = generateArray(size, max); 161 | int[] dis1 = copyArray(dis); 162 | int[] oil1 = copyArray(oil); 163 | int[] dis2 = copyArray(dis); 164 | int[] oil2 = copyArray(oil); 165 | boolean[] res1 = stations(dis1, oil1); 166 | boolean[] res2 = test(dis2, oil2); 167 | if (!isEqual(res1, res2)) { 168 | printArray(dis, oil); 169 | printBooleanArray(res1); 170 | printBooleanArray(res2); 171 | System.out.println("what a fucking day!"); 172 | break; 173 | } 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/class02/Code01_PathsToNums.java: -------------------------------------------------------------------------------- 1 | package class02; 2 | 3 | public class Code01_PathsToNums { 4 | 5 | public static void pathsToNums(int[] paths) { 6 | if (paths == null || paths.length == 0) { 7 | return; 8 | } 9 | // citiesPath -> distancesArray 10 | pathsToDistans(paths); 11 | 12 | // distancesArray -> countsArray 13 | distansToNums(paths); 14 | } 15 | 16 | public static void pathsToDistans(int[] paths) { 17 | int cap = 0; 18 | for (int start = 0; start != paths.length; start++) { 19 | if (paths[start] == start) { 20 | cap = start; 21 | } else if (paths[start] > -1) { 22 | int curI = paths[start]; 23 | paths[start] = -1; 24 | int preI = start; 25 | while (paths[curI] != curI) { 26 | if (paths[curI] > -1) { 27 | int nextI = paths[curI]; 28 | paths[curI] = preI; 29 | preI = curI; 30 | curI = nextI; 31 | } else { 32 | break; 33 | } 34 | } 35 | int value = paths[curI] == curI ? 0 : paths[curI]; 36 | while (paths[preI] != -1) { 37 | int lastPreI = paths[preI]; 38 | paths[preI] = --value; 39 | curI = preI; 40 | preI = lastPreI; 41 | } 42 | paths[preI] = --value; 43 | } 44 | } 45 | paths[cap] = 0; 46 | } 47 | 48 | public static void distansToNums(int[] disArr) { 49 | for (int i = 0; i != disArr.length; i++) { 50 | int index = disArr[i]; // index 负数 , 首都的index是0 51 | if (index < 0) { 52 | disArr[i] = 0; // important 53 | while (true) { 54 | index = -index; 55 | if (disArr[index] > -1) { 56 | disArr[index]++; 57 | break; 58 | } else { // 含义没变过来,还需要继续跳 59 | int nextIndex = disArr[index]; 60 | disArr[index] = 1; 61 | index = nextIndex; 62 | } 63 | } 64 | } 65 | } 66 | disArr[0] = 1; 67 | } 68 | 69 | public static void printArray(int[] arr) { 70 | if (arr == null || arr.length == 0) { 71 | return; 72 | } 73 | for (int i = 0; i != arr.length; i++) { 74 | System.out.print(arr[i] + " "); 75 | } 76 | System.out.println(); 77 | } 78 | 79 | public static void main(String[] args) { 80 | int[] paths = { 9, 1, 4, 9, 0, 4, 8, 9, 0, 1 }; 81 | printArray(paths); 82 | pathsToNums(paths); 83 | printArray(paths); 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/class02/Code02_CandyProblem.java: -------------------------------------------------------------------------------- 1 | package class02; 2 | 3 | public class Code02_CandyProblem { 4 | 5 | public static int candy1(int[] arr) { 6 | if (arr == null || arr.length == 0) { 7 | return 0; 8 | } 9 | int index = nextMinIndex1(arr, 0); 10 | int res = rightCands(arr, 0, index++); 11 | int lbase = 1; 12 | int next = 0; 13 | int rcands = 0; 14 | int rbase = 0; 15 | while (index != arr.length) { 16 | if (arr[index] > arr[index - 1]) { 17 | res += ++lbase; 18 | index++; 19 | } else if (arr[index] < arr[index - 1]) { 20 | next = nextMinIndex1(arr, index - 1); 21 | rcands = rightCands(arr, index - 1, next++); 22 | rbase = next - index + 1; 23 | res += rcands + (rbase > lbase ? -lbase : -rbase); 24 | lbase = 1; 25 | index = next; 26 | } else { 27 | res += 1; 28 | lbase = 1; 29 | index++; 30 | } 31 | } 32 | return res; 33 | } 34 | 35 | public static int nextMinIndex1(int[] arr, int start) { 36 | for (int i = start; i != arr.length - 1; i++) { 37 | if (arr[i] <= arr[i + 1]) { 38 | return i; 39 | } 40 | } 41 | return arr.length - 1; 42 | } 43 | 44 | public static int rightCands(int[] arr, int left, int right) { 45 | int n = right - left + 1; 46 | return n + n * (n - 1) / 2; 47 | } 48 | 49 | public static int candy2(int[] arr) { 50 | if (arr == null || arr.length == 0) { 51 | return 0; 52 | } 53 | int index = nextMinIndex2(arr, 0); 54 | int[] data = rightCandsAndBase(arr, 0, index++); 55 | int res = data[0]; 56 | int lbase = 1; 57 | int same = 1; 58 | int next = 0; 59 | while (index != arr.length) { 60 | if (arr[index] > arr[index - 1]) { 61 | res += ++lbase; 62 | same = 1; 63 | index++; 64 | } else if (arr[index] < arr[index - 1]) { 65 | next = nextMinIndex2(arr, index - 1); 66 | data = rightCandsAndBase(arr, index - 1, next++); 67 | if (data[1] <= lbase) { 68 | res += data[0] - data[1]; 69 | } else { 70 | res += -lbase * same + data[0] - data[1] + data[1] * same; 71 | } 72 | index = next; 73 | lbase = 1; 74 | same = 1; 75 | } else { 76 | res += lbase; 77 | same++; 78 | index++; 79 | } 80 | } 81 | return res; 82 | } 83 | 84 | public static int nextMinIndex2(int[] arr, int start) { 85 | for (int i = start; i != arr.length - 1; i++) { 86 | if (arr[i] < arr[i + 1]) { 87 | return i; 88 | } 89 | } 90 | return arr.length - 1; 91 | } 92 | 93 | public static int[] rightCandsAndBase(int[] arr, int left, int right) { 94 | int base = 1; 95 | int cands = 1; 96 | for (int i = right - 1; i >= left; i--) { 97 | if (arr[i] == arr[i + 1]) { 98 | cands += base; 99 | } else { 100 | cands += ++base; 101 | } 102 | } 103 | return new int[] { cands, base }; 104 | } 105 | 106 | public static void main(String[] args) { 107 | int[] test1 = { 3, 0, 5, 5, 4, 4, 0 }; 108 | System.out.println(candy1(test1)); 109 | 110 | int[] test2 = { 3, 0, 5, 5, 4, 4, 0 }; 111 | System.out.println(candy2(test2)); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/class02/Code03_MinCameraCover.java: -------------------------------------------------------------------------------- 1 | package class02; 2 | 3 | public class Code03_MinCameraCover { 4 | 5 | public static class Node { 6 | public int value; 7 | public Node left; 8 | public Node right; 9 | } 10 | 11 | public static int minCameraCover1(Node root) { 12 | Info data = process1(root); 13 | return (int) Math.min(data.uncovered + 1, 14 | Math.min(data.coveredNoCamera, data.coveredHasCamera)); 15 | } 16 | 17 | // 潜台词:x是头节点,x下方的点都被覆盖的情况下 18 | public static class Info { 19 | public long uncovered; // x没有被覆盖,x为头的树至少需要几个相机 20 | public long coveredNoCamera; // x被相机覆盖,但是x没相机,x为头的树至少需要几个相机 21 | public long coveredHasCamera; // x被相机覆盖了,并且x上放了相机,x为头的树至少需要几个相机 22 | 23 | public Info(long un, long no, long has) { 24 | uncovered = un; 25 | coveredNoCamera = no; 26 | coveredHasCamera = has; 27 | } 28 | } 29 | 30 | // 所有可能性都穷尽了 31 | public static Info process1(Node X) { 32 | if (X == null) { // base case 33 | return new Info(Integer.MAX_VALUE, 0, Integer.MAX_VALUE); 34 | } 35 | 36 | 37 | Info left = process1(X.left); 38 | Info right = process1(X.right); 39 | // x uncovered x自己不被覆盖,x下方所有节点,都被覆盖 40 | // 左孩子: 左孩子没被覆盖,左孩子以下的点都被覆盖 41 | // 左孩子被覆盖但没相机,左孩子以下的点都被覆盖 42 | // 左孩子被覆盖也有相机,左孩子以下的点都被覆盖 43 | long uncovered = left.coveredNoCamera + right.coveredNoCamera; 44 | 45 | 46 | 47 | // x下方的点都被covered,x也被cover,但x上没相机 48 | long coveredNoCamera = Math.min( 49 | // 1) 50 | left.coveredHasCamera + right.coveredHasCamera, 51 | 52 | Math.min( 53 | // 2) 54 | left.coveredHasCamera + right.coveredNoCamera, 55 | 56 | // 3) 57 | left.coveredNoCamera + right.coveredHasCamera) 58 | ); 59 | 60 | 61 | // x下方的点都被covered,x也被cover,且x上有相机 62 | long coveredHasCamera = Math.min( 63 | 64 | left.uncovered, 65 | Math.min( 66 | left.coveredNoCamera, 67 | left.coveredHasCamera) 68 | ) 69 | 70 | 71 | + 72 | Math.min( 73 | right.uncovered, 74 | Math.min( 75 | right.coveredNoCamera, 76 | right.coveredHasCamera)) 77 | 78 | 79 | + 1; 80 | 81 | 82 | return new Info(uncovered, coveredNoCamera, coveredHasCamera); 83 | } 84 | 85 | public static int minCameraCover2(Node root) { 86 | Data data = process2(root); 87 | return data.cameras + (data.status == Status.UNCOVERED ? 1 : 0); 88 | } 89 | 90 | // 以x为头,x下方的节点都是被covered,x自己的状况,分三种 91 | public static enum Status { 92 | UNCOVERED, COVERED_NO_CAMERA, COVERED_HAS_CAMERA 93 | } 94 | 95 | // 以x为头,x下方的节点都是被covered,得到的最优解中: 96 | // x是什么状态,在这种状态下,需要至少几个相机 97 | public static class Data { 98 | public Status status; 99 | public int cameras; 100 | 101 | public Data(Status status, int cameras) { 102 | this.status = status; 103 | this.cameras = cameras; 104 | } 105 | } 106 | 107 | public static Data process2(Node X) { 108 | if (X == null) { 109 | return new Data(Status.COVERED_NO_CAMERA, 0); 110 | } 111 | Data left = process2(X.left); 112 | Data right = process2(X.right); 113 | int cameras = left.cameras + right.cameras; 114 | if (left.status == Status.UNCOVERED || right.status == Status.UNCOVERED) { 115 | return new Data(Status.COVERED_HAS_CAMERA, cameras + 1); 116 | } 117 | 118 | 119 | // 左右孩子,不存在没被覆盖的情况 120 | if (left.status == Status.COVERED_HAS_CAMERA 121 | || 122 | right.status == Status.COVERED_HAS_CAMERA) { 123 | return new Data(Status.COVERED_NO_CAMERA, cameras); 124 | } 125 | // 左右孩子,不存在没被覆盖的情况,也都没有相机 126 | return new Data(Status.UNCOVERED, cameras); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/class02/Code04_MaximumSumof3NonOverlappingSubarrays.java: -------------------------------------------------------------------------------- 1 | package class02; 2 | 3 | public class Code04_MaximumSumof3NonOverlappingSubarrays { 4 | 5 | public static int[] maxSumOfThreeSubarrays(int[] nums, int k) { 6 | int N = nums.length; 7 | int[] range = new int[N]; 8 | int[] left = new int[N]; 9 | int sum = 0; 10 | for (int i = 0; i < k; i++) { 11 | sum += nums[i]; 12 | } 13 | range[0] = sum; 14 | left[k - 1] = 0; 15 | int max = sum; 16 | for (int i = k; i < N; i++) { 17 | sum = sum - nums[i - k] + nums[i]; 18 | range[i - k + 1] = sum; 19 | left[i] = left[i - 1]; 20 | if (sum > max) { 21 | max = sum; 22 | left[i] = i - k + 1; 23 | } 24 | } 25 | sum = 0; 26 | for (int i = N - 1; i >= N - k; i--) { 27 | sum += nums[i]; 28 | } 29 | max = sum; 30 | int[] right = new int[N]; 31 | right[N - k] = N - k; 32 | for (int i = N - k - 1; i >= 0; i--) { 33 | sum = sum - nums[i + k] + nums[i]; 34 | right[i] = right[i + 1]; 35 | if (sum >= max) { 36 | max = sum; 37 | right[i] = i; 38 | } 39 | } 40 | int a = 0; 41 | int b = 0; 42 | int c = 0; 43 | max = 0; 44 | for (int i = k; i < N - 2 * k + 1; i++) { // 中间一块的起始点 (0...k-1)选不了 i == N-1 45 | int part1 = range[left[i - 1]]; 46 | int part2 = range[i]; 47 | int part3 = range[right[i + k]]; 48 | if (part1 + part2 + part3 > max) { 49 | max = part1 + part2 + part3; 50 | a = left[i - 1]; 51 | b = i; 52 | c = right[i + k]; 53 | } 54 | } 55 | return new int[] { a, b, c }; 56 | } 57 | 58 | public static void main(String[] args) { 59 | int[] nums = { 9, 8, 7, 6, 2, 2, 2, 2 }; 60 | int k = 2; 61 | int[] ans = maxSumOfThreeSubarrays(nums, k); 62 | System.out.println(ans[0] + "," + ans[1] + "," + ans[2]); 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/class03/Code01_NiuNiuSplitField.java: -------------------------------------------------------------------------------- 1 | package class03; 2 | 3 | import java.util.*; 4 | 5 | public class Code01_NiuNiuSplitField { 6 | 7 | // arr都是正数,0~i切的时候,怎么切最优,最优的结论生成一个数组返回 8 | public static int[] getAnswers(int[] arr) { 9 | if (arr == null || arr.length < 1) { 10 | return null; 11 | } 12 | // ans[i] 代表的含义: 13 | // arr[0..i]切两块的各种方案中,哪一种方案能让左右两部份的累加和最小值,尽量大 14 | int[] ans = new int[arr.length]; 15 | ans[0] = 0; 16 | int best = 0;// 左 0..0 右 无 17 | for (int i = 1; i < arr.length; i++) { 18 | while (best < i - 1 && getSplit(arr, best, i) < getSplit(arr, best + 1, i)) { 19 | best++; 20 | } 21 | ans[i] = getSplit(arr, best, i); 22 | } 23 | return ans; 24 | } 25 | 26 | public static int getSum(int[] arr, int i, int j) { 27 | return 0; 28 | } 29 | 30 | // arr[0..j] 如果我把切的这一刀定在m位置,左0..m,右m+1..j 31 | public static int getSplit(int[] arr, int m, int j) { 32 | return 0; 33 | } 34 | 35 | public static int maxMinSumIn16(int[][] matrix) { 36 | if (matrix == null || matrix.length < 4 || matrix[0].length < 4) { 37 | return 0; 38 | } 39 | // help[i][j] 含义,左上角为(0,0) 右下角为(i,j)的子矩阵累加和是多少 40 | int[][] help = generateSumRecord(matrix); 41 | // 通过help,得到任何子矩阵的累加和 42 | int col = matrix[0].length; 43 | int res = Integer.MIN_VALUE; 44 | // 3个for循环在暴力枚举纵向三刀 45 | for (int c1 = 0; c1 < col - 3; c1++) { 46 | for (int c2 = c1 + 1; c2 < col - 2; c2++) { 47 | for (int c3 = c2 + 1; c3 < col - 1; c3++) { 48 | // c1 c2 c3 49 | res = Math.max(res, getBestDicision(help, c1, c2, c3)); 50 | } 51 | } 52 | } 53 | return res; 54 | } 55 | 56 | // record[i][j] 左上角点0,0, 有效角点i、j , 该矩阵的累加和 57 | public static int[][] generateSumRecord(int[][] matrix) { 58 | int row = matrix.length; 59 | int col = matrix[0].length; 60 | int[][] record = new int[row][col]; 61 | record[0][0] = matrix[0][0]; 62 | for (int i = 1; i < row; i++) { 63 | record[i][0] = record[i - 1][0] + matrix[i][0]; 64 | } 65 | for (int j = 1; j < col; j++) { 66 | record[0][j] = record[0][j - 1] + matrix[0][j]; 67 | } 68 | for (int i = 1; i < row; i++) { 69 | for (int j = 1; j < col; j++) { 70 | record[i][j] = record[i][j - 1] + record[i - 1][j] - record[i - 1][j - 1] + matrix[i][j]; 71 | } 72 | } 73 | return record; 74 | } 75 | 76 | // 忘掉原来的矩阵,只使用help 77 | // 竖着三刀固定,c1,c2,c3 78 | // 所有横着切三刀的可能性中,那种切法能得到最好的结果,把结果返回 79 | public static int getBestDicision(int[][] help, int c1, int c2, int c3) { 80 | // 0~i 切一刀,出来八块,最优指标,up[i] 81 | int[] up = getUpSplitArray(help, c1, c2, c3); // 0行~i行 切一刀,分8块,min max 82 | 83 | // i ~ N-1 切一刀,出来八块,最优指标,down[i] 84 | int[] down = getDownSplitArray(help, c1, c2, c3); // i~n-1 切一刀 85 | 86 | int res = Integer.MIN_VALUE; 87 | for (int mid = 1; mid < help.length - 2; mid++) { 88 | res = Math.max(res, Math.min(up[mid], down[mid + 1])); 89 | } 90 | return res; 91 | } 92 | 93 | public static int value(int[][] record, int c1, int c2, int c3, int prow, int crow) { 94 | int value1 = area(record, prow, 0, crow, c1); 95 | int value2 = area(record, prow, c1 + 1, crow, c2); 96 | int value3 = area(record, prow, c2 + 1, crow, c3); 97 | int value4 = area(record, prow, c3 + 1, crow, record[0].length - 1); 98 | return Math.min(Math.min(value1, value2), Math.min(value3, value4)); 99 | } 100 | 101 | public static int area(int[][] record, int i1, int j1, int i2, int j2) { 102 | int all = record[i2][j2]; 103 | int left = j1 > 0 ? record[i2][j1 - 1] : 0; 104 | int up = i1 > 0 ? record[i1 - 1][j2] : 0; 105 | int makeUp = (i1 > 0 && j1 > 0) ? record[i1 - 1][j1 - 1] : 0; 106 | return all - left - up + makeUp; 107 | } 108 | 109 | public static int[] getUpSplitArray(int[][] record, int c1, int c2, int c3) { 110 | int size = record.length; 111 | int[] up = new int[size]; 112 | int split = 0; 113 | up[1] = Math.min(value(record, c1, c2, c3, 0, 0), value(record, c1, c2, c3, 1, 1)); 114 | for (int i = 2; i < size; i++) { 115 | int minsMax = towSubMatrixMin(record, c1, c2, c3, 0, split, i); 116 | while (split < i) { 117 | if (split == i - 1) { 118 | break; 119 | } 120 | int moved = towSubMatrixMin(record, c1, c2, c3, 0, split + 1, i); 121 | if (moved < minsMax) { 122 | break; 123 | } else { 124 | minsMax = moved; 125 | split++; 126 | } 127 | } 128 | up[i] = minsMax; 129 | } 130 | return up; 131 | } 132 | 133 | public static int[] getDownSplitArray(int[][] record, int c1, int c2, int c3) { 134 | int size = record.length; 135 | int[] down = new int[size]; 136 | int split = size - 1; 137 | down[size - 2] = Math.min(value(record, c1, c2, c3, size - 2, size - 2), 138 | value(record, c1, c2, c3, size - 1, size - 1)); 139 | for (int i = size - 3; i >= 0; i--) { 140 | int minsMax = towSubMatrixMin(record, c1, c2, c3, i, split - 1, size - 1); 141 | while (split > i) { 142 | if (split == i + 1) { 143 | break; 144 | } 145 | int moved = towSubMatrixMin(record, c1, c2, c3, i, split - 2, size - 1); 146 | if (moved < minsMax) { 147 | break; 148 | } else { 149 | minsMax = moved; 150 | split--; 151 | } 152 | } 153 | down[i] = minsMax; 154 | } 155 | return down; 156 | } 157 | 158 | // 159 | // public static int[] getSplitDpArray(int[] arr) { 160 | // int[] dp = new int[arr.length]; 161 | // int split = 0; 162 | // dp[1] = Math.min(arr[0], arr[1]); 163 | // for (int i = 2; i < arr.length; i++) { 164 | // int minsMax = Math.min(getSum(arr,0, split), getSum(arr,split+1,i)); 165 | // while (split < i - 1) { 166 | // int nextMin = Math.min(getSum(arr,0, split+1), getSum(arr,split+2,i)); 167 | // if (nextMin < minsMax) { 168 | // break; 169 | // } else { 170 | // minsMax = nextMin; 171 | // split++; 172 | // } 173 | // } 174 | // dp[i] = minsMax; 175 | // } 176 | // return dp; 177 | // } 178 | // 179 | // public static int getSum(int[] arr, int i, int j) { 180 | // return 0; 181 | // } 182 | // 183 | 184 | public static int towSubMatrixMin(int[][] record, int c1, int c2, int c3, int i, int split, int j) { 185 | return Math.min(value(record, c1, c2, c3, i, split), value(record, c1, c2, c3, split + 1, j)); 186 | } 187 | 188 | public static void main(String[] args) { 189 | Scanner in = new Scanner(System.in); 190 | while (in.hasNext()) { 191 | int n = in.nextInt(); 192 | int m = in.nextInt(); 193 | int[][] matrix = new int[n][m]; 194 | for (int i = 0; i < n; i++) { 195 | char[] chas = in.next().toCharArray(); 196 | for (int j = 0; j < m; j++) { 197 | matrix[i][j] = chas[j] - '0'; 198 | } 199 | } 200 | System.out.println(maxMinSumIn16(matrix)); 201 | } 202 | in.close(); 203 | } 204 | 205 | } -------------------------------------------------------------------------------- /src/class03/Code02_BricksFallingWhenHit1.java: -------------------------------------------------------------------------------- 1 | package class03; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Stack; 6 | 7 | public class Code02_BricksFallingWhenHit1 { 8 | 9 | // 每一个1,都有一个专属于自己的Dot 10 | public static class Dot { 11 | 12 | } 13 | 14 | public static class UnionFind { 15 | // 原始数组,经过炮弹的影响之后,所得到的grid 16 | private int[][] grid; // 主函数处理后的原始矩 17 | // 如果gird[i][j] == 1, dots[i][j] = new 的点 18 | private Dot[][] dots; // 位置到点的对应关系 19 | private int N; // 行数 20 | private int M; // 列数 21 | private int cellingAll; // 有多少个1能连接到天花板 22 | 23 | // 某个集合,是不是整体接到天花版上去了,如果是,假设这个集合代表点是X,cellingSet包含x 24 | // 如果不是,假设这个集合代表点是X,cellingSet不包含X 25 | private HashSet cellingSet; // 集合能够连到天花板,它的代表点才在里面 26 | private HashMap fatherMap; // 任何一个dot都有记录,value就是父节点 27 | private HashMap sizeMap; 28 | // 只有一个dot是代表点,才有记录,value表示这个集合的大小 29 | 30 | // matrix,炮弹会让某些位置的1变成2,2和0一样,表示不连通;只有1是联通的,上下左右 31 | public UnionFind(int[][] matrix) { 32 | initSpace(matrix); 33 | initConnect(); 34 | } 35 | 36 | private void initSpace(int[][] matrix) { 37 | grid = matrix; 38 | N = grid.length; 39 | M = grid[0].length; 40 | // 接到天花板上砖的数量 41 | cellingAll = 0; 42 | dots = new Dot[N][M]; // dot null 43 | cellingSet = new HashSet<>(); 44 | fatherMap = new HashMap<>(); 45 | sizeMap = new HashMap<>(); 46 | for (int row = 0; row < N; row++) { 47 | for (int col = 0; col < M; col++) { 48 | // 遍历每一个[i][j] 2 0 直接跳过 49 | if (grid[row][col] == 1) { // 该点是我关心的,不是1就不关心 50 | Dot cur = new Dot(); 51 | dots[row][col] = cur; 52 | fatherMap.put(cur, cur); 53 | sizeMap.put(cur, 1); 54 | if (row == 0) { // dot是天花板上的点 55 | cellingSet.add(cur); 56 | cellingAll++; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | private void initConnect() { 64 | for (int row = 0; row < N; row++) { 65 | for (int col = 0; col < M; col++) { 66 | union(row, col, row - 1, col); 67 | union(row, col, row + 1, col); 68 | union(row, col, row, col - 1); 69 | union(row, col, row, col + 1); 70 | } 71 | } 72 | } 73 | 74 | // row,col 的dot,所在的集合,代表dot是谁返回 75 | private Dot find(int row, int col) { 76 | Dot cur = dots[row][col]; 77 | Stack stack = new Stack<>(); 78 | while (cur != fatherMap.get(cur)) { 79 | stack.add(cur); 80 | cur = fatherMap.get(cur); 81 | } 82 | while (!stack.isEmpty()) { 83 | fatherMap.put(stack.pop(), cur); 84 | } 85 | return cur; 86 | } 87 | 88 | private void union(int r1, int c1, int r2, int c2) { 89 | if (valid(r1, c1) && valid(r2, c2)) { 90 | Dot father1 = find(r1, c1); 91 | Dot father2 = find(r2, c2); 92 | if (father1 != father2) { 93 | int size1 = sizeMap.get(father1); 94 | int size2 = sizeMap.get(father2); 95 | 96 | // Dot big = size1 >= size2 ? father1 : father2; 97 | // Dot small = big == father1 ? father2 : father1; 98 | // fatherMap.put(small, big); 99 | // sizeMap.put(big, size1 + size2); 100 | // // 集合1整体连不连的到天花板上 101 | // boolean status1 = cellingSet.contains(father1); 102 | // // 集合2整体连不连的到天花板上 103 | // boolean status2 = cellingSet.contains(father2); 104 | // if(status1 ^ status2) { 105 | // cellingSet.add(big); 106 | // cellingAll += status1 ? size2 : size1; 107 | // } 108 | // 109 | // 集合1整体连不连的到天花板上 110 | boolean status1 = cellingSet.contains(father1); 111 | // 集合2整体连不连的到天花板上 112 | boolean status2 = cellingSet.contains(father2); 113 | if (size1 <= size2) { 114 | // 集合1与集合2,已经合完了,共同的父节点father2 115 | fatherMap.put(father1, father2); 116 | sizeMap.put(father2, size1 + size2); 117 | // 如果两个集合能否接到天花板的状态不一样 118 | if (status1 ^ status2) { 119 | cellingSet.add(father2); 120 | cellingAll += status1 ? size2 : size1; 121 | } 122 | } else { 123 | fatherMap.put(father2, father1); 124 | sizeMap.put(father1, size1 + size2); 125 | if (status1 ^ status2) { 126 | cellingSet.add(father1); 127 | cellingAll += status1 ? size2 : size1; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | private boolean valid(int row, int col) { 135 | return row >= 0 && row < N && col >= 0 && col < M && grid[row][col] == 1; 136 | } 137 | 138 | public int cellingNum() { 139 | return cellingAll; 140 | } 141 | 142 | // 原来row,col 2 finger 1 143 | // 在该位置变成1的情况下,并查集该如何变化,接到天花板上的1又会如何变化 144 | public int finger(int row, int col) { 145 | int pre = cellingAll; 146 | grid[row][col] = 1; 147 | Dot cur = new Dot(); 148 | dots[row][col] = cur; 149 | if (row == 0) { 150 | cellingSet.add(cur); 151 | cellingAll++; 152 | } 153 | fatherMap.put(cur, cur); 154 | sizeMap.put(cur, 1); 155 | union(row, col, row - 1, col); 156 | union(row, col, row + 1, col); 157 | union(row, col, row, col - 1); 158 | union(row, col, row, col + 1); 159 | int now = cellingAll; 160 | return now == pre ? 0 : now - pre - 1; 161 | } 162 | } 163 | 164 | public static int[] hitBricks(int[][] grid, int[][] hits) { 165 | // 把炮弹影响加上,grid会怎么变 166 | for (int i = 0; i < hits.length; i++) { 167 | if (grid[hits[i][0]][hits[i][1]] == 1) { 168 | grid[hits[i][0]][hits[i][1]] = 2; 169 | } 170 | } 171 | 172 | UnionFind unionFind = new UnionFind(grid); 173 | int[] ans = new int[hits.length]; 174 | for (int i = hits.length - 1; i >= 0; i--) { 175 | if (grid[hits[i][0]][hits[i][1]] == 2) { 176 | ans[i] = unionFind.finger(hits[i][0], hits[i][1]); 177 | } 178 | } 179 | return ans; 180 | } 181 | 182 | public static void main(String[] args) { 183 | int[][] grid = { { 1, 0, 1 }, { 1, 1, 1 } }; 184 | int[][] hits = { { 0, 0 }, { 0, 2 }, { 1, 1 } }; 185 | int[] ans = hitBricks(grid, hits); 186 | for (int i = 0; i < ans.length; i++) { 187 | System.out.println(ans[i]); 188 | } 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /src/class03/Code02_BricksFallingWhenHit2.java: -------------------------------------------------------------------------------- 1 | package class03; 2 | 3 | import java.util.Stack; 4 | 5 | public class Code02_BricksFallingWhenHit2 { 6 | 7 | public static class UnionFind { 8 | private int N; 9 | private int M; 10 | private int cellingAll; 11 | private int[][] grid; 12 | private boolean[] cellingSet; 13 | private int[] fatherMap; 14 | private int[] sizeMap; 15 | 16 | public UnionFind(int[][] matrix) { 17 | initSpace(matrix); 18 | initConnect(); 19 | } 20 | 21 | private void initSpace(int[][] matrix) { 22 | grid = matrix; 23 | N = grid.length; 24 | M = grid[0].length; 25 | int all = N * M; 26 | cellingAll = 0; 27 | cellingSet = new boolean[all]; 28 | fatherMap = new int[all]; 29 | sizeMap = new int[all]; 30 | for (int row = 0; row < N; row++) { 31 | for (int col = 0; col < M; col++) { 32 | if (grid[row][col] == 1) { 33 | int index = row * M + col; 34 | fatherMap[index] = index; 35 | sizeMap[index] = 1; 36 | if (row == 0) { 37 | cellingSet[index] = true; 38 | cellingAll++; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | private void initConnect() { 46 | for (int row = 0; row < N; row++) { 47 | for (int col = 0; col < M; col++) { 48 | union(row, col, row - 1, col); 49 | union(row, col, row + 1, col); 50 | union(row, col, row, col - 1); 51 | union(row, col, row, col + 1); 52 | } 53 | } 54 | } 55 | 56 | private int find(int row, int col) { 57 | Stack stack = new Stack<>(); 58 | int index = row * M + col; 59 | while (index != fatherMap[index]) { 60 | stack.add(index); 61 | index = fatherMap[index]; 62 | } 63 | while (!stack.isEmpty()) { 64 | fatherMap[stack.pop()] = index; 65 | } 66 | return index; 67 | } 68 | 69 | private void union(int r1, int c1, int r2, int c2) { 70 | if (valid(r1, c1) && valid(r2, c2)) { 71 | int father1 = find(r1, c1); 72 | int father2 = find(r2, c2); 73 | if (father1 != father2) { 74 | int size1 = sizeMap[father1]; 75 | int size2 = sizeMap[father2]; 76 | boolean status1 = cellingSet[father1]; 77 | boolean status2 = cellingSet[father2]; 78 | if (size1 <= size2) { 79 | fatherMap[father1] = father2; 80 | sizeMap[father2] = size1 + size2; 81 | if (status1 ^ status2) { 82 | cellingSet[father2] = true; 83 | cellingAll += status1 ? size2 : size1; 84 | } 85 | } else { 86 | fatherMap[father2] = father1; 87 | sizeMap[father1] = size1 + size2; 88 | if (status1 ^ status2) { 89 | cellingSet[father1] = true; 90 | cellingAll += status1 ? size2 : size1; 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | private boolean valid(int row, int col) { 98 | return row >= 0 && row < N && col >= 0 && col < M && grid[row][col] == 1; 99 | } 100 | 101 | public int cellingNum() { 102 | return cellingAll; 103 | } 104 | 105 | public int finger(int row, int col) { 106 | grid[row][col] = 1; 107 | int cur = row * M + col; 108 | if (row == 0) { 109 | cellingSet[cur] = true; 110 | cellingAll++; 111 | } 112 | fatherMap[cur] = cur; 113 | sizeMap[cur] = 1; 114 | int pre = cellingAll; 115 | union(row, col, row - 1, col); 116 | union(row, col, row + 1, col); 117 | union(row, col, row, col - 1); 118 | union(row, col, row, col + 1); 119 | int now = cellingAll; 120 | if (row == 0) { 121 | return now - pre; 122 | } else { 123 | return now == pre ? 0 : now - pre - 1; 124 | } 125 | } 126 | } 127 | 128 | public static int[] hitBricks(int[][] grid, int[][] hits) { 129 | for (int i = 0; i < hits.length; i++) { 130 | if (grid[hits[i][0]][hits[i][1]] == 1) { 131 | grid[hits[i][0]][hits[i][1]] = 2; 132 | } 133 | } 134 | UnionFind unionFind = new UnionFind(grid); 135 | int[] ans = new int[hits.length]; 136 | for (int i = hits.length - 1; i >= 0; i--) { 137 | if (grid[hits[i][0]][hits[i][1]] == 2) { 138 | ans[i] = unionFind.finger(hits[i][0], hits[i][1]); 139 | } 140 | } 141 | return ans; 142 | } 143 | 144 | public static void main(String[] args) { 145 | int[][] grid = { 146 | {1, 0, 1, 1, 0}, 147 | {1, 1, 0, 1, 0}, 148 | {1, 0, 0, 1, 1}, 149 | {1, 1, 0, 1, 0} 150 | }; 151 | int[][] hits = {{1,0},{2,3},{0,3}}; 152 | int[] ans = hitBricks(grid, hits); 153 | for (int i = 0; i < ans.length; i++) { 154 | System.out.println(ans[i]); 155 | } 156 | 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/class03/Code03_TallestBillboard.java: -------------------------------------------------------------------------------- 1 | package class03; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Code03_TallestBillboard { 6 | 7 | public int tallestBillboard(int[] rods) { 8 | // key 集合对的某个差 9 | // value 满足差值为key的集合对中,最好的一对,较小集合的累加和 10 | // 较大 -> value + key 11 | HashMap dp = new HashMap<>(), cur; 12 | dp.put(0, 0);// 空集 和 空集 13 | for (int num : rods) { 14 | if (num != 0) { 15 | // cur 内部数据完全和dp一样 16 | cur = new HashMap<>(dp); // 考虑x之前的集合差值状况拷贝下来 17 | for (int d : cur.keySet()) { 18 | int diffMore = cur.get(d); // 最好的一对,较小集合的累加和 19 | // x决定放入,比较大的那个 20 | dp.put(d + num, Math.max(diffMore, dp.getOrDefault(num + d, 0))); 21 | // x决定放入,比较小的那个 22 | // 新的差值 Math.abs(x - d) 23 | // 之前差值为Math.abs(x - d),的那一对,就要和这一对,决策一下 24 | // 之前那一对,较小集合的累加和diffXD 25 | int diffXD = dp.getOrDefault(Math.abs(num - d), 0); 26 | if (d >= num) { // x决定放入比较小的那个, 但是放入之后,没有超过这一对较大的那个 27 | dp.put(d - num, Math.max(diffMore + num, diffXD)); 28 | } else { // x决定放入比较小的那个, 但是放入之后,没有超过这一对较大的那个 29 | dp.put(num - d, Math.max(diffMore + d, diffXD)); 30 | } 31 | } 32 | } 33 | } 34 | return dp.get(0); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/class03/Code04_DistinctSubseq.java: -------------------------------------------------------------------------------- 1 | package class03; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Code04_DistinctSubseq { 6 | 7 | public static int distinctSubseq1(String s) { 8 | char[] str = s.toCharArray(); 9 | int result = 0; 10 | int[] dp = new int[str.length]; 11 | Arrays.fill(dp, 1); 12 | for (int i = 0; i < str.length; i++) { 13 | for (int j = 0; j < i; j++) { 14 | if (str[j] != str[i]) { 15 | dp[i] += dp[j]; 16 | } 17 | } 18 | result += dp[i]; 19 | } 20 | return result; 21 | } 22 | 23 | public static int distinctSubseq2(String s) { 24 | if (s == null || s.length() == 0) { 25 | return 0; 26 | } 27 | char[] str = s.toCharArray(); 28 | int[] dp = new int[str.length]; 29 | Arrays.fill(dp, 1); 30 | int[] count = new int[26]; 31 | int result = 0; 32 | for (int i = 0; i < str.length; i++) { 33 | int index = str[i] - 'a'; 34 | dp[i] += result - count[index]; 35 | result += dp[i]; 36 | count[index] = count[index] + dp[i]; 37 | } 38 | return result; 39 | } 40 | 41 | public static int distinctSubseq3(String s) { 42 | if (s == null || s.length() == 0) { 43 | return 0; 44 | } 45 | char[] str = s.toCharArray(); 46 | int[] count = new int[26]; 47 | int result = 0; 48 | for (int i = 0; i < str.length; i++) { 49 | int index = str[i] - 'a'; 50 | int pre = result - count[index] + 1; 51 | count[index] += pre; 52 | result += pre; 53 | } 54 | return result; 55 | } 56 | 57 | public static int distinctSubseq4(String s) { 58 | if (s == null || s.length() == 0) { 59 | return 0; 60 | } 61 | char[] str = s.toCharArray(); 62 | // a - z 63 | // count[0] = a的统计 64 | // ... 65 | // count[25] = z的统计 66 | int[] count = new int[26]; 67 | int all = 0; // 不算空集 68 | for(char x : str) { 69 | int add = all + 1 - count[x - 'a']; 70 | all += add; 71 | count[x - 'a'] += add; 72 | } 73 | return all; 74 | } 75 | 76 | public static int ketang(String s) { 77 | if (s == null || s.length() == 0) { 78 | return 0; 79 | } 80 | char[] str = s.toCharArray(); 81 | // a - z 82 | // count[0] = a的统计 83 | // ... 84 | // count[25] = z的统计 85 | int[] count = new int[26]; 86 | int all = 1; // 算空集 87 | for(char x : str) { 88 | int add = all - count[x - 'a']; 89 | all += add; 90 | count[x - 'a'] += add; 91 | } 92 | return all; 93 | } 94 | 95 | 96 | public static String random(int len, int varible) { 97 | int size = (int) (Math.random() * len) + 1; 98 | char[] str = new char[size]; 99 | for (int i = 0; i < size; i++) { 100 | str[i] = (char) ((int) (Math.random() * varible) + 'a'); 101 | } 102 | return String.valueOf(str); 103 | } 104 | 105 | public static void main(String[] args) { 106 | int len = 10; 107 | int varible = 5; 108 | for (int i = 0; i < 1000000; i++) { 109 | String test = random(len, varible); 110 | if (distinctSubseq1(test) != distinctSubseq2(test) || distinctSubseq2(test) != distinctSubseq4(test)) { 111 | System.out.println("fuck"); 112 | } 113 | } 114 | 115 | System.out.println("hello"); 116 | 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/class03/Main.java: -------------------------------------------------------------------------------- 1 | //不要拷贝包信息的内容 2 | package class03; 3 | 4 | //本文件是Code01_NiuNiuSplitField问题的牛客题目解答 5 | 6 | //这是牛客的测试链接: 7 | //https://www.nowcoder.com/questionTerminal/fe30a13b5fb84b339cb6cb3f70dca699 8 | //把如下的全部代码拷贝进编辑器(java) 9 | //可以直接通过 10 | 11 | import java.util.Scanner; 12 | 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | Scanner in = new Scanner(System.in); 17 | while (in.hasNext()) { 18 | int n = in.nextInt(); 19 | int m = in.nextInt(); 20 | int[][] matrix = new int[n][m]; 21 | for (int i = 0; i < n; i++) { 22 | char[] chas = in.next().toCharArray(); 23 | for (int j = 0; j < m; j++) { 24 | matrix[i][j] = chas[j] - '0'; 25 | } 26 | } 27 | System.out.println(maxMinSumIn16(matrix)); 28 | } 29 | in.close(); 30 | } 31 | 32 | public static int maxMinSumIn16(int[][] matrix) { 33 | if (matrix == null || matrix.length < 4 || matrix[0].length < 4) { 34 | return 0; 35 | } 36 | int[][] record = generateSumRecord(matrix); 37 | int col = matrix[0].length; 38 | int res = Integer.MIN_VALUE; 39 | for (int c1 = 0; c1 < col - 3; c1++) { 40 | for (int c2 = c1 + 1; c2 < col - 2; c2++) { 41 | for (int c3 = c2 + 1; c3 < col - 1; c3++) { 42 | res = Math.max(res, bestSplit(record, c1, c2, c3)); 43 | } 44 | } 45 | } 46 | return res; 47 | } 48 | 49 | public static int[][] generateSumRecord(int[][] matrix) { 50 | int row = matrix.length; 51 | int col = matrix[0].length; 52 | int[][] record = new int[row][col]; 53 | record[0][0] = matrix[0][0]; 54 | for (int i = 1; i < row; i++) { 55 | record[i][0] = record[i - 1][0] + matrix[i][0]; 56 | } 57 | for (int j = 1; j < col; j++) { 58 | record[0][j] = record[0][j - 1] + matrix[0][j]; 59 | } 60 | for (int i = 1; i < row; i++) { 61 | for (int j = 1; j < col; j++) { 62 | record[i][j] = record[i][j - 1] + record[i - 1][j] - record[i - 1][j - 1] + matrix[i][j]; 63 | } 64 | } 65 | return record; 66 | } 67 | 68 | public static int bestSplit(int[][] record, int c1, int c2, int c3) { 69 | int[] up2 = bestMinSplit2FromUp(record, c1, c2, c3); 70 | int[] down2 = bestMinSplit2FromDown(record, c1, c2, c3); 71 | int max = Integer.MIN_VALUE; 72 | for (int mid = 1; mid < record.length - 2; mid++) { 73 | max = Math.max(max, Math.min(up2[mid], down2[mid + 1])); 74 | } 75 | return max; 76 | } 77 | 78 | public static int[] bestMinSplit2FromUp(int[][] record, int c1, int c2, int c3) { 79 | int size = record.length; 80 | int[] max = new int[size]; 81 | int split = 0; 82 | for (int i = 1; i < size; i++) { 83 | int minsMax = twoValuesMin(record, c1, c2, c3, 0, split, i); 84 | for (; split < i - 1; split++) { 85 | int nextMin = twoValuesMin(record, c1, c2, c3, 0, split + 1, i); 86 | if (nextMin >= minsMax) { 87 | minsMax = nextMin; 88 | } else { 89 | break; 90 | } 91 | } 92 | max[i] = minsMax; 93 | } 94 | return max; 95 | } 96 | 97 | public static int[] bestMinSplit2FromDown(int[][] record, int c1, int c2, int c3) { 98 | int size = record.length; 99 | int[] max = new int[size]; 100 | int split = size - 1; 101 | for (int i = size - 2; i >= 0; i--) { 102 | int minsMax = twoValuesMin(record, c1, c2, c3, i, split - 1, size - 1); 103 | for (; split > i + 1; split--) { 104 | int nextMin = twoValuesMin(record, c1, c2, c3, i, split - 2, size - 1); 105 | if (nextMin >= minsMax) { 106 | minsMax = nextMin; 107 | } else { 108 | break; 109 | } 110 | } 111 | max[i] = minsMax; 112 | } 113 | return max; 114 | } 115 | 116 | // 两部分最小值返回 117 | public static int twoValuesMin(int[][] record, int c1, int c2, int c3, int i, int split, int j) { 118 | return Math.min(value(record, c1, c2, c3, i, split), value(record, c1, c2, c3, split + 1, j)); 119 | } 120 | 121 | // 提取出最小值 122 | public static int value(int[][] record, int c1, int c2, int c3, int prow, int crow) { 123 | int value1 = area(record, prow, 0, crow, c1); 124 | int value2 = area(record, prow, c1 + 1, crow, c2); 125 | int value3 = area(record, prow, c2 + 1, crow, c3); 126 | int value4 = area(record, prow, c3 + 1, crow, record[0].length - 1); 127 | return Math.min(Math.min(value1, value2), Math.min(value3, value4)); 128 | } 129 | 130 | // 算出区域内的累加和 131 | public static int area(int[][] record, int i1, int j1, int i2, int j2) { 132 | int all = record[i2][j2]; 133 | int left = j1 > 0 ? record[i2][j1 - 1] : 0; 134 | int up = i1 > 0 ? record[i1 - 1][j2] : 0; 135 | int makeUp = (i1 > 0 && j1 > 0) ? record[i1 - 1][j1 - 1] : 0; 136 | return all - left - up + makeUp; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /src/class04/Code01_SplitArrayLargestSum.java: -------------------------------------------------------------------------------- 1 | package class04; 2 | 3 | public class Code01_SplitArrayLargestSum { 4 | 5 | public static int splitArray1(int[] nums, int m) { 6 | return process(nums, 0, m); 7 | } 8 | 9 | public static int process(int[] arr, int index, int part) { 10 | if (index == arr.length) { 11 | return 0; 12 | } 13 | if (part == 0) { 14 | return -1; 15 | } 16 | int first = 0; 17 | int min = Integer.MAX_VALUE; 18 | for (int end = index; arr.length - end >= part; end++) { 19 | first += arr[end]; 20 | int next = process(arr, end + 1, part - 1); 21 | if (next != -1) { 22 | min = Math.min(min, Math.max(first, next)); 23 | } 24 | } 25 | return min; 26 | } 27 | 28 | public static int splitArray2(int[] nums, int M) { 29 | int N = nums.length; 30 | int[] help = new int[nums.length + 1]; 31 | for (int i = 0; i < N; i++) { 32 | help[i + 1] = help[i] + nums[i]; 33 | } 34 | int[][] dp = new int[N][M + 1]; 35 | for (int i = 0; i < N; i++) { 36 | dp[i][1] = help[i + 1] - help[0]; 37 | } 38 | for (int i = 1; i < Math.min(N, M); i++) { 39 | dp[i][i + 1] = Math.max(dp[i - 1][i], nums[i]); 40 | } 41 | for (int i = 2; i < N; i++) { 42 | for (int j = 2; j <= Math.min(i, M); j++) { 43 | dp[i][j] = Integer.MAX_VALUE; 44 | for (int k = i; k >= j - 1; k--) { 45 | dp[i][j] = Math.min(dp[i][j], Math.max(dp[k - 1][j - 1], help[i + 1] - help[k])); 46 | } 47 | } 48 | } 49 | return dp[N - 1][M]; 50 | } 51 | 52 | public static int splitArray3(int[] nums, int M) { 53 | int N = nums.length; 54 | int[] help = new int[nums.length + 1]; 55 | for (int i = 0; i < N; i++) { 56 | help[i + 1] = help[i] + nums[i]; 57 | } 58 | int[][] dp = new int[N][M + 1]; 59 | int[][] best = new int[N][M + 1]; 60 | for (int i = 0; i < N; i++) { 61 | dp[i][1] = help[i + 1] - help[0]; 62 | } 63 | for (int i = 1; i < Math.min(N, M); i++) { 64 | dp[i][i + 1] = Math.max(dp[i - 1][i], nums[i]); 65 | best[i][i + 1] = i; 66 | } 67 | for (int i = 2; i < N; i++) { 68 | for (int j = Math.min(i, M); j >= 2; j--) { 69 | dp[i][j] = Integer.MAX_VALUE; 70 | int left = best[i - 1][j]; 71 | int right = j + 1 > M ? i : best[i][j + 1]; 72 | for (int k = left; k <= right; k++) { 73 | int curAns = Math.max(dp[k - 1][j - 1], help[i + 1] - help[k]); 74 | if (dp[i][j] > curAns) { 75 | dp[i][j] = curAns; 76 | best[i][j] = k; 77 | } 78 | } 79 | } 80 | } 81 | return dp[N - 1][M]; 82 | } 83 | 84 | public static int splitArray4(int[] nums, int M) { 85 | long sum = 0; 86 | for (int i = 0; i < nums.length; i++) { 87 | sum += nums[i]; 88 | } 89 | long l = 0; 90 | long r = sum; 91 | long ans = 0; 92 | while (l <= r) { 93 | long mid = (l + r) / 2; 94 | long cur = getNeedParts(nums, mid); 95 | if (cur <= M) { 96 | ans = mid; 97 | r = mid - 1; 98 | } else { 99 | l = mid + 1; 100 | } 101 | } 102 | return (int) ans; 103 | } 104 | 105 | public static int getNeedParts(int[] arr, long aim) { 106 | for (int i = 0; i < arr.length; i++) { 107 | if (arr[i] > aim) { 108 | return Integer.MAX_VALUE; 109 | } 110 | } 111 | int parts = 1; 112 | int all = arr[0]; 113 | for (int i = 1; i < arr.length; i++) { 114 | if (all + arr[i] > aim) { 115 | parts++; 116 | all = arr[i]; 117 | } else { 118 | all += arr[i]; 119 | } 120 | } 121 | return parts; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/class04/Code02_ThrowChessPiecesProblem.java: -------------------------------------------------------------------------------- 1 | package class04; 2 | 3 | public class Code02_ThrowChessPiecesProblem { 4 | 5 | public static int solution1(int nLevel, int kChess) { 6 | if (nLevel < 1 || kChess < 1) { 7 | return 0; 8 | } 9 | return Process1(nLevel, kChess); 10 | } 11 | 12 | // rest还剩多少层楼需要去验证 13 | // k还有多少颗棋子能够使用 14 | // 一定要验证出最高的不会碎的楼层!但是每次都是坏运气。 15 | // 返回至少需要扔几次? 16 | public static int Process1(int rest, int k) { 17 | if (rest == 0) { 18 | return 0; 19 | } 20 | if (k == 1) { 21 | return rest; 22 | } 23 | int min = Integer.MAX_VALUE; 24 | for (int i = 1; i != rest + 1; i++) { // 第一次扔的时候,仍在了i层 25 | min = Math.min(min, 26 | Math.max(Process1(i - 1, k - 1), Process1(rest - i, k))); 27 | } 28 | return min + 1; 29 | } 30 | 31 | public static int solution2(int nLevel, int kChess) { 32 | if (nLevel < 1 || kChess < 1) { 33 | return 0; 34 | } 35 | if (kChess == 1) { 36 | return nLevel; 37 | } 38 | int[][] dp = new int[nLevel + 1][kChess + 1]; 39 | for (int i = 1; i != dp.length; i++) { 40 | dp[i][1] = i; 41 | } 42 | for (int i = 1; i != dp.length; i++) { 43 | for (int j = 2; j != dp[0].length; j++) { 44 | int min = Integer.MAX_VALUE; 45 | for (int k = 1; k != i + 1; k++) { 46 | min = Math.min(min, Math.max(dp[k - 1][j - 1], dp[i - k][j])); 47 | } 48 | dp[i][j] = min + 1; 49 | } 50 | } 51 | return dp[nLevel][kChess]; 52 | } 53 | 54 | public static int solution3(int nLevel, int kChess) { 55 | if (nLevel < 1 || kChess < 1) { 56 | return 0; 57 | } 58 | if (kChess == 1) { 59 | return nLevel; 60 | } 61 | int[] preArr = new int[nLevel + 1]; 62 | int[] curArr = new int[nLevel + 1]; 63 | for (int i = 1; i != curArr.length; i++) { 64 | curArr[i] = i; 65 | } 66 | for (int i = 1; i != kChess; i++) { 67 | int[] tmp = preArr; 68 | preArr = curArr; 69 | curArr = tmp; 70 | for (int j = 1; j != curArr.length; j++) { 71 | int min = Integer.MAX_VALUE; 72 | for (int k = 1; k != j + 1; k++) { 73 | min = Math.min(min, Math.max(preArr[k - 1], curArr[j - k])); 74 | } 75 | curArr[j] = min + 1; 76 | } 77 | } 78 | return curArr[curArr.length - 1]; 79 | } 80 | 81 | public static int solution4(int nLevel, int kChess) { 82 | if (nLevel < 1 || kChess < 1) { 83 | return 0; 84 | } 85 | if (kChess == 1) { 86 | return nLevel; 87 | } 88 | int[][] dp = new int[nLevel + 1][kChess + 1]; 89 | for (int i = 1; i != dp.length; i++) { 90 | dp[i][1] = i; 91 | } 92 | int[] cands = new int[kChess + 1]; 93 | for (int i = 1; i != dp[0].length; i++) { 94 | dp[1][i] = 1; 95 | cands[i] = 1; 96 | } 97 | for (int i = 2; i < nLevel + 1; i++) { 98 | for (int j = kChess; j > 1; j--) { 99 | int min = Integer.MAX_VALUE; 100 | int minEnum = cands[j]; 101 | int maxEnum = j == kChess ? i / 2 + 1 : cands[j + 1]; 102 | for (int k = minEnum; k < maxEnum + 1; k++) { 103 | int cur = Math.max(dp[k - 1][j - 1], dp[i - k][j]); 104 | if (cur <= min) { 105 | min = cur; 106 | cands[j] = k; 107 | } 108 | } 109 | dp[i][j] = min + 1; 110 | } 111 | } 112 | return dp[nLevel][kChess]; 113 | } 114 | 115 | public static int solution5(int nLevel, int kChess) { 116 | if (nLevel < 1 || kChess < 1) { 117 | return 0; 118 | } 119 | int bsTimes = log2N(nLevel) + 1; 120 | if (kChess >= bsTimes) { 121 | return bsTimes; 122 | } 123 | int[] dp = new int[kChess]; 124 | int res = 0; 125 | while (true) { 126 | res++; 127 | int previous = 0; 128 | for (int i = 0; i < dp.length; i++) { 129 | int tmp = dp[i]; 130 | dp[i] = dp[i] + previous + 1; 131 | previous = tmp; 132 | if (dp[i] >= nLevel) { 133 | return res; 134 | } 135 | } 136 | } 137 | } 138 | 139 | public static int log2N(int n) { 140 | int res = -1; 141 | while (n != 0) { 142 | res++; 143 | n >>>= 1; 144 | } 145 | return res; 146 | } 147 | 148 | public static void main(String[] args) { 149 | System.out.println(solution1(21, 2)); 150 | System.out.println(solution2(21, 2)); 151 | System.out.println(solution3(21, 2)); 152 | System.out.println(solution4(21, 2)); 153 | System.out.println(solution5(21, 2)); 154 | 155 | System.out.println("=============="); 156 | 157 | System.out.println(solution2(105, 2)); 158 | System.out.println(solution3(105, 2)); 159 | System.out.println(solution4(105, 2)); 160 | System.out.println(solution5(105, 2)); 161 | 162 | System.out.println("=============="); 163 | 164 | System.out.println(solution2(3000, 10)); 165 | System.out.println(solution3(3000, 10)); 166 | System.out.println(solution4(3000, 10)); 167 | System.out.println(solution5(3000, 10)); 168 | 169 | System.out.println("=============="); 170 | 171 | System.out.println(solution2(6884, 5)); 172 | System.out.println(solution3(6884, 5)); 173 | System.out.println(solution4(6884, 5)); 174 | System.out.println(solution5(6884, 5)); 175 | 176 | System.out.println("=============="); 177 | 178 | System.out.println(solution2(6885, 5)); 179 | System.out.println(solution3(6885, 5)); 180 | System.out.println(solution4(6885, 5)); 181 | System.out.println(solution5(6885, 5)); 182 | 183 | System.out.println("=============="); 184 | 185 | int nLevel = 100000000; 186 | int kChess = 10; 187 | long start = System.currentTimeMillis(); 188 | System.out.println(solution5(nLevel, kChess)); 189 | long end = System.currentTimeMillis(); 190 | System.out.println("cost time: " + (end - start) + " ms"); 191 | 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /src/class04/Code03_PostOfficeProblem.java: -------------------------------------------------------------------------------- 1 | package class04; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Code03_PostOfficeProblem { 6 | 7 | public static int minDis1(int[] arr, int num) { 8 | if (arr == null || arr.length < 2 || num < 1) { 9 | return 0; 10 | } 11 | // record[L][R]表示如果arr[L...R]上只建立一个邮局,总距离最小是多少? 12 | int[][] record = getRecord(arr); 13 | int N = arr.length; 14 | int[][] dp = new int[N][num + 1]; 15 | // dp[...][0] 0个邮局的时候如何如何 16 | // dp[0][...] 0 17 | for (int i = 0; i < N; i++) { 18 | // 0...i 1 19 | dp[i][1] = record[0][i]; 20 | } 21 | for (int i = 1; i < N; i++) { 22 | for (int j = 2; j <= Math.min(num, i); j++) { 23 | // dp[i][j] 24 | // 枚举最后一个邮局负责的范围,K...i 25 | // i..i 26 | // i-1..i 27 | // i-2..i 28 | // 1....i 29 | // 0....i 单列 30 | // 0...k-1 j-1个邮局 + 31 | dp[i][j] = record[0][i]; 32 | for (int k = i; k > 0; k--) { // 1 .... i 33 | dp[i][j] = Math.min(dp[i][j], dp[k - 1][j - 1] + record[k][i]); 34 | } 35 | } 36 | } 37 | return dp[N - 1][num]; 38 | } 39 | 40 | public static int minDis2(int[] arr, int num) { 41 | if (arr == null || arr.length < 2 || num < 1) { 42 | return 0; 43 | } 44 | // record[L][R]表示如果arr[L...R]上只建立一个邮局,总距离最小是多少? 45 | int[][] record = getRecord(arr); 46 | int N = arr.length; 47 | int[][] dp = new int[N][num + 1]; 48 | // dp[...][0] 49 | // dp[0][...] 0..0 0 50 | // choose[0][..] 0 51 | // choose[i][j] 当时在求dp[i][j]的时候, 52 | // 最右的邮局,如果是在负责k...i这一段的时候,取得的最优解,请把choose[i][j] = k 53 | int[][] choose = new int[N][num + 1]; 54 | for (int i = 0; i < N; i++) { 55 | // 0..i 1个邮局 0...i 0 56 | dp[i][1] = record[0][i]; 57 | } 58 | for (int i = 1; i < N; i++) { 59 | for (int j = Math.min(num, i); j >= 2; j--) { 60 | int down = choose[i - 1][j]; 61 | int up = j == Math.min(num, i) ? i : choose[i][j + 1]; 62 | dp[i][j] = record[0][i]; 63 | for (int k = Math.max(1, down); k <= Math.min(up, i); k++) { 64 | if (dp[k - 1][j - 1] + record[k][i] < dp[i][j]) { 65 | dp[i][j] = dp[k - 1][j - 1] + record[k][i]; 66 | choose[i][j] = k; 67 | } 68 | } 69 | } 70 | } 71 | return dp[N - 1][num]; 72 | } 73 | 74 | public static int[][] getRecord(int[] arr) { 75 | int N = arr.length; 76 | int[][] record = new int[N][N]; 77 | for (int L = 0; L < N; L++) { 78 | for (int R = L + 1; R < N; R++) { 79 | record[L][R] = record[L][R - 1] + arr[R] - arr[(L + R) >> 1]; 80 | } 81 | } 82 | return record; 83 | } 84 | 85 | public static int minDistances1(int[] arr, int num) { 86 | if (arr == null || num < 1 || arr.length < num) { 87 | return 0; 88 | } 89 | int[][] w = new int[arr.length + 1][arr.length + 1]; 90 | for (int i = 0; i < arr.length; i++) { 91 | for (int j = i + 1; j < arr.length; j++) { 92 | w[i][j] = w[i][j - 1] + arr[j] - arr[(i + j) / 2]; 93 | } 94 | } 95 | int[][] dp = new int[num][arr.length]; 96 | for (int j = 0; j != arr.length; j++) { 97 | dp[0][j] = w[0][j]; 98 | } 99 | for (int i = 1; i < num; i++) { 100 | for (int j = i + 1; j < arr.length; j++) { 101 | dp[i][j] = Integer.MAX_VALUE; 102 | for (int k = 0; k <= j; k++) { 103 | dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + w[k + 1][j]); 104 | } 105 | } 106 | } 107 | return dp[num - 1][arr.length - 1]; 108 | } 109 | 110 | public static int minDistances2(int[] arr, int num) { 111 | if (arr == null || num < 1 || arr.length < num) { 112 | return 0; 113 | } 114 | int[][] w = new int[arr.length + 1][arr.length + 1]; 115 | for (int i = 0; i < arr.length; i++) { 116 | for (int j = i + 1; j < arr.length; j++) { 117 | w[i][j] = w[i][j - 1] + arr[j] - arr[(i + j) / 2]; 118 | } 119 | } 120 | int[][] dp = new int[num][arr.length]; 121 | int[][] s = new int[num][arr.length]; 122 | for (int j = 0; j != arr.length; j++) { 123 | dp[0][j] = w[0][j]; 124 | s[0][j] = 0; 125 | } 126 | int minK = 0; 127 | int maxK = 0; 128 | int cur = 0; 129 | for (int i = 1; i < num; i++) { 130 | for (int j = arr.length - 1; j > i; j--) { 131 | minK = s[i - 1][j]; 132 | maxK = j == arr.length - 1 ? arr.length - 1 : s[i][j + 1]; 133 | dp[i][j] = Integer.MAX_VALUE; 134 | for (int k = minK; k <= maxK; k++) { 135 | cur = dp[i - 1][k] + w[k + 1][j]; 136 | if (cur <= dp[i][j]) { 137 | dp[i][j] = cur; 138 | s[i][j] = k; 139 | } 140 | } 141 | } 142 | } 143 | return dp[num - 1][arr.length - 1]; 144 | } 145 | 146 | // for test 147 | public static int[] getSortedArray(int len, int range) { 148 | int[] arr = new int[len]; 149 | for (int i = 0; i != len; i++) { 150 | arr[i] = (int) (Math.random() * range); 151 | } 152 | Arrays.sort(arr); 153 | return arr; 154 | } 155 | 156 | // for test 157 | public static void printArray(int[] arr) { 158 | for (int i = 0; i != arr.length; i++) { 159 | System.out.print(arr[i] + " "); 160 | } 161 | System.out.println(); 162 | } 163 | 164 | // for test 165 | public static void main(String[] args) { 166 | int[] arr = { 1,3,8,10,12 }; 167 | int num = 3; 168 | System.out.println(minDis1(arr, num)); 169 | System.out.println(minDistances1(arr, num)); 170 | System.out.println(minDistances2(arr, num)); 171 | 172 | int times = 100; // test time 173 | int len = 1000; // test array length 174 | int range = 2000; // every number in [0,range) 175 | int p = 50; // post office number max 176 | long time1 = 0; // method1 all run time 177 | long time2 = 0;// method2 all run time 178 | long time3 = 0; 179 | long start = 0; 180 | long end = 0; 181 | int res1 = 0; 182 | int res2 = 0; 183 | int res3 = 0; 184 | for (int i = 0; i != times; i++) { 185 | int office = (int) (Math.random() * p) + 1; 186 | arr = getSortedArray(len, range); 187 | start = System.currentTimeMillis(); 188 | res1 = minDistances1(arr, office); 189 | end = System.currentTimeMillis(); 190 | time1 += end - start; 191 | start = System.currentTimeMillis(); 192 | res2 = minDis2(arr, office); 193 | end = System.currentTimeMillis(); 194 | time2 += end - start; 195 | 196 | start = System.currentTimeMillis(); 197 | res3 = minDis1(arr, office); 198 | end = System.currentTimeMillis(); 199 | time3 += end - start; 200 | if (res1 != res2 || res1 != res3) { 201 | printArray(arr); 202 | break; 203 | } 204 | if (i % 10 == 0) { 205 | System.out.print(". "); 206 | } 207 | } 208 | System.out.println(); 209 | System.out.println("method1 all run time(ms): " + time1); 210 | System.out.println("method2 all run time(ms): " + time2); 211 | System.out.println("method3 all run time(ms): " + time3); 212 | 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/class04/Code04_MergeRecord.java: -------------------------------------------------------------------------------- 1 | package class04; 2 | 3 | public class Code04_MergeRecord { 4 | 5 | /* 6 | * 腾讯原题 7 | * 8 | * 给定整数power,给定一个数组arr,给定一个数组reverse。含义如下: 9 | * arr的长度一定是2的power次方,reverse中的每个值一定都在0~power范围。 10 | * 例如power = 2, arr = {3, 1, 4, 2},reverse = {0, 1, 0, 2} 11 | * 任何一个在前的数字可以和任何一个在后的数组,构成一对数。可能是升序关系、相等关系或者降序关系。 12 | * 比如arr开始时有如下的降序对:(3,1)、(3,2)、(4,2),一共3个。 13 | * 接下来根据reverse对arr进行调整: 14 | * reverse[0] = 0, 表示在arr中,划分每1(2的0次方)个数一组,然后每个小组内部逆序,那么arr变成 15 | * [3,1,4,2],此时有3个逆序对。 16 | * reverse[1] = 1, 表示在arr中,划分每2(2的1次方)个数一组,然后每个小组内部逆序,那么arr变成 17 | * [1,3,2,4],此时有1个逆序对 18 | * reverse[2] = 0, 表示在arr中,划分每1(2的0次方)个数一组,然后每个小组内部逆序,那么arr变成 19 | * [1,3,2,4],此时有1个逆序对。 20 | * reverse[3] = 2, 表示在arr中,划分每4(2的2次方)个数一组,然后每个小组内部逆序,那么arr变成 21 | * [4,2,3,1],此时有4个逆序对。 22 | * 所以返回[3,1,1,4],表示每次调整之后的逆序对数量。 23 | * 24 | * 输入数据状况: 25 | * power的范围[0,20] 26 | * arr长度范围[1,10的7次方] 27 | * reverse长度范围[1,10的6次方] 28 | * 29 | * */ 30 | 31 | public static int[] reversePair1(int[] originArr, int[] reverseArr, int power) { 32 | int[] ans = new int[reverseArr.length]; 33 | for (int i = 0; i < reverseArr.length; i++) { 34 | reverseArray(originArr, 1 << (reverseArr[i])); 35 | ans[i] = countReversePair(originArr); 36 | } 37 | return ans; 38 | } 39 | 40 | public static void reverseArray(int[] originArr, int teamSize) { 41 | if (teamSize < 2) { 42 | return; 43 | } 44 | for (int i = 0; i < originArr.length; i += teamSize) { 45 | reversePart(originArr, i, i + teamSize - 1); 46 | } 47 | } 48 | 49 | public static void reversePart(int[] arr, int L, int R) { 50 | while (L < R) { 51 | int tmp = arr[L]; 52 | arr[L++] = arr[R]; 53 | arr[R--] = tmp; 54 | } 55 | } 56 | 57 | public static int countReversePair(int[] originArr) { 58 | int ans = 0; 59 | for (int i = 0; i < originArr.length; i++) { 60 | for (int j = i + 1; j < originArr.length; j++) { 61 | if (originArr[i] > originArr[j]) { 62 | ans++; 63 | } 64 | } 65 | } 66 | return ans; 67 | } 68 | 69 | public static int[] reversePair2(int[] originArr, int[] reverseArr, int power) { 70 | int[] reverse = copyArray(originArr); 71 | reversePart(reverse, 0, reverse.length - 1); 72 | int[] recordDown = new int[power + 1]; 73 | int[] recordUp = new int[power + 1]; 74 | process(originArr, 0, originArr.length - 1, power, recordDown); 75 | process(reverse, 0, reverse.length - 1, power, recordUp); 76 | int[] ans = new int[reverseArr.length]; 77 | for (int i = 0; i < reverseArr.length; i++) { 78 | int curPower = reverseArr[i]; 79 | for (int p = 1; p <= curPower; p++) { 80 | int tmp = recordDown[p]; 81 | recordDown[p] = recordUp[p]; 82 | recordUp[p] = tmp; 83 | } 84 | for (int p = 1; p <= power; p++) { 85 | ans[i] += recordDown[p]; 86 | } 87 | } 88 | return ans; 89 | } 90 | 91 | // arr[L...R] 一共有2的power次方个数 92 | // arr[0...7] 一共有2的3次方个数 93 | public static void process(int[] arr, int L, int R, int power, int[] record) { 94 | if (L == R) { 95 | return; 96 | } 97 | int mid = L + ((R - L) >> 1); 98 | process(arr, L, mid, power - 1, record); 99 | process(arr, mid + 1, R, power - 1, record); 100 | record[power] += merge(arr, L, mid, R); 101 | } 102 | 103 | public static int merge(int[] arr, int L, int m, int r) { 104 | int[] help = new int[r - L + 1]; 105 | int i = 0; 106 | int p1 = L; 107 | int p2 = m + 1; 108 | int ans = 0; 109 | while (p1 <= m && p2 <= r) { 110 | ans += arr[p1] > arr[p2] ? (m - p1 + 1) : 0; 111 | help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; 112 | } 113 | while (p1 <= m) { 114 | help[i++] = arr[p1++]; 115 | } 116 | while (p2 <= r) { 117 | help[i++] = arr[p2++]; 118 | } 119 | for (i = 0; i < help.length; i++) { 120 | arr[L + i] = help[i]; 121 | } 122 | return ans; 123 | } 124 | 125 | // for test 126 | public static int[] generateRandomOriginArray(int power, int value) { 127 | int[] ans = new int[1 << power]; 128 | for (int i = 0; i < ans.length; i++) { 129 | ans[i] = (int) (Math.random() * value); 130 | } 131 | return ans; 132 | } 133 | 134 | // for test 135 | public static int[] generateRandomReverseArray(int len, int power) { 136 | int[] ans = new int[len]; 137 | for (int i = 0; i < ans.length; i++) { 138 | ans[i] = (int) (Math.random() * (power + 1)); 139 | } 140 | return ans; 141 | } 142 | 143 | // for test 144 | public static void printArray(int[] arr) { 145 | System.out.println("arr size : " + arr.length); 146 | for (int i = 0; i < arr.length; i++) { 147 | System.out.print(arr[i] + " "); 148 | } 149 | System.out.println(); 150 | } 151 | 152 | // for test 153 | public static int[] copyArray(int[] arr) { 154 | if (arr == null) { 155 | return null; 156 | } 157 | int[] res = new int[arr.length]; 158 | for (int i = 0; i < arr.length; i++) { 159 | res[i] = arr[i]; 160 | } 161 | return res; 162 | } 163 | 164 | // for test 165 | public static boolean isEqual(int[] arr1, int[] arr2) { 166 | if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) { 167 | return false; 168 | } 169 | if (arr1 == null && arr2 == null) { 170 | return true; 171 | } 172 | if (arr1.length != arr2.length) { 173 | return false; 174 | } 175 | for (int i = 0; i < arr1.length; i++) { 176 | if (arr1[i] != arr2[i]) { 177 | return false; 178 | } 179 | } 180 | return true; 181 | } 182 | 183 | public static void main(String[] args) { 184 | int powerMax = 8; 185 | int msizeMax = 10; 186 | int value = 30; 187 | int testTime = 50000; 188 | System.out.println("test begin"); 189 | for (int i = 0; i < testTime; i++) { 190 | int power = (int) (Math.random() * powerMax) + 1; 191 | int msize = (int) (Math.random() * msizeMax) + 1; 192 | int[] originArr = generateRandomOriginArray(power, value); 193 | int[] originArr1 = copyArray(originArr); 194 | int[] originArr2 = copyArray(originArr); 195 | int[] reverseArr = generateRandomReverseArray(msize, power); 196 | int[] reverseArr1 = copyArray(reverseArr); 197 | int[] reverseArr2 = copyArray(reverseArr); 198 | int[] ans1 = reversePair1(originArr1, reverseArr1, power); 199 | int[] ans2 = reversePair2(originArr2, reverseArr2, power); 200 | if (!isEqual(ans1, ans2)) { 201 | System.out.println("Oops!"); 202 | } 203 | } 204 | System.out.println("test finish!"); 205 | 206 | powerMax = 20; 207 | msizeMax = 1000000; 208 | value = 1000; 209 | int[] originArr = generateRandomOriginArray(powerMax, value); 210 | int[] reverseArr = generateRandomReverseArray(msizeMax, powerMax); 211 | // int[] ans1 = reversePair1(originArr1, reverseArr1, powerMax); 212 | long start = System.currentTimeMillis(); 213 | reversePair2(originArr, reverseArr, powerMax); 214 | long end = System.currentTimeMillis(); 215 | System.out.println("run time : " + (end - start) + " ms"); 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /src/class04/Code05_FactorialProblem.java: -------------------------------------------------------------------------------- 1 | package class04; 2 | 3 | public class Code05_FactorialProblem { 4 | 5 | public static int zeroNum1(int num) { 6 | if (num < 0) { 7 | return 0; 8 | } 9 | int res = 0; 10 | int cur = 0; 11 | for (int i = 5; i < num + 1; i = i + 5) { 12 | cur = i; 13 | while (cur % 5 == 0) { 14 | res++; 15 | cur /= 5; 16 | } 17 | } 18 | return res; 19 | } 20 | 21 | public static int zeroNum2(int num) { 22 | if (num < 0) { 23 | return 0; 24 | } 25 | int res = 0; 26 | while (num != 0) { 27 | res += num / 5; 28 | num /= 5; 29 | } 30 | return res; 31 | } 32 | 33 | public static int rightOne1(int num) { 34 | if (num < 1) { 35 | return -1; 36 | } 37 | int res = 0; 38 | while (num != 0) { 39 | num >>>= 1; 40 | res += num; 41 | } 42 | return res; 43 | } 44 | 45 | public static int rightOne2(int num) { 46 | if (num < 1) { 47 | return -1; 48 | } 49 | int ones = 0; 50 | int rightOne = 0; 51 | while (num != 0) { 52 | rightOne = (num & (~num + 1)); 53 | num -= rightOne; 54 | ones++; 55 | } 56 | return num - ones; 57 | } 58 | 59 | public static void main(String[] args) { 60 | int num = 1000000000; 61 | 62 | System.out.println(zeroNum2(num)); 63 | System.out.println(zeroNum1(num)); 64 | 65 | System.out.println(rightOne2(num)); 66 | System.out.println(rightOne1(num)); 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/class05/Code01_PalindromePairs.java: -------------------------------------------------------------------------------- 1 | package class05; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | 7 | public class Code01_PalindromePairs { 8 | 9 | // [ [0,1] [3, 8] ] 10 | public static List> palindromePairs(String[] words) { 11 | HashMap wordset = new HashMap<>(); 12 | for (int i = 0; i < words.length; i++) { 13 | wordset.put(words[i], i); 14 | } 15 | List> res = new ArrayList<>(); 16 | for (int i = 0; i < words.length; i++) { 17 | res.addAll(findAll(words[i], i, wordset)); 18 | } 19 | return res; 20 | } 21 | 22 | public static List> findAll(String word, int index, 23 | HashMap words) { 24 | List> res = new ArrayList<>(); 25 | String reverse = reverse(word); 26 | Integer rest = words.get(""); 27 | if (rest != null && rest != index && word.equals(reverse)) { 28 | addRecord(res, rest, index); 29 | addRecord(res, index, rest); 30 | } 31 | int[] rs = manacherss(word); 32 | int mid = rs.length >> 1; 33 | for (int i = 1; i < mid; i++) { 34 | if (i - rs[i] == -1) { 35 | rest = words.get(reverse.substring(0, mid - i)); 36 | if (rest != null && rest != index) { 37 | addRecord(res, rest, index); 38 | } 39 | } 40 | } 41 | for (int i = mid + 1; i < rs.length; i++) { 42 | if (i + rs[i] == rs.length) { 43 | rest = words.get(reverse.substring((mid << 1) - i)); 44 | if (rest != null && rest != index) { 45 | addRecord(res, index, rest); 46 | } 47 | } 48 | } 49 | return res; 50 | } 51 | 52 | public static void addRecord(List> res, int left, int right) { 53 | List newr = new ArrayList<>(); 54 | newr.add(left); 55 | newr.add(right); 56 | res.add(newr); 57 | } 58 | 59 | public static int[] manacherss(String word) { 60 | char[] mchs = manachercs(word); 61 | int[] rs = new int[mchs.length]; 62 | int center = -1; 63 | int pr = -1; 64 | for (int i = 0; i != mchs.length; i++) { 65 | rs[i] = pr > i ? Math.min(rs[(center << 1) - i], pr - i) : 1; 66 | while (i + rs[i] < mchs.length && i - rs[i] > -1) { 67 | if (mchs[i + rs[i]] != mchs[i - rs[i]]) { 68 | break; 69 | } 70 | rs[i]++; 71 | } 72 | if (i + rs[i] > pr) { 73 | pr = i + rs[i]; 74 | center = i; 75 | } 76 | } 77 | return rs; 78 | } 79 | 80 | public static char[] manachercs(String word) { 81 | char[] chs = word.toCharArray(); 82 | char[] mchs = new char[chs.length * 2 + 1]; 83 | int index = 0; 84 | for (int i = 0; i != mchs.length; i++) { 85 | mchs[i] = (i & 1) == 0 ? '#' : chs[index++]; 86 | } 87 | return mchs; 88 | } 89 | 90 | public static String reverse(String str) { 91 | char[] chs = str.toCharArray(); 92 | int l = 0; 93 | int r = chs.length - 1; 94 | while (l < r) { 95 | char tmp = chs[l]; 96 | chs[l++] = chs[r]; 97 | chs[r--] = tmp; 98 | } 99 | return String.valueOf(chs); 100 | } 101 | 102 | public static void main(String[] args) { 103 | String test = "112321"; 104 | System.out.println(String.valueOf(manachercs(test))); 105 | int[] arr = manacherss(test); 106 | for (int i = 0; i < arr.length; i++) { 107 | System.out.print(arr[i] + " "); 108 | } 109 | System.out.println(); 110 | 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /src/class05/Code02_LongestConsecutive.java: -------------------------------------------------------------------------------- 1 | package class05; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Code02_LongestConsecutive { 6 | 7 | public static int longestConsecutive(int[] arr) { 8 | if (arr == null || arr.length == 0) { 9 | return 0; 10 | } 11 | int max = 1; 12 | // 不区分开头和结尾 13 | // (key, value) 14 | // key所在的连续区域,这个区域一共有几个数,value 15 | HashMap map = new HashMap(); 16 | for (int i = 0; i < arr.length; i++) { // 从左到右遍历每一个数字 17 | if (!map.containsKey(arr[i])) { 18 | map.put(arr[i], 1); // arr[i] ~ arr[i] 19 | if (map.containsKey(arr[i] - 1)) { // 是否有arr[i] - 1的结尾 20 | max = Math.max(max, merge(map, arr[i] - 1, arr[i])); 21 | } 22 | if (map.containsKey(arr[i] + 1)) { // 是否有arr[i] + 1的开头 23 | max = Math.max(max, merge(map, arr[i], arr[i] + 1)); 24 | } 25 | } 26 | } 27 | return max; 28 | } 29 | 30 | public static int merge(HashMap map, int preRangeEnd, int curRangeStart) { 31 | int preRangeStart = preRangeEnd - map.get(preRangeEnd) + 1; 32 | int curRangeEnd = curRangeStart + map.get(curRangeStart) - 1; 33 | int len = curRangeEnd - preRangeStart + 1; 34 | map.put(preRangeStart, len); 35 | map.put(curRangeEnd, len); 36 | return len; 37 | } 38 | 39 | public static void main(String[] args) { 40 | int[] arr = { 100, 4, 200, 1, 3, 2 }; 41 | System.out.println(longestConsecutive(arr)); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/class05/Code03_TarjanAndDisjointSetsForLCA.java: -------------------------------------------------------------------------------- 1 | package class05; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Stack; 8 | 9 | public class Code03_TarjanAndDisjointSetsForLCA { 10 | 11 | public static class Element { 12 | public V value; 13 | 14 | public Element(V value) { 15 | this.value = value; 16 | } 17 | 18 | } 19 | 20 | public static class UnionFindSet { 21 | public HashMap> elementMap; 22 | public HashMap, Element> fatherMap; 23 | public HashMap, Integer> sizeMap; 24 | 25 | public UnionFindSet(List list) { 26 | elementMap = new HashMap<>(); 27 | fatherMap = new HashMap<>(); 28 | sizeMap = new HashMap<>(); 29 | for (V value : list) { 30 | Element element = new Element(value); 31 | elementMap.put(value, element); 32 | fatherMap.put(element, element); 33 | sizeMap.put(element, 1); 34 | } 35 | } 36 | 37 | private Element findHead(Element element) { 38 | Stack> path = new Stack<>(); 39 | while (element != fatherMap.get(element)) { 40 | path.push(element); 41 | element = fatherMap.get(element); 42 | } 43 | while (!path.isEmpty()) { 44 | fatherMap.put(path.pop(), element); 45 | } 46 | return element; 47 | } 48 | 49 | // 返回node所在集合的代表节点 50 | public V findHead(V node) { 51 | return elementMap.containsKey(node) ? findHead(elementMap 52 | .get(node)).value : null; 53 | } 54 | 55 | public boolean isSameSet(V a, V b) { 56 | if (elementMap.containsKey(a) && elementMap.containsKey(b)) { 57 | return findHead(elementMap.get(a)) == findHead(elementMap 58 | .get(b)); 59 | } 60 | return false; 61 | } 62 | 63 | public void union(V a, V b) { 64 | if (elementMap.containsKey(a) && elementMap.containsKey(b)) { 65 | Element aF = findHead(elementMap.get(a)); 66 | Element bF = findHead(elementMap.get(b)); 67 | if (aF != bF) { 68 | int aFrank = sizeMap.get(aF); 69 | int bFrank = sizeMap.get(bF); 70 | if (aFrank >= bFrank) { 71 | fatherMap.put(bF, aF); 72 | sizeMap.put(aF, aFrank + bFrank); 73 | sizeMap.remove(bF); 74 | } else { 75 | fatherMap.put(aF, bF); 76 | sizeMap.put(bF, aFrank + bFrank); 77 | sizeMap.remove(aF); 78 | } 79 | } 80 | } 81 | } 82 | 83 | } 84 | 85 | public static class Node { 86 | public int value; 87 | public Node left; 88 | public Node right; 89 | 90 | public Node(int data) { 91 | this.value = data; 92 | } 93 | } 94 | 95 | public static class Query { 96 | public Node o1; 97 | public Node o2; 98 | 99 | public Query(Node o1, Node o2) { 100 | this.o1 = o1; 101 | this.o2 = o2; 102 | } 103 | } 104 | 105 | public static Node[] tarJanQuery(Node head, Query[] quries) { 106 | HashMap> queryMap = new HashMap<>(); 107 | HashMap> indexMap = new HashMap<>(); 108 | // key 某个集合的代表节点 value 代表节点所在集合中的所有节点,祖先是谁 109 | 110 | 111 | // key 表示一个集合的代表节点 112 | // value 这个key所在集合的所有节点,tag点 113 | HashMap tagMap = new HashMap<>(); 114 | UnionFindSet sets = new UnionFindSet<>(getAllNodes(head)); 115 | Node[] ans = new Node[quries.length]; 116 | // 提前填好无效问题的解,对于有效问题,生成好queryMap和indexMap 117 | setQueriesAndSetEasyAnswers(quries, ans, queryMap, indexMap); 118 | 119 | // 二叉树头节点head,遍历 120 | // 并查集sets,打tag,还有tagMap表 121 | // queryMap, indexMap可以方便的知道有哪些问题 122 | // ans 知道答案了可以填写 123 | // 递归遍历的过程中,把有效问题解决,填到答案里去 124 | setAnswers(head, ans, queryMap, indexMap, tagMap, sets); 125 | return ans; 126 | } 127 | 128 | public static List getAllNodes(Node head) { 129 | List res = new ArrayList<>(); 130 | process(head, res); 131 | return res; 132 | } 133 | 134 | public static void process(Node head, List res) { 135 | if (head == null) { 136 | return; 137 | } 138 | res.add(head); 139 | process(head.left, res); 140 | process(head.right, res); 141 | } 142 | 143 | public static void setQueriesAndSetEasyAnswers(Query[] ques, Node[] ans, 144 | HashMap> queryMap, 145 | HashMap> indexMap) { 146 | Node o1 = null; 147 | Node o2 = null; 148 | for (int i = 0; i != ans.length; i++) { 149 | o1 = ques[i].o1; 150 | o2 = ques[i].o2; 151 | if (o1 == o2 || o1 == null || o2 == null) { 152 | ans[i] = o1 != null ? o1 : o2; 153 | } else { 154 | if (!queryMap.containsKey(o1)) { 155 | queryMap.put(o1, new LinkedList()); 156 | indexMap.put(o1, new LinkedList()); 157 | } 158 | if (!queryMap.containsKey(o2)) { 159 | queryMap.put(o2, new LinkedList()); 160 | indexMap.put(o2, new LinkedList()); 161 | } 162 | queryMap.get(o1).add(o2); 163 | indexMap.get(o1).add(i); 164 | queryMap.get(o2).add(o1); 165 | indexMap.get(o2).add(i); 166 | } 167 | } 168 | } 169 | 170 | public static void setAnswers( 171 | Node head, 172 | Node[] ans, 173 | HashMap> queryMap, 174 | HashMap> indexMap, 175 | HashMap tagMap, 176 | UnionFindSet sets) { 177 | if (head == null) { 178 | return; 179 | } 180 | setAnswers(head.left, ans, queryMap, indexMap, tagMap, sets); 181 | sets.union(head.left, head); 182 | tagMap.put(sets.findHead(head), head); 183 | setAnswers(head.right, ans, queryMap, indexMap, tagMap, sets); 184 | sets.union(head.right, head); 185 | tagMap.put(sets.findHead(head), head); 186 | // 处理有关于head的问题 187 | LinkedList nList = queryMap.get(head); 188 | LinkedList iList = indexMap.get(head); 189 | Node node = null; 190 | Node nodeFather = null; 191 | int index = 0; 192 | // 3 {7,8,9} 193 | // 7,8,9 194 | // 7 195 | while (nList != null && !nList.isEmpty()) { 196 | node = nList.poll(); // head node 197 | index = iList.poll(); // index 198 | nodeFather = sets.findHead(node); // node在集合中的代表节点 199 | if (tagMap.containsKey(nodeFather)) { // node所在的集合是否设置过tag 200 | ans[index] = tagMap.get(nodeFather); 201 | } 202 | } 203 | } 204 | 205 | // for test -- print tree 206 | public static void printTree(Node head) { 207 | System.out.println("Binary Tree:"); 208 | printInOrder(head, 0, "H", 17); 209 | System.out.println(); 210 | } 211 | 212 | public static void printInOrder(Node head, int height, String to, int len) { 213 | if (head == null) { 214 | return; 215 | } 216 | printInOrder(head.right, height + 1, "v", len); 217 | String val = to + head.value + to; 218 | int lenM = val.length(); 219 | int lenL = (len - lenM) / 2; 220 | int lenR = len - lenM - lenL; 221 | val = getSpace(lenL) + val + getSpace(lenR); 222 | System.out.println(getSpace(height * len) + val); 223 | printInOrder(head.left, height + 1, "^", len); 224 | } 225 | 226 | public static String getSpace(int num) { 227 | String space = " "; 228 | StringBuffer buf = new StringBuffer(""); 229 | for (int i = 0; i < num; i++) { 230 | buf.append(space); 231 | } 232 | return buf.toString(); 233 | } 234 | 235 | public static void main(String[] args) { 236 | Node head = new Node(1); 237 | head.left = new Node(2); 238 | head.right = new Node(3); 239 | head.left.left = new Node(4); 240 | head.left.right = new Node(5); 241 | head.right.left = new Node(6); 242 | head.right.right = new Node(7); 243 | head.right.right.left = new Node(8); 244 | printTree(head); 245 | System.out.println("==============="); 246 | 247 | Query[] qs = new Query[7]; 248 | qs[0] = new Query(head.left.right, head.right.left); 249 | qs[1] = new Query(head.left.left, head.left); 250 | qs[2] = new Query(head.right.left, head.right.right.left); 251 | qs[3] = new Query(head.left.left, head.right.right); 252 | qs[4] = new Query(head.right.right, head.right.right.left); 253 | qs[5] = new Query(head, head); 254 | qs[6] = new Query(head.left, head.right.right.left); 255 | 256 | Node[] ans = tarJanQuery(head, qs); 257 | 258 | for (int i = 0; i != ans.length; i++) { 259 | System.out.println("o1 : " + qs[i].o1.value); 260 | System.out.println("o2 : " + qs[i].o2.value); 261 | System.out.println("ancestor : " + ans[i].value); 262 | System.out.println("==============="); 263 | } 264 | 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/class05/Code04_MaximalRectangle.java: -------------------------------------------------------------------------------- 1 | package class05; 2 | 3 | import java.util.Stack; 4 | 5 | public class Code04_MaximalRectangle { 6 | 7 | public static int maxRecSize(int[][] map) { 8 | if (map == null || map.length == 0 || map[0].length == 0) { 9 | return 0; 10 | } 11 | int maxArea = 0; 12 | int[] height = new int[map[0].length]; 13 | for (int i = 0; i < map.length; i++) { 14 | for (int j = 0; j < map[0].length; j++) { 15 | height[j] = map[i][j] == 0 ? 0 : height[j] + 1; 16 | } 17 | maxArea = Math.max(maxRecFromBottom(height), maxArea); 18 | } 19 | return maxArea; 20 | } 21 | 22 | // height是正方图数组 23 | public static int maxRecFromBottom(int[] height) { 24 | if (height == null || height.length == 0) { 25 | return 0; 26 | } 27 | int maxArea = 0; 28 | // 左右两侧离最近,小的 ,,,, 底 -> 顶 小 -> 大 29 | Stack stack = new Stack(); 30 | for (int i = 0; i < height.length; i++) { 31 | while (!stack.isEmpty() && height[i] <= height[stack.peek()]) { 32 | int j = stack.pop(); // 结算哪个位置的答案 33 | int k = stack.isEmpty() ? -1 : stack.peek(); // 左边不能扩到的位置 34 | int curArea = (i - k - 1) * height[j]; 35 | maxArea = Math.max(maxArea, curArea); 36 | } 37 | stack.push(i); 38 | } 39 | while (!stack.isEmpty()) { 40 | int j = stack.pop(); 41 | int k = stack.isEmpty() ? -1 : stack.peek(); 42 | int curArea = (height.length - k - 1) * height[j]; 43 | maxArea = Math.max(maxArea, curArea); 44 | } 45 | return maxArea; 46 | } 47 | 48 | public static void main(String[] args) { 49 | int[][] map = { { 1, 0, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 0 }, }; 50 | System.out.println(maxRecSize(map)); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/class06/Code01_RemoveBoxes.java: -------------------------------------------------------------------------------- 1 | package class06; 2 | 3 | public class Code01_RemoveBoxes { 4 | 5 | public static int removeBoxes(int[] boxes) { 6 | int N = boxes.length; 7 | int[][][] dp = new int[N][N][N]; 8 | int ans = process(boxes, 0, N - 1, 0, dp); 9 | return ans; 10 | } 11 | 12 | public static int process(int[] boxes, int L, int R, int K, int[][][] dp) { 13 | if (L > R) { 14 | return 0; 15 | } 16 | if (dp[L][R][K] > 0) { 17 | return dp[L][R][K]; 18 | } 19 | int last = L; 20 | while (last + 1 <= R && boxes[last + 1] == boxes[L]) { 21 | last++; 22 | } 23 | int pre = K + last - L; 24 | int ans = (pre + 1) * (pre + 1) + process(boxes, last + 1, R, 0, dp); 25 | for (int i = last + 2; i <= R; i++) { 26 | if (boxes[i] == boxes[L] && boxes[i - 1] != boxes[L]) { 27 | ans = Math.max(ans, process(boxes, last + 1, i - 1, 0, dp) + process(boxes, i, R, pre + 1, dp)); 28 | } 29 | } 30 | dp[L][R][K] = ans; 31 | return ans; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/class06/Code02_StrangePrinter.java: -------------------------------------------------------------------------------- 1 | package class06; 2 | 3 | public class Code02_StrangePrinter { 4 | 5 | public static int strangePrinter(String s) { 6 | if (s == null || s.length() == 0) { 7 | return 0; 8 | } 9 | char[] str = s.toCharArray(); 10 | int N = str.length; 11 | int[][] dp = new int[N][N]; 12 | dp[N - 1][N - 1] = 1; 13 | for (int i = 0; i < N - 1; i++) { 14 | dp[i][i] = 1; 15 | dp[i][i + 1] = str[i] == str[i + 1] ? 1 : 2; 16 | } 17 | for (int L = N - 3; L >= 0; L--) { 18 | for (int R = L + 2; R < N; R++) { 19 | 20 | // L....R 21 | 22 | dp[L][R] = R - L + 1; 23 | 24 | // L...k-1 k...R 25 | for (int k = L + 1; k <= R; k++) { 26 | dp[L][R] = Math.min(dp[L][R], dp[L][k - 1] + dp[k][R] - (str[L] == str[k] ? 1 : 0)); 27 | } 28 | } 29 | } 30 | return dp[0][N - 1]; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/class06/Code03_SmallestRangeCoveringElementsfromKLists.java: -------------------------------------------------------------------------------- 1 | package class06; 2 | 3 | import java.util.Comparator; 4 | import java.util.List; 5 | import java.util.TreeSet; 6 | 7 | public class Code03_SmallestRangeCoveringElementsfromKLists { 8 | 9 | public static class Node { 10 | public int value; 11 | public int arrid; 12 | public int index; 13 | 14 | public Node(int v, int ai, int i) { 15 | value = v; 16 | arrid = ai; 17 | index = i; 18 | } 19 | } 20 | 21 | public static class NodeComparator implements Comparator { 22 | 23 | @Override 24 | public int compare(Node o1, Node o2) { 25 | return o1.value != o2.value ? o1.value - o2.value : o1.arrid - o2.arrid; 26 | } 27 | 28 | } 29 | 30 | public static int[] smallestRange(List> nums) { 31 | int N = nums.size(); 32 | TreeSet orderSet = new TreeSet<>(new NodeComparator()); 33 | for (int i = 0; i < N; i++) { 34 | orderSet.add(new Node(nums.get(i).get(0), i, 0)); 35 | } 36 | boolean set = false; 37 | int a = 0; 38 | int b = 0; 39 | while (orderSet.size() == N) { 40 | Node min = orderSet.first(); 41 | Node max = orderSet.last(); 42 | if (!set || (max.value - min.value < b - a)) { 43 | set = true; 44 | a = min.value; 45 | b = max.value; 46 | } 47 | min = orderSet.pollFirst(); 48 | int arrid = min.arrid; 49 | int index = min.index + 1; 50 | if (index != nums.get(arrid).size()) { 51 | orderSet.add(new Node(nums.get(arrid).get(index), arrid, index)); 52 | } 53 | } 54 | return new int[] { a, b }; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/class06/Code04_RestoreWays.java: -------------------------------------------------------------------------------- 1 | package class06; 2 | 3 | public class Code04_RestoreWays { 4 | 5 | /* 6 | * 整型数组arr长度为n(3 <= n <= 10^4),最初每个数字是<=200的正数且满足如下条件: 1. 0位置的要求:arr[0] <= 7 | * arr[1] 2. n-1位置的要求:arr[n-1] <= arr[n-2] 3. 中间i位置的要求:arr[i] <= max(arr[i-1], 8 | * arr[i+1]) 但是在arr有些数字丢失了,比如k位置的数字之前是正数,丢失之后k位置的数字为0。 请你根据上述条件, 9 | * 计算可能有多少种不同的arr可以满足以上条件。 比如 [6,0,9] 只有还原成 [6,9,9]满足全部三个条件,所以返回1种。 [6,9,9] 达标 10 | * 11 | * [ ...... 0 0] 12 | */ 13 | 14 | public static int ways0(int[] arr) { 15 | return process0(arr, 0); 16 | } 17 | 18 | public static int process0(int[] arr, int index) { 19 | if (index == arr.length) { 20 | return isValid(arr) ? 1 : 0; 21 | } else { 22 | if (arr[index] != 0) { 23 | return process0(arr, index + 1); 24 | } else { 25 | int ways = 0; 26 | for (int v = 1; v < 201; v++) { 27 | arr[index] = v; 28 | ways += process0(arr, index + 1); 29 | } 30 | arr[index] = 0; 31 | return ways; 32 | } 33 | } 34 | } 35 | 36 | public static boolean isValid(int[] arr) { 37 | if (arr[0] > arr[1]) { 38 | return false; 39 | } 40 | if (arr[arr.length - 1] > arr[arr.length - 2]) { 41 | return false; 42 | } 43 | for (int i = 1; i < arr.length - 1; i++) { 44 | if (arr[i] > Math.max(arr[i - 1], arr[i + 1])) { 45 | return false; 46 | } 47 | } 48 | return true; 49 | } 50 | 51 | public static int ways1(int[] arr) { 52 | int N = arr.length; 53 | if (arr[N - 1] != 0) { 54 | return process1(arr, N - 1, arr[N - 1], 2); 55 | } else { 56 | int ways = 0; 57 | for (int v = 1; v < 201; v++) { 58 | ways += process1(arr, N - 1, v, 2); 59 | } 60 | return ways; 61 | } 62 | } 63 | 64 | // 如果i位置的数字变成了v, 65 | // 并且arr[i]和arr[i+1]的关系为s, 66 | // s==0,代表arr[i] < arr[i+1] 右大 67 | // s==1,代表arr[i] == arr[i+1] 68 | // s==2,代表arr[i] > arr[i+1] 右小 69 | // 返回0...i范围上有多少种有效的转化方式? 70 | public static int process1(int[] arr, int i, int v, int s) { 71 | if (i == 0) { // 0...i 只剩一个数了,0...0 72 | return ((s == 0 || s == 1) && (arr[i] == 0 || v == arr[i])) ? 1 : 0; 73 | } 74 | // i > 0 75 | if (arr[i] != 0 && v != arr[i]) { 76 | return 0; 77 | } 78 | // i>0 并且 i位置的数真的可以变成V, 79 | int ways = 0; 80 | if (s == 0 || s == 1) { // [i - 1] [i] <= 右 81 | for (int pre = 1; pre < 201; pre++) { 82 | ways += process1(arr, i - 1, pre, pre < v ? 0 : (pre == v ? 1 : 2)); 83 | } 84 | } else { // s == 2 i > 右 i-1 >= i > 右 85 | for (int pre = v; pre < 201; pre++) { 86 | ways += process1(arr, i - 1, pre, pre == v ? 1 : 2); 87 | } 88 | } 89 | return ways; 90 | } 91 | 92 | public static int ways2(int[] arr) { 93 | int N = arr.length; 94 | int[][][] dp = new int[N][201][3]; 95 | // dp[0][...][...] 96 | // dp[0][...][2] = 0 97 | // dp[0][...][0] = 1 98 | // dp[0][...][1] = 1 99 | if (arr[0] != 0) { 100 | dp[0][arr[0]][0] = 1; 101 | dp[0][arr[0]][1] = 1; 102 | } else { 103 | for (int v = 1; v < 201; v++) { 104 | dp[0][v][0] = 1; 105 | dp[0][v][1] = 1; 106 | } 107 | } 108 | for (int i = 1; i < N; i++) { 109 | for (int v = 1; v < 201; v++) { 110 | for (int s = 0; s < 3; s++) { 111 | if (arr[i] == 0 || v == arr[i]) { 112 | if (s == 0 || s == 1) { 113 | for (int pre = 1; pre < 201; pre++) { 114 | dp[i][v][s] += dp[i - 1][pre][pre < v ? 0 : (pre == v ? 1 : 2)]; 115 | } 116 | } else { 117 | for (int pre = v; pre < 201; pre++) { 118 | dp[i][v][s] += dp[i - 1][pre][pre < v ? 0 : (pre == v ? 1 : 2)]; 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | if (arr[N - 1] != 0) { 126 | return dp[N - 1][arr[N - 1]][2]; 127 | } else { 128 | int ways = 0; 129 | for (int v = 1; v < 201; v++) { 130 | ways += dp[N - 1][v][2]; 131 | } 132 | return ways; 133 | } 134 | } 135 | 136 | public static int ways3(int[] arr) { 137 | int N = arr.length; 138 | int[][][] dp = new int[N][201][3]; 139 | if (arr[0] != 0) { 140 | dp[0][arr[0]][0] = 1; 141 | dp[0][arr[0]][1] = 1; 142 | } else { 143 | for (int v = 1; v < 201; v++) { 144 | dp[0][v][0] = 1; 145 | dp[0][v][1] = 1; 146 | } 147 | } 148 | // presum[0~V][0] -> sum0[] 149 | // presum[0~V][1] -> sum1[] 150 | // presum[0~V][2] -> sum2[] 151 | int[][] presum = new int[201][3]; 152 | // presum -> dp[0][..][..] 三张表 153 | for (int v = 1; v < 201; v++) { 154 | for (int s = 0; s < 3; s++) { 155 | presum[v][s] = presum[v - 1][s] + dp[0][v][s]; 156 | } 157 | } 158 | for (int i = 1; i < N; i++) { 159 | for (int v = 1; v < 201; v++) { 160 | for (int s = 0; s < 3; s++) { 161 | if (arr[i] == 0 || v == arr[i]) { 162 | if (s == 0 || s == 1) { 163 | // dp[i][..][..] -> dp[i-1][..][..] 164 | dp[i][v][s] += sum(1, v - 1, 0, presum); 165 | dp[i][v][s] += dp[i - 1][v][1]; 166 | dp[i][v][s] += sum(v + 1, 200, 2, presum); 167 | } else { 168 | dp[i][v][s] += dp[i - 1][v][1]; 169 | dp[i][v][s] += sum(v + 1, 200, 2, presum); 170 | } 171 | } 172 | } 173 | } 174 | for (int v = 1; v < 201; v++) { 175 | for (int s = 0; s < 3; s++) { 176 | presum[v][s] = presum[v - 1][s] + dp[i][v][s]; 177 | } 178 | } 179 | } 180 | if (arr[N - 1] != 0) { 181 | return dp[N - 1][arr[N - 1]][2]; 182 | } else { 183 | return sum(1, 200, 2, presum); 184 | } 185 | } 186 | 187 | public static int sum(int begin, int end, int relation, int[][] presum) { 188 | return presum[end][relation] - presum[begin - 1][relation]; 189 | } 190 | 191 | // for test 192 | public static int[] generateRandomArray(int len) { 193 | int[] ans = new int[(int) (Math.random() * len) + 2]; 194 | for (int i = 0; i < ans.length; i++) { 195 | if (Math.random() < 0.5) { 196 | ans[i] = 0; 197 | } else { 198 | ans[i] = (int) (Math.random() * 200) + 1; 199 | } 200 | } 201 | return ans; 202 | } 203 | 204 | // for test 205 | public static void printArray(int[] arr) { 206 | System.out.println("arr size : " + arr.length); 207 | for (int i = 0; i < arr.length; i++) { 208 | System.out.print(arr[i] + " "); 209 | } 210 | System.out.println(); 211 | } 212 | 213 | public static void main(String[] args) { 214 | int len = 3; 215 | int testTime = 10; 216 | System.out.println("test begin"); 217 | for (int i = 0; i < testTime; i++) { 218 | int[] arr = generateRandomArray(len); 219 | int ans0 = ways0(arr); 220 | int ans1 = ways1(arr); 221 | int ans2 = ways2(arr); 222 | int ans3 = ways3(arr); 223 | if (ans0 != ans1 || ans2 != ans3 || ans0 != ans2) { 224 | System.out.println("Oops!"); 225 | } 226 | } 227 | System.out.println("test finish"); 228 | int[] arr = generateRandomArray(100000); 229 | System.out.println(arr.length); 230 | long begin = System.currentTimeMillis(); 231 | ways3(arr); 232 | long end = System.currentTimeMillis(); 233 | System.out.println("run time : " + (end - begin) + " ms"); 234 | 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/class07/Code01_TSP.java: -------------------------------------------------------------------------------- 1 | package class07; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Code01_TSP { 7 | 8 | public static int t1(int[][] matrix) { 9 | int N = matrix.length; // 0...N-1 10 | // set 11 | // set.get(i) != null i这座城市在集合里 12 | // set.get(i) == null i这座城市不在集合里 13 | List set = new ArrayList<>(); 14 | for (int i = 0; i < N; i++) { 15 | set.add(1); 16 | } 17 | return func1(matrix, set, 0); 18 | } 19 | 20 | // 任何两座城市之间的距离,可以在matrix里面拿到 21 | // set中表示着哪些城市的集合, 22 | // start这座城一定在set里, 23 | // 从start出发,要把set中所有的城市过一遍,最终回到0这座城市,最小距离是多少 24 | public static int func1(int[][] matrix, List set, int start) { 25 | int cityNum = 0; 26 | for (int i = 0; i < set.size(); i++) { 27 | if (set.get(i) != null) { 28 | cityNum++; 29 | } 30 | } 31 | if (cityNum == 1) { 32 | return matrix[start][0]; 33 | } 34 | // 不只start这一座城 35 | set.set(start, null); 36 | int min = Integer.MAX_VALUE; 37 | for (int i = 0; i < set.size(); i++) { 38 | if (set.get(i) != null && i != start) { 39 | // start -> i i... -> 0 40 | int cur = matrix[start][i] + func1(matrix, set, i); 41 | min = Math.min(min, cur); 42 | } 43 | } 44 | set.set(start, 1); 45 | return min; 46 | } 47 | 48 | public static int t2(int[][] matrix) { 49 | int N = matrix.length; // 0...N-1 50 | // 7座城 1111111 51 | int allCity = (1 << N) - 1; 52 | return f2(matrix, allCity, 0); 53 | } 54 | 55 | // 任何两座城市之间的距离,可以在matrix里面拿到 56 | // set中表示着哪些城市的集合, 57 | // start这座城一定在set里, 58 | // 从start出发,要把set中所有的城市过一遍,最终回到0这座城市,最小距离是多少 59 | public static int f2(int[][] matrix, int cityStatus, int start) { 60 | // cityStatus == cityStatux & (~cityStaus + 1) 61 | 62 | if (cityStatus == (cityStatus & (~cityStatus + 1))) { 63 | return matrix[start][0]; 64 | } 65 | 66 | // 把start位的1去掉, 67 | cityStatus &= (~(1 << start)); 68 | int min = Integer.MAX_VALUE; 69 | // 枚举所有的城市 70 | for (int move = 0; move < matrix.length; move++) { 71 | if (move != start && (cityStatus & (1 << move)) != 0) { 72 | int cur = matrix[start][move] + f2(matrix, cityStatus, move); 73 | min = Math.min(min, cur); 74 | } 75 | } 76 | cityStatus |= (1 << start); 77 | return min; 78 | } 79 | 80 | public static int t3(int[][] matrix) { 81 | int N = matrix.length; // 0...N-1 82 | // 7座城 1111111 83 | int allCity = (1 << N) - 1; 84 | int[][] dp = new int[1 << N][N]; 85 | for (int i = 0; i < (1 << N); i++) { 86 | for (int j = 0; j < N; j++) { 87 | dp[i][j] = -1; 88 | } 89 | } 90 | return f3(matrix, allCity, 0, dp); 91 | } 92 | 93 | // 任何两座城市之间的距离,可以在matrix里面拿到 94 | // set中表示着哪些城市的集合, 95 | // start这座城一定在set里, 96 | // 从start出发,要把set中所有的城市过一遍,最终回到0这座城市,最小距离是多少 97 | public static int f3(int[][] matrix, int cityStatus, int start, int[][] dp) { 98 | if (dp[cityStatus][start] != -1) { 99 | return dp[cityStatus][start]; 100 | } 101 | if (cityStatus == (cityStatus & (~cityStatus + 1))) { 102 | dp[cityStatus][start] = matrix[start][0]; 103 | } else { 104 | // 把start位的1去掉, 105 | cityStatus &= (~(1 << start)); 106 | int min = Integer.MAX_VALUE; 107 | // 枚举所有的城市 108 | for (int move = 0; move < matrix.length; move++) { 109 | if (move != start && (cityStatus & (1 << move)) != 0) { 110 | int cur = matrix[start][move] + f3(matrix, cityStatus, move, dp); 111 | min = Math.min(min, cur); 112 | } 113 | } 114 | cityStatus |= (1 << start); 115 | dp[cityStatus][start] = min; 116 | } 117 | return dp[cityStatus][start]; 118 | } 119 | 120 | public static int t4(int[][] matrix) { 121 | int N = matrix.length; // 0...N-1 122 | int statusNums = 1 << N; 123 | int[][] dp = new int[statusNums][N]; 124 | 125 | for (int status = 0; status < statusNums; status++) { 126 | for (int start = 0; start < N; start++) { 127 | if ((status & (1 << start)) != 0) { 128 | if (status == (status & (~status + 1))) { 129 | dp[status][start] = matrix[start][0]; 130 | } else { 131 | int min = Integer.MAX_VALUE; 132 | // start 城市在status里去掉之后,的状态 133 | int preStatus = status & (~(1 << start)); 134 | // start -> i 135 | for (int i = 0; i < N; i++) { 136 | if ((preStatus & (1 << i)) != 0) { 137 | int cur = matrix[start][i] + dp[preStatus][i]; 138 | min = Math.min(min, cur); 139 | } 140 | } 141 | dp[status][start] = min; 142 | } 143 | } 144 | } 145 | } 146 | return dp[statusNums - 1][0]; 147 | } 148 | 149 | // matrix[i][j] -> i城市到j城市的距离 150 | public static int tsp1(int[][] matrix, int origin) { 151 | if (matrix == null || matrix.length < 2 || origin < 0 || origin >= matrix.length) { 152 | return 0; 153 | } 154 | // 要考虑的集合 155 | ArrayList cities = new ArrayList<>(); 156 | // cities[0] != null 表示0城在集合里 157 | // cities[i] != null 表示i城在集合里 158 | for (int i = 0; i < matrix.length; i++) { 159 | cities.add(1); 160 | } 161 | // null,1,1,1,1,1,1 162 | // origin城不参与集合 163 | cities.set(origin, null); 164 | return process(matrix, origin, cities, origin); 165 | } 166 | 167 | // matrix 所有距离,存在其中 168 | // origin 固定参数,唯一的目标 169 | // cities 要考虑的集合,一定不含有origin 170 | // 当前来到的城市是谁,cur 171 | public static int process(int[][] matrix, int aim, ArrayList cities, int cur) { 172 | boolean hasCity = false; // 集团中还是否有城市 173 | int ans = Integer.MAX_VALUE; 174 | for (int i = 0; i < cities.size(); i++) { 175 | if (cities.get(i) != null) { 176 | hasCity = true; 177 | cities.set(i, null); 178 | // matrix[cur][i] + f(i, 集团(去掉i) ) 179 | ans = Math.min(ans, matrix[cur][i] + process(matrix, aim, cities, i)); 180 | cities.set(i, 1); 181 | } 182 | } 183 | return hasCity ? ans : matrix[cur][aim]; 184 | } 185 | 186 | // cities 里,一定含有cur这座城 187 | // 解决的是,集合从cur出发,通过集合里所有的城市,最终来到aim,最短距离 188 | public static int process2(int[][] matrix, int aim, ArrayList cities, int cur) { 189 | if (cities.size() == 1) { 190 | return matrix[cur][aim]; 191 | } 192 | cities.set(cur, null); 193 | int ans = Integer.MAX_VALUE; 194 | for (int i = 0; i < cities.size(); i++) { 195 | if (cities.get(i) != null) { 196 | int dis = matrix[cur][i] + process2(matrix, aim, cities, i); 197 | ans = Math.min(ans, dis); 198 | } 199 | } 200 | cities.set(cur, 1); 201 | return ans; 202 | } 203 | 204 | public static int tsp2(int[][] matrix, int origin) { 205 | if (matrix == null || matrix.length < 2 || origin < 0 || origin >= matrix.length) { 206 | return 0; 207 | } 208 | int N = matrix.length - 1; // 除去origin之后是n-1个点 209 | int S = 1 << N; // 状态数量 210 | int[][] dp = new int[S][N]; 211 | int icity = 0; 212 | int kcity = 0; 213 | for (int i = 0; i < N; i++) { 214 | icity = i < origin ? i : i + 1; 215 | // 00000000 i 216 | dp[0][i] = matrix[icity][origin]; 217 | } 218 | for (int status = 1; status < S; status++) { 219 | // 尝试每一种状态 status = 0 0 1 0 0 0 0 0 0 220 | // 下标 8 7 6 5 4 3 2 1 0 221 | for (int i = 0; i < N; i++) { 222 | // i 枚举的出发城市 223 | dp[status][i] = Integer.MAX_VALUE; 224 | if ((1 << i & status) != 0) { 225 | // 如果i这座城是可以枚举的,i = 6 , i对应的原始城的编号,icity 226 | icity = i < origin ? i : i + 1; 227 | for (int k = 0; k < N; k++) { // i 这一步连到的点,k 228 | if ((1 << k & status) != 0) { // i 这一步可以连到k 229 | kcity = k < origin ? k : k + 1; // k对应的原始城的编号,kcity 230 | dp[status][i] = Math.min(dp[status][i], dp[status ^ (1 << i)][k] + matrix[icity][kcity]); 231 | } 232 | } 233 | } 234 | } 235 | } 236 | int ans = Integer.MAX_VALUE; 237 | for (int i = 0; i < N; i++) { 238 | icity = i < origin ? i : i + 1; 239 | ans = Math.min(ans, dp[S - 1][i] + matrix[origin][icity]); 240 | } 241 | return ans; 242 | } 243 | 244 | public static int[][] generateGraph(int maxSize, int maxValue) { 245 | int len = (int) (Math.random() * maxSize) + 1; 246 | int[][] matrix = new int[len][len]; 247 | for (int i = 0; i < len; i++) { 248 | for (int j = 0; j < len; j++) { 249 | matrix[i][j] = (int) (Math.random() * maxValue) + 1; 250 | } 251 | } 252 | for (int i = 0; i < len; i++) { 253 | matrix[i][i] = 0; 254 | } 255 | return matrix; 256 | } 257 | 258 | public static void main(String[] args) { 259 | int len = 10; 260 | int value = 100; 261 | System.out.println("功能测试开始"); 262 | for (int i = 0; i < 20000; i++) { 263 | int[][] matrix = generateGraph(len, value); 264 | int origin = (int) (Math.random() * matrix.length); 265 | int ans1 = t3(matrix); 266 | int ans2 = t4(matrix); 267 | int ans3 = tsp2(matrix, origin); 268 | if (ans1 != ans2 || ans1 != ans3) { 269 | System.out.println("fuck"); 270 | } 271 | } 272 | System.out.println("功能测试结束"); 273 | 274 | len = 22; 275 | System.out.println("性能测试开始,数据规模 : " + len); 276 | int[][] matrix = new int[len][len]; 277 | for (int i = 0; i < len; i++) { 278 | for (int j = 0; j < len; j++) { 279 | matrix[i][j] = (int) (Math.random() * value) + 1; 280 | } 281 | } 282 | for (int i = 0; i < len; i++) { 283 | matrix[i][i] = 0; 284 | } 285 | long start; 286 | long end; 287 | start = System.currentTimeMillis(); 288 | t4(matrix); 289 | end = System.currentTimeMillis(); 290 | System.out.println("运行时间 : " + (end - start) + " 毫秒"); 291 | System.out.println("性能测试结束"); 292 | 293 | } 294 | 295 | } 296 | -------------------------------------------------------------------------------- /src/class07/Code02_PavingTile.java: -------------------------------------------------------------------------------- 1 | package class07; 2 | 3 | public class Code02_PavingTile { 4 | 5 | /* 6 | * 2*M铺地的问题非常简单,这个是解决N*M铺地的问题 7 | */ 8 | 9 | public static int ways1(int N, int M) { 10 | if (N < 1 || M < 1 || ((N * M) & 1) != 0) { 11 | return 0; 12 | } 13 | if (N == 1 || M == 1) { 14 | return 1; 15 | } 16 | int[] pre = new int[M]; // pre代表-1行的状况 17 | for (int i = 0; i < pre.length; i++) { 18 | pre[i] = 1; 19 | } 20 | return process(pre, 0, N); 21 | } 22 | 23 | // pre 表示level-1行的状态 24 | // level表示,正在level行做决定 25 | // N 表示一共有多少行 固定的 26 | // level-2行及其之上所有行,都摆满砖了 27 | // level做决定,让所有区域都满,方法数返回s 28 | public static int process(int[] pre, int level, int N) { 29 | if (level == N) { // base case 30 | for (int i = 0; i < pre.length; i++) { 31 | if (pre[i] == 0) { 32 | return 0; 33 | } 34 | } 35 | return 1; 36 | } 37 | 38 | // 没到终止行,可以选择在当前的level行摆瓷砖 39 | int[] op = getOp(pre); 40 | return dfs(op, 0, level, N); 41 | } 42 | 43 | // op[i] == 0 可以考虑摆砖 44 | // op[i] == 1 只能竖着向上 45 | public static int dfs(int[] op, int col, int level, int N) { 46 | // 在列上自由发挥,玩深度优先遍历,当col来到终止列,i行的决定做完了 47 | // 轮到i+1行,做决定 48 | if (col == op.length) { 49 | return process(op, level + 1, N); 50 | } 51 | int ans = 0; 52 | // col位置不横摆 53 | ans += dfs(op, col + 1, level, N); // col位置上不摆横转 54 | // col位置横摆, 向右 55 | if (col + 1 < op.length && op[col] == 0 && op[col + 1] == 0) { 56 | op[col] = 1; 57 | op[col + 1] = 1; 58 | ans += dfs(op, col + 2, level, N); 59 | op[col] = 0; 60 | op[col + 1] = 0; 61 | } 62 | return ans; 63 | } 64 | 65 | public static int[] getOp(int[] pre) { 66 | int[] cur = new int[pre.length]; 67 | for (int i = 0; i < pre.length; i++) { 68 | cur[i] = pre[i] ^ 1; 69 | } 70 | return cur; 71 | } 72 | 73 | public static int ways2(int N, int M) { 74 | if (N < 1 || M < 1 || ((N * M) & 1) != 0) { 75 | return 0; 76 | } 77 | if (N == 1 || M == 1) { 78 | return 1; 79 | } 80 | int big = N > M ? N : M; 81 | int small = big == N ? M : N; 82 | // big * small 83 | int sn = 1 << small; 84 | int limit = sn - 1; // 全满状态 85 | int[] dp = new int[sn]; 86 | dp[limit] = 1; // -1行全是满的 87 | // dp -1 行的状况 88 | // dp[0000] 0 89 | // dp[0001] 0 90 | // dp[1111] 1 91 | int[] cur = new int[sn]; // 当前行, 要算出所有状态下的解 92 | for (int level = 0; level < big; level++) { 93 | for (int status = 0; status < sn; status++) { 94 | if (dp[status] != 0) { // 状态出现了 95 | // 0...1100 96 | // 1...0011 97 | // 0...1111 98 | // 0...0011 99 | int op = (~status) & limit; 100 | dfs(dp[status], op, 0, small - 1, cur); 101 | } 102 | } 103 | for (int i = 0; i < sn; i++) { 104 | dp[i] = 0; 105 | } 106 | int[] tmp = dp; 107 | dp = cur; 108 | cur = tmp; 109 | } 110 | return dp[limit]; 111 | } 112 | 113 | public static void dfs(int way, int op, int index, int end, int[] cur) { 114 | if (index == end) { 115 | cur[op] += way; 116 | } else { 117 | dfs(way, op, index + 1, end, cur); 118 | if (((3 << index) & op) == 0) { // 11 << index 可以放砖 119 | dfs(way, op | (3 << index), index + 1, end, cur); 120 | } 121 | } 122 | } 123 | 124 | public static void main(String[] args) { 125 | int N = 8; 126 | int M = 8; 127 | System.out.println(ways1(N, M)); 128 | System.out.println(ways2(N, M)); 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/class08/Code01_CreateMaximumNumber.java: -------------------------------------------------------------------------------- 1 | package class08; 2 | 3 | // 测试链接: https://leetcode.com/problems/create-maximum-number/ 4 | public class Code01_CreateMaximumNumber { 5 | 6 | public static int[] maxNumber1(int[] nums1, int[] nums2, int k) { 7 | int len1 = nums1.length; 8 | int len2 = nums2.length; 9 | if (k < 0 || k > len1 + len2) { 10 | return null; 11 | } 12 | int[] res = new int[k]; 13 | int[][] dp1 = getdp(nums1); // 生成dp1这个表,以后从nums1中,只要固定拿N个数, 14 | int[][] dp2 = getdp(nums2); 15 | for (int get1 = Math.max(0, k - len2); get1 <= Math.min(k, len1); get1++) { 16 | // arr1 挑 get1个,怎么得到一个最优结果 17 | int[] pick1 = maxPick(nums1, dp1, get1); 18 | int[] pick2 = maxPick(nums2, dp2, k - get1); 19 | int[] merge = merge(pick1, pick2); 20 | res = preMoreThanLast(res, 0, merge, 0) ? res : merge; 21 | } 22 | return res; 23 | } 24 | 25 | public static int[] merge(int[] nums1, int[] nums2) { 26 | int k = nums1.length + nums2.length; 27 | int[] ans = new int[k]; 28 | for (int i = 0, j = 0, r = 0; r < k; ++r) { 29 | ans[r] = preMoreThanLast(nums1, i, nums2, j) ? nums1[i++] : nums2[j++]; 30 | } 31 | return ans; 32 | } 33 | 34 | public static boolean preMoreThanLast(int[] nums1, int i, int[] nums2, int j) { 35 | while (i < nums1.length && j < nums2.length && nums1[i] == nums2[j]) { 36 | i++; 37 | j++; 38 | } 39 | return j == nums2.length || (i < nums1.length && nums1[i] > nums2[j]); 40 | } 41 | 42 | public static int[] maxNumber2(int[] nums1, int[] nums2, int k) { 43 | int len1 = nums1.length; 44 | int len2 = nums2.length; 45 | if (k < 0 || k > len1 + len2) { 46 | return null; 47 | } 48 | int[] res = new int[k]; 49 | int[][] dp1 = getdp(nums1); 50 | int[][] dp2 = getdp(nums2); 51 | for (int get1 = Math.max(0, k - len2); get1 <= Math.min(k, len1); get1++) { 52 | int[] pick1 = maxPick(nums1, dp1, get1); 53 | int[] pick2 = maxPick(nums2, dp2, k - get1); 54 | int[] merge = mergeBySuffixArray(pick1, pick2); 55 | res = moreThan(res, merge) ? res : merge; 56 | } 57 | return res; 58 | } 59 | 60 | public static boolean moreThan(int[] pre, int[] last) { 61 | int i = 0; 62 | int j = 0; 63 | while (i < pre.length && j < last.length && pre[i] == last[j]) { 64 | i++; 65 | j++; 66 | } 67 | return j == last.length || (i < pre.length && pre[i] > last[j]); 68 | } 69 | 70 | public static int[] mergeBySuffixArray(int[] nums1, int[] nums2) { 71 | int size1 = nums1.length; 72 | int size2 = nums2.length; 73 | int[] nums = new int[size1 + 1 + size2]; 74 | for (int i = 0; i < size1; i++) { 75 | nums[i] = nums1[i] + 2; 76 | } 77 | nums[size1] = 1; 78 | for (int j = 0; j < size2; j++) { 79 | nums[j + size1 + 1] = nums2[j] + 2; 80 | } 81 | DC3 dc3 = new DC3(nums, 11); 82 | int[] rank = dc3.rank; 83 | int[] ans = new int[size1 + size2]; 84 | int i = 0; 85 | int j = 0; 86 | int r = 0; 87 | while (i < size1 && j < size2) { 88 | ans[r++] = rank[i] > rank[j + size1 + 1] ? nums1[i++] : nums2[j++]; 89 | } 90 | while (i < size1) { 91 | ans[r++] = nums1[i++]; 92 | } 93 | while (j < size2) { 94 | ans[r++] = nums2[j++]; 95 | } 96 | return ans; 97 | } 98 | 99 | public static class DC3 { 100 | 101 | public int[] sa; 102 | public int[] rank; 103 | 104 | public DC3(int[] nums, int max) { 105 | sa = sa(nums, max); 106 | rank = rank(); 107 | } 108 | 109 | private int[] sa(int[] nums, int max) { 110 | int n = nums.length; 111 | int[] arr = new int[n + 3]; 112 | for (int i = 0; i < n; i++) { 113 | arr[i] = nums[i]; 114 | } 115 | return skew(arr, n, max); 116 | } 117 | 118 | private int[] skew(int[] nums, int n, int K) { 119 | int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2; 120 | int[] s12 = new int[n02 + 3], sa12 = new int[n02 + 3]; 121 | for (int i = 0, j = 0; i < n + (n0 - n1); ++i) { 122 | if (0 != i % 3) { 123 | s12[j++] = i; 124 | } 125 | } 126 | radixPass(nums, s12, sa12, 2, n02, K); 127 | radixPass(nums, sa12, s12, 1, n02, K); 128 | radixPass(nums, s12, sa12, 0, n02, K); 129 | int name = 0, c0 = -1, c1 = -1, c2 = -1; 130 | for (int i = 0; i < n02; ++i) { 131 | if (c0 != nums[sa12[i]] || c1 != nums[sa12[i] + 1] || c2 != nums[sa12[i] + 2]) { 132 | name++; 133 | c0 = nums[sa12[i]]; 134 | c1 = nums[sa12[i] + 1]; 135 | c2 = nums[sa12[i] + 2]; 136 | } 137 | if (1 == sa12[i] % 3) { 138 | s12[sa12[i] / 3] = name; 139 | } else { 140 | s12[sa12[i] / 3 + n0] = name; 141 | } 142 | } 143 | if (name < n02) { 144 | sa12 = skew(s12, n02, name); 145 | for (int i = 0; i < n02; i++) { 146 | s12[sa12[i]] = i + 1; 147 | } 148 | } else { 149 | for (int i = 0; i < n02; i++) { 150 | sa12[s12[i] - 1] = i; 151 | } 152 | } 153 | int[] s0 = new int[n0], sa0 = new int[n0]; 154 | for (int i = 0, j = 0; i < n02; i++) { 155 | if (sa12[i] < n0) { 156 | s0[j++] = 3 * sa12[i]; 157 | } 158 | } 159 | radixPass(nums, s0, sa0, 0, n0, K); 160 | int[] sa = new int[n]; 161 | for (int p = 0, t = n0 - n1, k = 0; k < n; k++) { 162 | int i = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 163 | int j = sa0[p]; 164 | if (sa12[t] < n0 ? leq(nums[i], s12[sa12[t] + n0], nums[j], s12[j / 3]) 165 | : leq(nums[i], nums[i + 1], s12[sa12[t] - n0 + 1], nums[j], nums[j + 1], s12[j / 3 + n0])) { 166 | sa[k] = i; 167 | t++; 168 | if (t == n02) { 169 | for (k++; p < n0; p++, k++) { 170 | sa[k] = sa0[p]; 171 | } 172 | } 173 | } else { 174 | sa[k] = j; 175 | p++; 176 | if (p == n0) { 177 | for (k++; t < n02; t++, k++) { 178 | sa[k] = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 179 | } 180 | } 181 | } 182 | } 183 | return sa; 184 | } 185 | 186 | private void radixPass(int[] nums, int[] input, int[] output, int offset, int n, int k) { 187 | int[] cnt = new int[k + 1]; 188 | for (int i = 0; i < n; ++i) { 189 | cnt[nums[input[i] + offset]]++; 190 | } 191 | for (int i = 0, sum = 0; i < cnt.length; ++i) { 192 | int t = cnt[i]; 193 | cnt[i] = sum; 194 | sum += t; 195 | } 196 | for (int i = 0; i < n; ++i) { 197 | output[cnt[nums[input[i] + offset]]++] = input[i]; 198 | } 199 | } 200 | 201 | private boolean leq(int a1, int a2, int b1, int b2) { 202 | return a1 < b1 || (a1 == b1 && a2 <= b2); 203 | } 204 | 205 | private boolean leq(int a1, int a2, int a3, int b1, int b2, int b3) { 206 | return a1 < b1 || (a1 == b1 && leq(a2, a3, b2, b3)); 207 | } 208 | 209 | private int[] rank() { 210 | int n = sa.length; 211 | int[] ans = new int[n]; 212 | for (int i = 0; i < n; i++) { 213 | ans[sa[i]] = i + 1; 214 | } 215 | return ans; 216 | } 217 | 218 | } 219 | 220 | public static int[][] getdp(int[] arr) { 221 | int size = arr.length; // 0~N-1 222 | int pick = arr.length + 1; // 1 ~ N 223 | int[][] dp = new int[size][pick]; 224 | // get 不从0开始,因为拿0个无意义 225 | // get 1 226 | for (int get = 1; get < pick; get++) { // 1 ~ N 227 | int maxIndex = size - get; 228 | // i~N-1 229 | for (int i = size - get; i >= 0; i--) { 230 | if (arr[i] >= arr[maxIndex]) { 231 | maxIndex = i; 232 | } 233 | dp[i][get] = maxIndex; 234 | } 235 | } 236 | return dp; 237 | } 238 | 239 | public static int[] maxPick(int[] arr, int[][] dp, int pick) { 240 | int[] res = new int[pick]; 241 | for (int resIndex = 0, dpRow = 0; pick > 0; pick--, resIndex++) { 242 | res[resIndex] = arr[dp[dpRow][pick]]; 243 | dpRow = dp[dpRow][pick] + 1; 244 | } 245 | return res; 246 | } 247 | 248 | } 249 | -------------------------------------------------------------------------------- /src/class08/Code02_LastSubstringInLexicographicalOrder.java: -------------------------------------------------------------------------------- 1 | package class08; 2 | 3 | // 测试链接: https://leetcode.com/problems/last-substring-in-lexicographical-order/ 4 | public class Code02_LastSubstringInLexicographicalOrder { 5 | 6 | public static String lastSubstring(String s) { 7 | if (s == null || s.length() == 0) { 8 | return s; 9 | } 10 | int N = s.length(); 11 | char[] str = s.toCharArray(); 12 | int min = Integer.MAX_VALUE; 13 | int max = Integer.MIN_VALUE; 14 | for (char cha : str) { 15 | min = Math.min(min, cha); 16 | max = Math.max(max, cha); 17 | } 18 | int[] arr = new int[N]; 19 | for (int i = 0; i < N; i++) { 20 | arr[i] = str[i] - min + 1; 21 | } 22 | DC3 dc3 = new DC3(arr, max - min + 1); 23 | return s.substring(dc3.sa[N - 1]); 24 | } 25 | 26 | public static class DC3 { 27 | 28 | public int[] sa; 29 | 30 | public int[] rank; 31 | 32 | public DC3(int[] nums, int max) { 33 | sa = sa(nums, max); 34 | rank = rank(); 35 | } 36 | 37 | private int[] sa(int[] nums, int max) { 38 | int n = nums.length; 39 | int[] arr = new int[n + 3]; 40 | for (int i = 0; i < n; i++) { 41 | arr[i] = nums[i]; 42 | } 43 | return skew(arr, n, max); 44 | } 45 | 46 | private int[] skew(int[] nums, int n, int K) { 47 | int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2; 48 | int[] s12 = new int[n02 + 3], sa12 = new int[n02 + 3]; 49 | for (int i = 0, j = 0; i < n + (n0 - n1); ++i) { 50 | if (0 != i % 3) { 51 | s12[j++] = i; 52 | } 53 | } 54 | radixPass(nums, s12, sa12, 2, n02, K); 55 | radixPass(nums, sa12, s12, 1, n02, K); 56 | radixPass(nums, s12, sa12, 0, n02, K); 57 | int name = 0, c0 = -1, c1 = -1, c2 = -1; 58 | for (int i = 0; i < n02; ++i) { 59 | if (c0 != nums[sa12[i]] || c1 != nums[sa12[i] + 1] || c2 != nums[sa12[i] + 2]) { 60 | name++; 61 | c0 = nums[sa12[i]]; 62 | c1 = nums[sa12[i] + 1]; 63 | c2 = nums[sa12[i] + 2]; 64 | } 65 | if (1 == sa12[i] % 3) { 66 | s12[sa12[i] / 3] = name; 67 | } else { 68 | s12[sa12[i] / 3 + n0] = name; 69 | } 70 | } 71 | if (name < n02) { 72 | sa12 = skew(s12, n02, name); 73 | for (int i = 0; i < n02; i++) { 74 | s12[sa12[i]] = i + 1; 75 | } 76 | } else { 77 | for (int i = 0; i < n02; i++) { 78 | sa12[s12[i] - 1] = i; 79 | } 80 | } 81 | int[] s0 = new int[n0], sa0 = new int[n0]; 82 | for (int i = 0, j = 0; i < n02; i++) { 83 | if (sa12[i] < n0) { 84 | s0[j++] = 3 * sa12[i]; 85 | } 86 | } 87 | radixPass(nums, s0, sa0, 0, n0, K); 88 | int[] sa = new int[n]; 89 | for (int p = 0, t = n0 - n1, k = 0; k < n; k++) { 90 | int i = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 91 | int j = sa0[p]; 92 | if (sa12[t] < n0 ? leq(nums[i], s12[sa12[t] + n0], nums[j], s12[j / 3]) 93 | : leq(nums[i], nums[i + 1], s12[sa12[t] - n0 + 1], nums[j], nums[j + 1], s12[j / 3 + n0])) { 94 | sa[k] = i; 95 | t++; 96 | if (t == n02) { 97 | for (k++; p < n0; p++, k++) { 98 | sa[k] = sa0[p]; 99 | } 100 | } 101 | } else { 102 | sa[k] = j; 103 | p++; 104 | if (p == n0) { 105 | for (k++; t < n02; t++, k++) { 106 | sa[k] = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 107 | } 108 | } 109 | } 110 | } 111 | return sa; 112 | } 113 | 114 | private void radixPass(int[] nums, int[] input, int[] output, int offset, int n, int k) { 115 | int[] cnt = new int[k + 1]; 116 | for (int i = 0; i < n; ++i) { 117 | cnt[nums[input[i] + offset]]++; 118 | } 119 | for (int i = 0, sum = 0; i < cnt.length; ++i) { 120 | int t = cnt[i]; 121 | cnt[i] = sum; 122 | sum += t; 123 | } 124 | for (int i = 0; i < n; ++i) { 125 | output[cnt[nums[input[i] + offset]]++] = input[i]; 126 | } 127 | } 128 | 129 | private boolean leq(int a1, int a2, int b1, int b2) { 130 | return a1 < b1 || (a1 == b1 && a2 <= b2); 131 | } 132 | 133 | private boolean leq(int a1, int a2, int a3, int b1, int b2, int b3) { 134 | return a1 < b1 || (a1 == b1 && leq(a2, a3, b2, b3)); 135 | } 136 | 137 | private int[] rank() { 138 | int n = sa.length; 139 | int[] ans = new int[n]; 140 | for (int i = 0; i < n; i++) { 141 | ans[sa[i]] = i + 1; 142 | } 143 | return ans; 144 | } 145 | 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/class08/Code03_InsertS2MakeMostAlphabeticalOrder.java: -------------------------------------------------------------------------------- 1 | package class08; 2 | 3 | public class Code03_InsertS2MakeMostAlphabeticalOrder { 4 | 5 | // 暴力方法 6 | public static String right(String s1, String s2) { 7 | if (s1 == null || s1.length() == 0) { 8 | return s2; 9 | } 10 | if (s2 == null || s2.length() == 0) { 11 | return s1; 12 | } 13 | String p1 = s1 + s2; 14 | String p2 = s2 + s1; 15 | String ans = p1.compareTo(p2) > 0 ? p1 : p2; 16 | for (int end = 1; end < s1.length(); end++) { 17 | String cur = s1.substring(0, end) + s2 + s1.substring(end); 18 | if (cur.compareTo(ans) > 0) { 19 | ans = cur; 20 | } 21 | } 22 | return ans; 23 | } 24 | 25 | // 正式方法 26 | public static String max(String s1, String s2) { 27 | if (s1 == null || s1.length() == 0) { 28 | return s2; 29 | } 30 | if (s2 == null || s2.length() == 0) { 31 | return s1; 32 | } 33 | char[] str1 = s1.toCharArray(); 34 | char[] str2 = s2.toCharArray(); 35 | int N = str1.length; 36 | int M = str2.length; 37 | int min = str1[0]; 38 | int max = str1[0]; 39 | for (int i = 1; i < N; i++) { 40 | min = Math.min(min, str1[i]); 41 | max = Math.max(max, str1[i]); 42 | } 43 | for (int i = 0; i < M; i++) { 44 | min = Math.min(min, str2[i]); 45 | max = Math.max(max, str2[i]); 46 | } 47 | int[] all = new int[N + M + 1]; 48 | int index = 0; 49 | for (int i = 0; i < N; i++) { 50 | all[index++] = str1[i] - min + 2; 51 | } 52 | all[index++] = 1; 53 | for (int i = 0; i < M; i++) { 54 | all[index++] = str2[i] - min + 2; 55 | } 56 | DC3 dc3 = new DC3(all, max - min + 2); 57 | int[] rank = dc3.rank; 58 | int comp = N + 1; 59 | for (int i = 0; i < N; i++) { 60 | if (rank[i] < rank[comp]) { 61 | int best = whereSplit(s1, s2, i); 62 | return s1.substring(0, best) + s2 + s1.substring(best); 63 | } 64 | } 65 | return s1 + s2; 66 | } 67 | 68 | public static class DC3 { 69 | 70 | public int[] sa; 71 | public int[] rank; 72 | 73 | public DC3(int[] nums, int max) { 74 | sa = sa(nums, max); 75 | rank = rank(); 76 | } 77 | 78 | private int[] sa(int[] nums, int max) { 79 | int n = nums.length; 80 | int[] arr = new int[n + 3]; 81 | for (int i = 0; i < n; i++) { 82 | arr[i] = nums[i]; 83 | } 84 | return skew(arr, n, max); 85 | } 86 | 87 | private int[] skew(int[] nums, int n, int K) { 88 | int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2; 89 | int[] s12 = new int[n02 + 3], sa12 = new int[n02 + 3]; 90 | for (int i = 0, j = 0; i < n + (n0 - n1); ++i) { 91 | if (0 != i % 3) { 92 | s12[j++] = i; 93 | } 94 | } 95 | radixPass(nums, s12, sa12, 2, n02, K); 96 | radixPass(nums, sa12, s12, 1, n02, K); 97 | radixPass(nums, s12, sa12, 0, n02, K); 98 | int name = 0, c0 = -1, c1 = -1, c2 = -1; 99 | for (int i = 0; i < n02; ++i) { 100 | if (c0 != nums[sa12[i]] || c1 != nums[sa12[i] + 1] || c2 != nums[sa12[i] + 2]) { 101 | name++; 102 | c0 = nums[sa12[i]]; 103 | c1 = nums[sa12[i] + 1]; 104 | c2 = nums[sa12[i] + 2]; 105 | } 106 | if (1 == sa12[i] % 3) { 107 | s12[sa12[i] / 3] = name; 108 | } else { 109 | s12[sa12[i] / 3 + n0] = name; 110 | } 111 | } 112 | if (name < n02) { 113 | sa12 = skew(s12, n02, name); 114 | for (int i = 0; i < n02; i++) { 115 | s12[sa12[i]] = i + 1; 116 | } 117 | } else { 118 | for (int i = 0; i < n02; i++) { 119 | sa12[s12[i] - 1] = i; 120 | } 121 | } 122 | int[] s0 = new int[n0], sa0 = new int[n0]; 123 | for (int i = 0, j = 0; i < n02; i++) { 124 | if (sa12[i] < n0) { 125 | s0[j++] = 3 * sa12[i]; 126 | } 127 | } 128 | radixPass(nums, s0, sa0, 0, n0, K); 129 | int[] sa = new int[n]; 130 | for (int p = 0, t = n0 - n1, k = 0; k < n; k++) { 131 | int i = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 132 | int j = sa0[p]; 133 | if (sa12[t] < n0 ? leq(nums[i], s12[sa12[t] + n0], nums[j], s12[j / 3]) 134 | : leq(nums[i], nums[i + 1], s12[sa12[t] - n0 + 1], nums[j], nums[j + 1], s12[j / 3 + n0])) { 135 | sa[k] = i; 136 | t++; 137 | if (t == n02) { 138 | for (k++; p < n0; p++, k++) { 139 | sa[k] = sa0[p]; 140 | } 141 | } 142 | } else { 143 | sa[k] = j; 144 | p++; 145 | if (p == n0) { 146 | for (k++; t < n02; t++, k++) { 147 | sa[k] = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 148 | } 149 | } 150 | } 151 | } 152 | return sa; 153 | } 154 | 155 | private void radixPass(int[] nums, int[] input, int[] output, int offset, int n, int k) { 156 | int[] cnt = new int[k + 1]; 157 | for (int i = 0; i < n; ++i) { 158 | cnt[nums[input[i] + offset]]++; 159 | } 160 | for (int i = 0, sum = 0; i < cnt.length; ++i) { 161 | int t = cnt[i]; 162 | cnt[i] = sum; 163 | sum += t; 164 | } 165 | for (int i = 0; i < n; ++i) { 166 | output[cnt[nums[input[i] + offset]]++] = input[i]; 167 | } 168 | } 169 | 170 | private boolean leq(int a1, int a2, int b1, int b2) { 171 | return a1 < b1 || (a1 == b1 && a2 <= b2); 172 | } 173 | 174 | private boolean leq(int a1, int a2, int a3, int b1, int b2, int b3) { 175 | return a1 < b1 || (a1 == b1 && leq(a2, a3, b2, b3)); 176 | } 177 | 178 | private int[] rank() { 179 | int n = sa.length; 180 | int[] ans = new int[n]; 181 | for (int i = 0; i < n; i++) { 182 | ans[sa[i]] = i + 1; 183 | } 184 | return ans; 185 | } 186 | 187 | } 188 | 189 | public static int whereSplit(String str1, String str2, int first) { 190 | int M = str2.length(); 191 | String bestPrefix = str2; 192 | int bestSplit = first; 193 | for (int i = first + 1, j = M - 1; i <= Math.min(str1.length(), first + M); i++, j--) { 194 | String curPrefix = str1.substring(first, i) + str2.substring(0, j); 195 | if (curPrefix.compareTo(bestPrefix) >= 0) { 196 | bestPrefix = curPrefix; 197 | bestSplit = i; 198 | } 199 | } 200 | return bestSplit; 201 | } 202 | 203 | // for test 204 | public static String randomNumberString(int len, int range) { 205 | char[] str = new char[len]; 206 | for (int i = 0; i < len; i++) { 207 | str[i] = (char) ((int) (Math.random() * range) + '0'); 208 | } 209 | return String.valueOf(str); 210 | } 211 | 212 | // for test 213 | public static void main(String[] args) { 214 | int range = 10; 215 | int len = 50; 216 | int testTime = 100000; 217 | System.out.println("功能测试开始"); 218 | for (int i = 0; i < testTime; i++) { 219 | int s1Len = (int) (Math.random() * len); 220 | int s2Len = (int) (Math.random() * len); 221 | String s1 = randomNumberString(s1Len, range); 222 | String s2 = randomNumberString(s2Len, range); 223 | String ans1 = right(s1, s2); 224 | String ans2 = max(s1, s2); 225 | if (!ans1.equals(ans2)) { 226 | System.out.println("Oops!"); 227 | System.out.println(s1); 228 | System.out.println(s2); 229 | System.out.println(ans1); 230 | System.out.println(ans2); 231 | break; 232 | } 233 | } 234 | System.out.println("功能测试结束"); 235 | System.out.println("=========="); 236 | System.out.println("性能测试开始"); 237 | 238 | int s1Len = 1000000; 239 | int s2Len = 50; 240 | String s1 = randomNumberString(s1Len, range); 241 | String s2 = randomNumberString(s2Len, range); 242 | long start = System.currentTimeMillis(); 243 | max(s1, s2); 244 | long end = System.currentTimeMillis(); 245 | System.out.println("运行时间 : " + (end - start) + " ms"); 246 | System.out.println("性能测试结束"); 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /src/class08/DC3.java: -------------------------------------------------------------------------------- 1 | package class08; 2 | 3 | public class DC3 { 4 | 5 | public int[] sa; 6 | 7 | public int[] rank; 8 | 9 | public DC3(int[] nums, int max) { 10 | sa = sa(nums, max); 11 | rank = rank(); 12 | } 13 | 14 | private int[] sa(int[] nums, int max) { 15 | int n = nums.length; 16 | int[] arr = new int[n + 3]; 17 | for (int i = 0; i < n; i++) { 18 | arr[i] = nums[i]; 19 | } 20 | return skew(arr, n, max); 21 | } 22 | 23 | private int[] skew(int[] nums, int n, int K) { 24 | int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2; 25 | int[] s12 = new int[n02 + 3], sa12 = new int[n02 + 3]; 26 | for (int i = 0, j = 0; i < n + (n0 - n1); ++i) { 27 | if (0 != i % 3) { 28 | s12[j++] = i; 29 | } 30 | } 31 | radixPass(nums, s12, sa12, 2, n02, K); 32 | radixPass(nums, sa12, s12, 1, n02, K); 33 | radixPass(nums, s12, sa12, 0, n02, K); 34 | int name = 0, c0 = -1, c1 = -1, c2 = -1; 35 | for (int i = 0; i < n02; ++i) { 36 | if (c0 != nums[sa12[i]] || c1 != nums[sa12[i] + 1] || c2 != nums[sa12[i] + 2]) { 37 | name++; 38 | c0 = nums[sa12[i]]; 39 | c1 = nums[sa12[i] + 1]; 40 | c2 = nums[sa12[i] + 2]; 41 | } 42 | if (1 == sa12[i] % 3) { 43 | s12[sa12[i] / 3] = name; 44 | } else { 45 | s12[sa12[i] / 3 + n0] = name; 46 | } 47 | } 48 | if (name < n02) { 49 | sa12 = skew(s12, n02, name); 50 | for (int i = 0; i < n02; i++) { 51 | s12[sa12[i]] = i + 1; 52 | } 53 | } else { 54 | for (int i = 0; i < n02; i++) { 55 | sa12[s12[i] - 1] = i; 56 | } 57 | } 58 | int[] s0 = new int[n0], sa0 = new int[n0]; 59 | for (int i = 0, j = 0; i < n02; i++) { 60 | if (sa12[i] < n0) { 61 | s0[j++] = 3 * sa12[i]; 62 | } 63 | } 64 | radixPass(nums, s0, sa0, 0, n0, K); 65 | int[] sa = new int[n]; 66 | for (int p = 0, t = n0 - n1, k = 0; k < n; k++) { 67 | int i = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 68 | int j = sa0[p]; 69 | if (sa12[t] < n0 ? leq(nums[i], s12[sa12[t] + n0], nums[j], s12[j / 3]) 70 | : leq(nums[i], nums[i + 1], s12[sa12[t] - n0 + 1], nums[j], nums[j + 1], s12[j / 3 + n0])) { 71 | sa[k] = i; 72 | t++; 73 | if (t == n02) { 74 | for (k++; p < n0; p++, k++) { 75 | sa[k] = sa0[p]; 76 | } 77 | } 78 | } else { 79 | sa[k] = j; 80 | p++; 81 | if (p == n0) { 82 | for (k++; t < n02; t++, k++) { 83 | sa[k] = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2; 84 | } 85 | } 86 | } 87 | } 88 | return sa; 89 | } 90 | 91 | private void radixPass(int[] nums, int[] input, int[] output, int offset, int n, int k) { 92 | int[] cnt = new int[k + 1]; 93 | for (int i = 0; i < n; ++i) { 94 | cnt[nums[input[i] + offset]]++; 95 | } 96 | for (int i = 0, sum = 0; i < cnt.length; ++i) { 97 | int t = cnt[i]; 98 | cnt[i] = sum; 99 | sum += t; 100 | } 101 | for (int i = 0; i < n; ++i) { 102 | output[cnt[nums[input[i] + offset]]++] = input[i]; 103 | } 104 | } 105 | 106 | private boolean leq(int a1, int a2, int b1, int b2) { 107 | return a1 < b1 || (a1 == b1 && a2 <= b2); 108 | } 109 | 110 | private boolean leq(int a1, int a2, int a3, int b1, int b2, int b3) { 111 | return a1 < b1 || (a1 == b1 && leq(a2, a3, b2, b3)); 112 | } 113 | 114 | private int[] rank() { 115 | int n = sa.length; 116 | int[] ans = new int[n]; 117 | for (int i = 0; i < n; i++) { 118 | ans[sa[i]] = i + 1; 119 | } 120 | return ans; 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /src/class08/DC3_Algorithm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algorithmzuo/trainingcamp005/b599b4c33a1653c1e1b43e8d04d1d77162e206c7/src/class08/DC3_Algorithm.pdf --------------------------------------------------------------------------------