From 046f5a4728267f835299d6a65a2e88c2294975f6 Mon Sep 17 00:00:00 2001 From: Alex Klymenko Date: Thu, 15 Aug 2024 10:43:47 +0200 Subject: [PATCH] refactor: `atoi` (#5324) --- .../com/thealgorithms/strings/MyAtoi.java | 111 ++++++++---------- .../com/thealgorithms/strings/MyAtoiTest.java | 36 +++--- 2 files changed, 68 insertions(+), 79 deletions(-) diff --git a/src/main/java/com/thealgorithms/strings/MyAtoi.java b/src/main/java/com/thealgorithms/strings/MyAtoi.java index f58ab1ac..5a7c2ce5 100644 --- a/src/main/java/com/thealgorithms/strings/MyAtoi.java +++ b/src/main/java/com/thealgorithms/strings/MyAtoi.java @@ -1,76 +1,65 @@ -// Implement the myAtoi(string s) function, which converts a string to a 32-bit signed integer -// (similar to C/C++'s atoi function). Here is my implementation - package com.thealgorithms.strings; +/** + * A utility class that provides a method to convert a string to a 32-bit signed integer (similar to C/C++'s atoi function). + */ public final class MyAtoi { private MyAtoi() { } + + /** + * Converts the given string to a 32-bit signed integer. + * The conversion discards any leading whitespace characters until the first non-whitespace character is found. + * Then, it takes an optional initial plus or minus sign followed by as many numerical digits as possible and interprets them as a numerical value. + * The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function. + * + * If the number is out of the range of a 32-bit signed integer: + * - Returns {@code Integer.MAX_VALUE} if the value exceeds {@code Integer.MAX_VALUE}. + * - Returns {@code Integer.MIN_VALUE} if the value is less than {@code Integer.MIN_VALUE}. + * + * If no valid conversion could be performed, a zero is returned. + * + * @param s the string to convert + * @return the converted integer, or 0 if the string cannot be converted to a valid integer + */ public static int myAtoi(String s) { - s = s.trim(); - char[] char1 = s.toCharArray(); - String number = ""; - boolean negative = false; - boolean zero = false; - boolean isDigit = false; - - for (char ch : char1) { - if (Character.isDigit(ch)) { - if (number.length() > 1 && !isDigit) { - number = "0"; - break; - } - isDigit = true; - if (zero) { - number = "0"; - break; - } - if (ch >= '0' && ch <= '9') { - number += ch; - } - } else if (ch == '-' && !isDigit) { - number += "0"; - negative = true; - } else if (ch == '+' && !isDigit) { - number += "0"; - } else if (ch == '.' && isDigit) { - break; - } else if (ch == '.') { - zero = true; - } else { - if (!isDigit) { - number = "0"; - } - break; - } - } - - if (!isDigit) { + if (s == null || s.isEmpty()) { return 0; } - number = number.replaceFirst("^0+(?!$)", ""); - - if (number.length() > 10 && negative) { - return -2147483648; - } else if (number.length() > 10) { - return 2147483647; - } else if (number.length() == 10 && negative) { - double db1 = Double.parseDouble(number); - if (db1 >= 2147483648d) { - return -2147483648; - } - } else if (number.length() == 10) { - double db1 = Double.parseDouble(number); - if (db1 > (2147483647)) { - return 2147483647; - } + s = s.trim(); + int length = s.length(); + if (length == 0) { + return 0; } - if (negative) { - return Integer.parseInt(number) * -1; + int index = 0; + boolean negative = false; + + // Check for the sign + if (s.charAt(index) == '-' || s.charAt(index) == '+') { + negative = s.charAt(index) == '-'; + index++; } - return Integer.parseInt(number); + int number = 0; + while (index < length) { + char ch = s.charAt(index); + if (!Character.isDigit(ch)) { + break; + } + + int digit = ch - '0'; + + // Check for overflow + if (number > (Integer.MAX_VALUE - digit) / 10) { + return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + + number = number * 10 + digit; + index++; + } + + return negative ? -number : number; } } diff --git a/src/test/java/com/thealgorithms/strings/MyAtoiTest.java b/src/test/java/com/thealgorithms/strings/MyAtoiTest.java index 45f91585..8d235491 100644 --- a/src/test/java/com/thealgorithms/strings/MyAtoiTest.java +++ b/src/test/java/com/thealgorithms/strings/MyAtoiTest.java @@ -3,41 +3,41 @@ package com.thealgorithms.strings; 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.CsvSource; public class MyAtoiTest { - @Test - void testOne() { - assertEquals(42, MyAtoi.myAtoi("42")); + @ParameterizedTest + @CsvSource({"'42', 42", "' -42', -42", "'4193 with words', 4193", "'words and 987', 0", "'-91283472332', -2147483648", "'21474836460', 2147483647", "' +123', 123", "'', 0", "' ', 0", "'-2147483648', -2147483648", "'+2147483647', 2147483647", "' -0012a42', -12", + "'9223372036854775808', 2147483647", "'-9223372036854775809', -2147483648", "'3.14159', 3", "' -0012', -12", "' 0000000000012345678', 12345678", "' -0000000000012345678', -12345678", "' +0000000000012345678', 12345678", "'0', 0", "'+0', 0", "'-0', 0"}) + void + testMyAtoi(String input, int expected) { + assertEquals(expected, MyAtoi.myAtoi(input)); } @Test - void testTwo() { - assertEquals(-42, MyAtoi.myAtoi(" -42")); + void testNullInput() { + assertEquals(0, MyAtoi.myAtoi(null)); } @Test - void testThree() { - assertEquals(4193, MyAtoi.myAtoi("4193 with words")); + void testSinglePlus() { + assertEquals(0, MyAtoi.myAtoi("+")); } @Test - void testFour() { - assertEquals(0, MyAtoi.myAtoi("0")); + void testSingleMinus() { + assertEquals(0, MyAtoi.myAtoi("-")); } @Test - void testFive() { - assertEquals(5678, MyAtoi.myAtoi("5678")); + void testIntegerMinBoundary() { + assertEquals(Integer.MIN_VALUE, MyAtoi.myAtoi("-2147483648")); } @Test - void testSix() { - assertEquals(42, MyAtoi.myAtoi("+42")); - } - - @Test - void testSeven() { - assertEquals(0, MyAtoi.myAtoi(" +0 ")); + void testIntegerMaxBoundary() { + assertEquals(Integer.MAX_VALUE, MyAtoi.myAtoi("2147483647")); } }