Method that checks if a parameter has occurred in a hashmap(Key) - java

I have two parameters represent two case-sensitive words that might have been found in a document. I need a method that must return true if the first parameter has occurred at least once in the document and was immediately followed at least once by the second word. Otherwise it must return false.
Here is my code.
public boolean nextTo(String firstInput, String secondInput) {
Iterator it = Words.keySet().iterator();
while (it.hasNext() == true)
{
it.next();
if (Words.containsKey(firstInput))
{
if(Words.higherKey(secondInput))
{
return true;
}
}
}
return false;

Solution 1:
Represent the document as a String[] and just iterate the words in the document. When you see firstInput, test that the next word is secondInput.
Solution 2:
Create a reverse index for the document; i.e. a Map<String, int[]> where the String keys are the words and the int[] values contain the indexes for each occurrence of the word in the document.
Populate the reverse index from the document.
Then, to find if firstInput followed by secondInput:
int[] fi = reverseIndex.get(firstInput);
int[] si = reverseIndex.get(secondInput);
if (fi == null || si == null) {
return false;
}
for (int i = 0; i < fi.length; i++) {
for (int j = 0; j < si.length; j++) {
if (fi[i] == si[j] - 1) {
return true;
}
}
}
return false.

Related

Can't find the problem with my solution to leetcode problem

I am trying the ransom note challenge:
Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.
Each letter in magazine can only be used once in ransomNote.
Example 1:
Input: ransomNote = "a", magazine = "b"
Output: false
Example 2:
Input: ransomNote = "aa", magazine = "ab"
Output: false
Example 3:
Input: ransomNote = "aa", magazine = "aab"
Output: true
here is my solution:
public static boolean canConstruct(String ransomNote, String magazine) {
ArrayList<Character> ransomChar = new ArrayList<Character>();
ArrayList<Character> magazineChar = new ArrayList<Character>();
if (ransomNote.length() == 1 && magazine.length() == 1) {
if (ransomNote.equals(magazine)) {
return true;
}
return false;
}
else if (ransomNote.length() == 1 && magazine.length() > 1) {
for (int i = 0; i < magazine.length(); i++) {
if (magazine.charAt(i) == ransomNote.charAt(0)) {
return true;
}
}
return false;
}
else if (ransomNote.length() > 1 && magazine.length() > 1) {
for (int i = 0; i < ransomNote.length(); i++) {
ransomChar.add(ransomNote.charAt(i));
}
for (int i = 0; i < magazine.length(); i++) {
magazineChar.add(magazine.charAt(i));
}
while (ransomChar.size() > 1) {
for (int i = 0; i < ransomChar.size(); i++) {
boolean flag = false;
for (int j = 0; j < magazineChar.size(); j++) {
if (ransomChar.get(i).equals(magazineChar.get(j))) {
ransomChar.remove(i);
magazineChar.remove(j);
flag = true;
}
else if (ransomChar.isEmpty()) {
return true;
}
}
if (!flag) {
return false;
}
}
}
if (ransomChar.size() == 1 && magazineChar.size() == 1) {
if (ransomChar.equals(magazineChar)) {
return true;
}
return false;
}
else if (ransomChar.size() == 1 && magazineChar.size() > 1) {
for (int i = 0; i < magazineChar.size(); i++) {
if (ransomChar.get(0).equals(magazineChar.get(i))) {
return true;
}
}
return false;
}
}
return false;
}
I am passing most test cases but it throws an error at input:
"bg"
"efjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"
It throws error:
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at line: if (ransomChar.get(i).equals(magazineChar.get(j)))
Here's a simple way to attack your problem by building a set of candidate characters from magazine. Once you've done that, you just iterate over the ransomNote, checking the set for each character. If you find it, you remove it from the set. If you don't, then you return false. If you make it all the way through, you return true. You need to use a MultiSet because you need to be able to represent multiple copies of the same character in the magazine.
Here's how to do that:
public static boolean canConstruct(String ransomNote, String magazine) {
MultiSet<Character> magazineChars = new HashMultiSet<>();
for (int i = 0; i < magazine.length(); i++)
magazineChars.add(magazine.charAt(i));
for (int i = 0 ; i < ransomNote.length(); i++) {
Character c = ransomNote.charAt(i);
if (magazineChars.contains(c))
magazineChars.remove(c);
else
return false;
}
return true;
}
On each iteration of this loop:
for (int i = 0; i < ransomChar.size(); i++) {
boolean flag = false;
for (int j = 0; j < magazineChar.size(); j++) {
if (ransomChar.get(i).equals(magazineChar.get(j))) {
ransomChar.remove(i);
magazineChar.remove(j);
flag = true;
}
else if (ransomChar.isEmpty()) {
return true;
}
}
if (!flag) {
return false;
}
}
, you know that i is initially less than ransomChar.size(), so that it is safe to perform ransomChar.get(i).
However, the inner loop may remove one (or more!) elements of ransomChar, after which it may no longer be true that i is less than ransomChar.size(). The inner loop continues to iterate, and as a result, it can attempt to retrieve an element of ransomChar that does not exist.
Honestly, the code overall is a mess. Other than this specific issue,
I see no need why you need special cases for all the variations on sizes of note and magazine. I think you might write better code for this if you devoted some effort to designing an approach that just works correctly for all cases.
you are not making good use of the available features of the classes you are using
you are not making good use of general Java language features that would be applicable.
For example, I might write that particular loop as:
for (Character c : ransomChar) {
if (!magazineChar.remove(c)) {
return false;
}
}
return true;
And that's before we come to the fact that you've chosen a suboptimal algorithm. Its execution time will scale as note size * magazine size, whereas there are alternatives that will scale as note size + magazine size, instead. That may in fact be important, because choice of an efficient algorithm is one thing that the test cases for coding challenges such as this often try to detect.
Please find small and simple solution with Time complexity O(n) and Space complexity O(256) or O(1)
int[] count = new int[256];
for (char c : magazine.toCharArray()) {
count[c]++;
}
for (char c : ransomNote.toCharArray()) {
if (count[c]-- == 0) return false;
}
return true;
Result
#Harsh so you are trying to access the element of ransomChar which do not even exists. look at the lines
if (ransomChar.get(i).equals(magazineChar.get(j))) {
ransomChar.remove(i);
magazineChar.remove(j);
flag = true;
}
you are removing the elements from the lists and and every time you remove the elements from the list their indexing changes and and when it rechecks the condition the list is already empty after several iteration. Hence giving the run time error. to avoid this you should check whether the list is empty or not , first (you are checking it after).

Duplicate output in Java

I'm new here and still learning. Today I learn find duplicate in string. From https://www.javatpoint.com/program-to-find-the-duplicate-characters-in-a-string, I try to learn complete code from web.
When string = "Great responsibility" the output will be:
Duplicate characters in a given string:
r
e
t
s
i
because it has duplicate character r e t s i
And when string is "great" the output is
Duplicate characters in a given string:
The output is blank because there are no duplicate characters, so I give a description "no duplicate" to define no character duplicate and the output goes like this
Duplicate characters in a given string:
no duplicates
no duplicates
no duplicates
no duplicates
no duplicates
This returns too many descriptions.
My code
public class DuplicateCharacters {
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0')
System.out.println(string[i]);
else
System.out.println("no duplicates");
}
}
}
How can I print only one description without repetition? I tried return 0; but it does not work.
Expected output
Duplicate characters in a given string:
no duplicates
Separate the logic for finding duplicates from how you report the findings to the user. Move the logic for finding the duplicates into a method. Pass the results of that output to another method. The main method invokes the first and passes the output to the second.
public static void main(String[] args) {
String s = .... whatever you are searching for duplicates in ....
reportDuplicates(findDuplicates(s)):
}
public static List<Character> findDuplicates(String s) {
... returns a List containing duplicates ...
}
public static void reportDuplicates(List<Character> duplicates) {
if (null == duplicates || duplicates.isEmpty()) {
... report no duplicates ...
} else {
... output the duplicates
}
}
Add a flag to your program that indicates whether there are duplicates or not. And after loop check whether this flag is true or false.
This method would look like below. I commented code where I updated it.
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
// here is flag added
boolean noDuplicates = true;
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0') {
System.out.println(string[i]);
//here is flag updated if duplicates are found
noDuplicates = false;
}
}
//here is flag check
if (noDuplicates) {
System.out.println("no duplicates");
}
}
And btw. Your algorithm has O(n^2) time complexity. You can figure out one that is better ;-)
It's normal your System.out.println("no duplicates"); is in your loop so each time a character is not duplicate you print "no duplicates".
You can defined a boolean that will become true if one duplicate it's found, like this :
public class DuplicateCharacters {
public static void main(String[] args) {
String string1 = "Great";
int count;
//Converts given string into character array
char string[] = string1.toCharArray();
System.out.println("Duplicate characters in a given string: ");
//Counts each character present in the string
Boolean dupCarac = false;
for(int i = 0; i <string.length; i++) {
count = 1;
for(int j = i+1; j <string.length; j++) {
if(string[i] == string[j] && string[i] != ' ') {
count++;
//Set string[j] to 0 to avoid printing visited character
string[j] = '0';
}
}
//A character is considered as duplicate if count is greater than 1
if(count > 1 && string[i] != '0'){
System.out.println(string[i]);
dupCarac = true;
}
}
if (!dupCarac){
System.out.println("no duplicates");
}
}
PS: Please put {} on your if and else.
You might find interesting the following approach of how you can do the same, using Streams more efficiently, without iterating through the same String multiple times.
String input = "Great responsibility";
Map<String, Long > map = Arrays.stream(input.split("")) //create a stream for each character in String
.collect((Collectors.groupingBy(item -> item, Collectors.counting()))) //Collect into a map all occurrences
.entrySet().stream().filter(e -> e.getValue() > 1 && !e.getKey().equals(" ")) //filter only duplicate occurrences and not empty spaces
.map(e -> Map.entry(e.getKey(), e.getValue() -1)) // keep count only of duplicate occurrences not total occurrences
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); //gather duplicates in a map
if (map.isEmpty()){
System.out.println("No duplicates found");
} else {
map.forEach((key, value) -> System.out.printf("%s appears %d more times in given string%n", key, value));
}

