PrefixAgain solution in codingbat - java

I'm currently doing codingbat problems for fun, and I just done this problem.
"Given a string, consider the prefix string made of the first N chars of the string. Does that prefix string appear somewhere else in the string? Assume
that the string is not empty and that N is in the range 1..str.length(). prefixAgain("abXYabc", 1) → true prefixAgain("abXYabc", 2) → true prefixAgain("abXYabc",
3) → false"
http://codingbat.com/prob/p136417
And my solution is:
public boolean prefixAgain(String str, int n) {
return (str.replaceFirst(Character.toString(str.charAt(n-1)),"").contains(Character.toString(str.charAt(n-1))));
}
Now, I didn't really understand the problem while writing this code and I thought only to find the occurance of the character of the specified index and
ignore the characters before it using the .contains() method. So I'm really not finding the prefix as the problem instructed. I just found my mistake after submitting it. However, this solution passed the exercise.
When I test it with my own input, such as
prefixAgain("abcccccbx", 2);
it returned true instead of false. So am I missing some reason why codingbat accepted my solution even though it's totally wrong?

public boolean prefixAgain(String str, int n)
String prefix = str.substring(0, n);
int length = str.length();
for (int i = n; i <= length - n; i++) {
if (prefix.equals(str.substring(i, i + n))) {
return true;
}
}
return false;
}

Restate your strategy (algorithm): Do the first N characters in a string appear anywhere else in the string? Simplest solution would be to look for that string in the 2nd through last characters of the original string. Like below (even if someone gives you an assumption, always check!)
public boolean prefixAgain(String str, int n) {
boolean result = false;
if (n < str.length() &&
(str.substring(1)).indexOf(str.substring(0,n)) > -1
) {
result = true;
}
return result;
}

Maybe i missed something but this seems correct and elegant:
public boolean prefixAgain(String str, int n) {
if(str.substring(n).contains(str.substring(0, n))) return true;
return false;
}
If n > str.length() it returns false.

public boolean prefixAgain(String str, int n) {
int l= str.length();
String test = str.substring(0,n);
boolean flag = false;
str = str.substring(1);
l= str.length();
for(int i=0;i<l;i++){
if((i+n <= l)){
if((str.substring(i,n+i).equals(test)))
return true;
}
}
return flag;
}

This is mine (considering that indexOf() is not introduced yet):
public boolean prefixAgain(String str, int n) {
for (int i=1; i <= str.length()-n; i++)
if (str.substring(i, i+n).equals(str.substring(0, n)))
return true;
return false;
}
But I found this solution the most elegant so far:
public boolean prefixAgain(String str, int n) {
return (str.indexOf(str.substring(0, n), 1) != -1);
}

public boolean prefixAgain(String str, int n) {
return str.substring(n).contains(str.substring(0,n));
}
just looking the prefix(str.substring(0,n)) in the substring of str without the prefix this means starting from n which is (str.substring(n)).

public boolean prefixAgain(String str, int n) {
return (str.substring(n).contains(str.substring(0,n)));
}

This has been posted basically, but I revised it a little to make it super easy to read instead of going for the one liner.
public boolean prefixAgain(String str, int n) {
String prefix = str.substring(0, n);
String afterPrefix = str.substring(n);
return afterPrefix.contains(prefix);
}
First, we grab the prefix which will start at index zero and go up to not including n. afterPrefix is simply the rest of the string which will start at n. Finally, return whether everything after the prefix contains the prefix.

public boolean prefixAgain(String str, int n) {
String pre = str.substring(0, n);
for (int i=n; i<str.length()-n+1; i++)
{
if (str.substring(i, i+n).equals(pre))
return true;
}
return false;
}

A solution, not the fastest but clear.
public boolean prefixAgain(String str, int n) {
String prefix = str.substring(0,n); // prefix String
int index = str.indexOf(prefix); //first loc of prefix
if(str.lastIndexOf(prefix) > index){ //see if it appears again
return true;
}
else return false; //if we get here, doesn't appear again, false
}

Related

How to check that one String can be spelled using characters from another String?

