From d804a1e99cce03c8465252181347a4873d584853 Mon Sep 17 00:00:00 2001 From: abigailvo2005 Date: Sun, 21 Aug 2022 17:04:03 +0700 Subject: [PATCH] adding java classes with modified code smell & jUnit testing classes --- src/main/java/DecodeWays.java | 39 ++++++++++ src/main/java/EditDistance.java | 42 ++++++++++ .../java/FirstUniqueCharacterInAString.java | 43 ++++++++++ src/main/java/ReverseWordsInAString.java | 17 ++++ src/main/java/RomanToInteger.java | 38 +++++++++ src/main/java/SpiralMatrix.java | 66 ++++++++++++++++ src/main/java/jUnit/DecodeWaysTest.java | 42 ++++++++++ src/main/java/jUnit/EditDistanceTest.java | 43 ++++++++++ .../FirstUniqueCharacterInAStringTest.java | 49 ++++++++++++ .../java/jUnit/ReverseWordsInAStringTest.java | 27 +++++++ src/main/java/jUnit/RomanToIntegerTest.java | 33 ++++++++ src/main/java/jUnit/SpiralMatrixTest.java | 78 +++++++++++++++++++ 12 files changed, 517 insertions(+) create mode 100644 src/main/java/DecodeWays.java create mode 100644 src/main/java/EditDistance.java create mode 100644 src/main/java/FirstUniqueCharacterInAString.java create mode 100644 src/main/java/ReverseWordsInAString.java create mode 100644 src/main/java/RomanToInteger.java create mode 100644 src/main/java/SpiralMatrix.java create mode 100644 src/main/java/jUnit/DecodeWaysTest.java create mode 100644 src/main/java/jUnit/EditDistanceTest.java create mode 100644 src/main/java/jUnit/FirstUniqueCharacterInAStringTest.java create mode 100644 src/main/java/jUnit/ReverseWordsInAStringTest.java create mode 100644 src/main/java/jUnit/RomanToIntegerTest.java create mode 100644 src/main/java/jUnit/SpiralMatrixTest.java diff --git a/src/main/java/DecodeWays.java b/src/main/java/DecodeWays.java new file mode 100644 index 00000000..759cec86 --- /dev/null +++ b/src/main/java/DecodeWays.java @@ -0,0 +1,39 @@ +// A message containing letters from A-Z is being encoded to numbers using the following mapping: + +// 'A' -> 1 +// 'B' -> 2 +// ... +// 'Z' -> 26 + +// Given an encoded message containing digits, determine the total number of ways to decode it. + +// For example, +// Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). + +// The number of ways decoding "12" is 2. + +package src.main.java; + +public class DecodeWays { + public int numDecodings(String s) { + int n = s.length(); + + if(n == 0) { + return 0; + } + + int[] dp = new int[n + 1]; + dp[n] = 1; + dp[n - 1] = s.charAt(n - 1) != '0' ? 1 : 0; + + for(int i = n - 2; i >= 0; i--) { + if(s.charAt(i) == '0') { + continue; + } else { + dp[i] = (Integer.parseInt(s.substring(i, i + 2)) <= 26) ? dp[i + 1] + dp[i + 2] : dp[i + 1]; + } + } + + return dp[0]; + } +} diff --git a/src/main/java/EditDistance.java b/src/main/java/EditDistance.java new file mode 100644 index 00000000..f82ec9a4 --- /dev/null +++ b/src/main/java/EditDistance.java @@ -0,0 +1,42 @@ +// Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.) + +// You have the following 3 operations permitted on a word: + +// a) Insert a character +// b) Delete a character +// c) Replace a character + +package src.main.java; +public class EditDistance { + public int minDistance(String word1, String word2) { + int m = word1.length(); + int n = word2.length(); + + int[][] dp = new int[m + 1][n + 1]; + + for(int i = 0; i <= m; i++) { + dp[i][0] = i; + } + + for(int i = 0; i <= n; i++) { + dp[0][i] = i; + } + + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { + if(word1.charAt(i) == word2.charAt(j)) { + dp[i + 1][j + 1] = dp[i][j]; + } else { + int a = dp[i][j]; + int b = dp[i][j + 1]; + int c = dp[i + 1][j]; + + dp[i + 1][j + 1] = Math.min(a, Math.min(b, c)); + dp[i + 1][j + 1]++; + } + } + } + + return dp[m][n]; + } +} diff --git a/src/main/java/FirstUniqueCharacterInAString.java b/src/main/java/FirstUniqueCharacterInAString.java new file mode 100644 index 00000000..e720d02e --- /dev/null +++ b/src/main/java/FirstUniqueCharacterInAString.java @@ -0,0 +1,43 @@ + +package src.main.java; +import java.util.HashMap; + +//Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1. +// +//Examples: +// +//s = "leetcode" +//return 0. +// +//s = "loveleetcode", +//return 2. +//Note: You may assume the string contain only lowercase letters. + +public class FirstUniqueCharacterInAString { + public int firstUniqChar(String s) { + + //instead of assuming, always convert the characters into lowercase letters. + s = s.toLowerCase(); + + HashMap characters = new HashMap(); + + for(int i = 0; i < s.length(); i++) { + char current = s.charAt(i); + if(characters.containsKey(current)) { + characters.put(current, -1); + } else { + characters.put(current, i); + } + } + + int min = Integer.MAX_VALUE; + for(char c: characters.keySet()) { + if(characters.get(c) > -1 && characters.get(c) < min) { + min = characters.get(c); + } + } + + return min == Integer.MAX_VALUE ? -1 : min; + + } +} diff --git a/src/main/java/ReverseWordsInAString.java b/src/main/java/ReverseWordsInAString.java new file mode 100644 index 00000000..8b7b0e02 --- /dev/null +++ b/src/main/java/ReverseWordsInAString.java @@ -0,0 +1,17 @@ +//Given an input string, reverse the string word by word. +//For example, +//Given s = "the sky is blue", +//return "blue is sky the". + +package src.main.java; +public class ReverseWordsInAString { + public String reverseWords(String s) { + String[] words = s.trim().split("\\s+"); + String result = ""; + for(int i = words.length - 1; i > 0; i--) { + result += words[i] + " "; + } + + return result + words[0]; + } +} diff --git a/src/main/java/RomanToInteger.java b/src/main/java/RomanToInteger.java new file mode 100644 index 00000000..d2a14cf7 --- /dev/null +++ b/src/main/java/RomanToInteger.java @@ -0,0 +1,38 @@ +package src.main.java; +import java.util.HashMap; + +// Given a roman numeral, convert it to an integer. + +// Input is guaranteed to be within the range from 1 to 3999 + +public class RomanToInteger { + public int romanToInt(String s) { + //instead of assuming, always convert the roman numerals into uppercase letters. + //to avoid unexpected errors as roman numerals are accepted input as lowercased too + s = s.toUpperCase(); + + HashMap map = new HashMap(); + + map.put('I', 1); + map.put('V', 5); + map.put('X', 10); + map.put('L', 50); + map.put('C', 100); + map.put('D', 500); + map.put('M', 1000); + + int total = 0; + + for(int i = 0; i < s.length() - 1; i++) { + if(map.get(s.charAt(i)) < map.get(s.charAt(i + 1))) { + total -= map.get(s.charAt(i)); + } else { + total += map.get(s.charAt(i)); + } + } + + total += map.get(s.charAt(s.length() - 1)); + + return total; + } +} diff --git a/src/main/java/SpiralMatrix.java b/src/main/java/SpiralMatrix.java new file mode 100644 index 00000000..87e3dcd5 --- /dev/null +++ b/src/main/java/SpiralMatrix.java @@ -0,0 +1,66 @@ +package src.main.java; + +import java.util.ArrayList; +import java.util.List; + +//Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. +// +//Example 1: +// +//Input: +//[ + //[ 1, 2, 3 ], + //[ 4, 5, 6 ], + //[ 7, 8, 9 ] +//] +//Output: [1,2,3,6,9,8,7,4,5] +//Example 2: +// +//Input: +//[ + //[1, 2, 3, 4], + //[5, 6, 7, 8], + //[9,10,11,12] +//] +//Output: [1,2,3,4,8,12,11,10,9,5,6,7] + +public class SpiralMatrix { + public List spiralOrder(int[][] matrix) { + List result = new ArrayList(); + if(matrix == null || matrix.length == 0) { + return result; + } + + int rowStart = 0; + int rowEnd = matrix.length - 1; + int colStart = 0; + int colEnd = matrix[0].length - 1; + while(rowStart <= rowEnd && colStart <= colEnd) { + for(int i = colStart; i <= colEnd; i++) { + result.add(matrix[rowStart][i]); + } + rowStart++; + + for(int i = rowStart; i <= rowEnd; i++) { + result.add(matrix[i][colEnd]); + } + colEnd--; + + if(rowStart <= rowEnd) { + for(int i = colEnd; i >= colStart; i--) { + result.add(matrix[rowEnd][i]); + } + } + rowEnd--; + + if(colStart <= colEnd) { + for(int i = rowEnd; i >= rowStart; i--) { + result.add(matrix[i][colStart]); + } + } + colStart++; + } + + return result; + } +} diff --git a/src/main/java/jUnit/DecodeWaysTest.java b/src/main/java/jUnit/DecodeWaysTest.java new file mode 100644 index 00000000..b3db7842 --- /dev/null +++ b/src/main/java/jUnit/DecodeWaysTest.java @@ -0,0 +1,42 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import src.main.java.DecodeWays; + + +//A message containing letters from A-Z is being encoded to numbers using the following mapping: + +//'A' -> 1 +//'B' -> 2 +//... +//'Z' -> 26 + +//Given an encoded message containing digits, determine the total number of ways to decode it. + +//For example, +//Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). + +//The number of ways decoding "12" is 2. + +class DecodeWaysTest { + + DecodeWays testDW = new DecodeWays(); + + /* ways of decoding message match the function's result */ + @Test + void testMatch() { + assertEquals(3, testDW.numDecodings("123")); + //123 = A,B,C | AB,C | A,BC + } + + + /* ways of decoding message don't match the function's result */ + @Test + void testNoMatch() { + assertEquals(12, testDW.numDecodings("123")); + //123 = A,B,C | AB,C | A,BC + } +} diff --git a/src/main/java/jUnit/EditDistanceTest.java b/src/main/java/jUnit/EditDistanceTest.java new file mode 100644 index 00000000..cd3d5b6a --- /dev/null +++ b/src/main/java/jUnit/EditDistanceTest.java @@ -0,0 +1,43 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +//Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. +// (each operation - add, delete, replace is counted as 1 step.) + +import org.junit.jupiter.api.Test; + +import src.main.java.EditDistance; + +class EditDistanceTest { + + EditDistance test = new EditDistance(); + + /* only requires add 1 letter */ + @Test + void testOneChar() { + assertEquals(1, test.minDistance("a", "ab")); + } + + /* requires add 2 letters */ + @Test + void testTwoChar() { + assertEquals(2, test.minDistance("a", "abc")); + //each character is counted as 1 operation. + } + + /* requires add 2 letters and delete 1 letter */ + @Test + void testAddReplace() { + assertEquals(2, test.minDistance("a", "bc")); + //b is not a, so a is replaced by b, therefore, there are only 2 steps: replace and add. + } + + /* requires add 2 letters and delete 2 letters */ + @Test + void testAddDelete() { + assertEquals(2, test.minDistance("de", "bc")); + //can also be understood as replace 2 characters + } + +} \ No newline at end of file diff --git a/src/main/java/jUnit/FirstUniqueCharacterInAStringTest.java b/src/main/java/jUnit/FirstUniqueCharacterInAStringTest.java new file mode 100644 index 00000000..17177e01 --- /dev/null +++ b/src/main/java/jUnit/FirstUniqueCharacterInAStringTest.java @@ -0,0 +1,49 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +//Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1. +// +//Examples: +// +//s = "leetcode" +//return 0. +// +//s = "loveleetcode", +//return 2. + + +import org.junit.jupiter.api.Test; + +import src.main.java.FirstUniqueCharacterInAString; + +class FirstUniqueCharacterInAStringTest { + + FirstUniqueCharacterInAString testFUC = new FirstUniqueCharacterInAString(); + + /* the second letter unique */ + @Test + void testSecond() { + assertEquals(1, testFUC.firstUniqChar("sos")); + } + + /* the first and second letters are unique */ + @Test + void testTwoUnique() { + assertEquals(0, testFUC.firstUniqChar("so")); + } + + /* no letters are unique */ + @Test + void testNo() { + assertEquals(-1, testFUC.firstUniqChar("soos")); + } + + /* the first non-unique letter is being cased different from its duplicate*/ + @Test + void testUpper() { + assertEquals(1, testFUC.firstUniqChar("saS")); + //fix code smell in order to have correct result + } + +} diff --git a/src/main/java/jUnit/ReverseWordsInAStringTest.java b/src/main/java/jUnit/ReverseWordsInAStringTest.java new file mode 100644 index 00000000..a9d472d6 --- /dev/null +++ b/src/main/java/jUnit/ReverseWordsInAStringTest.java @@ -0,0 +1,27 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +//Given an input string, reverse the string word by word. + +import org.junit.jupiter.api.Test; + +import src.main.java.ReverseWordsInAString; + +class ReverseWordsInAStringTest { + + ReverseWordsInAString test = new ReverseWordsInAString(); + + /* test with normal strings */ + @Test + void testNormal() { + assertEquals("morning good", test.reverseWords("good morning")); + } + + /* test strings with punctuation */ + @Test + void testPunctuation() { + assertEquals("morning! good", test.reverseWords("good morning!")); + } + +} diff --git a/src/main/java/jUnit/RomanToIntegerTest.java b/src/main/java/jUnit/RomanToIntegerTest.java new file mode 100644 index 00000000..16af420a --- /dev/null +++ b/src/main/java/jUnit/RomanToIntegerTest.java @@ -0,0 +1,33 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +//Given a roman numeral, convert it to an integer. + +//Input is guaranteed to be within the range from 1 to 3999 + + +import org.junit.jupiter.api.Test; + +import src.main.java.RomanToInteger; + +class RomanToIntegerTest { + + /* test uppercase roman numerals */ + @Test + void testUppercase() { + RomanToInteger testRTI = new RomanToInteger(); + assertEquals(34, testRTI.romanToInt("XXXIV")); + } + + /* test lowercase roman numerals */ + @Test + void testLowercase() { + RomanToInteger testRTI = new RomanToInteger(); + assertEquals(34, testRTI.romanToInt("xxxiv")); + + //code smell: always convert the roman numerals into uppercase letters. + //to avoid unexpected errors as roman numerals are accepted input as lowercased too + } + +} diff --git a/src/main/java/jUnit/SpiralMatrixTest.java b/src/main/java/jUnit/SpiralMatrixTest.java new file mode 100644 index 00000000..e8bba334 --- /dev/null +++ b/src/main/java/jUnit/SpiralMatrixTest.java @@ -0,0 +1,78 @@ +package src.main.java.jUnit; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.List; + +//Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. +// +//Example 1: +// +//Input: +//[ +//[ 1, 2, 3 ], +//[ 4, 5, 6 ], +//[ 7, 8, 9 ] +//] +//Output: [1,2,3,6,9,8,7,4,5] +//Example 2: +// +//Input: +//[ +//[1, 2, 3, 4], +//[5, 6, 7, 8], +//[9,10,11,12] +//] +//Output: [1,2,3,4,8,12,11,10,9,5,6,7] + +import org.junit.jupiter.api.Test; + +import company.microsoft.SpiralMatrix; + +class SpiralMatrixTest { + + /* assuming the spiral is in clockwise direction */ + @Test + void testClockwise() { + SpiralMatrix testSM = new SpiralMatrix(); + + int[][] matrix = { + { 1, 2, 3 }, + { 4, 5, 6 } + }; + + List res = new ArrayList(); + res.add(1); + res.add(2); + res.add(3); + res.add(6); + res.add(5); + res.add(4); + + assertEquals(res, testSM.spiralOrder(matrix)); + } + + /* assuming the spiral is not in clockwise direction */ + @Test + void testAntiClockwise() { + SpiralMatrix testSM = new SpiralMatrix(); + + int[][] matrix = { + { 1, 2, 3 }, + { 4, 5, 6 } + }; + + List res = new ArrayList(); + res.add(1); + res.add(4); + res.add(5); + res.add(6); + res.add(3); + res.add(2); + + assertEquals(res, testSM.spiralOrder(matrix)); + } + + +}