views:

135

answers:

5

I must write a function that takes two words (strings) as arguments, and determines if the first word can be transformed into the second word using only one first-order transformation.

  • First-order transformations alter only one letter in a word

  • The allowed transformations are: insert, remove and replace

    • insert = insert a letter at any position in the word
    • remove = delete a letter from any position in the word
    • replace = replace a letter with another one

Any suggestions? Any Java examples would be great!

A: 

You can use the Levenshtein distance and only allow distances of 1 (which means, one char must be altered). There are several implementations just google "Levenshtein java" or so.

The other "not so smart" but working thing would be the good old brute force. Just try out every situation with every char and you get what you want. :-)

InsertNickHere
Levenshtein for a single first-order transformation brings to mind using a chainsaw to trim your fingernails :) But no, the downvote isn't from me.
Carl Smotricz
@Carl: It is from me, but I didn't feel the need to explain.
Moron
@Moron If you dont explain, how could I learn from my failure?
InsertNickHere
@Moron - unfortunatly we can't downvote a comment. That would be a clear -1 from me.
Andreas_D
@InsertNickHere. I usually do explain. This one was clear enough, though and I was expecting you to understand without any explanation and if not, someone kind enough like Carl would explain it. In any case, please do notice that I was paying attention and if you had wanted an explanation (and no one else ventured), I would have given it myself. On second thoughts, maybe I should have just explained! This comment has become much longer than the explanation would have been :-)
Moron
@Andreas_D: You are entitled to your opinions. I am done with this though. Please don't expect any responses from me on this topic.
Moron
@Moron Let us not make it bigger than it is. :) Thanks for your feedback anyway.
InsertNickHere
@Moron, I don't need an answer or a reaction. It is just my personal opinion that one should (1) downvote if and only if the answer is not useful for the OP, (2) always leave an explanation and (3) if the answer is edited and not 'not useful' anymore, remove the downvote. As I said, just me personal opinion.
Andreas_D
Thank you, this is very usefull !
Matey
+6  A: 

Think: If you're only allowed a single transformation, then the difference in length between the "before" and "after" words should give you a very strong hint as to which of those three transformations has any chance of being successful. By the same token, you can tell at a glance which transformations will be simply impossible.

Once you've decided on which transformation, the rest of the problem becomes a job for Brute Force Man and his sidekick, Looping Lady.

Carl Smotricz
+2  A: 

This does look like homework so I'm not going to give you the answer, but any time you approach a problem like this the best thing to do is start sketching out some ideas. Break the problem down into smaller chunks, and then it becomes easier to solve.

For example, let's look at the insert operation. To insert an letter, what is that going to do to the length of the word in which we are inserting the letter? Increase it or decrease it? If we increase the length of the word, and the length of this new word is not equal to the length of the word we are trying to match, then what does that tell you? So one condition here is that if you are going to perform an insert operation on the first word to make it match the second word, then there is a known length that the first word must be.

You can apply similar ideas to the other 2 operations.

So once you establish these conditions, it becomes easier to develop an algorithm to solve the problem.

The important thing in any type of assignment like this is to think through it. Don't just ask somebody, "give me the code", you learn nothing like that. When you get stuck, it's ok to ask for help (but show us what you've done so far), but the purpose of homework is to learn.

dcp
I asked just for suggestions dude, not for code !
Matey
@Matey - "Any Java examples would be great" - That sounds like asking for code to me. And again, you didn't provide any evidence of your effort in solving the problem or what you've done so far.
dcp
A: 

It's not a homework, this is a real world problem !

Matey
I just asked for suggestions !
Matey
+1  A: 

If you need to check if there is one and exactly one edit from s1 to s2, then this is very easy to check with a simple linear scan.

  • If both have the same length, then there must be exactly one index where the two differ
    • They must agree up to a common longest prefix, then skipping exactly one character from both, they must then agree on a common suffix
  • If one is shorter than the other, then the difference in length must be exactly one
    • They must agree up to a common longest prefix, then skipping exactly one character from the longer one, they must then agree on a common suffix

If you also allow zero edit from s1 to s2, then simply check if they're equal.

Here's a Java implementation:

static int firstDifference(String s1, String s2, int L) {
    for (int i = 0; i < L; i++) {
        if (s1.charAt(i) != s2.charAt(i)) {
            return i;
        }
    }
    return L;
}
static boolean oneEdit(String s1, String s2) {
    if (s1.length() > s2.length()) {
        return oneEdit(s2, s1);
    }
    final int L = s1.length();
    final int index = firstDifference(s1, s2, L);
    if (s1.length() == s2.length() && index != L) {
        return s1.substring(index+1).equals(s2.substring(index+1));
    } else if (s2.length() == L + 1) {
        return s1.substring(index).equals(s2.substring(index+1));
    } else {
        return false;
    }
}

Then we can test it as follows:

    String[][] tests = {
        { "1", "" },
        { "123", "" },
        { "this", "that" },
        { "tit", "tat" },
        { "word", "sword" },
        { "desert", "dessert" },
        { "lulz", "lul" },
        { "same", "same" },
    };
    for (String[] test : tests) {
        System.out.printf("[%s|%s] = %s%n",
            test[0], test[1], oneEdit(test[0], test[1])
        );
    }

This prints (as seen on ideone.com):

[1|] = true
[123|] = false
[this|that] = false
[tit|tat] = true
[word|sword] = true
[desert|dessert] = true
[lulz|lul] = true
[same|same] = false
polygenelubricants
thank you very much !
Matey