Printing out longest palindromes in list - java

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.

Related

How to Find the word that comes after a specified word in java String

My program has a String inputted Eg. hello i am john who are you oh so i see you are also john i am happy
my program then has a keyword inputted Eg. i (the program doesn't like capitals or punctuation yet)
then it reads the initial String and finds all the times it mentions the keyword + the word after the keyword, Eg. i am, i see, i am.
with this is finds the most common occurrence and outputs that second word as the new keyword and repeats. this will produce
i am john/happy (when it comes to an equal occurrence of a second word it stops (it is meant to))
What i want to know is how i find the word after the keyword.
package main;
import java.util.Scanner;
public class DeepWriterMain {
public static void main(String[] args) {
String next;
Scanner scanner = new Scanner(System.in);
System.out.println("text:");
String input = scanner.nextLine();
System.out.println("starting word:");
String start = scanner.nextLine();
input.toLowerCase();
start.toLowerCase();
if (input.contains(start)) {
System.out.println("Loading... (this is where i find the most used word after the 'start' variable)");
next = input.substring(5, 8);
System.out.println(next);
}else {
System.out.println("System has run into a problem");
}
}
}
If you use split to split all your words into an array, you can iterate through the array looking for the keyword, and if it is not the last in the array, you can print the next word
String arr [] = line.split(" ");
for (int i = 0; i < arr.length -1; i++) {
if (arr[i].equalsIgnoreCase(keyword)) {
sop(arr[i] + " " arr[i + 1]);
}
if it is not the last in the array, iterate only to length - 1
The String class includes a method called public int indexOf(String str). You could use this as follows:
int nIndex = input.indexOf(start) + start.length()
You then only need to check if nIndex == -1 in the case that start is not in the input string. Otherwise, it gets you the position of the first character of the word that follows. Using the same indexOf method to find the next space provides the end index.
This would allow you to avoid a linear search through the input, although the indexOf method probably does one anyway.

Palindrome using three stacks - only output is "is a palindrome" (java logical error)

i've been looking at every post with the word palindrome, but i haven't come across any with the same sort of issue i'm having...
my goal is to identify palindromes using three stacks - when "madam" is inputted, the output should be "madam is a palindrome" and when "orange" is inputted, the output should be "orange is not a palindrome". i am only able to get the "...is a palindrome" output, no matter what
i'm trying to follow the following algorithm:
push every character into original stack and temporary stack
pop every character off temporary stack and push character into new stack (reverse the order)
compare original stack to reversed stack
the thought process behind this is that every time one of the characters in the original stack don't match the reversed stack, the variable mismatches is incremented and if there is more than zero mismatches, the word entered is a palindrome
here is the code:
import java.util.Scanner;
import java.util.Stack;
public class Palindrome {
public static boolean is_palindrome(String input) {
Stack<Character> original = new Stack<Character>();
Stack<Character> reversedStack = new Stack<Character>();
Stack<Character> tempStack = new Stack<Character>();
Character letter; //one character from the input string
int mismatches = 0; //number of spots that mismatched
int index; //index for the input string
for(index = 0; index < input.length(); index++) {
letter = input.charAt(index);
if(Character.isLetter(letter)) {
original.push(letter);
tempStack.push(letter);
}
reversedStack.push(tempStack.pop());
}
while(!original.isEmpty()) {
if(!original.pop().equals(reversedStack.pop())) { mismatches++; }
}
return (mismatches == 0);
}
//main() method, used for testing program
#SuppressWarnings("resource")
public static void main(String[] args) {
Scanner input = new Scanner(System.in); //user input
String word; //one input line
do {
System.out.print("Enter a word: ");
word = input.nextLine();
if(is_palindrome(word)) { System.out.println(word + " is a palindrome."); }
else { System.out.println(word + " is not a palindrome."); }
break;
} while(word.length() != 0);
}
}
any hints as to why this is only printing "...is a palindrome"?
Let's assume that the input is all letters. Then, your initial for loop will:
Push the letter onto original.
Push the letter onto tempStack.
Pop tempStack, and push that onto reversedStack.
In other words, that's just a silly way to do:
Push the letter onto original
Push the letter onto reversedStack
tempStack remains empty.
Clearly not what you want. You need a new, separate while loop for the 'pop tempStack and push into reversedStack' feature.
NB: As a sidenote, this is a crazy complicated algorithm to do the job, but presumably the assignment is to learn about stacks, and to do so by doing a Rube Goldberg machine job. Just in case that wasn't the point, this can be done near trivially by simply looping once, from 0 to half the input length, and comparing the char at index i with the char at index len - i. The entire methods can fit in 4 lines and takes zero objects to get the job done.
You do not need three stacks. It can be solved using a single stack.
Push each character to a Stack.
Compare the popped characters with the characters of the string from the beginning. Return false as soon as a mismatch is found; otherwise, return true if all characters match.
Demo:
import java.util.Stack;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(isPallindrome("madam"));
System.out.println(isPallindrome("orange"));
}
static boolean isPallindrome(String s) {
Stack<Character> stack = new Stack<>();
char[] arr = s.toCharArray();
for (char c : arr) {
stack.push(c);
}
for (char c : arr) {
if (c != stack.pop()) {
return false;
}
}
return true;
}
}
Output:
true
false
However, if you are free to use any other way to solve it, given below is a simpler way:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(isPallindrome("madam"));
System.out.println(isPallindrome("orange"));
}
static boolean isPallindrome(String str) {
return new StringBuilder(str).reverse().toString().equals(str);
}
}
Output:
true
false
This is extremely complicated approach! You can decide whether a word is palindrome in just one for loop (and you have to go through just half the word) - compare chars at index i and index length - i, go through Math.floor(wordLength / 2) chars and if you have one mismatch, it's not palindrome - break loop and print fail...

