Kattis - Secret Chamber - java

I'm required to solve the following problem for one of my classes: https://open.kattis.com/problems/secretchamber
My solution seems to work, but it's failing the third test case. I implemented every rule given by the problem description, and it solves the two sample test cases no problem. I'm at my wit's end, and I don't know what I'm doing wrong.
I'm not asking for anyone to do my homework by any means whatsoever, but any pointers on what I'm missing would be greatly appreciated.
import java.io.*;
import java.util.*;
class secretchamber
{
public static void main(String[] args)
{
Scanner stdin = new Scanner(System.in);
int numTranslations = stdin.nextInt();
int numPairs = stdin.nextInt();
stdin.nextLine();
ArrayList<Character> trans1 = new ArrayList<Character>(numTranslations);
ArrayList<Character> trans2 = new ArrayList<Character>(numTranslations);
for(int i = 0; i < numTranslations; i++)
{
String temp = stdin.nextLine();
trans1.add(temp.charAt(0));
trans2.add(temp.charAt(2));
}
for(int i = 0; i < numPairs; i++)
{
String temp = stdin.nextLine();
String[] pair = temp.split("\\s+");
char[] a = pair[0].toCharArray();
char[] b = pair[1].toCharArray();
if(translates(a, b, numTranslations, trans1, trans2))
{
System.out.println("yes");
}
else
{
System.out.println("no");
}
}
}
public static boolean translates(char[] a, char[] b, int numTranslations, ArrayList trans1, ArrayList trans2)
{
//false if strings are unequal in length
if(a.length != b.length)
{
return false;
}
//true if strings are the same
else if(a == b)
{
return true;
}
else
{
for(int i = 0; i < a.length; i++)
{
//if current characters are the same, continue
if(a[i] == b[i])
{
continue;
}
//if current index of a directly translates to index of b
else if(trans1.indexOf(a[i]) == trans2.indexOf(b[i]))
{
continue;
}
//if one or both of the characters do not exist within the list of translations
else if(!(trans1.contains(a[i]) && trans2.contains(b[i])))
{
return false;
}
else
{
continue;
}
}
}
return true;
}
}

Your understanding for the problem is worng. You need to read again this part in the problem.
Two words match if they have the same length and if each letter of the first word can be turned into the corresponding letter of the
second word by using the available translations zero or more times.
This input can make your output goes worng.
Input
2 1
a c
d b
aaa abc
Expected output
no
Your output
yes
Below is solution sketch for this problem.
I got it from icpc website.

It's happenstance that your code works on the sample cases. Check the it -> of translation in the provided example carefully. i doesn't directly translate to o, but it does directy translate to r, and r translates to o. You need to follow all translation paths step by step for each character and build a graph that lets you efficiently test whether a translation is possible.
Consider buiding a structure like HashMap<Character, Set<Character>> that maps each of the 26 letters to all of the possible characters it can translate to. For the provided example, o would map to {'r', 'o', 't', 'c', 'f', 'e'}. Repeat the same procedure for each of the provided translations.
Once you've built this data structure, it's a straightforward task of iterating over characters and performing lookups. a should have the same length as b and b[i] should be in the translation set for a[i], for all i.

Related

the counter is not updating with my loop and I don't know why

