Shifter Words Challenge in Java


The challenge

You probably know that some characters written on a piece of paper, after turning this sheet 180 degrees, can be read, although sometimes in a different way. So, uppercase letters “H”, “I”, “N”, “O”, “S”, “X”, “Z” after rotation are not changed, the letter “M” becomes a “W”, and Vice versa, the letter “W” becomes a “M”.

We will call a word “shifter” if it consists only of letters “H”, “I”, “N”, “O”, “S”, “X”, “Z”, “M” and “W”. After turning the sheet, this word can also be read, although in a different way. So, the word “WOW “turns into the word “MOM”. On the other hand, the word “HOME” is not a shifter.

Find the number of unique shifter words in the input string (without duplicates). All shifters to be counted, even if they are paired (like “MOM” and “WOW”). String contains only uppercase letters.

Examples

// shifter words are "SOS" and "IN"
Shifter.count("SOS IN THE HOME") == 2

// shifter words are "WHO", "IS", "NO"
Shifter.count("WHO IS SHIFTER AND WHO IS NO") == 3

// no shifter words
Shifter.count("TASK") == 0

// no shifter words in empty string
Shifter.count("") == 0

The solution in Java code

Option 1:

import java.util.*;

public class Shifter{
    public static int count(String st){
        
        Map<String, Integer> m = new HashMap<>();
      
        for (String word : st.split("\\s+")) {
          if (isShifter(word)) m.put(word, 1);
        }
        
        return m.size();
    }
  
    public static boolean isShifter(String word) {
      
        if (word==null || word=="") return false;
        
        for (char c : word.toCharArray()) {
            if ("HINOSXZMW".indexOf(c)==-1) return false;
        }
        
        return true;
    }
}

Option 2:

import java.util.Arrays;
import java.util.LinkedHashSet;
public class Shifter{
    public static int count(String st){
        String[] stringArray = st.split(" ");
        LinkedHashSet<String> noduplicate 
          = new LinkedHashSet<>(Arrays.asList(stringArray));
        stringArray = noduplicate.toArray(new String[]{});
        int count = 0;
      for(String s: stringArray){
        if(s.matches("[HINOSXZMW]+"))count++;
      }
      return count;
    }
}

Option 3:

import java.util.Arrays;
import java.util.regex.Pattern;

public class Shifter{
    public static int count(String value){
        Pattern pattern = Pattern.compile("^[HINOSXZMW]+$");
        return (int) Arrays.stream(value.split("\\s+"))
                .distinct()
                .filter(token -> pattern.matcher(token).find())
                .count();
    }
}

Test cases to validate our solution

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;

public class SolutionTest{
    @Test
    public void on(){
        assertEquals(1, Shifter.count("ON"));
    }
    @Test
    public void osIsUpdated(){
        assertEquals(2, Shifter.count("OS IS UPDATED"));
    }
    @Test
    public void whoIsWho(){
        assertEquals(2, Shifter.count("WHO IS WHO"));
    }
    @Test
    public void js(){
        assertEquals(0, Shifter.count("JS"));
    }
    @Test
    public void iIiiIIii(){
        assertEquals(2, Shifter.count("I III I III"));
    }
    @Test
    public void empty(){
        assertEquals(0, Shifter.count(""));
    }
}