Java method that returns strings using recursion - java

Here is my code:
private static String recString(final int i) {
return (i>0 ? i + "." + recString(i-1) : i<0? "." + recString(i+1) : "" ) ;
}
The method should return i dots and the number of dots at begin (example recString(4) returns "4....") when i>0 and just dots when i<=0 (example recString(-4) returns "...."). The condition is that I use just one return line any other modification is not allowed. All I get "4.3.2.1." when I call recString(4). I see where is the problem but cant figure out how to take variable just at the beginning and not change it ? Thanks in advance

As for a positive number you have to output the initial number only once, and you can only output that number in the 'positive' branch, you have to leave that 'positive' branch after one iteration.
A possible solution is to negate your number after you output it in your 'positive' branch and then allow the 'negative' branch to finish the job (output all the dots):
return (i > 0 ? i + recString(-i) : i < 0 ? "." + recString(i + 1) : "");
The initial code of the question author worked for non-negative numbers. The suggested sulution makes it work for positive ones too.

If non-recursive solutions are allowed, you can use
public static String recString(final int length) {
return String.format("%d%" + length + "s", length, "").replace(' ', '.');
}
Which returns "1." for length = 1, "2.." for length = 2, and so on, but fails for length < 1. If you also need the non-positive numbers, you can use:
public static String recString(final int length) {
return length < 1
? length + ""
: String.format("%d%" + length + "s", length, "").replace(' ', '.');
}
By the way: »Only one return line« could also mean that your you are allowed to write functions like the following.
public static String recString(final int length) {
String result;
// do something
return result;
}

if i value is >0 i is appended to a StringBuilder and then i dots follow otherwise i dots are appended to this StringBuilder, finally a String is returned from the our StringBuilder using toString method.
private static String recString(final int i) {
StringBuilder recString= new StringBuilder();
if (i > 0) {
recString.append(i);
for (int x = 0; x < i; x++) {
recString.append(".");
}
} else {
for (int x = 0; x > i; x--)
recString.append(".");
}
return recString.toString();
}

Related

Return a string with characters that come one after the other using while loop Java

How are you =)
I have task to return string with characters "#" "#" one after another with string length of 5 using While loop.
I have an idea to assign "#" to odd numbers, "#" to even numbers.
Where "#" is 0, "#" is 1, "#" is 2, and so on until the end of the length of the line.
Unfortunately, I can't find information how I can do this.
Please check the following code, I hope it will be more clear what I am talking about.
I will be glad for any hint or advice, thank you :)
public String drawLine(int length) {
int i = 0;
while (i < length) {
//I know that the following code will take only the int length, it's just an idea
if(length % 2 == 0) {
i++;
System.out.print("#");
}
else {
i++;
System.out.print("#");
}
}
return new String("");
}
public static void main(String[] args) {
JustATest helper = new JustATest();
//The result should be #####
System.out.println(helper.drawLine(5));
}
First of all we've two address two issues here as some have already pointed out in the comments beneath your questions.
You define in your question that your task is to return the final string instead of printing it directly. For such things you can either use a StringBuiler (see my example below) or simply concatenate in any other way ( e.g. "A" + "B" -> "AB")
The second issue is the iteration itself. You use mod 2 to determine if the value you test is even or not. This part is correct. However you're always comparing the desired length length % 2 == 0 instead of the current position i of the character to print. Therefore you'll only ever print # or # length-times depending on the desired length being even (leading to #) or odd (leading to #).
Below you can find my example on how to properly solve your task. Simply exchange length within the if clause with i and concatenate the result and return it.
public String drawLine(int length)
{
int i = 0;
StringBuilder builder = new StringBuilder();
while ( i < length )
{
//I know that the following code will take only the int length, it's just an idea
if( i % 2 == 0 )
{
i++;
builder.append( "#" );
} else
{
i++;
builder.append( "#" );
}
}
return builder.toString();
}

Count Words Using indexOf