LeetCode 14. longest common prefix

Question:
Write a function to find the longest common prefix string among an array of strings. If there is no common prefix, return an empty string "".
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
Code:
public class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs==null || strs.length==0)
return "";
for(int i=0;i<strs[0].length();i++) {
char x = strs[0].charAt(i);
for(int j=0;j<strs.length;j++) {
if((strs[j].length()==i)||(strs[j].charAt(i)!=x)) {
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
This is the second solution, but I don't understand the inner loop.
I think if the second element in strs returns a string and ends the for loop, the third element will not have a chance to be compared.
You have to check same position in all of the words and just compare it.
positions
word 0 1 2 3 4 5
=====================
w[0] F L O W E R
w[1] F L O W
w[2] F L I G H T
In Java:
class Main {
public static void main(String[] args) {
String[] words = {"dog","racecar","car"};
String prefix = commonPrefix(words);
System.out.println(prefix);
// return empty string
String[] words2 = {"dog","racecar","car"};
String prefix2 = commonPrefix(words2);
System.out.println(prefix2);
// Return "fl" (2 letters)
}
private static String commonPrefix(String[] words) {
// Common letter counter
int counter = 0;
external:
for (int i = 0; i < words[0].length(); i++) {
// Get letter from first word
char letter = words[0].charAt(i);
// Check rest of the words on that same positions
for (int j = 1; j < words.length; j++) {
// Break when word is shorter or letter is different
if (words[j].length() <= i || letter != words[j].charAt(i)) {
break external;
}
}
// Increase counter, because all of words
// has the same letter (e.g. "E") on the same position (e.g. position "5")
counter++;
}
// Return proper substring
return words[0].substring(0, counter);
}
}
Your first loop is itterating over all chars in the first string of array. Second loop is checking char at i posistion of all strings of array. If characters do not match, or length of string is the same as i it returns substring result.
I think the best way to understand is debug this example.
If the char in the second string is different than the char in the first one, then it is correct to return, since it means that the common prefix ends there. Checking the third and following strings is not necessary.
Basically it returns as soon as it finds a mismatch char.
If we first sort them then it would be very easy we have to only go and compare the first and the last element in the vector present there so,
the code would be like,This is C++ code for the implementation.
class Solution {
public:
string longestCommonPrefix(vector<string>& str) {
int n = str.size();
if(n==0) return "";
string ans = "";
sort(begin(str), end(str));
string a = str[0];
string b = str[n-1];
for(int i=0; i<a.size(); i++){
if(a[i]==b[i]){
ans = ans + a[i];
}
else{
break;
}
}
return ans;
}
};
public class Solution {
public string LongestCommonPrefix(string[] strs) {
if(strs.Length == 0)
{
return string.Empty;
}
var prefix = strs[0];
for(int i=1; i<strs.Length; i++) //always start from 1.index
{
while(!strs[i].StartsWith(prefix))
{
prefix = prefix.Substring(0, prefix.Length-1);
}
}
return prefix;
}
}

Returning different return value

When i have a problem with the code im writing, i usually handle it like a story. Each command is a sentence in a story. The sentences needs to make sense in order for the story to be complete/right.
So im learning java from scratch now with the MOOC course at Helsinki University. I got somewhat stuck at exercise 68. The program is suppose to compare integer values of a list(array) together with user input. What i programmed is a method that return true if the user input number is already on the list, and false if its not.
What I said about story at the start: The commented out code is my initial code. This did not past the last test but in my head both the commented out code and the other code say basically the same
Error message (from last test):
"Answer wrong when parameter was list [0, 7, 9, -1, 13, 8, -1] and value 8 expected: false but was: true"
public static boolean moreThanOnce(ArrayList<Integer> list, int searched)
// if (list.size()==1) {return false;}
//
// for (int i = 0; i < list.size();i++ ){
// if (list.contains(searched))
//
// {
//
// return true; }
//
// }
//return false;
//
int counter = 0;
for (int num : list) {
if (searched == num) {
counter++;
}
}
if (counter >= 2){
return true;
} else {
return false;
}
}
I understand that there is something wrong, just cant seem to figure it out. Do you see why the last code would be accepted, but not the first (commented out one) ?
If any use, the rest of the code (not my work) is this:
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(2);
list.add(7);
list.add(2);
System.out.println("Type a number: ");
int number = Integer.parseInt(reader.nextLine());
if (moreThanOnce(list, number)) {
System.out.println(number + " appears more than once.");
} else {
System.out.println(number + " does not appear more than once. ");
}
}
}
Code that is commented out guaranties only that if true there is at least one of occurance in array, maybe there are more but not guaranted. If function returns false thes may be 1 or no occurance.
Reason: If arrary os bigger than 1 it does not mean that there are 2 or more occurances of value you search for.
Posible solution: Add counter like uncommented code.
Your first algorithm has a few flaws, first you test for a length of one explicitly. Not null, and not an empty List. Second, you should prefer the List interface to the ArrayList explicit type. And finally, you need to consider the sublist offset by one of the current position when you call contains (clearly the list contains at least the current value).
I think you wanted something like
public static boolean moreThanOnce(List<Integer> list, int searched) {
if (list == null || list.size() < 2) {
return false;
}
int len = list.size();
for (int i = 0; i < len - 1; i++) {
if (list.get(i).equals(searched)
&& list.subList(i + 1, list.size()).contains(searched)) {
return true;
}
}
return false;
}
And, we can express that as generic method. Like,
public static <T> boolean moreThanOnce(List<T> list, T searched) {
if (list == null || list.size() < 2) {
return false;
}
int len = list.size();
for (int i = 0; i < len - 1; i++) {
if (list.get(i).equals(searched)
&& list.subList(i + 1, list.size()).contains(searched)) {
return true;
}
}
return false;
}
or, if you're using Java 8+, use a Stream and filter and then count like
public static <T> boolean moreThanOnce(List<T> list, T searched) {
if (list == null || list.size() < 2) {
return false;
}
return list.stream().filter(v -> v.equals(searched)).count() > 1;
}