I'm trying to practice for a techniqual test where I have to count the number of characters in a DNA sequence, but no matter what I do the counter won't update, this is really frustrating as I learnt code with ruby and it would update, but Java seems to have an issue. I know there's something wrong with my syntaxt but for the life of me I can't figure it out.
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String dna = dna1;
int aCount = 0;
int cCount = 0;
int tCount = 0;
for (int i = 0; i <= dna.length(); i++) {
if (dna.substring(i) == "A") {
aCount+= 1;
}
else if (dna.substring(i) == "C") {
cCount++;
}
else if (dna.substring(i) == "T") {
tCount++;
}
System.out.println(aCount);
}
}
}
It just keeps returning zero instead of adding one to it if the conditions are meet and reassigning the value.
Good time to learn some basic debugging!
Let's look at what's actually in that substring you're looking at. Add
System.out.println(dna.substring(i));
to your loop. You'll see:
ATGCGATACGCTTGA
TGCGATACGCTTGA
GCGATACGCTTGA
CGATACGCTTGA
GATACGCTTGA
ATACGCTTGA
TACGCTTGA
ACGCTTGA
CGCTTGA
GCTTGA
CTTGA
TTGA
TGA
GA
A
So, substring doesn't mean what you thought it did - it's taking the substring starting at that index and going to the end of the string. Only the last character has a chance of matching your conditions.
Though, that last one still won't match your condition, which is understandably surprising if you're new to the language. In Java, == is "referential equality" - when applied to non-primitives, it's asserting the two things occupy the same location in memory. For strings in particular, this can give surprising and inconsistent results. Java keeps a special section of memory for strings, and tries to avoid duplicates (but doesn't try that hard.) The important takeaway is that string1.equals(string2) is the correct way to check.
It's a good idea to do some visibility and sanity checks like that, when your program isn't doing what you think it is. With a little practice you'll get a feel for what values to inspect.
Edward Peters is right about misuse of substring that returns a String.
In Java, string must be places between double quotes. A String is an object and you must use method equals to compare 2 objects:
String a = "first string";
String b = "second string";
boolean result = a.equals(b));
In your case, you should consider using charAt(int) instead. Chars must be places between simple quotes. A char is a primitive type (not an object) and you must use a double equals sign to compare two of them:
char a = '6';
char b = 't';
boolean result = (a==b);
So, your code should look like this:
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String dna = dna1;
int aCount = 0;
int cCount = 0;
int tCount = 0;
for (int i = 0; i < dna.length(); i++) {
if (dna.charAt(i) == 'A') {
aCount += 1;
} else if (dna.charAt(i) == 'C') {
cCount++;
} else if (dna.charAt(i) == 'T') {
tCount++;
}
System.out.println(aCount);
}
}
}
substring(i) doesn't select one character but all the characters from i to the string length, then you also made a wrong comparison: == checks 'object identity', while you want to check that they are equals.
You could substitute
if (dna.substring(i) == "A")
with:
if (dna.charAt(i) == 'A')
this works because charAt(i) returns a primitive type, thus you can correctly compare it to 'A' using ==
One of the problems, as stated, was the way you are comparing Strings. Here is a way
that uses a switch statement and a iterated array of characters. I put all the strings in an array. If you only have one string, the outer loop can be eliminated.
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String[] dnaStrings =
{dna1,dna2,dna3};
int aCount = 0;
int cCount = 0;
int tCount = 0;
int gCount = 0;
for (String dnaString : dnaStrings) {
for (char c : dnaString.toCharArray()) {
switch (c) {
case 'A' -> aCount++;
case 'T' -> tCount++;
case 'C' -> cCount++;
case 'G' -> gCount++;
}
}
}
System.out.println("A's = " + aCount);
System.out.println("T's = " + tCount);
System.out.println("C's = " + cCount);
System.out.println("G's = " + gCount);
}
prints
A's = 14
T's = 13
C's = 6
G's = 10

Why doesn't my Pangram solution output correctly?

The question is as follows:
A pangram is a string that contains every letter of the alphabet. Given a sentence determine whether it is a pangram in the English alphabet. Ignore case. Return either pangram or not pangram as appropriate.
My code works for all input except "qmExzBIJmdELxyOFWv LOCmefk TwPhargKSPEqSxzveiun", for which it returns "not pangram", even though the correct answer is "pangram." Does anybody have any ideas as to why my code is outputting the incorrect solution?
public static String pangrams(String s) {
Hashtable<Character, Integer> alpha = new Hashtable<Character, Integer>();
s = s.toLowerCase();
for (int i = 0; i < s.length()-1; i++){
if (alpha.get(s.charAt(i)) != null){
int value = alpha.get(s.charAt(i));
alpha.put(s.charAt(i), value + 1);
}
else{
alpha.put(s.charAt(i), 1);
}
}
if (alpha.size() != 27){
return "not pangram";
}
else{
return "pangram";
}
}
As per your definition of pangram you might want to consider the following:
Use a Set instead of a Map
As far as I know, English has 26 letters
Make sure you don't mistakenly add digits or symbols to your set
Given the three above statements I would slightly change your code to reflect that. That would, more or less, look something like this:
public static String pangrams(String s) {
Set<Character> alpha = new HashSet<>();
s = s.toLowerCase();
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if (Character.isLetter(c)){
alpha.add(c);
}
}
if (alpha.size() == 26){
return "pangram";
}
return "not pangram";
}

Print vowels from a word in Java

