From 6d8f87bb87262a522dfc2c54c0f4bc3433df053b Mon Sep 17 00:00:00 2001 From: alxkm Date: Mon, 7 Jul 2025 23:55:00 +0200 Subject: [PATCH 1/3] refactor: optimize ValidParentheses methods and add parameterized tests --- .../strings/ValidParentheses.java | 88 +++++++++---------- .../strings/ValidParenthesesTest.java | 29 +++--- 2 files changed, 55 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java index 629fee495d84..c78d0d4e9730 100644 --- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java +++ b/src/main/java/com/thealgorithms/strings/ValidParentheses.java @@ -1,59 +1,57 @@ package com.thealgorithms.strings; -// Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine -// if the input string is valid. An input string is valid if: Open brackets must be closed by -// the same type of brackets. Open brackets must be closed in the correct order. Every close -// bracket has a corresponding open bracket of the same type. +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Map; + +/** + * Validates if a given string has valid matching parentheses. + *

+ * A string is considered valid if: + *

+ * + * Allowed characters: '(', ')', '{', '}', '[', ']' + */ public final class ValidParentheses { private ValidParentheses() { } + + private static final Map BRACKET_PAIRS = Map.of( + ')', '(', + '}', '{', + ']', '[' + ); + + /** + * Checks if the input string has valid parentheses. + * + * @param s the string containing only bracket characters + * @return true if valid, false otherwise + * @throws IllegalArgumentException if the string contains invalid characters or is null + */ public static boolean isValid(String s) { - char[] stack = new char[s.length()]; - int head = 0; + if (s == null) { + throw new IllegalArgumentException("Input string cannot be null"); + } + + Deque stack = new ArrayDeque<>(); + for (char c : s.toCharArray()) { - switch (c) { - case '{': - case '[': - case '(': - stack[head++] = c; - break; - case '}': - if (head == 0 || stack[--head] != '{') { - return false; - } - break; - case ')': - if (head == 0 || stack[--head] != '(') { - return false; - } - break; - case ']': - if (head == 0 || stack[--head] != '[') { + if (BRACKET_PAIRS.containsValue(c)) { + stack.push(c); // opening bracket + } else if (BRACKET_PAIRS.containsKey(c)) { + if (stack.isEmpty() || stack.pop() != BRACKET_PAIRS.get(c)) { return false; } - break; - default: - throw new IllegalArgumentException("Unexpected character: " + c); - } - } - return head == 0; - } - public static boolean isValidParentheses(String s) { - int i = -1; - char[] stack = new char[s.length()]; - String openBrackets = "({["; - String closeBrackets = ")}]"; - for (char ch : s.toCharArray()) { - if (openBrackets.indexOf(ch) != -1) { - stack[++i] = ch; } else { - if (i >= 0 && openBrackets.indexOf(stack[i]) == closeBrackets.indexOf(ch)) { - i--; - } else { - return false; - } + throw new IllegalArgumentException("Unexpected character: " + c); } } - return i == -1; + + return stack.isEmpty(); } } diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java index 2b6884c91c8f..a95f23fad751 100644 --- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java +++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java @@ -1,27 +1,22 @@ package com.thealgorithms.strings; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -public class ValidParenthesesTest { +import java.util.stream.Stream; - @Test - void testOne() { - assertTrue(ValidParentheses.isValid("()")); - assertTrue(ValidParentheses.isValidParentheses("()")); - } +public class ValidParenthesesTest { - @Test - void testTwo() { - assertTrue(ValidParentheses.isValid("()[]{}")); - assertTrue(ValidParentheses.isValidParentheses("()[]{}")); + @ParameterizedTest(name = "Input: \"{0}\" → Expected: {1}") + @MethodSource("parenthesesProvider") + void testIsValid(String input, boolean expected) { + assertEquals(expected, ValidParentheses.isValid(input)); } - @Test - void testThree() { - assertFalse(ValidParentheses.isValid("(]")); - assertFalse(ValidParentheses.isValidParentheses("(]")); + static Stream parenthesesProvider() { + return Stream.of(Arguments.of("()", true), Arguments.of("()[]{}", true), Arguments.of("(]", false), Arguments.of("{[]}", true), Arguments.of("([{}])", true), Arguments.of("([)]", false), Arguments.of("", true), Arguments.of("(", false), Arguments.of(")", false)); } } From cc6e0e1f34eed230bad3ab46c5943885dcdaabd6 Mon Sep 17 00:00:00 2001 From: alxkm Date: Mon, 7 Jul 2025 23:57:08 +0200 Subject: [PATCH 2/3] refactor: fix clang formatting issues --- .../java/com/thealgorithms/strings/ValidParentheses.java | 6 +----- .../com/thealgorithms/strings/ValidParenthesesTest.java | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java index c78d0d4e9730..25a72f379dec 100644 --- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java +++ b/src/main/java/com/thealgorithms/strings/ValidParentheses.java @@ -20,11 +20,7 @@ public final class ValidParentheses { private ValidParentheses() { } - private static final Map BRACKET_PAIRS = Map.of( - ')', '(', - '}', '{', - ']', '[' - ); + private static final Map BRACKET_PAIRS = Map.of(')', '(', '}', '{', ']', '['); /** * Checks if the input string has valid parentheses. diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java index a95f23fad751..cc2aae30053a 100644 --- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java +++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java @@ -2,12 +2,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - public class ValidParenthesesTest { @ParameterizedTest(name = "Input: \"{0}\" → Expected: {1}") From 2588cdcbce609574672f58c742db719bbfcbed36 Mon Sep 17 00:00:00 2001 From: alxkm Date: Tue, 8 Jul 2025 00:18:45 +0200 Subject: [PATCH 3/3] refactor: fix spotbugs issue --- .../thealgorithms/strings/ValidParenthesesTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java index cc2aae30053a..23d41b159fe2 100644 --- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java +++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java @@ -2,20 +2,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.CsvSource; public class ValidParenthesesTest { @ParameterizedTest(name = "Input: \"{0}\" → Expected: {1}") - @MethodSource("parenthesesProvider") + @CsvSource({"'()', true", "'()[]{}', true", "'(]', false", "'{[]}', true", "'([{}])', true", "'([)]', false", "'', true", "'(', false", "')', false"}) void testIsValid(String input, boolean expected) { assertEquals(expected, ValidParentheses.isValid(input)); } - - static Stream parenthesesProvider() { - return Stream.of(Arguments.of("()", true), Arguments.of("()[]{}", true), Arguments.of("(]", false), Arguments.of("{[]}", true), Arguments.of("([{}])", true), Arguments.of("([)]", false), Arguments.of("", true), Arguments.of("(", false), Arguments.of(")", false)); - } }