Noob, creating string method's indexof and substring - string

As an assignment we are supposed to create methods that copy what string methods do. We are just learning methods and I understand them, but am having trouble getting it to work.
given:
private String st = "";
public void setString(String p){
st = p;
}
public String getString(){
return st;
}
I need to create public int indexOf(char index){}, and public String substring(int start, int end){} I've succesfuly made charAt, and equals but I need some help. We are only allowed to use String methods charAt(), and length(), and + operator. No arrays or anything more advanced either. This is how I'm guessing you start these methods:
public int indexOf(char index){
for(int i = 0; i < st.length(); i++){
return index;
}
return 0;
}
public String substring(int start, int end){
for(int i = 0; i < st.length(); i++){
}
return new String(st + start);
}
thanks!
here's my two working methods:
public boolean equals(String index){
for(int a = 0; a < index.length() && a < st.length(); a++){
if(index.charAt(a) == st.charAt(a) && index.length() == st.length()){
return true;
}
else{
return false;
}
}
return false;
}
public char charAt(int index){
if(index >= 0 && index <= st.length() - 1)
return st.charAt(index);
else
return 0;
}

For your indexOf method, you're on the right track. You'll want to modify the code in the loop. Since you're looping through the whole String, and you only have two methods available, which will help you most to get the characters from the String? Look to your other methods (equals and charAt) to see how you did them, it might give a hint. Remember, you want find a single character in your String and print out the index in which you found it.
For your substring method what you need to do is get all the characters that are represented beginning at start index and go up until end index. A loop is a good start, but you will need a base String to hold your progress in (you will need an empty String). The beginning and end point of your loop need a looking at. For substring, you want to get everything starting at start and everything before end. For instance, if I do the following:
String myString = "Racecar";
String sub = myString.substring(1, 4);
System.out.println(sub);
I should get the output ace.
I would give you the answer, but I think helping guide your reasoning will give you more benefit. Enjoy your assignment!

Related

Optimal algorithm for this string decompression

I have been working on an exercise from google's dev tech guide. It is called Compression and Decompression you can check the following link to get the description of the problem Challenge Description.
Here is my code for the solution:
public static String decompressV2 (String string, int start, int times) {
String result = "";
for (int i = 0; i < times; i++) {
inner:
{
for (int j = start; j < string.length(); j++) {
if (isNumeric(string.substring(j, j + 1))) {
String num = string.substring(j, j + 1);
int times2 = Integer.parseInt(num);
String temp = decompressV2(string, j + 2, times2);
result = result + temp;
int next_j = find_next(string, j + 2);
j = next_j;
continue;
}
if (string.substring(j, j + 1).equals("]")) { // Si es un bracket cerrado
break inner;
}
result = result + string.substring(j,j+1);
}
}
}
return result;
}
public static int find_next(String string, int start) {
int count = 0;
for (int i = start; i < string.length(); i++) {
if (string.substring(i, i+1).equals("[")) {
count= count + 1;
}
if (string.substring(i, i +1).equals("]") && count> 0) {
count = count- 1;
continue;
}
if (string.substring(i, i +1).equals("]") && count== 0) {
return i;
}
}
return -111111;
}
I will explain a little bit about the inner workings of my approach. It is a basic solution involves use of simple recursion and loops.
So, let's start from the beggining with a simple decompression:
DevTech.decompressV2("2[3[a]b]", 0, 1);
As you can see, the 0 indicates that it has to iterate over the string at index 0, and the 1 indicates that the string has to be evaluated only once: 1[ 2[3[a]b] ]
The core here is that everytime you encounter a number you call the algorithm again(recursively) and continue where the string insides its brackets ends, that's the find_next function for.
When it finds a close brackets, the inner loop breaks, that's the way I choose to make the stop sign.
I think that would be the main idea behind the algorithm, if you read the code closely you'll get the full picture.
So here are some of my concerns about the way I've written the solution:
I could not find a more clean solution to tell the algorithm were to go next if it finds a number. So I kind of hardcoded it with the find_next function. Is there a way to do this more clean inside the decompress func ?
About performance, It wastes a lot of time by doing the same thing again, when you have a number bigger than 1 at the begging of a bracket.
I am relatively to programming so maybe this code also needs an improvement not in the idea, but in the ways It's written. So would be very grateful to get some suggestions.
This is the approach I figure out but I am sure there are a couple more, I could not think of anyone but It would be great if you could tell your ideas.
In the description it tells you some things that you should be awared of when developing the solutions. They are: handling non-repeated strings, handling repetitions inside, not doing the same job twice, not copying too much. Are these covered by my approach ?
And the last point It's about tets cases, I know that confidence is very important when developing solutions, and the best way to give confidence to an algorithm is test cases. I tried a few and they all worked as expected. But what techniques do you recommend for developing test cases. Are there any softwares?
So that would be all guys, I am new to the community so I am open to suggestions about the how to improve the quality of the question. Cheers!
Your solution involves a lot of string copying that really slows it down. Instead of returning strings that you concatenate, you should pass a StringBuilder into every call and append substrings onto that.
That means you can use your return value to indicate the position to continue scanning from.
You're also parsing repeated parts of the source string more than once.
My solution looks like this:
public static String decompress(String src)
{
StringBuilder dest = new StringBuilder();
_decomp2(dest, src, 0);
return dest.toString();
}
private static int _decomp2(StringBuilder dest, String src, int pos)
{
int num=0;
while(pos < src.length()) {
char c = src.charAt(pos++);
if (c == ']') {
break;
}
if (c>='0' && c<='9') {
num = num*10 + (c-'0');
} else if (c=='[') {
int startlen = dest.length();
pos = _decomp2(dest, src, pos);
if (num<1) {
// 0 repetitions -- delete it
dest.setLength(startlen);
} else {
// copy output num-1 times
int copyEnd = startlen + (num-1) * (dest.length()-startlen);
for (int i=startlen; i<copyEnd; ++i) {
dest.append(dest.charAt(i));
}
}
num=0;
} else {
// regular char
dest.append(c);
num=0;
}
}
return pos;
}
I would try to return a tuple that also contains the next index where decompression should continue from. Then we can have a recursion that concatenates the current part with the rest of the block in the current recursion depth.
Here's JavaScript code. It takes some thought to encapsulate the order of operations that reflects the rules.
function f(s, i=0){
if (i == s.length)
return ['', i];
// We might start with a multiplier
let m = '';
while (!isNaN(s[i]))
m = m + s[i++];
// If we have a multiplier, we'll
// also have a nested expression
if (s[i] == '['){
let result = '';
const [word, nextIdx] = f(s, i + 1);
for (let j=0; j<Number(m); j++)
result = result + word;
const [rest, end] = f(s, nextIdx);
return [result + rest, end]
}
// Otherwise, we may have a word,
let word = '';
while (isNaN(s[i]) && s[i] != ']' && i < s.length)
word = word + s[i++];
// followed by either the end of an expression
// or another multiplier
const [rest, end] = s[i] == ']' ? ['', i + 1] : f(s, i);
return [word + rest, end];
}
var strs = [
'2[3[a]b]',
'10[a]',
'3[abc]4[ab]c',
'2[2[a]g2[r]]'
];
for (const s of strs){
console.log(s);
console.log(JSON.stringify(f(s)));
console.log('');
}