Java - Boolean method always returning as false

public static boolean isValidNumber(String a1)
{
String x = ("0123456789");
boolean valid = false;
for (int i = 0; i < 4; i++) {
char c = a1.charAt(i);
for (int j = 0; j < 10; j++) {
if ( c == x.charAt(j)) {
valid = true;
}
else {
valid = false;
}
}
}
return valid;
}
The above method checks to see whether an input of a four character string is composed of the characters 0123456789. However, regardless of what the input is, the method always returns as false.
If I were to change the valid value in the else statement to true, the method would always return as true.
What is the error that I have made in this method?
As soon as you find a non matching character, break the loop otherwise the next matching character will set valid to true.
e.g. "123a456" is considered valid.
for (int j = 0; j < 10; j++) {
if ( c == x.charAt(j)) {
valid = true;
}
else {
valid = false;
break;
}
}
If for some reason you don't want to break the loop, you could keep an "invalid counter" and make sure that is 0 at the end.
Of course for what you are doing here, Integer.parseInt() might be your best bet ;-)
a String.equals method will check these two strings in a single statement if you are permitted to use that.
public static boolean isValidNumber(String a1)
{
String x = ("0123456789");
return x.equals(a1);
}
I would rewrite your function as given below,
String x = ("0123456789");
boolean valid = false;
for (int i = 0; i < 4; i++) {
char c = a1.charAt(i);
boolean isCharOK = false;
for (int j = 0; j < 10; j++) {
if ( c == x.charAt(j)) {
isCharOK = true;
break;
}
}
if (!isCharOK) {
valid = false;
break;
}
}
return valid;
John3136 is quite correct, but I would like to propose even better solution to your whole task:
final static String x = "0123456789";
public static boolean isValidNumber(String a1) {
for (int i = 0; i < a1.length(); ++i) {
if (x.indexOf(a1.charAt(i)) == -1) return false;
}
return true;
}
In short: the above code "looks up" every character in your parameter string a1 in the string composed of digits. If it can find it, continues. If it can't, it means a1 consist not only digits and returns false. If it passes through all a1 characters then it returns true :)
And as asked and described in the comments - handling of duplicate characters in argument string:
final static String x = "0123456789";
public static boolean isValidNumber(String a1) {
for (int i = 0; i < a1.length(); ++i) {
final char currentChar = a1.charAt(i);
if (x.indexOf(currentChar) == -1 || a1.indexOf(currentChar, i+1) != -1)
return false;
}
return true;
}
The function call a1.indexOf(currentChar, i+1) essentially checks if there is any duplicate character in the rest of the string (from position i+1 and farther). Which means if it will be able to find duplicate char, the method return false :) Hope this helps, here is more info on String.indexOf(int, int) function if you want:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(int, int)
You can use this one liner function to check for validity of a String as Number using Regular Expression
public static boolean isValidNumber(String a1)
{
return a1.matches("[\\d]+");
}
Hope this helps.

Categories