0

I am only a second semester CS student and can't use any of the well known efficient substring search algorithms. I need to implement the indexOf method with the following method signature:

int indexOf(String str, String pattern) which returns the index of the first location at which pattern appears as a substring of str.

This is what I attempted:

First I created an overloaded method index of with the signature indexOf(String str, char ch, int startIndex) that returns the index of the first location of char or -1 otherwise.

 private int indexOf(String str, char ch, int startIndex) {
    for(int i = startIndex; i < str.length(); i++)
        if(str.charAt(i) == ch) return i;

    return -1;
}

Now I write the method that searches for a substring (pattern).

private int indexOf(String str, String pattern) {
    int headIndex = indexOf(str, pattern.charAt(0), 0);
    int tailIndex = indexOf(str, pattern.charAt(pattern.length() - 1), 0);

    if(headIndex == -1 || tailIndex == -1) return -1; // no substring match

    while(true) {
        int j = 0;
        for(int i = headIndex; i <= tailIndex; i++)
            if(str.charAt(headIndex) != pattern.charAt(j++)) { //if substring does not match then compute a new head and tail Index
                headIndex = indexOf(str, pattern.charAt(0), headIndex);
                tailIndex = indexOf(str, pattern.charAt(pattern.length() - 1), tailIndex);
                j = 0;
                i = headIndex + 1;
                if(headIndex == -1 || tailIndex == -1) return -1;
                break;
            }

        if(headIndex >= 0) return headIndex;
    }
}

I believe I am close but calls like indexOf("Hellolo", "lo") returns 2 instead of 3. I'm trying to figure out where I went wrong with my logic and need help in doing so.

I am not allowed to use any special string methods except length.

Mutating Algorithm
  • 2,604
  • 2
  • 29
  • 66
  • 1
    Maybe it's because indexes start at 0 and not 1? – Keno Apr 11 '16 at 20:08
  • "can't use any of the well known efficient substring search algorithms" does that mean you can't use an existing implementation, or that you have to use an unknown and inefficient algorithm? – Andy Turner Apr 11 '16 at 20:09
  • @AndyTurner Can't use an existing implementation like Boyer-Moore – Mutating Algorithm Apr 11 '16 at 20:11
  • I think that your logic is somewhat convoluted. To implement a straightforward `O(mn)` algorithm, I don't believe you need the (first) `indexOf(String, char, int)` method. – Kedar Mhaswade Apr 11 '16 at 20:19
  • @KenoClayton If indexes started at 1, OP would expect to get 4, not 2 or 3. – Teepeemm Apr 11 '16 at 20:28
  • 1
    if you update `headIndex` and `tailIndex` with calls to the indexOf helper method starting at the existing `headIndex` and `tailIndex` values, you'll just get the same value back (you're doing this inside your for loop). Try starting at the next index for each of those and see where that gets you. – DGinzberg Apr 11 '16 at 21:11

4 Answers4

1

In your code you are looking for the first index of a single character instead of a string.

int headIndex = indexOf(str, pattern.charAt(0), 0);

If we assume that str = Hellolo" and pattern = "lo" then the code above is looking for the l and not the lo.

Edit: If you want to look for the first occurence of the string "lo" then you have to change the code to

int headIndex = indexOf(str, pattern, 0);
Keno
  • 2,018
  • 1
  • 16
  • 26
0

indexOf("Hellolo", "lo") returns 2 because the count is zero based... here the doc

public int indexOf(int ch)

Returns the index within this string of the first occurrence of the specified character. If a character with value ch occurs in the character sequence represented by this String object, then the index (in Unicode code units) of the first such occurrence is returned. For values of ch in the range from 0 to 0xFFFF (inclusive),

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
0

I'd just write the code in as simple a way as possible.

package com.ggl.testing;

public class MyString {

    public static void main(String[] args) {
        MyString myString = new MyString();
        String string = "abcdefghij";
        String pattern = "defg";
        System.out.println(myString.indexOf(string, pattern));

        pattern = "ghij";
        System.out.println(myString.indexOf(string, pattern));

        pattern = "asdf";
        System.out.println(myString.indexOf(string, pattern));
    }

    public int indexOf(String string, String pattern) {
        int length = string.length() - pattern.length();
        for (int index = 0; index <= length; index++) {
            if (patternMatch(string, index, pattern)) {
                return index;
            }
        }

        return -1;
    }

    private boolean patternMatch(String string, int index, String pattern) {
        int i = index;
        for (int j = 0; j < pattern.length(); j++) {
            if (string.charAt(i) != pattern.charAt(j)) {
                return false;
            }
            i++;
        }

        return true;
    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • 1
    `patternMatch` would be easier if you declared and incremented `i` in the for loop declaration (or just used `index + j` instead). – Andy Turner Apr 11 '16 at 20:43
0
int headIndex = indexOf(str, pattern.charAt(0));
int tailIndex = indexOf(str, pattern.charAt(pattern.length() - 1));

if(headIndex == -1 || tailIndex == -1) return -1; // no substring match

Buggy -> consider this case:

String str = "nevern";
String pattern = "vern";

I think focusing on the head char is enough:

public class Search {


    static private int indexOf(String src, char ch, int startIndex) {
        for(int i = startIndex; i < src.length(); i++)
            if(src.charAt(i) == ch) return i;

        return -1;
    }

    static private int indexOf(String src, String pat) {
        int head_in_src = 0;

        while (-1 != (head_in_src = indexOf(src, pat.charAt(0), head_in_src))) {
            if (head_in_src + pat.length() > src.length() - head_in_src)
                return -1;
            boolean match = true;
            int offset = 0;
            for (; offset < pat.length(); offset++) {
                if (src.charAt(offset + head_in_src) != pat.charAt(offset)) {
                    match = false;
                    break;
                }
            }
            if (true == match)
                return head_in_src;
            head_in_src += offset;
        }
        return -1;
    }

    public static void main(String[] args) {
        String src = "ne-nevern-nevern";
        String pat = "ever";
        String pat1 = "ne";
        String pat2 = "vern";
        String pat3 = "everne";
        String pat4= "-ne-";
        String pat5= "ner";

        System.out.printf("src=%1$s, pat=%2$s, index=%3$d%n", src, pat, indexOf(src, pat));
        System.out.printf("src=%1$s, pat1=%2$s, index=%3$d%n", src, pat1, indexOf(src, pat1));
        System.out.printf("src=%1$s, pat2=%2$s, index=%3$d%n", src, pat2, indexOf(src, pat2));
        System.out.printf("src=%1$s, pat3=%2$s, index=%3$d%n", src, pat3, indexOf(src, pat3));
        System.out.printf("src=%1$s, pat4=%2$s, index=%3$d%n", src, pat4, indexOf(src, pat4));
        System.out.printf("src=%1$s, pat5=%2$s, index=%3$d%n", src, pat5, indexOf(src, pat5));
    }
}

Output:

src=ne-nevern-nevern, pat=ever, index=4
src=ne-nevern-nevern, pat1=ne, index=0
src=ne-nevern-nevern, pat2=vern, index=5
src=ne-nevern-nevern, pat3=everne, index=-1
src=ne-nevern-nevern, pat4=-ne-, index=-1
src=ne-nevern-nevern, pat5=ner, index=-1