zoukankan      html  css  js  c++  java
  • [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;
        }
    }
  • 相关阅读:
    docker/qemu中是如何对设备管理的
    capacilitys docker中的权限设置 privileged
    比特币的价值
    js连接sqlserver进行查询
    easyUI 添加排序到datagrid
    jquery easyui datagrid 分页 详解
    ASP.net中DateTime获取当前系统时间的大全
    计算数据库中30天以内,30-60天,60-90天,90天以外的数据的个数(用sql实现)
    常用的.net开源项目
    数据库设计三大范式
  • 原文地址:https://www.cnblogs.com/airwindow/p/4815270.html
Copyright © 2011-2022 走看看