I've been trying to see if there is a way of solving this problem with a double loop. Looping over each word in the array and checking to see if all of the chars provided exist in that word.
Broken keyboard Problem:
Input A = "Hello, my dear friend!"
Input B = ['h', 'e', 'l, 'o', 'm']
We have a broken keyboard here in which only the alphabet keys (both lower case and upper case) in list B, number keys and punctuation keys work.
Write the function which take a string A and list of char B, and return how many words we can type.
Explanation input: A "Hello, my dear friend!", B = ['h', 'e', 'l, 'o', 'm'] output: 1
Explanation: For the first word "Hello," (including the comma), we can find every char in list B. Since all punctation key works fine, so output .
For the second word "my", we only can find char 'm' in list B, so we can't type the whole word. Then the same, "dear", can't find char 'd', so continue; "friend!", can't find char 'f', so continue;
This is what I have tried so far, but I can't use String's .contain() method as it only accepts a char sequence not a char array. How can I check each individual word for an array of chars using JAVA?
Thanks in advance, any support is appreciated.
public class BrokenKeyboard
{
public static void main(String[] args)
{
String stringText = "Hello my dear friend";
char [] charLetterArray = {'h', 'e', 'l', 'o', 'm'};
howManyWordsCalc(stringText, charLetterArray);
}
// Only words from stringText that can be typed in whole should be printed.
// If the letters present in the word aren't present in charLetterArray they don't get printed
public static int howManyWordsCalc(String text, char[] letters)
{
int wordCount = 0;
// sanitise input
if (text.isEmpty())
{
return 0;
}
else
{
text = text.toLowerCase();
String[] stringSeparated = text.split(" ");
for (int i = 0; i < stringSeparated.length; i )
{
System.out.println(stringSeparated[i]);
for (int j = 0; j < letters.length; j )
{
// stringSeparated[i].contains(letters)
if (stringSeparated[i].contains())
{
wordCount ;
}
}
}
return wordCount;
}
}
}
CodePudding user response:
Here's a sample solution:
public class Main{
public static void main(String[] args){
String stringText = "Hello my dear friend";
char [] charLetterArray = {'h', 'e', 'l', 'o', 'm'};
System.out.println(howManyWordsCalc(stringText, charLetterArray));
}
// Only words from stringText that can be typed in whole should be printed.
// If the letters present in the word aren't present in charLetterArray they don't get printed
public static int howManyWordsCalc(String text, char[] letters){
int wordCount = 0;
// sanitise input
if (text.isEmpty()){
return 0;
}
else{
text = text.toLowerCase();
String[] stringSeparated = text.split(" ");
for (int i = 0; i < stringSeparated.length; i ){
int validLetters = 0;
for(int j = 0; j < stringSeparated[i].length(); j ){
for(char c: letters){
if(c == stringSeparated[i].charAt(j)){
validLetters ;
break;
}
}
}
if(validLetters == stringSeparated[i].length()){
wordCount ;
}
}
return wordCount;
}
}
}
The way that this code works is exactly the same as yours, except the algorithm for checking whether or not a word can be made up of available letters.
The algorithm that I first iterate through every word in the array. Then, I create an integer called validLetters, where we will check how many letters in the word we can type. If the number of validLetters is equal to the length of the word, then the word can be typed.
To check whether a letter can be typed, we will loop through every letter in the word, and see if it is inside of the array letters. If it is, we increase our validLetters and exit the loop.
Alternatively, if you want to strictly do this in two for loops, this is a shortened version:
import java.util.*;
public class Main{
public static void main(String[] args){
String stringText = "Hello my dear friend";
char [] charLetterArray = {'h', 'e', 'l', 'o', 'm'};
System.out.println(howManyWordsCalc(stringText, charLetterArray));
}
// Only words from stringText that can be typed in whole should be printed.
// If the letters present in the word aren't present in charLetterArray they don't get printed
public static int howManyWordsCalc(String text, char[] letters){
int wordCount = 0;
// sanitise input
if (text.isEmpty()){
return 0;
}
else{
text = text.toLowerCase();
String[] stringSeparated = text.split(" ");
for (int i = 0; i < stringSeparated.length; i ){
int validLetters = 0;
for(int j = 0; j < stringSeparated[i].length(); j ){
if (new String(letters).indexOf(stringSeparated[i].charAt(j)) != -1) {
validLetters ;
}
}
if(validLetters == stringSeparated[i].length()){
wordCount ;
}
}
return wordCount;
}
}
}
Let me know if you have any questions/clarifications!
CodePudding user response:
I changed it a little bit, have a look:
public static void wordCalc(String input, char[] chars) {
String[] inputWords = input.toLowerCase().split(" ");
boolean[] allLetters = new boolean[26];
for(int i=0; i<chars.length; i ) {
allLetters[chars[i] - 'a'] = true;
}
int wordCount = 0;
for(String word : inputWords) {
boolean isWordPossible = true;
for(int i=0; i<word.length(); i ){
if(!allLetters[word.charAt(i) - 'a']){
isWordPossible = false;
break;
}
}
if(isWordPossible) {
System.out.println("word " word " is possible");
wordCount ;
}
}
System.out.println(wordCount);
}
I found this really neat trick on the internets once. Storing the allowed letters in a boolean array. That way, when you want to check if a char
is allowed, you can just check the value of the array at index corresponding to that char!
This does bring me to an important note however. Chars are stored as ints, which is why you can cast them back and forth and do funky stuff like word.charAt(i) - 'a'
(that will give you the position in the boolean array because it will give you the distance between the letter "a" and whatever letter is at position "i" in the word").
Strings are ultimately char arrays. So you can do:
char[] stuff = someString.toCharArray();
Its also pretty important to note that strings are immutable, and string literals point to the same object.
Final note on time complexity, its best to avoid nesting loops as much as possible. If you have loads of input, it will become really slow! If you have one loop, it's O(n) time, 2 loops its already O(n^2), which is quite slow as far as time complexity goes. I can't think of a different way for this case however. The structures you use and method of access can hugely impact performance. I think you'll really like HashSets, especially for this problem where allowed characters are unique anyway.
CodePudding user response:
You could just check if all the characters in the word are contained in letters
character array by using another loop (which actually has the same complexity as String::contains
).
Also, I'd suggest to get the words by splitting on repeated punctuation and/or whitespace characters using [\p{Z}\p{P}]
regex where \p{Z}
stands for whitespaces and \p{P}
for punctuation.
public static int howManyWordsCalc(String text, char[] letters) {
int wordCount = 0;
String[] words = text.toLowerCase().split("[\\p{P}\\p{Z}] ");
for (String word : words) {
// System.out.print("'" word "'\t");
boolean allFound = true;
for (char c : word.toCharArray()) {
boolean found = false;
for (char letter : letters) {
if (c == letter) {
found = true;
break;
}
}
if (!found) {
// System.out.println("not found letter: " c " in word " word);
allFound = false;
break;
}
}
if (allFound) {
wordCount ;
// System.out.println("all found");
}
}
return wordCount;
}
Test:
System.out.println(howManyWordsCalc(
"Hello, my dear friend!", new char[] {'h', 'e', 'l', 'o', 'm', 'y'}
));
Output (with debug prints enabled):
'hello' all found
'my' all found
'dear' not found letter: d in word dear
'friend' not found letter: f in word friend
2
CodePudding user response:
I have tried same in c#, but you also can use the HashSet collection and try the same. Java HashSet also has Contains().
I hope this will be helpful.
class Program
{
static void Main(string[] args)
{
string a = "Hello, my dear friend!";
string A = a.ToUpper();
string[] seperate = A.Split(new Char[] { ' ', ',', '.', '-', '\n', '\t', '!' });
HashSet<Char> hash = new HashSet<char>();
hash.Add('H');
hash.Add('E');
hash.Add('L');
hash.Add('O');
hash.Add('M');
int count = 0;
bool flag = true;
foreach (var w in seperate)
{
if (w.Length > 0) {
Char[] ca = w.ToCharArray();
foreach (var d in ca)
{
if(!hash.Contains(d))
{
flag = false;
break;
}
}
if(flag)
{
flag = true;
count ;
}
}
}
Console.WriteLine("Count : " count);
Console.Read();
}
}