I am a beginner at java and I am doing this course an needed some help with this. Basically, a user will input a string and then the program will print out only the vowels on one line.
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
System.out.print("In:");
String word = inp.nextLine();
//write your code below
for(int whatsat = 0; whatsat < word.length(); whatsat++){
if (word.charAt(whatsat).equals("a")){ //how to declare mutiple letters?
System.out.print(word.charAt(whatsat));
}
}
}
}
I agree with #Logan. You don't use equals() to compare primitive type values (int, char, boolean, etc.), just use simple == expression.
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
System.out.print("In:");
String word = inp.nextLine();
//write your code below
for(int whatsat = 0; whatsat < word.length(); whatsat++){
char c = Character.toLowerCase(word.charAt(whatsat));
if (c == 'a' || c == 'e'|| c == 'i' || c == 'o' || c == 'u'){
System.out.print(word.charAt(whatsat));
}
}
}
}
A simple way to do this (intentionally avoiding complex regex options) would be to use the String.indexOf() method within your loop.
In the example below, we basically check if "AEIOUaeiou" contains the char that we're pulling from the user's input. If so, we extract it:
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
System.out.print("In:");
String word = inp.nextLine();
//write your code below
// This will hold any matching vowels we find
StringBuilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++) {
// Check if our list of vowels contains the current char. If the current char exists in the String of vowels, it will have an index of 0 or greater.
if ("AEIOUaeiou".indexOf(word.charAt(i)) > -1) {
// If so, add it to our StringBuilder
sb.append(word.charAt(i));
}
}
// Finally, print the result
System.out.println(sb.toString());
}
The Result:
With test input of "This is my test input. Did it work?" the output is: iieiuiio
So there's two issues here:
Characters are compared differently from Strings.
Checking for multiple characters.
To compare characters, do something like:
if (word.charAt(whatsat) == 'a') {
...
}
Note the single quotes! 'a' not "a"!
If you're asking "why are comparisons for strings and characters different?", that's a good question. I actually don't know the reason, so we should both research it. Moving on.
To check for multiple characters:
for(int whatsat = 0; whatsat < word.length(); whatsat++){
if (word.charAt(whatsat) == 'a' || word.charAt(whatsat) == 'e' || word.charAt(whatsat) == 'i'){
System.out.print(word.charAt(whatsat));
}
}
Note that if you're input has capital letters, you'll need to either:
Convert your input to lowercase so you can just check for lowercase letters, or
Explicitly check for capital letters in your if statement, e.g
if (...word.charAt(whatsat) == 'A' ...)
Longterm, you'll want to research regular expressions like a Adrian suggested in the comments. It may be complicated for a beginning student, but if you're interested you should look into it.
Hope this helps.
I am really surprised nobody has suggested using Enums... Cleanest way and simplest way, in my opinion.
Simply define an Enum with all the vowels, go through the String and compare each character to the values inside of Enum, ignoring the case - note the cast of char into String. If it is present in the Enum, print it out.
public class VowelFind {
enum Vowels {
A, E, I, O, U
}
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
System.out.print("In:");
String word = inp.nextLine();
for (int i = 0; i < word.length(); i++) { //loop through word
for (Vowels v : Vowels.values()) { //loop through Enum values
if((word.charAt(i)+"").equalsIgnoreCase(v.name())) { //compare character to Enum value, ignoring case
System.out.print(word.charAt(i));
}
}
}
}
}
Input: Hello World
Output: eoo
I prefer to use Hashmap as lookup is O(1)
public class PrintVowelsInWord {
public static Map<Character, Character> vowels;
public static void main(String[] args) {
loadMap();
// for simplicity sake I am not using Scanner code here
getVowels("wewillrockyou");
}
public static void loadMap() {
if (vowels == null) {
vowels = new HashMap<>();
vowels.put('a', 'a');
vowels.put('e', 'e');
vowels.put('i', 'i');
vowels.put('o', 'o');
vowels.put('u', 'u');
}
}
public static void getVowels(String input) {
for (Character letter : input.toCharArray()) {
if (vowels.containsKey(letter)) {
System.out.print(letter);
}
}
}
}

Alphabetize a string array without using Array.sort() or compareTo()?