I can't use arrays, only simple Java (if, for, while, substring, length, indexOf)
public int howManyWords(String s){
myString = "I have a dream";
int count = 1;
int length = 0;
while(count>=0){
count = myString.substring(String.valueOf(length),myString.indexOf(" "));
count++;
length = myString.indexOf(" ");
}
return count;
}
Should return 4
First of all, you made infinite loop, because count is 1, and you just increase it.
Second, you haven't even try to write this code in some IDE, because it would throw you a syntax error, because you are assigning string to int, when you do count = myString.substring()
So, instead of using count in loop, you can use myString.indexOf
something like this could work if you don't care what is going to happen with myString
int count = 0;
while(myString.indexOf(" ") >= 0) {
count++;
myString = myString.substring(myString.indexOf(" ") + 1)
}
return count;
Let's assume that the string you are testing does not contain leading or trailing spaces, because that affects the solution. The example string in your question does not contain leading or trailing spaces.
Simply call method indexOf(String, int) in a loop and in each iteration you set the int parameter to one more than what you got in the previous iteration. Once the value returned by method indexOf() is -1 (minus one), you are done. But don't forget to add the last word after you exit the loop.
String myString = "I have a dream";
int count = 0;
int index = 0;
while (index >= 0 && index < myString.length()) {
index = myString.indexOf(" ", index);
System.out.println("index = " + index);
if (index >= 0) {
index++;
count++;
}
}
if (index < 0) {
count++;
}
System.out.println("count = " + count);
Edited : Added missing else case.
Try the following code :
Remove the counted words from your string using the substring and indexOf, and increment the count in each iteration.
public int countWords(String s){
String myString = "I have a dream";
int count = 0;
int length = myString.length();
while(length>0){
if((myString.indexOf(" ")!=-1) && (myString.indexOf(" ")+1)<length){
myString = myString.subString(myString.indexOf(" ")+1);
count++;
length = myString.length();
}
else {
length = 0;
break;
}
}
return count;
}
PS: Conventionally, your method names should denote actions, hence I suggested it to be countWords instead of howManyWords.

Need to encode repetitive pattern in String with * , such that * means "repeat from beginning"

