Java - Find the next word in lexicographic order - java

Please excuse me for my formatting mistakes as I am very new here.
I have a Java assignment, in which I have to find the lexicographic lowest word that is larger then the given word from a scanner without putting the string in lexicographic order. In this example the given word is "am". I have written the code below but I have the problems that I will explain at the end of this question.
public static void main (String[] args){
Scanner s = new Scanner("I am very happy with life");
String high = "";
String o = "am";
String curr = "";
while (s.hasNext()){
curr = s.next();
if (curr.compareTo(high) > 0)
high = curr;
}
Scanner ss = new Scanner("I am very happy with life");
while (ss.hasNext()){
curr = ss.next();
if (curr.compareTo(high) < 0 && curr.compareTo(o) > 0)
high = curr;
}
System.out.println(high);
}}
My problems are:
I have to write a method that does the computation rather than having the procedure in main. Also I have to use the Scanner once and I can not initialize another scanner with the same value.
This code works ok, but I have the hardest times converting it into a single functional loop method.
PS. Sorry for stupid var names.

Something like this (using a TreeSet):
import java.util.Scanner;
import java.util.TreeSet;
public class LexicographicScanner {
private final TreeSet<String> words = new TreeSet<String>();
public LexicographicScanner( final Scanner scanner )
{
while ( scanner.hasNext() )
{
words.add( scanner.next() );
}
scanner.close();
}
public String nextWord( final String word )
{
return words.higher( word );
}
public static void main(String[] args) {
final LexicographicScanner ls
= new LexicographicScanner ( new Scanner("I am very happy with life") );
System.out.println( ls.nextWord( "am" ) );
System.out.println( ls.nextWord( "I" ) );
System.out.println( ls.nextWord( "with" ) );
}
}
Output
happy
am
null
Edit
Without a TreeSet:
public class LexicographicScanner {
public static String nextWord( final Scanner scanner, final String word )
{
String higher = null, curr;
while ( scanner.hasNext() )
{
curr = scanner.next();
if ( curr.compareTo( word ) > 0 )
{
if ( higher == null || curr.compareTo( higher ) < 0 )
higher = curr;
}
}
return higher;
}
public static void main(String[] args) {
final Scanner s1 = new Scanner("I am very happy with life");
final Scanner s2 = new Scanner("I am very happy with life");
final Scanner s3 = new Scanner("I am very happy with life");
System.out.println( nextWord( s1, "am" ) );
System.out.println( nextWord( s2, "I" ) );
System.out.println( nextWord( s3, "with" ) );
s1.close();
s2.close();
s3.close();
}
}

First make some requirements:
The word i am looking for is lexicographic higher than my input word
The word i am looking for is the lexicographic lowest possible
So basically you have to walk over your input sentence word for word and check those two requirements. Here is some pseudo code, i hope this helps to understand your problem/this solution.
inputWord <= input
currentlyHighest <= null
for (word <= sentence) {
is word higher than inputWord?
no: discard word and analyze the next one
yes: go on
do i have a currently highest word?
no: save the word in currentlyHighest and analyze the next word
yes: go on
is word lower than currentlyHighest?
no: discard word and analyze the next one
yes: we have found a better match: save word in currentlyHighest and analyze the next one
}

Hint:
String res = null;
Scanner s = new Scanner(str);
for each curr in s scanner {
if (curr greater than given
and (dont have res or curr is less than res)) {
res = curr;
}
}

Related

Why do I get a out of bounds message when I try to run this code?