I have an exercise in class where you take names from the user and output them alphabetically. I'm not allowed to use Array.sort() or compareTo(). I seem to have gotten it to work for the most part... Except for when I enter something like a aaa aa, it outputs it in the following order:
aaa
aa
a
I'd really like to be able to output it in this order instead:
a
aa
aaa
This is what I have so far:
public static void main(String args[]) throws IOException {
BufferedReader key =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("Alphabetizing names\n");
System.out.println("Enter names separated by spaces:");
StringTokenizer names1 = new StringTokenizer(key.readLine());
int tokens = names1.countTokens();
String[] names2 = new String[tokens];
String y;
for (int a = 0; a < tokens; a++) {
names2[a] = names1.nextToken();
}
System.out.println("\nSorted names:");
for (int a = 0; a < tokens; a++) {
for (int b = a + 1; b < tokens; b++) {
if(alphabetize(names2[a], names2[b])) {
y = names2[a];
names2[a] = names2[b];
names2[b] = y;
}
}
}
for (int c = 0; c < tokens; c++) {
System.out.println(names2[c]);
}
}
static boolean alphabetize(String a, String b) {
for(int c = 0; ; c++) {
if((c == a.length()-1) && (c == b.length()-1)) {
return false;
}
if(c == a.length()-1) {
return true;
}
if(c == b.length()-1) {
return false;
}
if((a.toLowerCase().charAt(c) - b.toLowerCase().charAt(c)) > 0) {
return true;
}
}
}
Please help!! Thank you!
Hint 1: Look at the output. What does it look like is happening?
Hint 2: Based on the obvious conclusion from Hint 1 ... look at the alphabetize method ... and figure out why that causes what you are seeing.
Meta-hint: I think your problem here is that you don't have a consistent mental model of what alphabetize is supposed to be doing; i.e. the intended meaning of the result. There are two reasons for this:
The name of the method is opaque. The word "alphabetize" is not a verb whose meaning maps to the action you are attempting to perform. The http://www.thefreedictionary.com/alphabetize link says:
alphabetize (ˈælfəbəˌtaɪz) or alphabetise. vb (tr)
1. to arrange in conventional alphabetical order
2. to express by an alphabet
Your method is doing neither of those things.
Yes ... method names are important.
You don't have any comments to explain what the method should return. It is considered best practice to write a javadoc comment for any non-trivial method that forms the "contract" between the method and the code that calls the method. In this case, you need a comment that says something like "this method returns true if X, Y or Z, and false otherwise".
The problems are in alphabetizer:
First if: if a and b have the same length, you don't compare their last characters.
Second and Third if: if a and b have not the same length, you dont consider the last char of the shortest
Fourth if: you only consider the case where the char read from a is higher than the char read from b, you should also consider the case where b is higher than a.
Tip: The loop should continue only if the char that you read are equals,
Here how to solve your problem:
static boolean alphabetize(String a, String b) {
char ca;
char cb;
for(int c = 0; ; c++) {
ca = a.toLowerCase().charAt(c);
cb = b.toLowerCase().charAt(c);
if((c == a.length()-1) && (c == b.length()-1)) {
return (ca - cb) > 0;
} else if(c == a.length()-1) {
return false;
} else if(c == b.length()-1) {
return true;
} else if (ca - cb != 0) { //if are not equals
return (ca - cb) > 0;
}
}
}
I've tryed with many strings, for example this:
aaa ccc arc abr ald old mal ald aaaa bbbb aaaa car cro arc dsjd qhjk hdjgsdaj asidasiodu asi

In Java, I am trying to validate input by checking for invalid input. Somehow it is not correctly returning an error