How to make this code become more effcient?

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) {
...

split method not sperating special characters

I'm working a program that counts the accurrences of words in a text file. The program compiles and runs fine, but I'm tryting to use the split method to seperate special characters such as .,;:!?(){} from the words.
here is an output example
6 eyes,
3 eyes.
2 eyes;
1 eyes?
1 eyrie
As you can see the split fuction is not working. I have tried debugging, but no luck so far. Can anythone point me out to the right direction or tell me what I'm doing wrong. Thank you.
import java.util.*;
import java.io.*;
public class testingForLetters {
public static void main(String[] args) throws FileNotFoundException {
// open the file
Scanner console = new Scanner(System.in);
System.out.print("What is the name of the text file? ");
String fileName = console.nextLine();
Scanner input = new Scanner(new File(fileName));
// count occurrences
Map<String, Integer> wordCounts = new TreeMap<String, Integer>();
while (input.hasNext()) {
input.next().split("[ \n\t\r.,;:!?(){}]" );
String next = input.next().toLowerCase();
if (next.startsWith("a") || next.startsWith("b") || next.startsWith("c") || next.startsWith("d") || next.startsWith("e") ) {
if (!wordCounts.containsKey(next)) {
wordCounts.put(next, 1);
} else {
wordCounts.put(next, wordCounts.get(next) + 1);
}
}
}
// get cutoff and report frequencies
System.out.println("Total words = " + wordCounts.size());
for (String word : wordCounts.keySet()) {
int count = wordCounts.get(word);
System.out.println(count + "\t" + word);
}
}
}
The .split() method returns an array of strings, and right now you aren't setting input.next().split() equal to anything. You have to create an array and set it equal to input.next().split(), and then get the word(s) from the array. You basically need to handle it exactly like you handled the .toLowerCase() part where you set String next = input.next().toLowerCase(). Hope this helps.

if statement not adding value to my counter in word count program

I have a java program that reads a txt file and counts the words in that file. I setup my program so the String read from the txt file is saved as an ArrayList, and my variable word contains that ArrayList. The issue with my code is that my if statement does not seem to add a value to my count variable each time it detects space in the word string, it seems to only run the if statement once. How can I make it so the if statement finds a space, adds a +1 to my counter value, removes the space, and looks for the next space in the word variable's string? Here is the code:
import java.io.*;
import java.util.*;
public class FrequencyCounting
{
public static void main(String[] args) throws FileNotFoundException
{
// Read-in text from a file and store each word and its
// frequency (count) in a collection.
Scanner inputFile = new Scanner(new File("phrases.txt"));
String word= " ";
Integer count = 0;
List<String> ma = new ArrayList<String>();
while(
inputFile.hasNextLine()) {
word = word + inputFile.nextLine() + " ";
}
ma.add(word);
System.out.println(ma);
if(word.contains(" ")) {
ma.remove(" ");
count++;
System.out.println("does contain");
}
else {
System.out.println("does not contain");
}
System.out.println(count);
//System.out.println(ma);
inputFile.close();
// Output each word, followed by a tab character, followed by the
// number of times the word appeared in the file. The words should
// be in alphabetical order.
; // TODO: Your code goes here.
}
}
When I execute the program, I get a value of 1 for the variable count and I get a returned string representation of the txt file from my phrases.txt
phrases.txt is :
my watch fell in the water
time to go to sleep
my time to go visit
watch out for low flying objects
great view from the room
the world is a stage
the force is with you
you are not a jedi yet
an offer you cannot refuse
are you talking to me
Your if statement is not inside any loop, so it will only execute once.
A better approach, which would save a shit ton of runtime, is to read each line like you already do, use the String.split() method to split it on spaces, then add each element of the returned String[] to your list by using the ArrayList.addAll() method (if that one exist, otherwise (optionally, ensure the capacity and) add the elements one by one).
Then count by using the ArrayList.size() method to get the number of elements.
Based on the comments in your code :
// Read-in text from a file and store each word and its
// frequency (count) in a collection.
// Output each word, followed by a tab character, followed by the
// number of times the word appeared in the file. The words should
// be in alphabetical order.
My understanding is that you need to store count for every word, rather having a total count of words. For storing count for every word which should be stored itself in alphabetical order, it is better to go with a TreeMap.
public static void main(String[] args) {
Map<String, Integer> wordMap = new TreeMap<String, Integer>();
try {
Scanner inputFile = new Scanner(new File("phrases.txt"));
while(inputFile.hasNextLine()){
String line = inputFile.nextLine();
String[] words = line.split(" ");
for(int i=0; i<words.length; i++){
String word = words[i].trim();
if(word.length()==0){
continue;
}
int count = 0;
if(wordMap.containsKey(word)){
count = wordMap.get(word);
}
count++;
wordMap.put(word, count);
}
}
inputFile.close();
for(Entry<String,Integer> entry : wordMap.entrySet()){
System.out.println(entry.getKey()+"\t"+entry.getValue());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
What is your goal here ? Do you just want to read the file and count numbers of words?
You need to use a while loop instead of an if statement that'll just run once. Here's a better way to do what you want to do:
Scanner inputFile = new Scanner(new File("phrases.txt"));
StringBuilder sb = new StringBuilder();
String line;
int totalCount = 0;
while(inputFile.hasNextLine()) {
line = inputFile.nextLine();
sb.append(line).append("\n"); // This is more efficient than concatenating strings
int spacesOnLine = countSpacesOnLine(line);
totalCount += spacesOnLine;
// print line and spacesOnLine if you wish to here
}
// print text file
System.out.println(sb.toString());
// print total spaces in file
System.out.println("Total spaces" + totalCount);
inputFile.close();
Then add a method that counts the spaces on a line:
private int countSpacesOnLine(String line) {
int totalSpaces = 0;
for(int i = 0; i < line.length(); i++) {
if (line.charAt(i) == ' ')
totalSpaces += 1;
}
return totalSpaces;
}
You can achieve your objective with the following one liner too:
int words = Files.readAllLines(Paths.get("phrases.txt"), Charset.forName("UTF-8")).stream().mapToInt(string -> string.split(" ").length).sum();
probably I am late, but here is c# simple version:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace StackOverflowAnswers
{
class Program
{
static void Main(string[] args)
{
string contents = File.ReadAllText(#"C:\temp\test.txt");
var arrayString = contents.Split(' ');
Console.WriteLine("Number of Words {0}", arrayString.Length);
Console.ReadLine();
}
}
}

Categories