I am trying to match a pattern . Everything works except when I try to add a string like "1??2" with 2 "?" instead of 3 "?" I get the following error:"String index out of range: 4".
Please see my code below:
import java.util.Scanner;
import java.util.regex.*;
public class pattern {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
String str, result="";
int myArray = 0;
System.out.println("Enter a string: ");
str =in.next();
String REGEX = "[0-9]\\?{3}[0-9]";
Pattern pattern =Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(str);
boolean matches =matcher.matches();
if (matches = true) {
result=str;
} else {
System.out.print("False");
}
int resultLen= result.length();
int sum=0;
for (int i=0; i <resultLen-1; i++) {
char newChar=result.charAt(i);
int first= result.charAt(0)-'0';
int last=result.charAt(4)-'0';
sum=first+last;
}
System.out.print(sum==10? "True": "False");
}
}
Corrected code based on the comments by Elliot Frisch:
public static void main( String... args )
{
System.out.println( "Enter a string: " );
final var in = new Scanner( System.in );
final var str = in.next();
final var regex = "[0-9]\\?{3}[0-9]";
final var pattern = Pattern.compile( regex );
final var matcher = pattern.matcher( str );
if( matcher.matches() )
{
final var first = Character.getNumericValue( str.charAt( 0 ) );
final var last = Character.getNumericValue( str.charAt( 4 ) );
final var sum = first + last;
System.out.print( sum == 10 ? "True" : "False" );
}
else
{
System.out.print("False");
}
}
In the original code there was an assignment instead of a comparison:
…
boolean matches = matcher.matches();
if( matches = true ) // WRONG!
{
…
instead of
…
boolean matches = matcher.matches();
if( matches == true )
{
…
or
…
boolean matches = matcher.matches();
if( matches )
{
…
Next, the original program proceeded even the given input string did not match the regular expression, with the result that an exception could be thrown in such case.
Finally, the loop did not have any impact on the final value of sum, and was therefor superfluous.
Also several local variables were obsolete; they did not even support readability.
And that hack with substracting '0' to get the numeric value works, but is not intuitive; it also works only for digits in the ASCII realm.

Hacker Rank Java String Tokens

I'm working on the Java String Tokens on HackerRank. My code is as following:
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
// Write your code here.
scan.close();
// if length is 0
if (s.length() == 0 || s == null) {
System.out.println(0);
return;
}
// It seems we need to remove some spaces
s = s.trim();
String[] words = s.split("[ |!|,|\\?|\\.|_|'|#|]+");
System.out.println(words.length);
for (String word: words){
System.out.println(word);
}
}
}
It has passed most tests but failed when the input is null. I've attached a screenshot in this question:
So, can anyone plz explain what happened here? And how can I fix it?
Thank you so much!
Regex "[ |!|,|\\?|\\.|_|'|#|]+" is extraneous.
Do not separate characters in a [ ] character class by the | OR pattern, since that pattern only applies outside a character class.
There is no need to escape ? and . in a character class, since they are not special characters there.
Correct regex would be [ !,?._'#]+ or [^A-Za-z]+.
The main problem with the code in the question is that split() may return an array where the first element is an empty string.
Example 1: Input ",X," will return ["", "X"]. The empty string before the leading , is included, and the empty string after the trailing , is excluded, because the javadoc says so: "Trailing empty strings are therefore not included in the resulting array".
Example 2: Input "" will return [""], because the javadoc explicitly says so: "If the expression does not match any part of the input then the resulting array has just one element, namely this string". Note how the "trailing empty string" rule is not applied to this specific use case.
Example 3: Input ",," will return [], because trailing empty strings are excluded.
In examples 1 and 2, that leading empty string should be ignored.
I'll leave the actual fixing of the code to you, since this is your challenge to solve.
if (scan.hasNext()) {
s = scan.nextLine();
} else {
System.out.println(0);
return;
}
I edited your code a bit. For no String you have to use Scanner.hasNext(). If there is a String you will read it, otherwise just return and print 0.
The solution success with all test case
package com.example;
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
if (s.length() > 1 && s.length() < 400000) {
String textFiltered = s.trim();
if (textFiltered.length() > 0) {
String[] words = textFiltered.split("[!,?.*_'#\\ ]+");
int count = words.length;
System.out.println(count);
for (String word : words) {
System.out.println(word);
}
} else {
System.out.println(0);
}
} else {
System.out.println(0);
}
scan.close();
}
}
The issue is with .trim(), move it before s.length()
my working code
import java.util.*;
public class StringTokens {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
// Write your code here.
s = s.trim();
// if length is 0
if (s.length()>400000){
return ;
}else if (s.length()==0 || s == null){
System.out.println(0);
return ;
}else{
// It seems we need to remove some spaces
String[] words = s.split("[!,?.*_'#\\ ]+");
int count = words.length;
System.out.println(count);
for (String word : words){
System.out.println(word);
}
scan.close();
}
}
Need remove leading empty element in tokens array.
private static String[] getTokens(String s) {
if (s == null || s.isEmpty()) {
return new String[0];
}
String[] tokens = s.trim().split("[^a-zA-Z]+"); // or [^A-Za-z]+
if (tokens != null && tokens.length > 0 ) {
if (tokens[0].isEmpty()) {
return Arrays.copyOfRange(tokens, 1, tokens.length);
} else {
return tokens;
}
}
return new String[0];
}