First off, let me give you a small description of what I'm trying to do. For an assignment for college I have to recreate the game Mastermind in Java. So far everything's been going well, untill I came to a specific point in validating the user's input. I have an array of Strings called colorList, this list is filled with letters A to F (these are subtitutes for colors.)
When the user makes a guess, he enters a 4 letter code, for example ABCD. What I want to make sure is that every character in the guess is also contained in the colorList array to prevent users from guessing 'colors' that do not exist.
The code I'm using to validate this is as followed:
boolean incorrectInput = true;
while (incorrectInput) {
boolean ooitgoed = false;
outerloop: for (int a = 0; a < code.length(); a++) { // Select next letter in input.
for (int i = 0; i < colorList.size(); i++) { // Select next element in array to compare to.
ooitgoed = false; // Will put the boolean on false for as long as it does not find the selected char in the array.
if (colorList.get(i).charAt(0) == code.charAt(a)) { // If selected input character is equal to selected element from array:
System.out.println("Code char: " + code.charAt(a) + " - " + "Element from array: " + colorList.get(i) + " - correct input");
ooitgoed = true;
incorrectInput = false;
break; // Break out of the for-loop, which causes the next character of the input to be selected and then compared to every element in the array.
}
}
if (ooitgoed == false) { // If the selected char is never found in the array, the boolean will still be false and a new input will be requested.
System.out.println("Found incorrect input! Please only use 'A', 'B', 'C', 'D', 'E', or 'F'.");
System.out.println("Enter your guess: ");
input = in.next();
input = input.toUpperCase();
incorrectInput = true;
break outerloop; // Break back to outerloop, re-executing the entire validation process with the new input requested above.
}
}
}
I added some commentary to explain a couple of procedures during the code that SHOULD be working, and I'm not able to find why it's not working.
The output I get when I execute the program and take a guess is as followed:
Code = DCFF
Enter your guess:
DCFU
Code char: D - Element from array: D - correct input
Code char: C - Element from array: C - correct input
Code char: F - Element from array: F - correct input
Code char: F - Element from array: F - correct input
The U should have been found as invalid input, but somehow the program thinks it's an F and proceeds to validate it as such.
I added some commentary to explain a couple of procedures during the code that SHOULD be working, and I'm not able to find why it's not working.
If you need more info regarding my code please let me know, I'll provide you with as much as I need. I hope anyone can figure it out.
Thanks!
You are testing characters from code in your incorrectInput loop. Should be input.
Also a few comments about your code:
You don't need both ooitdoed and incorrectInput, either one is enough to hold your condition.
The outerloop is actually inner :) And you don't need that label - just break, without label will do.
Do not write boolean checks like if (ooitgoed == false) - just if(!ootitgoed)
You might find your implementation more clean and readable, if you make colorList a string "ABCDEF" instead of the array, and replace your innermost loop with incorrectInput = colorList.indexOf(input.charAt(a)) == -1
You can also validate the whole string at once, without any procedural loops with a regular expression: incorrectInput = !input.toUpperCase.matches("[A-F]+"). Or, if you want to also report which character was wrong:
Pattern p = Pattern.compile("[^A-F]", Pattern.CASE_INSENSITIVE); // Do this before all loops
// ...
Matcher m = p.matcher(input);
incorrectInput = m.find();
if(incorrectInput) System.out.println("This symbol is invalid: " + m.group());
First, let's create a method to validate the characters. Let's call it isCharValid:
public boolean isCharValid(char ch, List<String> list) {
for (String s : list) {
if (s.charAt(0) == ch) {
return true;
}
}
return false;
}
Now, change your code to:
while (true) {
String input = in.next().toUpperCase();
boolean validated = true;
for (char ch : input.toCharArray()) {
if (!isCharValid(ch, YOUR_COLOR_LIST)) {
validated = false;
break;
}
}
if (validated) {
// The input is OK!
}
else {
System.out.println("Invalid output. Please, try again.");
// Now it will go back to the beginning of the while-loop.
}
}
General pointer: Make use of Lists.
final List<Character> allowedInputs = new ArrayList<>();
allowedInputs.add('A');
allowedInputs.add('B');
allowedInputs.add('C');
allowedInputs.add('D');
final String input = getInput(); //gets the input from the user..
final char[] inputChars = input.toCharArray();
for (final char inputChar : inputChars) {
if (allowedInputs.contains(inputChar)) {
//All good
} else {
//Error in input!
}
This is a shorter way to do what you want:
private static final char[] COLORS = {'A', 'B', 'C', 'D', 'E', 'F'};
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input;
boolean inputOk;
do {
inputOk = true;
// read the input
System.out.print("Enter your guess: ");
input = br.readLine().toUpperCase();
// do the check
for (int i = 0; i < input.length() && inputOk; i++) {
for (int j = 0; j < COLORS.length; j++) {
if (input.charAt(i) == COLORS[j])
break;
if (j == COLORS.length - 1)
inputOk = false;
}
}
// input isn't ok
if (!inputOk)
System.out.println("Found incorrect input! Please only use 'A', 'B', 'C', 'D', 'E', or 'F'.");
} while (!inputOk);
}

Categories

Resources