From adcc11b17d6c6d81bf81e172a473f4782b19dbe2 Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Wed, 5 Nov 2025 14:10:45 +0100 Subject: [PATCH 1/7] string: Add bomb exercice --- src/main/java/strings/Bombe.java | 159 ++++++++++++++++ src/test/java/strings/BombeTest.java | 259 +++++++++++++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 src/main/java/strings/Bombe.java create mode 100644 src/test/java/strings/BombeTest.java diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java new file mode 100644 index 0000000..f6150b9 --- /dev/null +++ b/src/main/java/strings/Bombe.java @@ -0,0 +1,159 @@ +package strings; + +import java.util.HashMap; +import java.util.Map; + +/** + * Author: Alexis Englebert + * + * Context: Oh no, there’s a bomb in your kitchen! + * You must defuse it before it explodes. To do so, you need to solve a puzzle. + * You have a grid with n rows and m columns. Each cell contains a color. + * Each row has two arrows, one pointing left and the other pointing right. + * When you press the right arrow, all the colors in the row are shifted by one to the right. + * When you press the left arrow, they are shifted by one to the left. + * + * The rows wrap around (are cyclic), so if a color moves off one side of a row, + * it re-enters from the other side. + * + * Your goal is to find two rows that are identical after entering a sequence of arrows. + * If you find two identical rows, you have defused the bomb. + * If you can’t find two identical rows, the bomb explodes! + * + * You must return the indices of the two identical rows in increasing order. + * If there are multiple pairs, return the one with the smallest first index. + * If two pairs have the same first index, + * return the one with the smallest second index. + * If you don’t find two identical rows, return [-1, -1]. + * + * Time complexity O(n · m) + * + * Exemple: + * n = 4, m = 5 + * RGRBB + * RBBGB + * BBBRB + * GRBBR + * + * The answer is the pair (1, 4) because after one shift to the right on the 4th row, + * they are equals (GRBBR -> RGRBB) + */ + +public class Bombe { + // BEGIN STRIP + static final long MOD = (1L << 60); + static final long A = 91138; + + static long safeMod(long a) { + return (a % Bombe.MOD + Bombe.MOD) % Bombe.MOD; + } + + // END STRIP + + /** + * @param n The number of columns in the grid + * @param m The number of rows in the grid + * @param grid The input grid + * @return A list of 2 elements representing the indices of the two rows, or [-1, -1] + * if no rows are the same. + */ + public static int[] solve(int n, int m, char [][] grid) { + //TODO + // STUDENT return -1; + // BEGIN STRIP + long[] baseExponent = new long[m]; + baseExponent[0] = 1; + + for (int i = 1; i < m; i++) { + baseExponent[i] = safeMod(baseExponent[i - 1] * A); + } + + long[] hahes = new long[n]; + + Map> cnt = new HashMap<>(); + + for (int i = 0; i < n; i++) { + long hash = 0; + + for (int j = 0; j < m; j++) { + hash += grid[i][j] * baseExponent[j]; + hash = safeMod(hash); + } + hahes[i] = hash; + if(cnt.containsKey(hash)) { + cnt.get(hash).first = Math.min(i+1, cnt.get(hash).first); + }else { + cnt.put(hahes[i], new Pair<>(0, i + 1)); + } + } + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + hahes[i] -= (grid[i][m - j - 1] * baseExponent[m - 1]) % MOD; + hahes[i] %= MOD; + hahes[i] *= A; + hahes[i] %= MOD; + hahes[i] += grid[i][m - j - 1]; + hahes[i] %= MOD; + + cnt.computeIfAbsent(hahes[i], k -> new Pair<>(0, 0)); + Pair pair = cnt.get(hahes[i]); + + if (pair.first == 0 && (i+1) != pair.second) { + pair.first = i + 1; + } else if (pair.second == 0 && (i+1) != pair.first) { + pair.second = i + 1; + } else if((i+1) < pair.first && (i+1) != pair.second) { + pair.first = i+1; + } else if((i+1) < pair.second && (i+1) != pair.first) { + pair.second = i+1; + } + + int temp = pair.first; + pair.first = Math.min(pair.first, pair.second); + pair.second = Math.max(temp, pair.second); + cnt.replace(hahes[i], pair); + } + } + + Pair mini = new Pair<>(10_000_000_00, 10_000_000_00); + + for (Map.Entry> entry : cnt.entrySet()) { + Pair value = entry.getValue(); + + if (value.first == 0 || value.second == 0) continue; + if (value.compareTo(mini) < 0) mini = value; + } + + if (mini.first == 10_000_000_00 && mini.second == 10_000_000_00) { + return new int[]{-1, -1}; + } else { + System.out.println(mini.first + " " + mini.second); + return new int[]{mini.first, mini.second}; + } + // END STRIP + } + + // BEGIN STRIP + static class Pair, U extends Comparable> implements Comparable> { + T first; + U second; + + Pair(T first, U second) { + this.first = first; + this.second = second; + } + + @Override + public int compareTo(Pair other) { + int cmp = this.first.compareTo(other.first); + if (cmp != 0) { + return cmp; + } + return this.second.compareTo(other.second); + } + } + // END STRIP +} + + diff --git a/src/test/java/strings/BombeTest.java b/src/test/java/strings/BombeTest.java new file mode 100644 index 0000000..f289356 --- /dev/null +++ b/src/test/java/strings/BombeTest.java @@ -0,0 +1,259 @@ +package strings; + +import org.javagrader.Grade; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.security.SecureRandom; + +import strings.Bombe.*; + +public class BombeTest { + + + public static String randRow(int n, String letters) { + SecureRandom rnd = new SecureRandom(); + StringBuilder sb = new StringBuilder(n); + for (int i = 0; i < n; i++) { + sb.append(letters.charAt(rnd.nextInt(letters.length()))); + } + return sb.toString(); + } + + public static String rotateString(String s, int k) { + if (s == null || s.isEmpty()) return s; + List list = new ArrayList<>(s.length()); + for (char c : s.toCharArray()) list.add(c); + Collections.rotate(list, -k); + StringBuilder sb = new StringBuilder(list.size()); + for (char c : list) sb.append(c); + return sb.toString(); + } + + @Test + @Grade(value = 1) + public void sampleTest1() { + char[][] bomb = new char[][]{ + "RGRBB".toCharArray(), + "RBBGB".toCharArray(), + "BBBRB".toCharArray(), + "GRBBR".toCharArray() + }; + + assertArrayEquals(new int[]{1, 4}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void sampleTest2() { + char[][] bomb = new char[][]{ + "RRRRRR".toCharArray(), + "GGGGGG".toCharArray(), + "BBBBBB".toCharArray(), + "RGRGRG".toCharArray() + }; + + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void subPatternExists() { + char[][] bomb = new char[][]{ + "RGRGRGRGRGRGRGRG".toCharArray(), + "GRGRGRGRGRGRGRGR".toCharArray(), + }; + assertArrayEquals(new int[]{1, 2}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void almostRotation() { + char[][] bomb = new char[][]{ + "RGBRGBRGB".toCharArray(), + "RGBRGBRGG".toCharArray(), + }; + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void minOrder() { + char[][] bomb = new char[][]{ + "aaa".toCharArray(), + "bbb".toCharArray(), + "aaa".toCharArray(), + "bbb".toCharArray(), + "ccc".toCharArray(), + "ccc".toCharArray() + }; + assertArrayEquals(new int[]{1, 3}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void uniqueCharPerRow() { + char[][] bomb = new char[][]{ + "rrrrrrrrrrrr".toCharArray(), + "gggggggggggg".toCharArray(), + "cccccccccccc".toCharArray(), + "aaaaaaaaaaaa".toCharArray(), + "bbbbbbbbbbbb".toCharArray() + }; + + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestBoom1() { // n*m <= 5*10^5 (on donne une bonne marge) + char[][] bomb = new char[100][5000]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < 100; i++) { + bomb[i] = randRow(5000, letters).toCharArray(); + } + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestBoom2() { // n*m <= 5*10^5 (on donne une bonne marge) + char[][] bomb = new char[5000][100]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < 5000; i++) { + bomb[i] = randRow(100, letters).toCharArray(); + } + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestBoom3() { + char[][] bomb = new char[50][10000]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < 50; i++) { + bomb[i] = randRow(10000, letters).toCharArray(); + } + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void avoidSortOptimization() { + char[][] bomb = new char[50][10000]; + final String letters = "ab"; + + for(int i = 0; i < 50; i++) { + bomb[i] = randRow(10000, letters).toCharArray(); + } + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void avoidSortOptimization2() { + char[][] bomb = new char[50][10000]; + final String letters = "abcd"; + + for(int i = 0; i < 50; i++) { + bomb[i] = randRow(10000, letters).toCharArray(); + } + assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestSolution1() { + char[][] bomb = new char[50][10000]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < bomb.length; i++) { + bomb[i] = (randRow(bomb[0].length, letters).toCharArray()); + } + SecureRandom rnd = new SecureRandom(); + int first = rnd.nextInt(bomb.length); + int second = first; + while(second == first) { + second = rnd.nextInt(bomb.length); + } + + bomb[first] = bomb[second]; + String rotated = rotateString(new String(bomb[first]), rnd.nextInt(2*bomb[0].length)); + bomb[first] = rotated.toCharArray(); + assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestSolution2() { + char[][] bomb = new char[10000][50]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < bomb.length; i++) { + bomb[i] = (randRow(bomb[0].length, letters).toCharArray()); + } + SecureRandom rnd = new SecureRandom(); + int first = rnd.nextInt(bomb.length); + int second = first; + while(second == first) { + second = rnd.nextInt(bomb.length); + } + + bomb[first] = bomb[second]; + String rotated = rotateString(new String(bomb[first]), rnd.nextInt(2*bomb[0].length)); + bomb[first] = rotated.toCharArray(); + assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void smallRandom() { + char[][] bomb = new char[10][10]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < bomb.length; i++) { + bomb[i] = (randRow(bomb[0].length, letters).toCharArray()); + } + + SecureRandom rnd = new SecureRandom(); + int first = rnd.nextInt(bomb.length); + int second = first; + while(second == first) { + second = rnd.nextInt(bomb.length); + } + + bomb[first] = bomb[second]; + String rotated = rotateString(new String(bomb[first]), rnd.nextInt(2*bomb[0].length)); + bomb[first] = rotated.toCharArray(); + assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) + public void complexityTestSolution3() { + char[][] bomb = new char[707][707]; + final String letters = "abcdefghijklmnopqrstuvwxyz"; + + for(int i = 0; i < bomb.length; i++) { + bomb[i] = (randRow(bomb[0].length, letters).toCharArray()); + } + SecureRandom rnd = new SecureRandom(); + int first = rnd.nextInt(bomb.length); + int second = first; + while(second == first) { + second = rnd.nextInt(bomb.length); + } + + bomb[first] = bomb[second]; + String rotated = rotateString(new String(bomb[first]), rnd.nextInt(2*bomb[0].length)); + bomb[first] = rotated.toCharArray(); + assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + +} From 5e9ea4b29b4e484e56227e5d1f114e188166ec2e Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Wed, 5 Nov 2025 14:13:17 +0100 Subject: [PATCH 2/7] string: fix remaining print --- src/main/java/strings/Bombe.java | 1 - src/test/java/graphs/ElectricityTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java index f6150b9..e23ece5 100644 --- a/src/main/java/strings/Bombe.java +++ b/src/main/java/strings/Bombe.java @@ -128,7 +128,6 @@ public static int[] solve(int n, int m, char [][] grid) { if (mini.first == 10_000_000_00 && mini.second == 10_000_000_00) { return new int[]{-1, -1}; } else { - System.out.println(mini.first + " " + mini.second); return new int[]{mini.first, mini.second}; } // END STRIP diff --git a/src/test/java/graphs/ElectricityTest.java b/src/test/java/graphs/ElectricityTest.java index 54ae371..8d79361 100644 --- a/src/test/java/graphs/ElectricityTest.java +++ b/src/test/java/graphs/ElectricityTest.java @@ -78,5 +78,4 @@ public void complexityTest1() { assertEquals(answer, Electricity.minimumSpanningCost(n,edges)); } - } From fc63c8b276be006cd89d1011935fac0324fde357 Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Fri, 7 Nov 2025 14:54:12 +0100 Subject: [PATCH 3/7] string: Fixed typo & redundent code --- src/main/java/strings/Bombe.java | 38 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java index e23ece5..c2f90e9 100644 --- a/src/main/java/strings/Bombe.java +++ b/src/main/java/strings/Bombe.java @@ -68,7 +68,7 @@ public static int[] solve(int n, int m, char [][] grid) { baseExponent[i] = safeMod(baseExponent[i - 1] * A); } - long[] hahes = new long[n]; + long[] hashes = new long[n]; Map> cnt = new HashMap<>(); @@ -79,25 +79,27 @@ public static int[] solve(int n, int m, char [][] grid) { hash += grid[i][j] * baseExponent[j]; hash = safeMod(hash); } - hahes[i] = hash; + hashes[i] = hash; if(cnt.containsKey(hash)) { cnt.get(hash).first = Math.min(i+1, cnt.get(hash).first); }else { - cnt.put(hahes[i], new Pair<>(0, i + 1)); + cnt.put(hashes[i], new Pair<>(0, i + 1)); } } + Pair mini = new Pair<>(10_000_000_00, 10_000_000_00); + for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { - hahes[i] -= (grid[i][m - j - 1] * baseExponent[m - 1]) % MOD; - hahes[i] %= MOD; - hahes[i] *= A; - hahes[i] %= MOD; - hahes[i] += grid[i][m - j - 1]; - hahes[i] %= MOD; + hashes[i] -= (grid[i][m - j - 1] * baseExponent[m - 1]) % MOD; + hashes[i] %= MOD; + hashes[i] *= A; + hashes[i] %= MOD; + hashes[i] += grid[i][m - j - 1]; + hashes[i] %= MOD; - cnt.computeIfAbsent(hahes[i], k -> new Pair<>(0, 0)); - Pair pair = cnt.get(hahes[i]); + cnt.computeIfAbsent(hashes[i], k -> new Pair<>(0, 0)); + Pair pair = cnt.get(hashes[i]); if (pair.first == 0 && (i+1) != pair.second) { pair.first = i + 1; @@ -112,17 +114,11 @@ public static int[] solve(int n, int m, char [][] grid) { int temp = pair.first; pair.first = Math.min(pair.first, pair.second); pair.second = Math.max(temp, pair.second); - cnt.replace(hahes[i], pair); - } - } + cnt.replace(hashes[i], pair); - Pair mini = new Pair<>(10_000_000_00, 10_000_000_00); - - for (Map.Entry> entry : cnt.entrySet()) { - Pair value = entry.getValue(); - - if (value.first == 0 || value.second == 0) continue; - if (value.compareTo(mini) < 0) mini = value; + if (pair.first == 0 || pair.second == 0) continue; + if (pair.compareTo(mini) < 0) mini = pair; + } } if (mini.first == 10_000_000_00 && mini.second == 10_000_000_00) { From d1c2b2ac18713faaa4c31827ac57d1944e133315 Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Thu, 4 Dec 2025 16:24:08 +0100 Subject: [PATCH 4/7] Bombe: refactor code + given part of solution to the student --- src/main/java/strings/Bombe.java | 122 ++++++++++----------------- src/test/java/strings/BombeTest.java | 39 --------- 2 files changed, 45 insertions(+), 116 deletions(-) diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java index c2f90e9..638b9e5 100644 --- a/src/main/java/strings/Bombe.java +++ b/src/main/java/strings/Bombe.java @@ -21,9 +21,6 @@ * If you can’t find two identical rows, the bomb explodes! * * You must return the indices of the two identical rows in increasing order. - * If there are multiple pairs, return the one with the smallest first index. - * If two pairs have the same first index, - * return the one with the smallest second index. * If you don’t find two identical rows, return [-1, -1]. * * Time complexity O(n · m) @@ -40,16 +37,31 @@ */ public class Bombe { - // BEGIN STRIP static final long MOD = (1L << 60); static final long A = 91138; + static long[] hashes; + static long[] baseExponent; + //BEGIN STRIP + static int _n, _m; + //END STRIP - static long safeMod(long a) { - return (a % Bombe.MOD + Bombe.MOD) % Bombe.MOD; + /** + * Rotate A given hashed string to the right. + * @param hash The input hashed string + * @param toRemove The character to rotate + * @return The hash of the string rotated to the right. + */ + public static long rotateHash(long hash, char toRemove) { + //BEGIN STRIP + hash -= ( toRemove * baseExponent[_m - 1]) % MOD; + hash %= MOD; + hash *= A; + hash %= MOD; + hash += toRemove; + hash %= MOD; + //END STRIP + return hash; } - - // END STRIP - /** * @param n The number of columns in the grid * @param m The number of rows in the grid @@ -59,96 +71,52 @@ static long safeMod(long a) { */ public static int[] solve(int n, int m, char [][] grid) { //TODO - // STUDENT return -1; - // BEGIN STRIP - long[] baseExponent = new long[m]; + baseExponent = new long[m]; + hashes = new long[n]; baseExponent[0] = 1; + //BEGIN STRIP + _m = m; + _n = n; + HashMap match = new HashMap<>(); + //END STRIP for (int i = 1; i < m; i++) { - baseExponent[i] = safeMod(baseExponent[i - 1] * A); + baseExponent[i] = (baseExponent[i - 1] * A) % MOD; + baseExponent[i] %= MOD; } - - long[] hashes = new long[n]; - - Map> cnt = new HashMap<>(); - for (int i = 0; i < n; i++) { long hash = 0; for (int j = 0; j < m; j++) { hash += grid[i][j] * baseExponent[j]; - hash = safeMod(hash); + hash %= MOD; } hashes[i] = hash; - if(cnt.containsKey(hash)) { - cnt.get(hash).first = Math.min(i+1, cnt.get(hash).first); - }else { - cnt.put(hashes[i], new Pair<>(0, i + 1)); - } } - - Pair mini = new Pair<>(10_000_000_00, 10_000_000_00); + // STUDENT return -1; + // BEGIN STRIP + for(int i = 0; i < hashes.length; i++) { + match.put(hashes[i], i); + } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { - hashes[i] -= (grid[i][m - j - 1] * baseExponent[m - 1]) % MOD; - hashes[i] %= MOD; - hashes[i] *= A; - hashes[i] %= MOD; - hashes[i] += grid[i][m - j - 1]; - hashes[i] %= MOD; - - cnt.computeIfAbsent(hashes[i], k -> new Pair<>(0, 0)); - Pair pair = cnt.get(hashes[i]); - - if (pair.first == 0 && (i+1) != pair.second) { - pair.first = i + 1; - } else if (pair.second == 0 && (i+1) != pair.first) { - pair.second = i + 1; - } else if((i+1) < pair.first && (i+1) != pair.second) { - pair.first = i+1; - } else if((i+1) < pair.second && (i+1) != pair.first) { - pair.second = i+1; + hashes[i] = rotateHash(hashes[i], grid[i][m - j - 1]); + if (!match.containsKey(hashes[i])) { + match.put(hashes[i], i); } - int temp = pair.first; - pair.first = Math.min(pair.first, pair.second); - pair.second = Math.max(temp, pair.second); - cnt.replace(hashes[i], pair); - - if (pair.first == 0 || pair.second == 0) continue; - if (pair.compareTo(mini) < 0) mini = pair; + if(match.get(hashes[i]) != i) { + int a = match.get(hashes[i])+1; + int b = i+1; + return new int[]{Math.min(a, b), Math.max(a, b) }; + } } } - - if (mini.first == 10_000_000_00 && mini.second == 10_000_000_00) { - return new int[]{-1, -1}; - } else { - return new int[]{mini.first, mini.second}; - } // END STRIP + return new int[]{-1, -1}; } - // BEGIN STRIP - static class Pair, U extends Comparable> implements Comparable> { - T first; - U second; - - Pair(T first, U second) { - this.first = first; - this.second = second; - } - - @Override - public int compareTo(Pair other) { - int cmp = this.first.compareTo(other.first); - if (cmp != 0) { - return cmp; - } - return this.second.compareTo(other.second); - } - } - // END STRIP } diff --git a/src/test/java/strings/BombeTest.java b/src/test/java/strings/BombeTest.java index f289356..67d597e 100644 --- a/src/test/java/strings/BombeTest.java +++ b/src/test/java/strings/BombeTest.java @@ -5,8 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; - - import java.util.*; import java.util.concurrent.TimeUnit; import java.security.SecureRandom; @@ -81,20 +79,6 @@ public void almostRotation() { assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); } - @Test - @Grade(value = 1) - public void minOrder() { - char[][] bomb = new char[][]{ - "aaa".toCharArray(), - "bbb".toCharArray(), - "aaa".toCharArray(), - "bbb".toCharArray(), - "ccc".toCharArray(), - "ccc".toCharArray() - }; - assertArrayEquals(new int[]{1, 3}, Bombe.solve(bomb.length, bomb[0].length, bomb)); - } - @Test @Grade(value = 1) public void uniqueCharPerRow() { @@ -211,29 +195,6 @@ public void complexityTestSolution2() { assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); } - @Test - @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) - public void smallRandom() { - char[][] bomb = new char[10][10]; - final String letters = "abcdefghijklmnopqrstuvwxyz"; - - for(int i = 0; i < bomb.length; i++) { - bomb[i] = (randRow(bomb[0].length, letters).toCharArray()); - } - - SecureRandom rnd = new SecureRandom(); - int first = rnd.nextInt(bomb.length); - int second = first; - while(second == first) { - second = rnd.nextInt(bomb.length); - } - - bomb[first] = bomb[second]; - String rotated = rotateString(new String(bomb[first]), rnd.nextInt(2*bomb[0].length)); - bomb[first] = rotated.toCharArray(); - assertArrayEquals(new int[]{Math.min(first+1, second+1), Math.max(first+1, second+1)}, Bombe.solve(bomb.length, bomb[0].length, bomb)); - } - @Test @Grade(value = 1, cpuTimeout = 1000, unit = TimeUnit.MILLISECONDS) public void complexityTestSolution3() { From 0f1066642ba5a491c073dc463ad61f6966a791fb Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Thu, 4 Dec 2025 16:33:31 +0100 Subject: [PATCH 5/7] Bombe: added comment for base exponent array --- src/main/java/strings/Bombe.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java index 638b9e5..ab31a22 100644 --- a/src/main/java/strings/Bombe.java +++ b/src/main/java/strings/Bombe.java @@ -40,6 +40,7 @@ public class Bombe { static final long MOD = (1L << 60); static final long A = 91138; static long[] hashes; + // store the base at the ith power to avoid recomputing it every time. static long[] baseExponent; //BEGIN STRIP static int _n, _m; From 8e673f4163e9e48021387ade844c82e479f65b6f Mon Sep 17 00:00:00 2001 From: AlexisEnglebert Date: Thu, 11 Dec 2025 16:28:32 +0100 Subject: [PATCH 6/7] bombe: added min pair & tests --- src/main/java/graphs/Girth.java | 4 ++++ src/main/java/strings/Bombe.java | 15 ++++++++++++--- src/test/java/strings/BombeTest.java | 28 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/main/java/graphs/Girth.java diff --git a/src/main/java/graphs/Girth.java b/src/main/java/graphs/Girth.java new file mode 100644 index 0000000..927092e --- /dev/null +++ b/src/main/java/graphs/Girth.java @@ -0,0 +1,4 @@ +package graphs; + +public class Girth { +} diff --git a/src/main/java/strings/Bombe.java b/src/main/java/strings/Bombe.java index ab31a22..a5251c5 100644 --- a/src/main/java/strings/Bombe.java +++ b/src/main/java/strings/Bombe.java @@ -1,7 +1,5 @@ package strings; - import java.util.HashMap; -import java.util.Map; /** * Author: Alexis Englebert @@ -100,6 +98,8 @@ public static int[] solve(int n, int m, char [][] grid) { match.put(hashes[i], i); } + int left = Integer.MAX_VALUE; + int right = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { hashes[i] = rotateHash(hashes[i], grid[i][m - j - 1]); @@ -110,12 +110,21 @@ public static int[] solve(int n, int m, char [][] grid) { if(match.get(hashes[i]) != i) { int a = match.get(hashes[i])+1; int b = i+1; - return new int[]{Math.min(a, b), Math.max(a, b) }; + int mini = Math.min(a, b); + int maxi = Math.max(a, b); + if(mini <= left) { + left = mini; + right = Math.min(right, maxi); + } } } } + if(left != Integer.MAX_VALUE && right != Integer.MAX_VALUE){ + return new int[]{left, right}; + } // END STRIP return new int[]{-1, -1}; + } } diff --git a/src/test/java/strings/BombeTest.java b/src/test/java/strings/BombeTest.java index 67d597e..6e53bec 100644 --- a/src/test/java/strings/BombeTest.java +++ b/src/test/java/strings/BombeTest.java @@ -79,6 +79,34 @@ public void almostRotation() { assertArrayEquals(new int[]{-1, -1}, Bombe.solve(bomb.length, bomb[0].length, bomb)); } + @Test + @Grade(value = 1) + public void minOrder() { + char[][] bomb = new char[][]{ + "aaa".toCharArray(), + "bbb".toCharArray(), + "aaa".toCharArray(), + "bbb".toCharArray(), + "ccc".toCharArray(), + "ccc".toCharArray() + }; + assertArrayEquals(new int[]{1, 3}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + + @Test + @Grade(value = 1) + public void minOrder2() { + char[][] bomb = new char[][]{ + "aaa".toCharArray(), + "aab".toCharArray(), + "aac".toCharArray(), + "aab".toCharArray(), + "aaa".toCharArray(), + "aab".toCharArray() + }; + assertArrayEquals(new int[]{1, 5}, Bombe.solve(bomb.length, bomb[0].length, bomb)); + } + @Test @Grade(value = 1) public void uniqueCharPerRow() { From 72c5c1dc2c413e68e5642349aa4381e1fb76916d Mon Sep 17 00:00:00 2001 From: Alexis Englebert <39882142+AlexisEnglebert@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:02:02 +0100 Subject: [PATCH 7/7] Delete src/main/java/graphs/Girth.java --- src/main/java/graphs/Girth.java | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/main/java/graphs/Girth.java diff --git a/src/main/java/graphs/Girth.java b/src/main/java/graphs/Girth.java deleted file mode 100644 index 927092e..0000000 --- a/src/main/java/graphs/Girth.java +++ /dev/null @@ -1,4 +0,0 @@ -package graphs; - -public class Girth { -}