• [LeetCode#161] One Edit Distance


    Problem:

    Given two strings S and T, determine if they are both one edit distance apart.

    General Analysis:

    This problem is not hard. However, to write out more efficient and elegant solution, we need to dive more deep to understand the logic behind it. 
    
    Instant idea:
    1. The length difference betweeen string "s" and string "t" must not longer than 1, otherwise, no one edit operation could make them same. (at least two insert or two delete actions)
    2. For it is valid, it could be following cases:
    2.1 s.length() == t.length() 
    s and t have only one character in difference.
    
    2.2 s.length() == t.length() - 1 (s.length() < t.length())
    a. insert one character into s. 
    b. append one charcter after s. 
    
    Note: append one charcter after s is strange, it could easily break your solution!

    Wrong Solution 1:

    public class Solution {
        public boolean isOneEditDistance(String s, String t) {
            int s_len = s.length();
            int t_len = t.length();
            if (s_len == 0 && t_len == 0)
                return false;
            if (Math.abs(s_len - t_len) > 1) {
                return false;
            } else if(Math.abs(s_len - t_len) == 1) {
                String longer = s;
                String shorter = t;
                if (s_len < t_len) {
                    longer = t;
                    shorter = s;
                }
                for (int i = 0; i < longer.length(); i++) {
                    String new_longer = longer.substring(0, i) + longer.substring(i+1);
                    if (new_longer.equals(shorter))
                        return true;
                }
            } else{
                int diff_count = 0;
                for (int i = 0; i < s_len; i++) {
                    if (s.charAt(i) != t.charAt(i))
                        diff_count++;
                }
                if (diff_count != 1)
                    return false;
            }
            return true;
        }
    }

    Mistake Analysis:

    Input:
    "", ""
    Output:
    true
    Expected:
    false
    
    Mistakes:
    The above solution must be wrong!!! How could you mixed "return false" and "return true" in the middle of code! It could easily break your logic. 

    Inefficient Solution 1:

    public class Solution {
        public boolean isOneEditDistance(String s, String t) {
            int s_len = s.length();
            int t_len = t.length();
            if (s_len == 0 && t_len == 0)
                return false;
            if (Math.abs(s_len - t_len) > 1) {
                return false;
            } else if(Math.abs(s_len - t_len) == 1) {
                String longer = s;
                String shorter = t;
                if (s_len < t_len) {
                    longer = t;
                    shorter = s;
                }
                for (int i = 0; i < longer.length(); i++) {
                    String new_longer = longer.substring(0, i) + longer.substring(i+1);
                    if (new_longer.equals(shorter))
                        return true;
                }
            } else{
                int diff_count = 0;
                for (int i = 0; i < s_len; i++) {
                    if (s.charAt(i) != t.charAt(i))
                        diff_count++;
                }
                if (diff_count == 1)
                    return true;
            }
            return false;
        }
    }

    Analysis:

    Even though the above solution was accepted, it is quite slow. Cause for the case of "s.length() == t.length() - 1", we have tried to delete each character in the t. which actually is quite uncessary!!!! 
    
    What's more, I have a ugly code to assgin the longer and shorter string.
    --------------------------------------------------------------
    String longer = s;
    String shorter = t;
    if (s_len < t_len) {
        longer = t;
        shorter = s;
    }
    ---------------------------------------------------------------
    Which could be smartly written as 
    if (t_len < s_len)
        return isOneEditDistance(t, s);
    It means s is always the shorter String. 
    
    
    Improve analysis:
    Actually the above solution is really really ugly, we consturct a new string and make the compare every time. The efficiency is unacceptable!
    
    There actually could be a more easy way to do it!
    We know we actually could only do two things to make two string equal, one is to insert a new character in to the shorter string s or replace one character in s. And the two actions were only allowed to perform once!
    
    Basic idea:
    We compare the characters in s and t one by one. Once we detect a difference, we try to use following two ways to fix it. 
    1. insert the difference character into s.
    String inserted = (s.substring(0, i) + t.charAt(i) + s.substring(i));
    2. reaplce the character in s.
    String replaced = (s.substring(0, i) + t.charAt(i) + s.substring(i+1));   
    
    If one of them works, it means we could use only one edit to make those two string equal. However if both of them fail, we should return false!!!<Since we only allowed to do one edit, and the conflict at current position could not be simply solved by one edit>
    
    In the case of there is no difference in common length part of s and t, we should also distinguish following two cases:
    1. s == t, which should return false.
    2. s == t + 1, which should return true, since we could append one character after s to make them same.
    
    while (i < s_len && j < t_len) {
        if (s.charAt(i) != t.charAt(j)) {
            ...
            return replaced.equals(t) || inserted.equals(t);
        }
    ...
    return s_len + 1 == t_len;

    Efficient Solution 1:

    public class Solution {
        public boolean isOneEditDistance(String s, String t) {
            int s_len = s.length();
            int t_len = t.length();
            if (t_len < s_len)
                return isOneEditDistance(t, s);
            if (t_len - s_len > 1)
                return false;
            int i = 0;
            int j = 0;
            while (i < s_len && j < t_len) {
                if (s.charAt(i) != t.charAt(j)) {
                    String replaced = (s.substring(0, i) + t.charAt(i) + s.substring(i+1));   
                    String inserted = (s.substring(0, i) + t.charAt(i) + s.substring(i));
                    return replaced.equals(t) || inserted.equals(t);
                }
                i++;
                j++;
            }
            return s_len + 1 == t_len;
        }
    }

    Improve Analysis:

    The aove solution could be written in a more elegant way. 
    1. use only one index i, since until we return the result, i and j share the same start and pace.
    int i = 0;
    int j = 0;
    while (i < s_len && j < t_len) {
        ...
        i++;
        j++;
    }
    
    2. no need to compare the suppposed common part among s and t.
    String replaced = (s.substring(0, i) + t.charAt(i) + s.substring(i+1));   
    String inserted = (s.substring(0, i) + t.charAt(i) + s.substring(i));
    return replaced.equals(t) || inserted.equals(t);
    
    Since s.substring(0, i) is common is s and t. any after the edits, t.charAt(i) was inserted/replaced into s. We absolutely have no need to compare them again.
    if (s.charAt(i) != t.charAt(i))
        return s.substring(i+1).equals(t.substring(i+1)) || s.substring(i).equals(t.substring(i+1));

    Upgraded Solution:

    public class Solution {
        public boolean isOneEditDistance(String s, String t) {
            int s_len = s.length();
            int t_len = t.length();
            if (t_len < s_len)
                return isOneEditDistance(t, s);
            if (t_len - s_len > 1)
                return false;
            int i = 0;
            while (i < s_len) {
                if (s.charAt(i) != t.charAt(i))
                    return s.substring(i+1).equals(t.substring(i+1)) || s.substring(i).equals(t.substring(i+1));
                i++;
            }
            return s_len + 1 == t_len;
        }
    }
  • 相关阅读:
    C#在二维码中添加圆角logo
    保存emoji到数据库
    参数名ASCII码从小到大排序(字典序)
    SQL SERVER 2008 获取表字段的类型
    js对Cookie的读写操作
    sql server2008根据经纬度计算两点之间的距离
    sql server2008给数据表,字段,添加修改注释
    关闭浏览器的放大缩小功能
    SQL Server 阻止了对组件 'Ole Automation Procedures' 的 过程'sys.sp_OACreate' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用 sp_configur
    ASP.NET正则表达式(URL,Email)
  • 原文地址:https://www.cnblogs.com/airwindow/p/4815270.html
Copyright © 2020-2023  润新知