Encoding format: introduce * to indicate "repeat from beginning". Example. Input-{a,b,a,b,c,a,b,a,b,c,d} can be written as {a , b, * ,c, * , d}. Output:5; E.g 2: ABCABCE, output- 5.
Here * means repeat from beginning. For example if given String is ABCABCABCABC , it will return ABC**, another example is if String is ABCABCABC, it will return ABC*ABC.
I have the below code but this code assumes that the string will contain the repetitive pattern only and no other characters, I want to modify it to check :
1. Which pattern is repeating
2. Ignore non repeating patterns
2. encode that pattern according to the problem statement
import java.util.Scanner;
public class Magicpotion {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the string:");
String str = sc.nextLine();
int len = str.length();
if (len != 0) {
int lenby3 = len / 3;
int starcount = ( int).(Math.log(lenby3) / Math.log(2));
int leftstring = (lenby3 - (int) Math.pow(2, starcount));
int resultlen = (1 * 3) + starcount + (leftstring * 3);
System.out.println("ResultLength: " + resultlen);
System.out.print("ABC");
for (int i = 0; i < starcount; i++) {
System.out.print("*");
}
for (int i = 0; i < leftstring; i++) {
System.out.print("ABC");
}
} else
System.out.println("ResultLength: " + 0);
}
}
Here my assumption is that ABC will always be repeating pattern , hence I have divided the length by 3. I want to generalise it such that I find the repeating pattern which can be a AB or BC or ABCD and proceed accordingly.
This looks like homework. So instead of a full solution just some hints:
You can process the input string character by character and encode as you go. If you have at some point already read k characters and the next k characters are exactly the same, output a * and advance to position 2k.
Otherwise, output the next input character and advance position to k+1.
As mentioned by dyukha this algorithm does not always result in the shortest possible encoding. If this is required some more effort has to be put into the search.
This problem can be solved using dynamic programming.
Assume that you processed your stay at some position i. You want to understand what it the minimal length of encoding of str[0..i]. Let's call it ans[i]. You have two options:
Just add i-th character to the encoding. So the length is ans[i-1] + 1.
You may write *, when possible. In this case the length is ans[i / 2] + 1 or something like this.
The final length is in ans[n-1]. You can store how you obtained ans[i] to recover the encoding itself.
Checking whether you can write * can be optimized, using some hashing (to obtain O(n) solution instead of O(n^2)).
The difference with Henry's solution is that he always applies * when it's possible. It's not clear to me that it results into the minimal length (if I understood correctly, aaaaaa is a counterexample), so I'm giving a solution I'm sure about.
/**
* #author mohamed ali
* https://www.linkedin.com/in/oo0shaheen0oo/
*/
public class Magic_potion_encoding
{
private static int minimalSteps( String ingredients )
{
StringBuilder sb = new StringBuilder(ingredients);
for(int i =0;i<sb.length();i++)
{
char startChar = sb.charAt(i);
int walkingIndex1=i;
int startIndex2 =sb.toString().indexOf(startChar,i+1);
int walkingIndex2=startIndex2;
while(walkingIndex2 !=-1 && walkingIndex2<sb.length() && sb.charAt(walkingIndex1) == sb.charAt(walkingIndex2) )
{
if(walkingIndex1+1==startIndex2)
{
String subStringToBeEncoded = sb.substring(i,walkingIndex2+1);//substring the string found and the original "substring does not include the last index hence the +1
int matchStartIndex = sb.indexOf(subStringToBeEncoded,walkingIndex2+1);// look for first match for the whole string matched
int matchEndeIndex= matchStartIndex+subStringToBeEncoded.length();
int origStartIndex=i;
int origEndIndex = i+subStringToBeEncoded.length();
if (matchStartIndex!=-1 )
{
if(origEndIndex==matchStartIndex)
{
sb.replace(matchStartIndex,matchEndeIndex,"*");
}
else
{
while(matchStartIndex!=-1 && matchEndeIndex<sb.length() && sb.charAt(origEndIndex) == sb.charAt(matchEndeIndex) )
{
if(origEndIndex==matchStartIndex-1)// if the index of the 2 strings are right behind one another
{
sb.replace(matchStartIndex,matchEndeIndex+1,"*");
}
else
{
origEndIndex++;
matchEndeIndex++;
}
}
}
}
sb.replace(startIndex2,walkingIndex2+1,"*");
break;
}
walkingIndex1++;
walkingIndex2++;
}
}
System.out.println("orig= " + ingredients + " encoded = " + sb);
return sb.length();
}
public static void main( String[] args )
{
if ( minimalSteps("ABCABCE") == 5 &&
minimalSteps("ABCABCEA") == 6 &&
minimalSteps("abbbbabbbb") == 5 &&
minimalSteps("abcde") == 5 &&
minimalSteps("abcbcbcbcd") == 6 &&
minimalSteps("ababcababce") == 6 &&
minimalSteps("ababababxx") == 6 &&
minimalSteps("aabbccbbccaabbccbbcc") == 8)
{
System.out.println( "Pass" );
}
else
{
System.out.println( "Fail" );
}
}
}
Given that the repetitions are from the beginning, every such repeating substring will have the very first character of the given string. [Every repetition needs to be represented by a "star". (i.e ABCABCABC ans = ABC** ) . If all sequential repetitions are to be represented with one "star". (i.e ABCABCABC and = ABC* ), a slight modification to (2) will do the thing (i.e remove the if case where the just a star is added)]
Divide the given string to substrings based on the first character.
Eg. Given String = "ABABCABD"
Sub Strings = {"AB", "ABC", "AB", "ABD"}
Just traverse through the list of substrings and get the required result. I've used a map here, to make the search easy.
Just a rough write up.
SS = {"AB", "ABC", "AB", "ABD"};
result = SS[0];
Map<string, bool> map;
map.put(SS[0],true);
for (i = 1; i < SS.length; i++){
if (map.hasKey(SS[i])){
result += "*";
}
else {
res = nonRepeatingPart(SS[i], map);
result += "*" + res;
map.put(SS[i], true);
}
}
String nonRepeatingPart(str, map){
for (j = str.length-1; j >= 0; j--){
if (map.hasKey(str.subString(0, j))){
return str.subString(j, str.length-1);
}
}
return throwException("Wrong Input");
}
string getCompressed(string str){
string res;
res += str[0];
int i=1;
while(i<str.size()){
//check if current char is the first char in res
char curr = str[i];
if(res[0]==curr){
if(str.substr(0,i)==str.substr(i,i)){
res += '*';
i+=i; continue;
}else{
res += curr;
i++; continue;
}
}else {
res += curr;
i++; continue;
}
}
return res;
}
int main()
{
string s = "ABCABCABC";
string res = getCompressed(s);
cout<<res.size();
return 0;
}

