Given a string and a non-empty substring sub, compute recursively the largest substring which starts and ends with sub and return its length.
strDist("catcowcat", "cat") → 9
strDist("catcowcat", "cow") → 3
strDist("cccatcowcatxx", "cat") → 9
my solution
public int strDist(String str, String sub) {
int i = sub.length();
int j = str.length();
int count = 0;
if (str.length() == 1 && str.equals(sub)) {
return 1;
} else if (str.length() < sub.length() || str.length() <= 1) {
return 0;
}
if (str.substring(0, i).equals(sub)) {
if (str.substring(str.length() - i, str.length()).equals(sub)) {
return str.length();
} else {
strDist(str.substring(0, str.length() - i), sub);
}
} else {
strDist(str.substring(1, str.length()), sub);
}
return 0;
}
tell me how to correct my code?
Why does this need to be done with recursion?
Edit: fixed code to handle case where sub is not present in str, or only present once.
public int strDist(String str, String sub) {
int last=str.lastIndexOf(sub);
if (last != -1) {
int first=str.indexOf(sub);
if (first != last)
return last - first + sub.length();
}
}
return 0;
}
Recursion is great, if it is suited to the problem. In this case, recursion doesn't add value, and writing it with recursion for the sake of recursion makes the code inefficient.
This will , "compute recursively the largest substring which starts and ends with sub and return its length" as you described.
public class PuzzlingRecursion {
static String substringFound = "";
public static void main(String[] args) {
String sentence = "catcowcat";
String substring = "cat";
int sizeString = findNumberOfStrings(sentence, substring, 0);
System.out.println("you are searching for: " + substring);
System.out.println("in: " + sentence);
System.out.println("substring which starts and ends with sub and return its length is:"+substringFound + ", " + sizeString);
}
private static int findNumberOfStrings(String subStringPassed,
String setenecePassed, int count) {
if (subStringPassed.length() == 0) {
return count + 0;
}
if (subStringPassed.length() < setenecePassed.length()) {
return count + 0;
}
count++;
String lastStringMiddle = subStringPassed.replaceAll("(.*?)" + "("
+ setenecePassed + ")" + "(.*?)" + "(" + setenecePassed + ")"
+ "(.*?.*)", "$3");
if (subStringPassed.contains(setenecePassed)
&& lastStringMiddle.length() != setenecePassed.length()) {
if (subStringPassed.contains(setenecePassed)
&& lastStringMiddle.contains(setenecePassed)) {
// only found one item no pattern but according to the example
// you posted it should return the length of one word/substring
count = setenecePassed.length();
substringFound = subStringPassed;
return count;
}
}
// makesure the lastSrtringMiddle has the key we are search
if (!lastStringMiddle.equals(subStringPassed)) {
subStringPassed = subStringPassed.replaceFirst(setenecePassed, "");
String lastString = subStringPassed.substring(0,
subStringPassed.lastIndexOf(setenecePassed));
if (null != lastString && !"".equals(lastString)) {
count = lastStringMiddle.length() + setenecePassed.length()
+ setenecePassed.length();
substringFound = setenecePassed + lastStringMiddle
+ setenecePassed;
subStringPassed = "";
}
return findNumberOfStrings(subStringPassed, setenecePassed, count);
}
return count;
}
}
I think this is much nicer recursive solution:
public int strDist(String str, String sub) {
if (str.length()==0) return 0;
if (!str.startsWith(sub))
return strDist(str.substring(1),sub);
if (!str.endsWith(sub))
return strDist(str.substring(0,str.length()-1),sub);
return str.length();
}
Related
I'm trying to display the number of times a letter appears within a string and outputting it in a new string (compressedString).
For example: aabcccccaaa should display a2b1c5a3.
So far, I got a2 to display only because I've included the break statement. If I took that out, then I would get StringIndexOutOfBoundsException.
My question is: How would I continue going through the whole string to obtain the rest of the aforementioned output without getting StringIndexOutOfBoundsException?
I ran it through debugger but it still isn't clear to me.
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
if(str.charAt(i) != str.charAt(i + 1)) {
compressedString += "" + str.charAt(i) + countConsecutive;
break;
}
}
return compressedString;
}
}
modify your for loop to terminate when i < str.length() - 1--this is because you are comparing the character at i to the character at i + 1, which makes your loop go out of bounds.
Try this
public class Problem {
public static void main(String []args) {
String str = "aaabc";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
//avoid index out of bounds error
if(str.length() == (i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
break;
}
else if(str.charAt(i) != str.charAt(i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
}
}
return compressedString;
}
}
The other answers have good solutions, but I thought I would just add what I came up with:
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
if (str.length() == 1) return str + "1"; // Handles single character strings
int countConsecutive = 0;
String compressedString = "";
for (int i = 0; i < str.length(); i++) {
if (i > 0) {
countConsecutive++;
if (str.charAt(i) != str.charAt(i-1)) {
compressedString += "" + str.charAt(i-1) + countConsecutive;
countConsecutive = 0;
}
if (i == str.length()-1) {
countConsecutive++; // Needs to be incremented for the last character
compressedString += "" + str.charAt(i) + countConsecutive;
}
}
}
return compressedString;
}
}
Your condition should be like this:
if(i+1 < str.length() && str.charAt(i) != str.charAt(i + 1))
because when you are is at last index of your string then also you are comparing i'th index with i+1 th index.
But after correcting this, still, this code will not give you the expected output.
This is how I would change the code.
public static String compressBad(String str) {
String compressedString = "";
if (str != null && str.length() > 0) {
int countConsecutive = 1;
char prevChar = str.charAt(0);
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i) != prevChar) {
// End of a run. Update compressedString and reset counters
compressedString += String.valueOf(prevChar) + countConsecutive;
prevChar = str.charAt(i);
countConsecutive = 1;
continue;
}
countConsecutive++;
}
compressedString += String.valueOf(prevChar) + countConsecutive;
}
return compressedString;
}
Mukit09 has already mentioned the reason for your StringIndexOutOfBoundsException.
I offer you a more efficient implementation, using String Builder for concatenating strings:
private static String comppressedString(String str) {
if(str == null || str.equals("")) {
return str;
}
if(str.length() == 1) {
return str + "1";
}
StringBuilder sb = new StringBuilder();
sb.append(str.charAt(0)); // Add first letter
int j = 1; // Counter for current sequence length.
for (int i = 0; i < str.length() - 1; i++) {
if(str.charAt(i) != str.charAt(i + 1)) { // end of characters sequence.
sb.append(j); // Add length of previous sequence.
if(j > 1) {
j = 1; // Minimum sequence length is 1
}
sb.append(str.charAt(i+1)); // Add character of next sequence.
} else {
j++; // increase counter, in order to get the length of the current sequence.
}
}
sb.append(j); // Add length of last sequence.
return sb.toString();
}
public static void main(String[] args) {
System.out.println(comppressedString("")); // empty string
System.out.println(comppressedString("a")); // a1
System.out.println(comppressedString("ab")); // a1b1
System.out.println(comppressedString("abba")); // a1b2a1
System.out.println(comppressedString("aabcccccaaa")); // a2b1c5a3
}
((\d{1,2})/(\d{1,2})/(\d{2,4}))
Is there a way to retrieve a list of all the capture groups with the Pattern object. I debugged the object and all it says is how many groups there are (5).
I need to retrieve a list of the following capture groups.
Example of output:
0 ((\d{1,2})/(\d{1,2})/(\d{2,4}))
1 (\d{2})/(\d{2})/(\d{4})
2 \d{2}
3 \d{2}
4 \d{4}
Update:
I am not necessarily asking if a regular expression exists, but that would be most favorable. So far I have created a rudimentary parser (I do not check for most out-of-bounds conditions) that only matches inner-most groups. I would like to know if there is a way to hold reference to already-visited parenthesis. I would probably have to implement a tree structure?
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class App {
public final char S = '(';
public final char E = ')';
public final char X = '\\';
String errorMessage = "Malformed expression: ";
/**
* Actual Output:
* Groups: [(//), (\d{1,2}), (\d{1,2}), (\d{2,4})]
* Expected Output:
* Groups: [\\b((\\d{1,2})/(\\d{1,2})/(\\d{2,4}))\\b, ((\\d{1,2})/(\\d{1,2})/(\\d{2,4})), (\d{1,2}), (\d{1,2}), (\d{2,4})]
*/
public App() {
String expression = "\\b((\\d{1,2})/(\\d{1,2})/(\\d{2,4}))\\b";
String output = "";
if (isValidExpression(expression)) {
List<String> groups = findGroups(expression);
output = "Groups: " + groups;
} else {
output = errorMessage;
}
System.out.println(output);
}
public List<String> findGroups(String expression) {
List<String> groups = new ArrayList<>();
int[] pos;
int start;
int end;
String sub;
boolean done = false;
while (expression.length() > 0 && !done) {
pos = scanString(expression);
start = pos[0];
end = pos[1];
if (start == -1 || end == -1) {
done = true;
continue;
}
sub = expression.substring(start, end);
expression = splice(expression, start, end);
groups.add(0, sub);
}
return groups;
}
public int[] scanString(String str) {
int[] range = new int[] { -1, -1 };
int min = 0;
int max = str.length() - 1;
int start = min;
int end = max;
char curr;
while (start <= max) {
curr = str.charAt(start);
if (curr == S) {
range[0] = start;
}
start++;
}
end = range[0];
while (end > -1 && end <= max) {
curr = str.charAt(end);
if (curr == E) {
range[1] = end + 1;
break;
}
end++;
}
return range;
}
public String splice(String str, int start, int end) {
if (str == null || str.length() < 1)
return "";
if (start < 0 || end > str.length()) {
System.err.println("Positions out of bounds.");
return str;
}
if (start >= end) {
System.err.println("Start must not exceed end.");
return str;
}
String first = str.substring(0, start);
String last = str.substring(end, str.length());
return first + last;
}
public boolean isValidExpression(String expression) {
try {
Pattern.compile(expression);
} catch (PatternSyntaxException e) {
errorMessage += e.getMessage();
return false;
}
return true;
}
public static void main(String[] args) {
new App();
}
}
Here is my solution ... I simply provided a regex of the regex as #SotiriosDelimanolis commented out.
public static void printGroups() {
String sp = "((\\(\\\\d\\{1,2\\}\\))\\/(\\(\\\\d\\{1,2\\}\\))\\/(\\(\\\\d\\{2,4\\}\\)))";
Pattern p = Pattern.compile(sp);
Matcher m = p.matcher("(\\d{1,2})/(\\d{1,2})/(\\d{2,4})");
if (m.matches())
for (int i = 0; i <= m.groupCount(); i++)
System.out.println(m.group(i));
}
Pay attention that you cannot remove the if-statement because in order to use the group method you should call the matches method first (I didn't know it!). See this link as a reference about it.
Hope this is what you were asking for ...
I am suppose to use Boolean to check if the string is palindrome. I'm getting an error, not sure what I am doing wrong. My program already has 3 strings previously imputed by a user. Thank you, I am also using java
public boolean isPalindrome(String word1, String word2, String word3){
int word1Length = word1.length();
int word2Length = word2.length();
int word3Length = word3.length();
for (int i = 0; i < word1Length / 2; i++)
{
if (word1.charAt(i) != word1.charAt(word1Length – 1 – i))
{
return false;
}
}
return isPalindrome(word1);
}
for (int i = 0; i < word2Length / 2; i++)
{
if (word2.charAt(i) != word2.charAt(word2Length – 1 – i))
{
return false;
}
}
return isPalindrome(word2);
}
for (int i = 0; i < word3Length / 2; i++)
{
if (word3.charAt(i) != word3.charAt(word3Length – 1 – i))
{
return false;
}
}
return isPalindrome(word3);
}
// my output should be this
if (isPalindrome(word1)) {
System.out.println(word1 + " is a palindrome!");
}
if (isPalindrome(word2)) {
System.out.println(word2 + " is a palindrome!");
}
if (isPalindrome(word3)) {
System.out.println(word3 + " is a palindrome!");
}
You could do a method for it like this:
First you build a new String and than you check if it is equal.
private static boolean test(String word) {
String newWord = new String();
//first build a new String reversed from original
for (int i = word.length() -1; i >= 0; i--) {
newWord += word.charAt(i);
}
//check if it is equal and return
if(word.equals(newWord))
return true;
return false;
}
//You can call it several times
test("malam"); //sure it's true
test("hello"); //sure it's false
test("bob"); //sure its true
Problem:
Develop a recursive algorithm to determine if there is a palindrome hidden within a longer word or phrase. A palindrome is a word or phrase that has the same sequence of letters when read from left to right and when read from right to left, ignoring the spaces (e.g., Some like cake, but I prefer pie contains the palindrome I prefer pi).
Below is my code:
public class e125 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
int i = 0;
String sLine = "Some like cake, but I prefer pie";
sLine.replaceAll("\\s+", "");
System.out.println(PlainRet(sLine, i));
}
public static String PlainRet(String sLine, int i) {
int nNum;
char c = 0;
String sPlain = "";
if (i >= sLine.length()) {
return "No Plaindrome";
}
c = sLine.charAt(i);
nNum = Isgood(sLine, c, i);
if (nNum != 0) {
for (; i < nNum; i++) {
sPlain += sLine.charAt(i);
}
return sPlain;
}
return PlainRet(sLine, i + 1);
}
public static int Isgood(String sLine, char c, int i) {
for (int j = i + 1; j < sLine.length(); j++) {
if (Character.toUpperCase(sLine.charAt(j)) == Character.toUpperCase(c)) {
if (Isplain(sLine, i, j)) {
return j;
}
}
}
return 0;
}
public static boolean Isplain(String sLine, int i, int j) {
if (Character.toUpperCase(sLine.charAt(j)) != Character.toUpperCase(sLine.charAt(i))) {
return false;
}
else if (i == j || j == i + 1) {
return true;
}
return (Isplain(sLine, i + 1, j - 1));
}
}
I keep getting an output of "I"
I have no idea what is wrong.
Like FatalError commented sLine.replaceAll() returns a new String. You need to reassign sLine or pass the results of the replaceAll() into the method.
You'll find a new error to fix after you do that, but it's just an off-by-one!
EDIT: Really sorry, I mean Java! As for what I think, I would say the first contains if statement is for s == null or length 0, but I'm confused as to what to put in the
return spaceCount(s.substring(1, ......)) + ......;
part.
I'm trying to use some if statements to write a function that takes a string as a parameter and recursively coutns the number of blanks spaces " " it has. So far I have
public static int spaceCount (string s) {
if ( ...... ) {
return 0;
}
char c = s.charAt(0);
if (....... ) {
return spaceCount (.....);
} else {
return spaceCount(s.substring(1, ......)) + ......;
}
}
So in the first if statement, should I write the case of the string having zero length? I'm pretty sure that won't cover the case of no spaces at all, so I'm not sure how to proceed.
For the second and third, I know I have to scan the string for spaces, but I am not really sure how to do that either. Any hints or direction would be appreciated!
public static int spaceCount(final String s) {
if(s == null || s.length() == 0) {
return 0;
}
char c = s.charAt(0);
if(' ' != c) {
return spaceCount(s.substring(1));
} else {
return spaceCount(s.substring(1)) + 1;
}
}
You don't have to "scan the string for spaces", that's what the recursion passing the remainder of the string does.
s.length() - s.replaceAll(" ", "").length() returns you number of spaces.
how to count the spaces in a java string? has the answer. Probably it may help. the above line is the simplest.
[You didn't specify a programming language] Here is a solution in Java:
public static int spaceCount(String s)
{ return scRecursive (s, s.length, 0, 0); }
public static int scRecursive (String s, int len, int dex, int count)
{ if (len == dex) return count;
else
return scRecursive (s, len, dex + 1,
(' ' == s.charAt(dex) ? count + 1 : count)); }
This is tail recursive (which might imply some efficiency) and, more importantly, this does not copy/allocate substrings
Here is one in Scheme:
(define (space-count string)
(let ((length (string-length string)))
(let stepping ((index 0) (count 0)
(if (= index length)
count
(let ((char (string-ref string index)))
(stepping (+ index 1)
(if (equal? #\space char)
(+ 1 count)
count)))))))
The recursion is in the call to stepping which has two arguments - the current index and the current count of spaces. The recursion terminates when the index equals the length. The count is incremented when the current char is a space.
public class CountSpaces {
public static void main(String[] args) {
String str = " A ";
System.out.println(spaceCount(str, 0));
System.out.println(spaceCount(str));
}
public static int spaceCount(String str, int count) {
if (str == null) {
return 0;
} else if (str.length() > 0) {
char c = str.charAt(0);
if (Character.isWhitespace(c)) {
count++;
}
return spaceCount(str.substring(1), count);
} else {
return count;
}
}
public static int spaceCount(String s) {
if (s.length() == 0 || s == null) {
return 0;
}
char c = s.charAt(0);
if (!Character.isWhitespace(c)) {
return spaceCount(s.substring(1));
} else {
return spaceCount(s.substring(1, s.length())) + 1;
}
}
}