How to remove duplicate words in string without using array?

Is there any way we can remove duplicate words from a String without using Arrays?
For example, I have this sentence "this is java programming program",
and the output have to be "this java programming".
I see similar remove duplicate problems but all of them are using arrays.
well, in Java, Strings are actually objects wrappers for character arrays which primarily add immutability.
so, there is no actual way to not use arrays for your task.
even if you wrap your head around a solution which doesn't use any direct array creation in the code implementation, you will still be using arrays behind the scenes (if you want your solution to be optimal).
Remove duplicate words from a given string using simple way
package inffrd;
public class Q001
{
public static void removeduplicate(String input)
{
//convert the string to array by splitting it in words where space comes
String[] words=input.split(" ");
//put a for loop for outer comparison where words will start from "i" string
for(int i=0;i<words.length;i++)
{
//check if already duplicate word is replaced with null
if(words[i]!=null)
{
//put a for loop to compare outer words at i with inner word at j
for(int j =i+1;j<words.length;j++)
{
//if there is any duplicate word then make is Null
if(words[i].equals(words[j]))
{
words[j]=null;
}
}
}
}
//Print the output string where duplicate has been replaced with null
for(int k=0;k<words.length;k++)
{
//check if word is a null then don't print it
if(words[k]!=null)
{
System.out.print(words[k]+" ");
}
}
}
public static void main(String[] args)
{
String s1="i am dinesh i am kumar";
Q001.removeduplicate(s1);
}
}
Below is the updated code #Han
public class RemDup
{
public static void main ( String[] args )
{
String sentence = "this is java programming program progress";
int max_word_length = sentence.length()/2;
int min_word_length = 2;
while(max_word_length>=min_word_length)
{
int si = 0;
int ei = max_word_length;
while ( ei<sentence.length() )
{
int e=ei;
while ( e<sentence.length() )
{
int ind = sentence.indexOf ( sentence.substring ( si, ei ),e );
if ( ind!=-1 )
{
if(
sentence.substring(ind-1,ind).equals(" ")
&((ind+max_word_length)>=sentence.length()||
sentence.substring(ind+max_word_length,ind+max_word_length+1).equals(" "))
)
{
sentence = sentence.substring ( 0,ind ) +sentence.substring ( ind+max_word_length,sentence.length() );
}
e=ind+max_word_length;
}
else break;
}
si+=1;
ei+=1;
}
max_word_length--;
}
System.out.println(sentence);
}
}
Below code will help you :)
public class RemDup
{
public static void main ( String[] args )
{
String sentence = "this is java programming program";
int max_word_length = sentence.length()/2;
int min_word_length = 2;
while(max_word_length>=min_word_length)
{
int si = 0;
int ei = max_word_length;
while ( ei<sentence.length() )
{
int e=ei;
while ( e<sentence.length() )
{
int ind = sentence.indexOf ( sentence.substring ( si, ei ),e );
if ( ind!=-1 )
{
sentence = sentence.substring ( 0,ind ) +sentence.substring ( ind+max_word_length,sentence.length() );
e=ind+max_word_length;
}
else break;
}
si+=1;
ei+=1;
}
max_word_length--;
}
System.out.println(sentence);
}
}

how to search for keywords in strings