Binary search to find longest common prefix

For an school assignment, we are implementing suffixarray, with the methods of building it and finding the longest common prefix. I manage to build and sort the suffix array quite easily but struggle with the LCP.
I am trying to find the longest common prefix of a pattern string P in another string T, using one singular binary search. The algorithm should return the index of where the longest common prefix begins.
Examples:
If the pattern string P is "racad" and the string T is "abracadabra", the longest common prefix should be "racad", beginning at index 2.
Likewise, if the the pattern string is P "rax" then the longest common prefix should be "ra", beginning at index 2 or 9.
I´ve come quite far but the algorithm is not returning the right value. Here´s my code:
public int compareWithSuffix(int i, String pattern) {
int c = 0;
int j = 0;
while (j < pattern.length() && c == 0) {
if (i + j <= text.length()) {
c = pattern.charAt(0 + j) - text.charAt(i + j);
} else {
c = 1;
}
j++;
}
return c;
}
public int binarySearch(String pattern) {
int left = 0;
int right = text.length() - 1;
int mid, c = 0;
while (c != 0 && left <= right) {
mid = left + (right - left) / 2;
c = compareWithSuffix(mid, pattern);
if (c < 0) {
right = mid - 1;
} else if (c > 0) {
left = mid + 1;
} else if (c == 0) {
return mid;
}
}
return left;
}
I run it with this main-method:
public static void main(String[] args) {
String word = "abracadabra";
String prefix1 = "rax";
String prefix2 = "racad";
SuffixArray s = new SuffixArray(word);
System.out.println("Longest common prefix of: " + "'" + prefix1 + "'" + " in " + "'" + word + "'" + " begins at index: " + s.binarySearch(prefix1));
System.out.println("Longest common prefix of: " + "'" + prefix2 + "'" + " in " + "'" + word + "'" + " begins at index: " + s.binarySearch(prefix2));
}
The output is always whatever value I initialize the local variable left with.
The search algorithm must do a singular binary search. I´ve tried searching other stackoverflow-questions and other web-sources but have not found anything helpfull.
Anyone who can see any errors in my code?
I haven't looked deeply enough to know if this is the only problem in your code, but this immediately jumps out as an explanation for "The output is always whatever value I initialize the local variable left with":
int mid, c = 0;
while (c != 0 && left <= right) {
You set c to zero, and then immediately check if it's not equal to zero. Of course, it's not not equal to zero, so the loop condition is immediately false, thus the loop body is never run. Hence, you will return the initial value of left.
It's not obvious why you are checking c at all. In the only situation where c becomes zero inside the loop, you immediately return. So just change your loop guard to:
while (left <= right) {
(and move the declaration of c inside the loop).
You could easily have found this by stepping through the code with a debugger. I heartily recommend learning how to use one.
first point: analyzing the examples you gave, it appears that you are not interested in the longest common prefix, but in the longest common substring. A prefix always starts with the first letter of the word - https://en.wikipedia.org/wiki/Prefix
second point: perhaps are you interested in finding the longest common substring of a set of words, or just two words?
public class Main3 {
/*
same functionallity as compareWithSuffix, but i think this name
is more suggestive; also, no need to pass i (the starting index) as a
parameter; i will later apply substring(i) to text
*/
public String longestCommonPrefix(String text, String pattern)
{
String commonPrefix="";
for(int j=0; j<text.length() & j<pattern.length(); j++)
{
if(text.charAt(j)==pattern.charAt(j))
{
commonPrefix=commonPrefix+text.charAt(j);
}
else
{
break;
}
}
return commonPrefix;
//for params "abc", "abd", output will be "ab"
}
public String longestCommonSequence(String s1, String s2)
{
/*
take for example "xab" and "yab";in order to find the common
sequence 'ab", we need to chop both x and y; for this reason
i apply substring to both strings, cutting progressivelly their first letters
*/
String longestCommonSequence="";
for(int i=0;i<=s1.length()-1;i++)
{
for(int j=0;j<=s2.length()-1;j++)
{
String s1_temp=s1.substring(i);
String s2_temp=s2.substring(j);
String commonSequence_temp=longestCommonPrefix(s1_temp, s2_temp);
if(commonSequence_temp.length()>longestCommonSequence.length())
longestCommonSequence=commonSequence_temp;
}
}
return longestCommonSequence;
}
public static void main(String args[])
{
Main3 m = new Main3();
String common = m.longestCommonSequence("111abcd2222", "33abcd444");
System.out.println(common);//"abcd"
}
}
I am providing here a different answer, because the approach is totally different, and leads to a generalized solution. (find the common substring of an entire list of strings)
For each word, i build all its possible substrings. A substring is determined by its start and end index. If the length of a word is L, the start index can be: 0, 1, 2,... L-1; if the starting index is 0, the end index can take values from 1 to L-1, thus L-1 values; if the starting index is 1, there are L-2 possible values for the end index. Thus, a word of length L has (L-1) +(L-2) + ... +1 = L*(L-1)/2 substrings. This gives square complexity in regard to L, but that's not an issue, because words rarely exceed 15 letters in length. If the string is not a word, but a text paragraph, then we have a problem with the square complexity.
Next, after i have build the set of substrings for every word, i build the intersection of these sets. The main idea is that a common substring of more words is, in the first place, a substring inside every such word, and, moreover, a substring that is encountered in all of these words. This lead to the idea of building the set of substrings for every word, and then do the intersection.
After we have found all the common substrings, just iterate and keep the longest one
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Main4 {
HashSet<String> allSubstrings(String input)
{
HashSet<String> result = new HashSet<String>();
for(int i=0;i<=input.length()-1;i++)
for(int j=i+1;j<=input.length();j++)
result.add(input.substring(i,j));
return result;
}
public HashSet<String> allCommonSubstrings(ArrayList<String> listOfStrings)
{
ArrayList<HashSet<String>> listOfSetsOfSubstrings =new ArrayList<HashSet<String>>();
//for each string in the list, build the set of all its possible substrings
for(int i=0;i<listOfStrings.size();i++)
{
String currentString = listOfStrings.get(i);
HashSet<String> allSubstrings = allSubstrings(currentString);
listOfSetsOfSubstrings.add(allSubstrings);
}
//find the intersection of all the sets of substrings
HashSet<String> intersection = new HashSet<String>(listOfSetsOfSubstrings.get(0));
for(int i=0;i<listOfSetsOfSubstrings.size();i++)
{
HashSet<String> currentSet=listOfSetsOfSubstrings.get(i);
intersection.retainAll(currentSet);
//retainAll does the set intersection. see: https://stackoverflow.com/questions/8882097/how-to-calculate-the-intersection-of-two-sets
}
return intersection;
}
public String longestCommonSubstring(HashSet<String> setOfSubstrings)
{
if(setOfSubstrings.size()==0)
return null;//if there are no common substrings, then there is no longest common substrings
String result="";
Iterator<String> it = setOfSubstrings.iterator();
while(it.hasNext())
{
String current = it.next();
if(current.length()>result.length())
result=current;
}
return result;
}
public static void main(String[] args)
{
Main4 m = new Main4();
ArrayList<String> list=new ArrayList<String>();
list.add("bbbaaddd1");
list.add("bbbaaccc1");
list.add("dddaaccc1");
HashSet<String> hset = m.allCommonSubstrings(list);
Iterator<String> it = hset.iterator();
System.out.println("all coommon substrings:");
while(it.hasNext())
{
System.out.println(it.next());
}
System.out.println("longest common substring:");
String lcs=m.longestCommonSubstring(hset);
System.out.println(lcs);
}
}
output:
all coommon substrings:
aa
a
1
longest common substring:
aa

Find a character recursively in a String

This is a question in the openDSA interactive learning platform from Virginia Tech:
For function "countChr", write the missing part of the recursive call.
This function should return the number of times that the letter "A"
appears in string "str".
int countChr(String str) {
if (str.length() == 0) {
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
count = 1;
}
return count + <<Missing a Recursive call>>
}
I know how to find a character non recursively in the following way:
public static void main(String [] args) {
String str ="abdcfghaasdfaadftaxvvaacvbtradcea";
int count =0;
for(int n=0; n<= str.length()-1; n++) {
if(str.charAt(n)== 'a')
count++;
}
System.out.print(count);
}
I really don't know how to do the same recursively, especially following the exact pattern given in the question.
To recursively obtain the number of occurrences of the letter 'A', you need to recursively call the function with the substring from index 1 to the end of the string:
public class Example {
public static void main(String [] args) {
String str ="abdcfghaasdfaadftaxvvaacvbtradcea";
System.out.println(countChr(str));
String str2 ="abdcfAhaasdAaadftaxvAAAacvbtradcea";
System.out.println(countChr(str2));
}
static int countChr(String str) {
if (str.length() == 0) {
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
count = 1;
}
return count + countChr(str.substring(1));
}
}
Output:
0
5
Explanation of how this works:
The function is first called with the entire String
If the String length is 0 return 0 because there cannot be an occurrence of 'A'
Initialise a counter to 0, which will be used to count the number of occurrences.
If the first character of the String is 'A' increment the counter
Now to repeat this process, we need to call the same function with the same String, except without the first character. We add the result of this recursive call to the counter, and return it.
This process can be illustrated by adding some prints:
int countChr(String str) {
System.out.println(str);
if (str.length() == 0) {
System.out.println("String has length 0, returning 0");
return 0;
}
int count = 0;
if (str.substring(0, 1).equals("A")) {
System.out.println("Character is an 'A' adding 1 to the count");
count = 1;
}
return count + countChr(str.substring(1));
}
Output:
abdcfAhaasdAaadftaxvAAAacvbtradcea
bdcfAhaasdAaadftaxvAAAacvbtradcea
dcfAhaasdAaadftaxvAAAacvbtradcea
cfAhaasdAaadftaxvAAAacvbtradcea
fAhaasdAaadftaxvAAAacvbtradcea
AhaasdAaadftaxvAAAacvbtradcea
Character is an 'A' adding 1 to the count
haasdAaadftaxvAAAacvbtradcea
aasdAaadftaxvAAAacvbtradcea
asdAaadftaxvAAAacvbtradcea
sdAaadftaxvAAAacvbtradcea
dAaadftaxvAAAacvbtradcea
AaadftaxvAAAacvbtradcea
Character is an 'A' adding 1 to the count
aadftaxvAAAacvbtradcea
adftaxvAAAacvbtradcea
dftaxvAAAacvbtradcea
ftaxvAAAacvbtradcea
taxvAAAacvbtradcea
axvAAAacvbtradcea
xvAAAacvbtradcea
vAAAacvbtradcea
AAAacvbtradcea
Character is an 'A' adding 1 to the count
AAacvbtradcea
Character is an 'A' adding 1 to the count
Aacvbtradcea
Character is an 'A' adding 1 to the count
acvbtradcea
cvbtradcea
vbtradcea
btradcea
tradcea
radcea
adcea
dcea
cea
ea
a
String has length 0, returning 0
You have to call the countChr method again within the method, with the String up to the last character you called. So if you do this:
return count + countChr( str.substring(1) );
That will give you the desired result.
return count + countChr(str.substring(1, str.length()));
or a more compact form:
return count + countChr(str.substring(1));

Categories