String Containing only Vowels

Suppose I have a vector of string and it contains strings (aei,ou,a). I want to concatenate them in O(n). After concatination it will become (aeiou,aeia,oua). I want to do concatination in one for loop. How to do it?
Mind you, I haven't checked this, i just made this on the fly. but this sounds like its what you want.
public void variableStrings(arr[] strings) {
List<string> newList = new List<string>();
for(int i = 0; i+1 < strings.Length -1; i++)
{
newList.add(string.Format("{0}{1}",strings[i],strings[i+1]));
}
}

How do I delete a word with Recursion and count the times it deletes?

I've completed about half of my assignment where I have to count the "chickens" in a string, remove the chickens, and return the amount of times I have to remove them.
public static int countChickens(String word)
{
int val = word.indexOf("chicken");
int count = 0;
if(val > -1){
count++;
word = word.substring(val + 1);
//I'm aware the following line doesn't work. It's my best guess.
//word.remove.indexOf("chicken");
val = word.indexOf("chicken");
}
return count;
}
As is, the program counts the correct amount of chickens in the word itself. (Sending it "afunchickenhaschickenfun" returns 2.) However, I need it to be able to return 2 if I send it something like "chichickencken" because it removed the first chicken, and then the second chicken came into play. How do I do the remove part?
Not tested and writen in sudo code, but should give you a better idea on a way to approach this.
int numberOfChickens = 0;
public void CountAndReplaceChicken(string word)
{
int initCheck = word.indexOf("chicken");
if (initCheck > -1)
{
word = word.remove.indexOf("chicken"); // not sure about the syntax in Eclipse but given you figure this part out
numberOfChickens++;
int recursionCheck = word.indexOf("chicken");
if (recursionCheck > -1)
CountAndReplaceChicken(word);
}
}
Okay, the teacher showed us how to do it a few days later. If I understood David Lee's code right, this is just a simplified way of what he did.
public static int countChickens(String word)
{
int val = word.indexOf("chicken");
if(val > -1){
return 1 + countChickens(word.substring(0, val) + word.substring(val + 7));
}
return 0;
}

Why do I keep receiving a java.lang.StringIndexOutOfBoundsException

