I am currently working on a programming assignment where the user inputs a word
i.e. "that"
and the program should return all valid words that can be made from the given string
i.e. [that, hat, at]
The issue I am having is that the resulting words should be created using a recursive method that checks if the prefix is valid.
i.e. if the given word is "kevin" once the program tries the combination "kv" it should know that no words start with kv and try the next combination in order to save time.
Currently my code just creates ALL permutations which takes a relatively large amount of time when the input is larger than 8 letter.
protected static String wordCreator(String prefix, String letters) {
int length = letters.length();
//if each character has been used, return the current permutation of the letters
if (length == 0) {
return prefix;
}
//else recursively call on itself to permute possible combinations by incrementing the letters
else {
for (int i = 0; i < length; i++) {
words.add(wordCreator(prefix + letters.charAt(i), letters.substring(0, i) + letters.substring(i+1, length)));
}
}
return prefix;
}
If anyone could help me figure this out I'd be much appreciated. I am also using an AVL tree to store the dictionary words for validation incase that is needed.
Related
I am new to Java, and I'm trying to figure out how to count Characters in the given string and threat a combination of two characters "eu" as a single character, and still count all other characters as one character.
And I want to do that using recursion.
Consider the following example.
Input:
"geugeu"
Desired output:
4 // g + eu + g + eu = 4
Current output:
2
I've been trying a lot and still can't seem to figure out how to implement it correctly.
My code:
public static int recursionCount(String str) {
if (str.length() == 1) {
return 0;
}
else {
String ch = str.substring(0, 2);
if (ch.equals("eu") {
return 1 + recursionCount(str.substring(1));
}
else {
return recursionCount(str.substring(1));
}
}
}
OP wants to count all characters in a string but adjacent characters "ae", "oe", "ue", and "eu" should be considered a single character and counted only once.
Below code does that:
public static int recursionCount(String str) {
int n;
n = str.length();
if(n <= 1) {
return n; // return 1 if one character left or 0 if empty string.
}
else {
String ch = str.substring(0, 2);
if(ch.equals("ae") || ch.equals("oe") || ch.equals("ue") || ch.equals("eu")) {
// consider as one character and skip next character
return 1 + recursionCount(str.substring(2));
}
else {
// don't skip next character
return 1 + recursionCount(str.substring(1));
}
}
}
Recursion explained
In order to address a particular task using Recursion, you need a firm understanding of how recursion works.
And the first thing you need to keep in mind is that every recursive solution should (either explicitly or implicitly) contain two parts: Base case and Recursive case.
Let's have a look at them closely:
Base case - a part that represents a simple edge-case (or a set of edge-cases), i.e. a situation in which recursion should terminate. The outcome for these edge-cases is known in advance. For this task, base case is when the given string is empty, and since there's nothing to count the return value should be 0. That is sufficient for the algorithm to work, outcomes for other inputs should be derived from the recursive case.
Recursive case - is the part of the method where recursive calls are made and where the main logic resides. Every recursive call eventually hits the base case and stars building its return value.
In the recursive case, we need to check whether the given string starts from a particular string like "eu". And for that we don't need to generate a substring (keep in mind that object creation is costful). instead we can use method String.startsWith() which checks if the bytes of the provided prefix string match the bytes at the beginning of this string which is chipper (reminder: starting from Java 9 String is backed by an array of bytes, and each character is represented either with one or two bytes depending on the character encoding) and we also don't bother about the length of the string because if the string is shorter than the prefix startsWith() will return false.
Implementation
That said, here's how an implementation might look:
public static int recursionCount(String str) {
if(str.isEmpty()) {
return 0;
}
return str.startsWith("eu") ?
1 + recursionCount(str.substring(2)) : 1 + recursionCount(str.substring(1));
}
Note: that besides from being able to implement a solution, you also need to evaluate it's Time and Space complexity.
In this case because we are creating a new string with every call time complexity is quadratic O(n^2) (reminder: creation of the new string requires allocating the memory to coping bytes of the original string). And worse case space complexity also would be O(n^2).
There's a way of solving this problem recursively in a linear time O(n) without generating a new string at every call. For that we need to introduce the second argument - current index, and each recursive call should advance this index either by 1 or by 2 (I'm not going to implement this solution and living it for OP/reader as an exercise).
In addition
In addition, here's a concise and simple non-recursive solution using String.replace():
public static int count(String str) {
return str.replace("eu", "_").length();
}
If you would need handle multiple combination of character (which were listed in the first version of the question) you can make use of the regular expressions with String.replaceAll():
public static int count(String str) {
return str.replaceAll("ue|au|oe|eu", "_").length();
}
I just took a codility test and was wondering why my solution only scored 37/100. The problem was that you were given a String and had to search through it for valid passwords.
Here are the rules:
1) A valid password starts with a capital letter and cannot contain any numbers. The input is restricted to any combination of a-z, A-Z and 0-9.
2)The method they wanted you to create is suppose to return the size of the largest valid password. So for example if you input "Aa8aaaArtd900d" the number 4 is suppose to be outputted by the solution method. If no valid String is found the method should return -1
I cannot seem to figure out where I went wrong in my solution. Any help would be greatly appreciated! Also any suggestions on how to better test code for something like this would be greatly appreciated.
class Solution2 {
public int solution(String S) {
int first = 0;
int last = S.length()-1;
int longest = -1;
for(int i = 0; i < S.length(); i++){
if(Character.isUpperCase(S.charAt(i))){
first = i;
last = first;
while(last < S.length()){
if(Character.isDigit(S.charAt(last))){
i = last;
break;
}
last++;
}
longest = Math.max(last - first, longest);
}
}
return longest;
}
}
added updated solution, any thoughts to optimize this further?
Your solution is too complicated. Since you are not asked to find the longest password, only the length of the longest password, there is no reason to create or store strings with that longest password. Therefore, you do not need to use substring or an array of Strings, only int variables.
The algorithm for finding the solution is straightforward:
Make an int pos = 0 variable representing the current position in s
Make a loop that searches for the next candidate password
Starting at position pos, find the next uppercase letter
If you hit the end of line, exit
Starting at the position of the uppercase letter, find the next digit
If you hit the end of line, stop
Find the difference between the position of the digit (or the end of line) and the position of the uppercase letter.
If the difference is above max that you have previously found, replace max with the difference
Advance pos to the position of the last letter (or the end of line)
If pos is under s.length, continue the loop at step 2
Return max.
Demo.
EDIT: Just to clarify, the recursion is required as part of an assignment, so it must be recursive even though I know that's not the best way to do this problem
I made a program that, in part, will search through an extremely large dictionary and compare a given list of words with each word in the dictionary and return a list of words that begin with the same two letters of the user-given word.
This works for small dictionaries but I just discovered that for dictionaries over a certain amount there is a stack limit for the recursions, so I get a stack overflow error.
My idea is to limit each recursion to 1000 recursions, then increment a counter for another 1000 and start again where the recursive method last left off and then end again at 2000, then so on until the end of the dictionary.
Is this the best way to do it? And if so, does anyone have any ideas how? I'm having a really hard time implementing this idea!
(edit: If it's not the best way, does anyone have any ideas of how to do it more effectively?)
Here is the code I have so far, the 1000 recursions idea is barely implemented here because I've deleted some of the code I tried in the past already but honestly it was about as helpful as what I have here.
the call:
for(int i = 0; i < givenWords.size(); i++){
int thousand = 1000;
Dictionary.prefix(givenWords.get(i), theDictionary, 0, thousand);
thousand = thousand + 1000;
}
and the prefix method:
public static void prefix (String origWord, List<String> theDictionary, int wordCounter, int thousand){
if(wordCounter < thousand){
// if the words don't match recurse through this same method in order to move on to the next word
if (wordCounter < theDictionary.size()){
if ( origWord.charAt(0) != theDictionary.get(wordCounter).charAt(0) || origWord.length() != theDictionary.get(wordCounter).length()){
prefix(origWord, theDictionary, wordCounter+1, thousand+1);
}
// if the words first letter and size match, send the word to prefixLetterChecker to check for the rest of the prefix.
else{
prefixLetterChecker(origWord, theDictionary.get(wordCounter), 1);
prefix(origWord, theDictionary, wordCounter+1, thousand+1);
}
}
}
else return;
}
edit for clarification:
The dictionary is a sorted large dictionary with only one word per line, lowercase
the "given word" is actually one out of a list, in the program, the user inputs a string between 2-10 characters, letters only no spaces etc. The program creates a list of all possible permutations of this string, then goes through an array of those permutations and for each permutation returns another list of words beginning with the first two letters of the given word.
If as the program is going through it, any letter up to the first two letters doesn't match, the program moves on to the next given word.
This is actually a nice assignment. Let's make some assumptions....
26 letters in the alphabet, all words are in those letters.
no single word is more than.... 1000 or so characters long.
Create a class, call it 'Node', looks something like:
private static class Node {
Node[] children = new Node[26];
boolean isWord = false;
}
Now, create a tree using this node class. The root of this tree is:
private final Node root = new Node ();
Then, first word in the dictionary is the word 'a'. We add it to the tree. Note that 'a' is letter 0.
So, we 'recurse' in to the tree:
private static final int indexOf(char c) {
return c - 'a';
}
private final Node getNodeForChars(Node node, char[] chars, int pos) {
if (pos == chars.length) {
return this;
}
Node n = children[indexOf(chars[pos])];
if (n == null) {
n = new Node();
children[indexOf(chars[pos])] = n;
}
return getNodeForChars(n, chars, pos + 1);
}
So, with that, you can simply do:
Node wordNode = getNodeForChars(root, word.toCharArray(), 0);
wordNode.isWord = true;
So, you can create a tree of words..... Now, if you need to find all words starting with a given sequence of letters (the prefix), you can do:
Node wordNode = getNodeForChars(root, prefix.toCharArray(), 0);
Now, this node, if isWord is true, and all of its children that are not-null and isWord is true, are words with the prefix. You just have to rebuild the sequence. You may find it advantageous to store the actual word as part of the Node, instead of the boolean isWord flag. Your call.
The recursion depth will never be more than the longest word. The density of the data is 'fanned out' a lot. There are other ways to set up the Node that may be more (or less) efficient in terms of performance, or space. The idea though, is that you set up your data in a wide tree, and your search is thus very fast, and all the child nodes at any point have the same prefix as the parent (or, rather, the parent is the prefix).
So I am trying to solve the problem 1772 of the Caribbean online judge web page http://coj.uci.cu/24h/problem.xhtml?abb=1772, the problem asks to find if a substring of a bigger string contains at least one palindrome inside it:
e.g. Analyzing the sub-strings taken from the following string: "baraabarbabartaarabcde"
"bara" contains a palindrome "ara"
"abar" contains a palindrome "aba"
"babar" contains a palindrome "babar"
"taar" contains a palindrome "aa"
"abcde" does not contains any palindrome.
etc etc etc...
I believe my approach is really fast because I am iterating the strings starting at the first char and at the last char at the same time, advancing towards the center of the string looking only for the following patterns: "aa" "aba" whenever I find a pattern like those I can say the substring given contains a palindrome inside it. Now the problem is that the algorithm is taking a long time but I can't spot the problem on it. Please help me find it I am really lost on this one. Here is my algorithm
public static boolean hasPalindromeInside(String str)
{
int midpoint=(int) Math.ceil((float)str.length()/2.0);
int k = str.length()-1;
for(int i = 0; i < midpoint;i++)
{
char letterLeft = str.charAt(i);
char secondLetterLeft=str.charAt(i+1);
char letterRight = str.charAt(k);
char secondLetterRight = str.charAt(k-1);
if((i+2)<str.length())
{
char thirdLetterLeft=str.charAt(i+2);
char thirdLetterRight=str.charAt(k-2);
if(letterLeft == thirdLetterLeft || letterRight == thirdLetterRight)
{
return true;
}
}
if(letterLeft == secondLetterLeft || letterRight==secondLetterRight)
{
return true;
}
k--;
}
return false;
}
}
I have removed the code that grabs the input strings and intervals of sub-strings, I am using String.substring() to get the substrings and I don't think that will be causing the problem. If you need that code please let me know.
Thanks!
I think you can solve this in O(1) time per query given O(n) preprocessing to find the locations of all 2 and 3 character palindromes. (Any even plaindrome will have a 2 character plaindrome at the centre, while any odd will have a 3 character one so it suffices to check 2 and 3.)
For example,
Given your string baraabarbabartaarabcde, first compute an array indicating the locations of the 2 character palindromes:
baraabarbabartaarabcde
000100000000001000000-
Then compute the cumulative sum of this array:
baraabarbabartaarabcde
000100000000001000000-
000111111111112222222-
By doing a subtraction you can immediately work out whether there are any 2 character palindromes in a query range.
Similarly for three character plaindromes:
baraabarbabartaarabcde String
01001000100000010000-- Indicator
01112222333333344444-- Cumulative
I was asked in interview following question. I could not figure out how to approach this question. Please guide me.
Question: How to know whether a string can be segmented into two strings - like breadbanana is segmentable into bread and banana, while breadbanan is not. You will be given a dictionary which contains all the valid words.
Build a trie of the words you have in the dictionary, which will make searching faster.
Search the tree according to the following letters of your input string. When you've found a word, which is in the tree, recursively start from the position after that word in the input string. If you get to the end of the input string, you've found one possible fragmentation. If you got stuck, come back and recursively try another words.
EDIT: sorry, missed the fact, that there must be just two words.
In this case, limit the recursion depth to 2.
The pseudocode for 2 words would be:
T = trie of words in the dictionary
for every word in T, which can be found going down the tree by choosing the next letter of the input string each time we move to the child:
p <- length(word)
if T contains input_string[p:length(intput_string)]:
return true
return false
Assuming you can go down to a child node in the trie in O(1) (ascii indexes of children), you can find all prefixes of the input string in O(n+p), where p is the number of prefixes, and n the length of the input. Upper bound on this is O(n+m), where m is the number of words in dictionary. Checking for containing will take O(w) where w is the length of word, for which the upper bound would be m, so the time complexity of the algorithm is O(nm), since O(n) is distributed in the first phase between all found words.
But because we can't find more than n words in the first phase, the complexity is also limited to O(n^2).
So the search complexity would be O(n*min(n, m))
Before that you need to build the trie which will take O(s), where s is the sum of lengths of words in the dictionary. The upper bound on this is O(n*m), since the maximum length of every word is n.
you go through your dictionary and compare every term as a substring with the original term e.g. "breadbanana". If the first term matches with the first substring, cut the first term out of the original search term and compare the next dictionary entries with the rest of the original term...
let me try to explain that in java:
e.g.
String dictTerm = "bread";
String original = "breadbanana";
// first part matches
if (dictTerm.equals(original.substring(0, dictTerm.length()))) {
// first part matches, get the rest
String lastPart = original.substring(dictTerm.length());
String nextDictTerm = "banana";
if (nextDictTerm.equals(lastPart)) {
System.out.println("String " + original +
" contains the dictionary terms " +
dictTerm + " and " + lastPart);
}
}
The simplest solution:
Split the string between every pair of consecutive characters and see whether or not both substrings (to the left of the split point and to the right of it) are in the dictionary.
One approach could be:
Put all elements of dictionary in some set or list
now you can use contains & substring function to remove words which matches dictionary. if at the end string is null -> string can be segmented else not. You can also take care of count.
public boolean canBeSegmented(String s) {
for (String word : dictionary.getWords()) {
if (s.contains(word) {
String sub = s.subString(0, s.indexOf(word));
s = sub + s.subString(s.indexOf(word)+word.length(), s.length()-1);
}
return s.equals("");
}
}
This code checks if your given String can be fully segmented. It checks if a word from the dictionary is inside your string and then subtracks it. If you want to segment it in the process you have to order the subtracted sementents in the order they are inside the word.
Just two words makes it easier:
public boolean canBeSegmented(String s) {
boolean wordDetected = false;
for (String word : dictionary.getWords()) {
if (s.contains(word) {
String sub = s.subString(0, s.indexOf(word));
s = sub + s.subString(s.indexOf(word)+word.length(), s.length()-1);
if(!wordDetected)
wordDetected = true;
else
return s.equals("");
}
return false;
}
}
This code checks for one Word and if there is another word in the String and just these two words it returns true otherwise false.
this is a mere idea , you can implement it better if you want
package farzi;
import java.util.ArrayList;
public class StringPossibility {
public static void main(String[] args) {
String str = "breadbanana";
ArrayList<String> dict = new ArrayList<String>();
dict.add("bread");
dict.add("banana");
for(int i=0;i<str.length();i++)
{
String word1 = str.substring(0,i);
String word2 = str.substring(i,str.length());
System.out.println(word1+"===>>>"+word2);
if(dict.contains(word1))
{
System.out.println("word 1 found : "+word1+" at index "+i);
}
if(dict.contains(word2))
{
System.out.println("word 2 found : "+ word2+" at index "+i);
}
}
}
}