I need to do some keywords search and print if true.
works fine if i am comparing in order. but i want to
compare the following cases and expect them to be true.
do some java programming = true
some java = true
do programming = true
and finally most importantly
programming java = true
programming java some do = true
I need to return true for all the cases mentioned above but so far it only works for case 1 and 2
public class Examples {
public static void main(String[] args) {
String[] given = new String[20];
given[0] = ("do some java programming");
given[1] = ("do some grocery shopping");
given[2] = ("play soccer at the west field");
String input = new String();
Scanner userInput = new Scanner(System.in);
System.out.println("Enter the string to compare");
input[0] = userInput.nextLine();
for (int i=0; i <20; i++){
if(given[i].contains(input))
{
System.out.println(given[i]);
}
else
{
//do nothing
}
}
}
}
Outline of one way to solve this:
Each string in given should be converted to a Set<String> that is a set of all the words in the string. Use split() on each string to get the words, then go through the list of words and add each word to the Set.
For each input string, use split() to split it into words, then create any kind of collection (a Set<String> will work, but creating a List<String> by using Arrays.asList works too.
You can then see if the collection of words from the input is a subset of the set of words in each given string by using a Set's containsAll method.
(Note that you'll have to make sure the input string isn't the empty set first. Also, if the input string has more than one occurrence of any word, this approach won't catch that, without some extra logic.)
For this Regex will be your friend.
Here's some working code to play with:
String[] matches = input[0].split(" ");
for (int i=0; i <3; i++){
for(String s: matches){
if(given[i].contains(s))
System.out.println(given[i]);
break;
}
}
}
Split the given lines and store it in a List.
Again split the input line and compare word by word.
Below is the code snippet
public class StringCompare
{
public static final String delimiter = " ";
public static void main( String[] args )
{
String[] given = new String[20];
given[ 0 ] = ( "do some java programming" );
given[ 1 ] = ( "do some grocery shopping" );
given[ 2 ] = ( "play soccer at the west field" );
List< List< String >> listLineAsWords = new ArrayList< List< String >>();
//split each line and store it as list.
for ( String line : given )
{
if ( line == null )
break;
listLineAsWords.add( Arrays.asList( line.split( delimiter ) ) );
}
//Write your own logic to get the input line
String inputLine = "programming java";
if ( compareLine( inputLine, listLineAsWords ) )
System.out.println( "The input line is part of given lines" );
}
private static boolean compareLine( String inputLine, List< List< String >> listLineAsWords )
{
if ( inputLine == null )
return false;
List< String > words = Arrays.asList( inputLine.split( delimiter ) );
for ( List< String > listOfWords : listLineAsWords )
{
boolean isPartOfLine = true;
for ( String word : words )
{
if ( !listOfWords.contains( word ) )
{
isPartOfLine = false;
break;
}
}
if(isPartOfLine)
return true;
}
return false;
}
}
Your code is almost right, yet it needs some changes
First, since in your sample code you have 3 case, it is best to define your given array length 3.
String[] given = new String[3];
Note: for more cases, you can define bigger array length; for example, if you will add other 2 cases, your array length is 5
For all reference types, the default value is null if you have array length more than you need.
read more about it here
Second, in your if statement, you want to check if input contains given element of array or not
if (input.contains(given[i])) {
code:
String[] given = new String[3];
given[0] = ("do some java programming");
given[1] = ("do some grocery shopping");
given[2] = ("play soccer at the west field");
Scanner userInput = new Scanner(System.in);
System.out.println("Enter the string to compare");
String input = userInput.nextLine();
for (int i = 0; i < given.length; i++) {
if (input.contains(given[i])) {
System.out.println(given[i]);
} else {
// System.out.println("do nothing");
}
}
output:
Modify as below assuming everything else is fine
//here initialize 'given' array
//get the user input in a string that is 'input[0]' in your case
int count = 0;
for (String s : given) {
if (s != null && s.matches(input[0])) {
//it matches and print it
} else {
//either it's not a match or the 'given' array has a null at this index
}
count++;
}
I must say, get the user input in a string. I don't understand why you have it in input array.

find two words with the same hash code in a large file - weird output

I tried to find two words with the same hash code in /usr/share/dict/words on Ubuntu 12.04.
Trying keep Map<Integer, HashSet<String>>.
After reading word compute his hash code h and put the word in the set whose key is h.
Then iterate through all keys and print the sets whose size is > 1.
But I saw very weird output after running.
Code:
public static void main(String[] args) throws FileNotFoundException {
HashSet<String> fileWords = new HashSet<>();
Map<Integer, HashSet<String>> duplicats = new HashMap<>();
Scanner scan = new Scanner(new File("/usr/share/dict/words"));
while (scan.hasNext()) {
String word = scan.nextLine();
int h = word.hashCode();
fileWords.add(word);
duplicats.put(new Integer(h), fileWords);
}
Set<Integer> keySet = duplicats.keySet();
for (Integer key : keySet) {
HashSet<String> value = duplicats.get(key);
if (value.size() > 1) {
System.out.println(key + " : " + value.toString());
}
}
}
Output:
21917608 : [repaying, Zubenelgenubi, treason, indignation, eyetooth, ....// a lot of words
It looks very weird. I can't figure out what is wrong?
Update:
I've found solution:
public static void main(String[] args) throws FileNotFoundException {
Map<Integer, HashSet<String>> duplicats = new HashMap<>();
Scanner scan = new Scanner(new File("/usr/share/dict/words"));
while (scan.hasNext()) {
String word = scan.nextLine();
int h = word.hashCode();
if (!duplicats.containsKey(h))
{
HashSet<String> newSet = new HashSet<>();
newSet.add(word);
duplicats.put(new Integer(h), newSet);
}
else
{
duplicats.get(h).add(word);
}
} /// rest the same
How to solve this trouble?
HashSet<String> fileWords = new HashSet<>();
You instantiate just a single set and add all your words into it.
You must add logic which will:
check whether there is already a set under your current hashcode key;
if there is, just add the word to it;
if not, create a new set, add the word, and put it into the map.
The way you have it now, you are putting the same set under all the map keys.
I don't quite understand the purpose of your code, but in duplicats you are mapping each hashCode to the set of all Strings in the file (fileWords). And then displaying it. The following code works as it could be expected.
public static void main(String[] args) throws FileNotFoundException {
Map<Integer,HashSet<String>> duplicats= new HashMap<Integer, HashSet<String>>() ;
Scanner scan = new Scanner(new File("C:\\Downloads\\Software\\sourceforge.net\\souptonuts\\dictionary\\linuxwords.1\\linux.words"));
while( scan.hasNext() ) {
String word= scan.nextLine() ;
int hc= new Integer( word.hashCode() ) ;
HashSet<String> count= duplicats.get( hc ) ;
if( count == null ) {
count= new HashSet<String>() ;
duplicats.put(hc, count ) ;
}
count.add( word );
}
int nonCollisionHashCodes= 0 ;
int singleCollisionHashCodes= 0 ;
int doubleCollisionHashCodes= 0 ;
for(Entry<Integer, HashSet<String>> e : duplicats.entrySet() ) {
if( e.getValue().size() <= 1 ) {
nonCollisionHashCodes++;
} else if( e.getValue().size() <= 2 ) {
singleCollisionHashCodes++;
} else if( e.getValue().size() <= 3 ) {
doubleCollisionHashCodes++;
} else {
System.out.println(e.getKey() + " : " + e.getValue().size());
}
}
System.out.println("Number of non-collision hashCodes: "+ nonCollisionHashCodes );
System.out.println("Number of single-collision hashCodes: "+ singleCollisionHashCodes );
System.out.println("Number of double-collision hashCodes: "+ doubleCollisionHashCodes );
}
At least for my dictionary, output is:
Number of non-collision hashCodes: 626167
Number of single-collision hashCodes: 885
Number of double-collision hashCodes: 6
Note that there is no output for more than double-collision hashCodes.
To my taste, these stats are pretty good. Try it with your dictionary and post your results.

Categories