I am trying to write a program that takes a string and removes all instances of another string from it. For example: ("Remove them all!", "em") would print "Rove th all!". However, when I do run this, it give me java.lang.StringIndexOutOfBoundsException.
public class LabFive {
public static String removeAll(String oldPhrase, String removal){
String newPhrase = "";
for(int i = 0; i <= oldPhrase.length(); i++){
if(oldPhrase.substring(i, (removal.length() + i)) == removal)
newPhrase = newPhrase + oldPhrase.substring((removal.length() + 2 + i), oldPhrase.length());
}
return(newPhrase);
}
public static void main(String[] args) {
System.out.println(removeAll("AaAaAa", "a"));
}
}
The easiest way to explain the java.lang.StringIndexOutOfBoundsException is in your loop:
for(int i = 0; i <= oldPhrase.length(); i++){...}
since i is going to be equal to oldPhrase.length() you have a problem with getting the substring:
oldPhrase.substring(i, (removal.length() + i))
so you end up with eventually
oldPhrase.substring(oldPhrase.length(), (removal.length() + oldPhrase.length()))
This is a problem because the highest index in a string is length - 1 and you're trying to access the index at length.
A brute force way of doing removeAll would be to iterate over your string (as you did) and just check, for each character at i, if removal starts there and then the string you want to return would be
sub(0,i) + removeAll(the rest off your string starting at i+removal.length)
public static String removeAll(String oldPhrase,String removal) {
int rem = removal.length();
int n = oldPhrase.length();
// if length of oldPhrase is shorter than removal
// then there nothing you need to remove
if (n < rem) return oldPhrase;
// iterate over your string
for (int i = 0; i <= n - rem; i++) {
int j;
// check if there is a substring, removal, starting at i
for (j = 0; j < rem; j++) {
if (oldPhrase.charAt(i+j) != removal.charAt(j))
break;
}
// if there is...
if (j == rem) {
// return stuff before substring you want to remove +
// removeAll(the stuff after substring you want to remove)
return oldPhrase.substring(0,i) + removeAll(oldPhrase.substring(i+rem,n),removal);
}
}
return oldPhrase;
}
public static void main(String[] args) {
System.out.println(removeAll("AaAaAa", "a"));
}
output:
AAA
Your code seems to have several issues. Firstly, you can't use == to check for string equality, you have to use String.equals() method. Read here.
Secondly, your for loop iterates from 0 to oldPhrase.length() inclusive, but trying to use this length value for index will cause the exception to occur. In java, strings have zero-based index, so index starts from 0 and ends at oldPhrase.length()-1.
Third, your logic seems broken. The substring(int, int) method's parameters are beginIndex and endIndex. So:
newPhrase = newPhrase + oldPhrase.substring((removal.length() + 2 + i), oldPhrase.length());
concatenating part of the oldPhrase till the end to the newPhrase is not going to do what you want.
Here is the way I did it. The idea is simpler, and also clearer. I have added comment to make it clear.
Test the code live on Repl.it
public static String removeAll(String oldPhrase, String removal) {
// if removal is not found return the original string
if(oldPhrase.indexOf(removal) == -1) {
return oldPhrase;
}
int removalLength = removal.length(); // storing the length so as not to call .length() again and again
for(int i = 0; i < oldPhrase.length(); i++) { // note that <= will cause the exception too
int idxOfRemoval = oldPhrase.indexOf(removal);
if(idxOfRemoval == i) { // removal is found at the current index, i.e. at index i
// take substring from beginning to index of removal +
// substring from the end of removal to end of original string
oldPhrase = oldPhrase.substring(0, idxOfRemoval) + oldPhrase.substring(idxOfRemoval+removalLength);
}
}
return(oldPhrase);
}
public static void main(String[] args) {
System.out.println(removeAll("AaAaAa", "a"));
}
Output:
AAA

recursive method to display a string backwards but while loop doesn't work

I tried to write a recursive method that displays the contents of a string backwards. And I don't understand why the while loop in the method doesn't work as I expected, it keeps looping and looping.
However, if I use if/else loop, it seems to work perfectly.
But I just want to understand what happens to the while loop.
public class printString{
void BitString(String a, int i){
while (i > 0){
System.out.println(i);
//System.out.println(a.substring(i-1, i));
i--;
BitString(a.substring(0, i), i);
}
return;
}
public static void main(String args[]){
printString print = new printString();
String str = "I am a beginner.";
int i = str.length() -1;
print.BitString(str, i);
}
}
Bit modify the code.
Here 4 things missing
1)getting substring
What substring method says:The substring begins at the specified beginIndex and extends to the character at index endIndex - 1
Here every time last char is lost,Because of that index out of range exception is occuring
2)The count(length) should be decreased after substring method,while passing parameter
3)return statement is missing..!!,there must be return statement else program runs infinite times.
4)while condition while (i >= 0)
void BitString(String a, int i){
while (i >= 0){
System.out.print(a.charAt(i));
//i--;
BitString(a.substring(0, i), --i);
return;//Missing return
}
return;
}

Resources