Example: String a = "ACAHBBA" and String b = "ABAB" should return true, since both strings can spell ABAB.
I have tried with contains(), but that only works for equal sequences.
// The code should look like this.
public class task10 {
public static boolean contains(String a, String b) {
// check if b can be spelled using characters from a.
// if it can. return true.
// else
return false;
}
}
Posible solution?
public static boolean contains(String a, String b) {
for (int i = 0; i < b.length(); i++) {
if (a.indexOf(b.charAt(i)) == -1) {
return false;
}
}
return true;
}
Simply iterate thru one string and get the index of the character. If >= 0, replace character with non-alphabetic character and repeat. This algorithm presumes the need to match the correct number of characters. For example, hello would return false if the character set was helo.
public static boolean spelledFrom(String word, String chars) {
StringBuilder sb = new StringBuilder(chars);
for (String c : word.split("")) {
int i;
if ((i = sb.indexOf(c)) < 0) {
return false;
}
sb.setCharAt(i, '#');
}
return true;
}
You can try this:
public static boolean canSpell(String a, String b)
{
String shorter = (a.length() <= b.length()) ? a : b;
String longer = (shorter.equals(a)) ? b : a;
for(int i = 0; i < shorter.length(); i++)
{
if(!longer.contains("" + shorter.charAt(i)))
return false;
}
return true;
}
Once you've identified the shorter string, you just need to verify that each of its chars are contained in the longer string. This solution doesn't verify if a char "has already been used", which means inserting "AB" and "ABBA" will return true. If you need to do this, you just need to delete the verified char from the longer string in every loop.

Question >> print "True" or "False" if the string contains two or more characters

I have to make a method named 'contains' that accepts a string and a character as parameters and returns true if that character occurs two or more times in the string.
example: Input contains("Apple", 'p') should return "True"
private boolean contains(String a,char b) {
if(a.contains(b)) {
print("true");
}
else {
print("");
}
//boolean c = a.contains('l');
return false;
}
I know this code is wrong ... I want to know what I have to do and what I have to fix .
I would appreciate your advice
Thank you.
There are a few ways to do this but the simplest would just be to loop through the String looking for the char, if count reaches two then return true.
For this consider using
for (char c : input) {
if (c == myChar) count++;
if (count >= 2) return true;
}
return false;
Another way would be to use String.replace and replace the wanted char with ""
then compare the size of the before and after String
Your method may return a boolean based on the size difference between the original string, and the string without the given character :
return (a.length() - (a.replace(b, '')).length()) >= 2 ;
In theoretical terms:
First: you need to iterate over the input string characters using a for loop and then in each iteration compare the current character in the string with the other character argument which is given as method argument. If they match, then you can increase a counter (a variable). Then compare if the counter value is 2 and return true immediately it is so. At the method end you can return false just like you have done already.
Second : you are printing true , not returning true. Should use return true; when the value of variable becomes 2
countMatches(a,b) returns the count of b in String a. and it is from org.apache.commons.lang3
private boolean contains(String a,char b) {
return StringUtils.countMatches(a, b)>=2 ;
}
or in simple java you can use
private boolean contains(String a,char b) {
return (a.length() - a.replaceAll(String.valueOf(b),"").length())>=2 ;
}
This is one of simple ways to do this. Here the string is put into char array. This way it is easier to examine the elements of the char array and find out same characters.
private boolean contains(String a, char b) {
char[] c_array = a.toCharArray();
int count = 0;
for (int i = 0; i < c_array.length; i++) {
if (b == c_array[i]) {
count++;
continue;
} else {
continue;
}
}
if (count >= 2) {
return true;
} else {
return false;
}
}
public class Demo {
public static boolean contains(String str,char c){
//todo:check str for NullPointExecption
int flag=0;
for(int i=0;i<str.length();i++){
if(c==str.charAt(i)){
flag++; //if str contains char c,flag=flag+1
}
if(flag>=2){
return true; //if flag>=2,return true
}
}
return false;
}
public static void main(String[] args) {
System.out.println(contains("appple", 'p'));//result is true
}
}

Compile problems -- must return a String [duplicate]

