So I have been doing competitive programming using java, my code is ACCEPTED in codeforces. But I still think this code doesn't look so good, cause it needs 2 "for loops" to identify the duplication. if it is only one "for loops", it still has duplication in the strings.
This is the problem: https://codeforces.com/problemset/problem/236/A.
So basically, the code will try to find the distinct characters in the strings, then if the length of the string is odd, it will print "IGNORE HIM", else "CHAT WITH HER!".
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String a;
int counter=0;
Scanner sc= new Scanner(System.in);
a=sc.next();
StringBuilder b= new StringBuilder(a);
int count = 0;
for(int i=0;i<b.length();i++)
{
for(int j=i+1;j<b.length();j++) {
if(b.charAt(i)==b.charAt(j)) {
b=b.deleteCharAt(j);
}
}
}
for(int i=0;i<b.length();i++)
{
for(int j=i+1;j<b.length();j++) {
if(b.charAt(i)==b.charAt(j)) {
b=b.deleteCharAt(j);
}
}
}
counter=b.length();
if(counter%2==0)
{
System.out.println("CHAT WITH HER!");
}
else
{
System.out.println("IGNORE HIM!");
}
}
}
You can replace most of this code by this one line:
int count = a.chars().distinct().count();
This transforms you string input into a stream of characters, gets the distinct values and returns the count.
Using streams is a good option. If you want to go plain old route, then you can use a hashset. Basically if character is in hashset, then move to next char, else add to hashset and increase counter by 1.
Building upon and completing #Guillaume's answer
String a = "xiaodao";
String out = a.chars().distinct().count() % 2 == 0 ? "CHAT WITH HER!" : "IGNORE HIM!";
System.out.println(out);
I would use a Hashset because it will contain a distinct set of all characters you add. You can just go through the list once and use size() to get the unique character count.
...
Set<Character> characters = new HashSet<>()
for(int i=0;i<b.length();i++)
{
characters.add(b.charAt(i));
}
if(characters.size()%2==0) {
...
Related
I need to read the user input and compare this to a dictionary.txt. The user may input any number of characters and the program must return all the words in the English language that can be made from these characters. The letters can be used in any order and may only be used once.
For example:
User Input: "odg"
Output: "dog" , "god" ... and any others
After quite a substantial amount of research, I have come up with the following partial solution:
Read user input
Convert to an array of characters
Loop through the document depending on array length
Using indexOf to compare each character in this array to each line, then printing the word/s which do not return -1
How do I compare a set of characters inputted by the user to those found in a text file (dictionary) ? The characters do not have to be in any order to match .(as seen in the example used above)
Bear with me here, I know this must be one of the most inefficient ways to do such a task! Any further ideas on how to implement my original idea would be appreciated, while I am also open to any new and more efficient methods to perform this operation.
Below is what I have come up with thus far:
public static void main(String[] args) throws FileNotFoundException {
BufferedReader reader1 = new BufferedReader(new FileReader(FILENAME));
Scanner sc = new Scanner(System.in);
String line;
ArrayList<String> match = new ArrayList<>();
System.out.println("Enter characters to see which english words match: ");
String userInput = sc.next();
char arr[] = userInput.toCharArray();
int i;
try {
while ((line = reader1.readLine()) != null) {
for (i=0; i < arr.length; i++)
{
if ((line.indexOf(userInput.charAt(i)) != -1) && (line.length() == arr.length)) {
match.add(line);
}
else {
// System.out.println("no matches");
}
}
}
System.out.println(match);
}
catch (IOException e) {
e.printStackTrace();
}
**Current results: **
Words in text file:
cab
dog
god
back
dogs
quick
User input: "odg"
Program output:
[god, god, god, dog, dog, dog]
The program should return all words in the dictionary that can be made out of the string entered by the user I am managing to return both instances in this case, however, each are displayed for three times (arr.length).
First of all, interesting question. I implemented my solution and Ole V.V's solution. Here are the codes based on your post. I test the only test case you provided, not sure whether this is what you want. Let me know if it is not working as you expected.
Solution One: counting O(nk)
public static void main(String[] args) throws IOException {
BufferedReader reader1 = new BufferedReader(new FileReader(FILENAME));
Scanner sc = new Scanner(System.in);
System.out.println("Enter characters to see which english words match: ");
String userInput = sc.next();
Map<Character, Integer> counter = count(userInput);
String line;
while ((line = reader1.readLine()) != null) {
Map<Character, Integer> lineCounter = count(line);
if(lineCounter.equals(counter)) {
System.out.println(line);
}
}
}
public static Map<Character, Integer> count(String input) {
Map<Character, Integer> result = new HashMap<Character, Integer>();
for (char c: input.toCharArray()) {
result.putIfAbsent(c, 0);
result.put(c, result.get(c) + 1);
}
return result;
}
Solution Two: sorting O(nk)
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(FILENAME));
Scanner sc = new Scanner(System.in);
System.out.println("Enter characters to see which english words match: ");
String userInput = sc.next();
userInput = sort(userInput);
String line;
while ((line = reader.readLine()) != null) {
String sortedLine = sort(line);
if(sortedLine.equals(userInput)) {
System.out.println(new String(line));
}
}
}
// counting sort
public static String sort(String input) {
char c[] = input.toCharArray();
int length = c.length;
char output[] = new char[length];
int count[] = new int[256];
for (int i = 0; i < length; i++) {
count[c[i]] = count[c[i]] + 1;
}
for (int i = 1; i <= 255; i++) {
count[i] += count[i - 1];
}
for (int i = 0; i < length; i++) {
output[count[c[i]] - 1] = c[i];
count[c[i]] = count[c[i]] - 1;
}
return new String(output);
}
The standard solution to this kind of problem is: sort the characters of the user input. So odg will become dgo and back will become abck. For each word in the dictionary, do the same sorting. So cab will become abc and dog will be dgo — hey, that’s the same as the first user input, so now we know that this word should be output.
The strong point with this solution is you make sure every letter is used exactly once. It even takes duplicate letters into account: if the same letter comes twice in the user input, it will only find words that also contain that letter exactly twice.
If you like, you can prepare your word list in advance by building a map where the keys are the alphabetically sorted words and the values are lists of words that contain those same letters. So key dgo will map to a list of [dog, god]. Then you just have to sort the input and make a lookup.
I'll show you a solution that is easy to understand and implement but not the fastest available:
Possible solution: Array sorting
Treat input string and dictionary word as array of chars, sort them, then compare them:
public static boolean stringsMatchSort(String a, String b) {
// Different length? Definitely no match!
if (a.length() != b.length()) {
return false;
}
// Turn both Strings to char arrays
char[] charsA = a.toCharArray();
char[] charsB = b.toCharArray();
// Sort both arrays
Arrays.sort(charsA);
Arrays.sort(charsB);
// Compare them, if equal: match!
return Arrays.equals(charsA, charsB);
}
Note how I made the meat of your program / problem into a method. You can then easily use that method in a loop that iterates over all words of your dictionary. The method doesn't care where the words come from: a file, a collection, additional user input, the network, etc.
It also helps to simplify your program by dividing it into smaller parts, each with a smaller responsibility. This is commonly known as divide & conquer and is one of the most valuable strategies for both, new and old programmers alike, when it comes to tackling complicated problems.
Other solutions: Prime numbers, HashMaps, ...
There are other (including faster and more elegant) solutions available. Take a look at these related questions, which yours is pretty much a duplicate of:
"How to check if two words are anagrams"
"finding if two words are anagrams of each other"
Additional notes
Depending on your application, it might be a good idea to first read the dictionary into a suitable collection. This would be especially helpful if you perform multiple "queries" against the same dictionary. Or, if the dictionary is really huge, you could already strip out duplicates during the creation of the collection.
I was wondering if someone could point me in the right direction.
I have an external text file with like over 400,000 words, and the aim is to print out each word that is a palindrome, which I did, but now I am trying to figure out how to collect the 10 longest palindromes out of all the palindromes which are printed to the console, and separate the top 10, by printing them to the console as well.
If someone could get me started, I'm drawing a blank!
Here is the code I have:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Palindrome {
public static void main(String[] args) {
// store external text file into a new File object
File file = new File("dict.txt");
try {
// new Scanner object to read external file
Scanner sc = new Scanner(file);
while (sc.hasNextLine()) {
// read each word so long as there is a word on subsequent line
String word = sc.nextLine();
// if the word is a palindrome
if (isPalindrome(word)) {
// print out the palindrome word to console
System.out.println(word + " is a palindrome");
}
}
} catch(FileNotFoundException fnfe) {
// if file is not found, print error to console
System.out.println(fnfe.toString());
}
} // end main
public static boolean isPalindrome(String word) {
// if there is no word
if (word == null || word.length() == 0) {
// return false
return false;
}
// StringBuilder to hold a variable of the reverse of each word
String reverse = new StringBuilder(word).reverse().toString();
// if the reversed word equals the original word
if (reverse.equals(word)) {
// it is a palindrome
return true;
}
// return false if no palindrome found
return false;
} // end isPalindrome
} // end class Palindrome
Thanks in advance for any advice!
Sets and maps are nice, but if your word-list is long, they are expensive in memory. If you only need top-n for low n (say, n=10) the following is better on multiple counts:
// to compare strings by reverse length, and then alphabetically
private static final Comparator<String> lengthComparator = new Comparator<String>(){
public int compare(String a, String b) {
int c = b.length() - a.length();
return c==0 ? a.compareTo(b) : c;
}
};
// to update the top-n list. Pass in an empty list at the start
public static void updateTop10(String word, ArrayList<String> top, int n) {
int index = Collections.binarySearch(top, word, lengthComparator);
System.out.println("found at " + index + ": " + word);
if (index >= 0) {
// word already in list; no need to add it
return;
} else if (top.size()<n) {
// list not full - add it in
top.add(-1-index, word);
} else if (word.length() > top.get(n-1).length()) {
// larger than smallest word in list - insert into position
top.remove(n-1);
top.add(-1-index, word);
}
}
Lookup is faster than in sets (O(log(n)) - but your n is 10), not the size of the dictionary. Worst-case are inserts at the front, but moving 9 elements over is quite cheap, and probably much better than TreeMap traversal+insert.
You can, for example, collect all your palindromes in a collection and group them by size:
Map<Integer, Set<String>> palindromes = new HashMap<>();
when you find a palindrome add it there:
palindromes.computeIfAbsent(word.length(), f -> new HashSet<>()).add(word);
At the end of the loop you can find the largest keys of the Map and in the Set you have the words.
There are probably several ways to accomplish this, but the first one that comes to mind is to collect all of the palindromes into a collection, and then sort them by length to find the 10 longest.
So inside the if block call to isPalindrome, you can add the word to your collection. And then after your while loop, sort the list. I can't remember how easy/hard it is to provide custom sort rules to the default Java sort method.
There are multiple strings being passed to this program from standard input. The first int input T, is the number of test cases(Strings) being passed to this program. A string which has different alternate characters is perfect. If alternate characters are the same, you have need to delete 1 of those two characters. Basically, you have to count, how many characters, do you need to delete to get a perfect String? For example: ABABAB is pefect while AABABAA is not perfect. You need to delete 2 A's, the first one and the last one.In AAAA, you need to delete 3 A's to get a perfect string. String input can be very large. What is the fastest way to count number of such deletion? The code below, written by me, is working very slow.
public static void main(String[] args) {
Scanner scan = new Scanner (System.in);
int T= scan.nextInt();
String str;
int count=0;
for(int i=0; i<T; i++){
str=scan.next();
for(int j=0; j<str.length()-1; j++){
if(str.charAt(j)!=str.charAt(j+1)){
j+=2;
}
else{
count++;
}
}
System.out.println(count);
}
}
Before you worry about the performance, worry about whether your solution is correct. For the input ABAAB, your program returns 0, however 1 A must be removed to obtain a perfect string.
Then: what do you mean with "very large". How many characters is that? And what is "very slow"?
You will have to look at every character of the string at least once, so you will not get much faster. However, you might be able to optimize a bit. At the moment, it is possible that you look at a single character twice (once in str.charAt(j+1) and in the next iteration in str.charAt(j)). It is certainly possible to write your algorithm in such a way that every character of the string is visited exactly once. But again, you should focus on correctness before you focus on speed.
This is my working code after eliminating all the logical errors. For some test cases its execution time is up to 0.45-0.50 seconds. Can its performance be improved?
public static void main(String[] args) {
int T=0; String str;
Scanner sc = new Scanner(System.in);
T=sc.nextInt();
for(int i=0; i<T; i++){
str= sc.next();
solve(str);
}
}
public static void solve(String str){
char first, second; int count=0;
for(int i=0; i<str.length()-1; i++){
first= str.charAt(i);
second= str.charAt(i+1);
if(first==second){
count++;
}
}
System.out.println(count);
}
I want to build a program that takes inputs a set number of strings (int T) via scanner and stores them inside an arraylist. Then I want to check the input to see if it matches or contains characters from another Array.
Example Input:
1
ABCD
Example Output:
Good
Problem: When I run the code I do not get a "Good" or "Bad" output, instead I get an error and the debug console launches.
Exact Error:
Scanner.throwFor() line: not available. Source not found
import java.io.*;
import java.util.*;
public class RNA {
public static void main(String[] args) {
String X [] = {"A", "B", "C", "D"}; // Array to be checked against
List<String>A = new ArrayList(); // ArrayList to be imported
Scanner q = new Scanner(System.in);
System.out.println("How Many Sets of Strings do you want?");
int T = q.nextInt(); // number of Strings to be imported
q.nextInt(); // allows to reset Scanner
for(int i = 0 ; i < T; i ++){
A.add(q.nextLine()); //imports stuff to add to array A
}
Iterator<String> ListChecker = A.iterator();
while((ListChecker.hasNext())) { //continues as long as DNA Check has an index to go to
if (A.contains(X)) { //Checks A for X
System.out.println("Good"); //Prints out good if the check is good
}
else {
System.out.println("Bad"); //Prints out bad if the check is bad
}
}
}
}
Couple of issues:
You should use q.next(); to consume the new line character instead of q.nextInt(); which is basically you are getting input mismatch exception.
You are doing list.contains(Array) which is not supported. If you wish to check for each input from user whether its there in Array X then you should probably do something like:
List<String> list = Arrays.asList(X);
while((ListChecker.hasNext())) { //continues as long as DNA Check has an index to go to
if (list.contains(ListChecker.next())) { //Checks A for X
System.out.println("Good"); //Prints out good if the check is good
} else {
System.out.println("Bad"); //Prints out bad if the check is bad
}
}
You check if A contains an Array of String (directly the String[] object), not if it contains a String inside this array (What is inside this String[]).
Replace it with
List<String> result = Arrays.asList(X);
So you have a List from your Array, and then use contains
result.contains(A)
Your code could look like this
List<String> xAsList = Arrays.asList(X);
// [....]
while((ListChecker.hasNext())) { //continues as long as DNA Check has an index to go to
if (xAsList.contains(ListChecker.next())) { //Checks A for X
System.out.println("Good"); //Prints out good if the check is good
} else {
System.out.println("Bad");//Prints out bad if the check is bad
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
public class RNA {
public static void main(String[] args) {
String X [] = {"A", "B", "C", "D"}; // Array to be checked against
List<String>A = new ArrayList<String>(); // ArrayList to be imported
Scanner scanner = new Scanner(System.in);
System.out.println("How Many Sets of Strings do you want?");
int T = scanner.nextInt(); // number of Strings to be imported
scanner.nextLine();
for(int i = 0 ; i < T; i ++) {
String nextLine = scanner.nextLine();
A.add(nextLine); //imports stuff to add to array A
}
scanner.close();
Iterator<String> ListChecker = A.iterator();
while((ListChecker.hasNext())) { //continues as long as DNA Check has an index to go to
if (A.contains(X)) { //Checks A for X
System.out.println("Good"); //Prints out good if the check is good
}
else {
System.out.println("Bad"); //Prints out bad if the check is bad
}
ListChecker.next();
}
}
}
Try this.
instead of q.nextInt() to use q.nextLine() to reset.
Never use the same scanner for both nextInt() and nextLine(). They bug out. Use two scanners, one for ints, and one for strings. This will fix your program.
I'm working on an assignment for my programming class but I've run into some difficulty and I'm not sure where else to look. Basically the question asks that we write a program that checks for palindromes.
The user enters text (No non-alphanumberic chars allowed.)
The String is pushed one character at a time into a stack
The characters are pulled one at a time out of the stack thus reversing the String
If the original is the same as the reverse, we have a palindrome
I'm having some trouble with my loops though and don't know where to go from here, does anyone have any advice or pointers? What am I doing wrong?
Here's what I have so far.
import java.util.Stack;
import java.util.regex.*;
import javax.swing.*;
public class Question1 {
static Stack PDrome = new Stack();
public static String Reverse (String input) {
String reverse;
if (input.length() <= 1) {
return input;
}
//pushing onto the stack
for (int i=0; i<input.length();i++) {
PDrome.push(input.charAt(i));
}
//popping from the stack into the string
for (int i=0; i<input.length(); i++) {
PDrome.pop()=reverse.charAt(i);
}
return reverse;
}
//Illegal char check method
public static boolean checker (String input) {
Pattern p = Pattern.compile("[^a-z0-9]", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(input);
boolean b = m.find();
if (b) {
System.out.println("There is a special character in your string");
System.exit(0);
}
return b;
}
//Main
public static void main (String [] args) {
//input
String input = JOptionPane.showInputDialog("Enter text to check if it's a palndrome");
//error case
if (input==null); {
System.out.println("Nothing Entered");
System.exit(0);
}
//checking for illegal chars
checker(input);
}
}
This part:
String reverse;
...
//popping from the stack into the string
for (int i=0; i<input.length(); i++)
{
PDrome.pop()=reverse.charAt(i);
}
should be like this:
String reverse = "";
...
//popping from the stack into the string
for (int i=0; i<input.length(); i++)
{
// appends the popped character to reverse
reverse += PDrome.pop();
}
note that when appending a large number of string, this isn't the best way to do it since Java's string is immutable and repeatedly appending a string would require creating a new string each time. This problem is small enough that it wouldn't really matter though, but when the problem gets large you'll want to use StringBuffer/StringBuilder.
PDrome.pop()=reverse.charAt(i); is wrong.
reverse is null -> NullPointerException
Are you assigning a value to a function? (pop())
You have to build reverse from pop'ping from the stack.
So you should start with an empty string: reverse = ""; and add the chars taken from the stack:
while (!PDrome.isEmpty())
reverse += PDrome.pop();
Naming detail
Please use non capital letters to start fields and method names:
"someIntegerVariable"
"methodForCalculation"
and only capital letters to start class and interface names:
Stack
ArrayList
MyClass
:)
(from the Java conventions)
What are you actually doing here?
PDrome.pop()=reverse.charAt(i);
You should have use PDrome.pop() to retrieve one char at a time and append it to reverse.
This is a much cleaner way to write it in my opinion. It is a recursive approach.
bool isPalindrome(String s)
{
if(s.length() <= 1)
return true;
return s[0] == s[s.length() - 1] && isPalindrome(s.substr(1, s.length() - 2);
}
It is MUCH shorter as you can see.