Java – Exam – Congate Words

Some time ago, to be more honest last Sunday, I participated at some Java exam again. The results were not something to boast, quite on the contrary, but I did not have a lot of time to prepare 🙂 The contest was hosted by the SoftUni and the tasks were quite tough. At least this time I knew how to debug in Eclipse, so I did not waste time to learn it 🙂

The Java problem, which I had to resolve was concerning words.

CongationWords

Pretty much, you have a string as input where you should consider all the latin characters as words. You should return all triples, in which two words together make a third one. It is probably better to see the original examples in order to understand:

Example Table

Yup, I am probably the only person in the world, who knows enough HTML to format a table and still prefers to make a screenshot of it. Pretty much, I managed to resolve the problem after some time. This was my approach:

  1. I read the string;
  2. I replaced everything, which is not a latin character with a space (with a Regex 🙂 );
  3. In order to avoid some misunderstanding, if there were some places with more than one space, I replaced them with one space;
  4. I split by the space to make a string array;
  5. Then came the real part – I started three loops, which gave me values for b and c;
  6. Then I made the check for the condition;
  7. I wrote the solution in one ArrayList;
  8. I checked the frequency of my solution in the ArrayList;
  9. If the frequency was 1, I printed it;
  10. If I printed anything, I increased the counter plus one;
  11. At the end I made a check whether the counter is 0, in order to print “No” if true;

Here is the outstanding code:

import java.util.*;

public class CognateWords {
	public static void main(String[] args) {

		Scanner input = new Scanner(System.in);
		String Normal = input.nextLine();
		String MoreNormal = Normal.replaceAll("[^A-Za-z]", " ");
		String SuperNormal = MoreNormal.replaceAll("[ ]+", " ");
		String[] numsStr = SuperNormal.split(" ");
		int Counter = 0;
		ArrayList ar = new ArrayList();
		int myCount = 0;
		for (int k = 0; k < numsStr.length; k++) {
			for (int i = 0; i < numsStr.length; i++) {
				for (int z = 0; z < numsStr.length; z++) {
					String a = numsStr[k];
					String b = numsStr[i];
					String c = numsStr[z];

					if ((a + b).equals(c)) {
						String myString = a + "|" + b + "=" + c;
						ar.add(myString);
						for (String sA : ar) {
							myCount = Collections.frequency(ar, sA);
						}

						if (myCount == 1) {
							System.out.println(myString);
							Counter++;
						}
					}
				}
			}
		}
		if (Counter == 0) {
			System.out.println("No");
		}
	}
}

Pretty much I could have reduced a pair of lines, but I really thing it is a smooth decision.

The original solution was a bit better:

  1. It used HashSet<String> – thus, you do not have to check whether the value is unique or not;
  2. The reading of the first line and the split into an array is done in one line;
  3. I like the way the boolean check is declared and given value;
  4. Also, the original solution works with less variables, thus it should be faster;

Pretty much, this is how it looks like:

import java.util.Scanner;
import java.util.HashSet;

public class CognateWords {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String[] words = sc.nextLine().split("[^a-zA-Z]+");

		HashSet cognateWords = new HashSet<>();
		for (int a = 0; a < words.length; a++) {
			for (int b = 0; b < words.length; b++) {
				for (int c = 0; c < words.length; c++) {
					// Check if a!=b and a|b=c 
					if (a != b) {
						boolean check = (words[a] + words[b]).equals(words[c]);
						if (check) {
							cognateWords.add(words[a] + "|" + words[b] + "=" + words[c]);
						}
					}					
				}
			}

		if (cognateWords.isEmpty()) {
			System.out.println("No");
		} else {
			for (String cognate : cognateWords) {
				System.out.println(cognate);
			}
		}
	}
}

Enjoy it responsibly! 😀