This question already has answers here:
Why do I receive the error "This method must return a result of type ..."?
(5 answers)
Closed 6 years ago.
I am working on a codingbat problem and trying to remove an char from a String and return a string without that char. Below is my code. Please tell me what's wrong with it as I keep getting an error message saying it must return a String.
public String missingChar(String str, int n) {
if (str.length() < n) {
int idx = str.indexOf(n);
String a = str.substring(0,idx);
String b = str.substring(idx+1, str.length());
return a + b;
}
}
Compile problems:
Error: public String missingChar(String str, int n) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This method must return a result of type String
You need to return String even if the str.length() < n condition is not met
public String missingChar(String str, int n) {
if (str.length() < n) {
int idx = str.indexOf(n);
String a = str.substring(0,idx);
String b = str.substring(idx+1, str.length());
return a + b;
}
return str;
}
As the other answers and my comment already mentioned your code is missing a return statement in the else case. But your code logic is also quite flawed:
do not do int idx = str.indexOf(n);
invert the entire if logic
That will yield:
public String missingChar(String str, int n) {
if (n < str.length()){
String a = str.substring(0,n);
String b = str.substring(n+1, str.length());
return a + b;
}
return str;
}
Which results in the output hllo for given input "hello", 1.
Note that my assumption of the flaws logic results of you trying to compare n with the length of the string in the first place: comparing it to the length tells me n is supposed to be a index of the string - but then it makes absolutely no sense to call indexOf with that n. At the same time it could be that n is actually the char in the string you want to remove, but then its type should be char and you should some error handling in case the character is not found in the string.
The error is quite clear/simple
your method MUST return a string even if this condition is not met
if (str.length() < n){
modify the method in a way that you meet the contract with the return value.
public String missingChar(String str, int n) {
if (str.length() < n){
int idx = str.indexOf(n);
String a = str.substring(0,idx);
String b = str.substring(idx+1, str.length());
return a + b;
}else{
return something;
}
}
The problem is that all the return paths must return a string, and here you return string only in one of them...
If str.length() >= n, you have no return!

Compute recursively the largest substring which starts and ends with sub and return its length

The task is: Given a string and a non-empty substring sub, compute recursively the largest substring which starts and ends with sub and return its length.
Examples:
strDist("catcowcat", "cat") → 9
strDist("catcowcat", "cow") → 3
strDist("cccatcowcatxx", "cat") → 9
Can you please look at my code and tell me what is the problem with it?
public int strDist(String str, String sub)
{
if(str.length()<sub.length())
return 0;
if(str.length()==sub.length()&&str.equals(sub))
return str.length();
if(str.length()<2)
{
if(str.contains(sub))
{
return 1;
}
return 0;
}
if (str.length()==2)
{
if (sub.length()==2 && str.equals(sub))
return 2;
if (str.contains(sub))
return 1;
return 0;
}
if(str.length()>2)
{
if(str.startsWith(sub)&&str.endsWith(sub))
{
return str.length();
}
if(str.substring(0,sub.length()).equals(sub))
{
strDist(str.substring(0,str.length()-2),sub);
}
if(str.substring(str.length()-sub.length(),str.length()-1).equals(sub))
strDist(str.substring(1,str.length()-1),sub);
}
return strDist(str.substring(1,str.length()-1),sub);
}
it doesn't work for the case strDist("hiHellohihihi", "hih") → 5
and returns zero.
First, to answer your question, I found a number of issues in your code. My corrected version follows, with comments about the changes I did.
public int strDist(String str, String sub) {
if (str.length() < sub.length())
return 0;
// simplified condition
if (str.equals(sub))
return str.length();
if (str.length() < 2) {
if (str.contains(sub)) {
// corrected (if str and sub are both empty strings, you don’t want to return 1)
return str.length();
}
return 0;
}
// deleted str.length() == 2 case that didn’t work correctly
if (str.startsWith(sub) && str.endsWith(sub)) {
return str.length();
}
if (str.startsWith(sub)) { // simplified
// subtracting only 1 and added return statement
return strDist(str.substring(0, str.length() - 1), sub);
}
// changed completely -- didn’t understand; added return statement, I believe this solved your test case
if (str.endsWith(sub))
return strDist(str.substring(1), sub);
return strDist(str.substring(1, str.length() - 1), sub);
}
Now if I do:
System.out.println(strDist("catcowcat", "cat"));
System.out.println(strDist("catcowcat", "cow"));
System.out.println(strDist("cccatcowcatxx", "cat"));
System.out.println(strDist("hiHellohihihi", "hih"));
I get:
9
3
9
5
Second, as I said in a comment, I see no point in using recursion here (except perhaps for the exercise). The following version of your method doesn’t, it’s much simpler and it works the same:
public int strDist(String str, String sub) {
int firstOccurrence = str.indexOf(sub);
if (firstOccurrence == -1) { // sub not in str
return 0;
}
int lastOccurrence = str.lastIndexOf(sub);
return lastOccurrence - firstOccurrence + sub.length();
}
Finally, and this may or may not be helpful, a recursive version needs not be as complicated as yours:
public int strDist(String str, String sub) {
if (sub.isEmpty()) {
throw new IllegalArgumentException("sub mustn’t be empty");
}
if (str.length() <= sub.length()) {
if (str.equals(sub)) {
return str.length();
} else { // sub cannot be in str
return 0;
}
}
if (str.startsWith(sub)) {
if (str.endsWith(sub)) {
return str.length();
} else {
return strDist(str.substring(0, str.length() - 1), sub);
}
} else {
return strDist(str.substring(1), sub);
}
}
It’s fine to get something to work first if you can, even if it’s not the most simple and elegant solution. When either it works or it doesn’t, is a good time to think of ways to simplify. It will make it easier to nail down the bug(s) and also ease maintenance later. Special cases, like length 1 and length 2, are often a good candidate for simplification: see if the general code already caters for them or can easily be made to.
this is my way of solving it, it is kinda similar but i find it simpler (hope it helps) :
public int strDist(String str, String sub) {
if(str.length() < sub.length())
return 0;
if(!str.contains(sub))return 0;
if(str.startsWith(sub)&& str.endsWith(sub))
return str.length();
if(str.startsWith(sub) )
return strDist(str.substring(0,str.length()-1),sub);
if(str.endsWith(sub))
return strDist(str.substring(1,str.length()),sub);
else return strDist(str.substring(1,str.length()-1),sub);
}
Your implementation is hard to follow. It would be more appropriate to describe the algorithm rather to provide the implementation.
Based on the description, below is my implementation. I think it is concise and easy to understand.
class Example {
private static int indexOf(String str, int idx, String sub, int res) {
if (str.length() < sub.length()) return res;
int tmp = str.indexOf(sub, idx);
if (tmp < 0) return res;
return Math.max(tmp, indexOf(str, tmp + 1, sub, res));
}
public static int strDist(String str, String sub) {
if (str.length() < sub.length()) return 0;
int from = str.indexOf(sub);
int to = indexOf(str, from + 1, sub, from);
return to - from + sub.length();
}
public static void main(String[] args) {
System.out.println();
System.out.println(strDist("catcowcat", "cat"));
System.out.println(strDist("catcowcat", "cow"));
System.out.println(strDist("cccatcowcatxx", "cat"));
System.out.println(strDist("hiHellohihihi", "hih"));
}
}
Result:
9
3
9
5
Since, others have already answered with the recursive code, I have included an O(n) solution using KMP algorithm
#include <iostream>
#include <vector>
using namespace std;
vector<int> failureFunction(string a){
int n= a.length();
vector<int> f(n+1);
f[0]=f[1]=0;
for(int i=2;i<=n;i++){
int j = f[i-1];
while(1){
if( a[j]== a[i-1]){
f[i]= j+1;
break;
}
else if (j==0){
f[i]= 0;
break;
}
else j = f[j];
}
}
return f;
}
int strDist(string str , string sub ){
int n= sub.length();
int m= str.length();
vector<int> f = failureFunction(sub);
vector<int> ff(m+1);
ff[0]= (str[0]==sub[0]) ? 1 : 0;
for(int i=1;i<m;i++){
int j = ff[i-1];
if(j==n)
j=f[j];
while(1){
if( sub[j] == str[i] ){
ff[i]= j+1;
break;
}
else if(j==0){
ff[i]= 0;
break;
}
else j= f[j];
}
}
int first_occ = -1, last_occ= -1;
for(int i=0;i<m;i++){
if( ff[i]==n ){
if( first_occ == -1 ){
first_occ = i-n+1;
}
last_occ = i;
}
}
if ( first_occ == -1 )
return 0;
else
return last_occ - first_occ + 1;
}
int main() {
// your code goes here
cout<<strDist("catcowcat", "cat")<<endl;
cout<<strDist("hiHellohihihi", "hih")<<endl;
cout<<strDist("catcowcat", "cow")<<endl;
cout<<strDist("cccatcowcatxx", "cat")<<endl;
cout<<strDist("xx","y");
return 0;
}
A small solution with explanation
public int strDist(String str, String sub) {
// base case
if(str.length() < sub.length() || !str.contains(sub)) return 0;
// success case
if(str.startsWith(sub) && str.endsWith(sub)) {
return str.length();
}
// cleaning the end of the string to be able to find the success case if exists
if(str.startsWith(sub)) {
return strDist(str.substring(0, str.length() - 1), sub);
}
// cleaning the begin of the string to be able to find the success case if exists
return strDist(str.substring(1), sub);
}
Here's a more raw solution.
public int strDist(String str, String sub) {
//first base case to check if the string doesnt have the substring
if(str.length() < sub.length()) return 0;
//check if the string starts with the substring
if(str.substring(0,sub.length()).equals(sub)){
//check if the string ends with the substring, if so return the length of the string
if(str.substring(str.length() - sub.length(),str.length()).equals(sub)){
return str.length();
}
//if the above condition fails, shave the last charater of the string and recurse
return strDist(str.substring(0,str.length()-1),sub);
}
//keep searching for the substring to appear in the string
return strDist(str.substring(1),sub);
}

For with if statement java

I need to chek where the char c index is on string , and if the char c is'nt there - return -1.
public class Find {
private String _st;
int i;
public Find(String st) {
_st = st;
}
public int whatIstheIndex(char c) {
for (i=0;i<_st.length();i++)
if (_st.charAt(i) == c) {
return i;
} else {
return -1;
}
return i;
}
}
I'm getting always -1. Why? Is the last return i; unnecessary?
Remove the else clause, it's returning -1 if the first character in the string isn't correct.
You would then also need to change the return statement at the end of the method.
Why don't you just use the built-in indexOf method? That would be a lot easier and quicker than looping through the string and testing each and every character.
But if you have to use this method for some strange reason, get rid of your else clause, because it makes the function return -1 every time the character tested is not matched.
Here is an alternative solution which also works.
public int whatIstheIndex(char c) {
int result = -1;
for (int i = 0; i < _st.length(); i++) {
if (_st.charAt(i) == c) {
result = i;
}
}
return result;
}
It's just a different way of thinking about the problem. I suppose it's slightly "worse" because it adds an extra line of code, but I hope you see how/why this works.
Your code should be like this:
public int whatIstheIndex(char c) {
for (int i = 0; i < _st.length(); i++)
if (_st.charAt(i) == c) {
return i;
}
return -1;
}
Hope this helps!
Why not use String.indexOf(int) method.
public int whatIstheIndex (char c) {
return _st.indexOf(c);
}
Else, return a -1 only after the loop finishes:
public int whatIstheIndex (char c) {
for (i=0;i<_st.length();i++)
if (_st.charAt(i) == c ) {
return i;
}
}
return -1;
}
What's happening is that it's looking at the first character, and if that doesn't match, it immediately returns -1 (and hence, doesn't continue looping through the chars until it finds the right one).
You need to return -1 only if you have finished the for loop and have not found the character. So it needs to be:
public int whatIstheIndex(char c) {
for (i = 0; i < _st.length(); i++) {
if (_st.charAt(i) == c) {
return i;
}
}
return -1;
}
You are always returning after looking at the first character. Your test doesn't look at other characters. A debugger would show you this. The last return i is only called if the length is 0.
Your current implementation will only ever return one of two values, 0, or -1. 0 is returned when the first index is that which the character resides, or -1 if its not found there. Remove the else clause and return -1 after you've finished the for loop to indicate that you've exhaustively searched all indexes, and found no answer.

Categories