Welcome to Subscribe On Youtube
Question
Formatted question description: https://leetcode.ca/all/161.html
Given two strings s
and t
, return true
if they are both one edit distance apart, otherwise return false
.
A string s
is said to be one distance apart from a string t
if you can:
- Insert exactly one character into
s
to gett
. - Delete exactly one character from
s
to gett
. - Replace exactly one character of
s
with a different character to gett
.
Example 1:
Input: s = "ab", t = "acb" Output: true Explanation: We can insert 'c' into s to get t.
Example 2:
Input: s = "", t = "" Output: false Explanation: We cannot get t from s by only one step.
Constraints:
0 <= s.length, t.length <= 104
s
andt
consist of lowercase letters, uppercase letters, and digits.
Algorithm
Step 1: Ensure s
is the Longer String
if len(s) < len(t):
return self.isOneEditDistance(t, s)
If s
is shorter than t
, the method recursively calls itself with the arguments reversed to ensure that s
is always the longer string. This simplification allows the algorithm to focus on deletion or replacement operations without separately handling insertions.
Step 2: Check for Significant Length Differences
m, n = len(s), len(t)
if m - n > 1:
return False
If the length difference between s
and t
is greater than one, it’s impossible for them to be one edit distance apart. In such cases, the method immediately returns False
.
Step 3: Identify the Type of Edit Required
for i, c in enumerate(t):
if c != s[i]:
return s[i + 1 :] == t[i + 1 :] if m == n else s[i + 1 :] == t[i:]
The method iterates through the characters of the shorter string t
. If it encounters a character c
that doesn’t match the corresponding character in s
, it then checks the type of edit required:
- If
s
andt
are of equal length (m == n
), the method checks for a replacement operation by comparing the substrings ofs
andt
after the differing character. - If
s
is longer thant
(m > n
), the method checks for a deletion operation ins
by comparing the substring ofs
after the differing character with the rest oft
.
If either condition is true, the strings are one edit distance apart, and the method returns True
.
Step 4: Handle Edge Cases
return m == n + 1
After the loop, if no differing characters were found, there are a few possible scenarios:
s
is exactly one character longer thant
(m == n + 1
), implying a deletion operation is needed to matcht
withs
. The method returnsTrue
because they are one edit distance apart.s
andt
are of the same length but identical, which means they are not one edit distance apart. The method correctly returnsFalse
due to the check at the beginning.s
andt
differ in length by more than one character, which was already handled earlier in the method.
Code
-
import java.util.Objects; public class One_Edit_Distance { // best solution ha! public boolean isOneEditDistance(String s, String t) { for (int i = 0; i < Math.min(s.length(), t.length()); ++i) { if (s.charAt(i) != t.charAt(i)) { if (s.length() == t.length()) { return Objects.equals(s.substring(i + 1), t.substring(i + 1)); } if (s.length() < t.length()) { return Objects.equals(s.substring(i), t.substring(i + 1)); } else { return Objects.equals(s.substring(i + 1), t.substring(i)); } } } // case: abc, abcdefg return Math.abs((int)s.length() - (int)t.length()) == 1; } class Solution_true_dp { public boolean isOneEditDistance(String s, String t) { int m = s.length(), n = t.length(), i, j; int[][] dp = new int[m + 1][n + 1]; for (i = 0; i <= m; i++) dp[i][0] = i; for (j = 0; j <= n; j++) dp[0][j] = j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (s.charAt(i) == t.charAt(j)) dp[i + 1][j + 1] = dp[i][j]; else { dp[i + 1][j + 1] = Math.min(dp[i + 1][j], Math.min(dp[i][j + 1], dp[i][j])) + 1; } } } return dp[m][n] == 1; } } public class Solution_dp { public boolean isOneEditDistance(String s, String t) { if (s.length() < t.length()) return isOneEditDistance(t, s); // so 't' is always the shorter one in below logic int m = s.length(), n = t.length(), diff = m - n; if (diff >= 2) return false; else if (diff == 1) { for (int i = 0; i < n; ++i) { if (s.charAt(i) != t.charAt(i)) { return s.substring(i + 1).equals(t.substring(i)); } } return true; // meaning, diff is happening at the final char } else { int cnt = 0; for (int i = 0; i < m; ++i) { if (s.charAt(i) != t.charAt(i)) ++cnt; } return cnt == 1; } } } } ////// class Solution { public boolean isOneEditDistance(String s, String t) { int m = s.length(), n = t.length(); if (m < n) { return isOneEditDistance(t, s); } if (m - n > 1) { return false; } for (int i = 0; i < n; ++i) { if (s.charAt(i) != t.charAt(i)) { if (m == n) { return s.substring(i + 1).equals(t.substring(i + 1)); } return s.substring(i + 1).equals(t.substring(i)); } } return m == n + 1; } }
-
// OJ: https://leetcode.com/problems/one-edit-distance/ // Time: O(MN) // Space: O(min(M,N)) class Solution { private: int editDistance(string &s, string &t) { if (s.size() < t.size()) swap(s, t); int M = s.size(), N = t.size(); vector<int> dp(N + 1, 0); for (int i = 1; i <= N; ++i) dp[i] = i; for (int i = 1; i <= M; ++i) { int pre = dp[0]; dp[0] = i; for (int j = 1; j <= N; ++j) { int tmp = dp[j]; if (s[i - 1] == t[j - 1]) dp[j] = pre; else dp[j] = min(pre, min(dp[j - 1], dp[j])) + 1; pre = tmp; } } return dp[N]; } public: bool isOneEditDistance(string s, string t) { return editDistance(s, t) == 1; } };
-
class Solution: def isOneEditDistance(self, s: str, t: str) -> bool: if len(s) < len(t): # goal is to ensure t is always the shorter one return self.isOneEditDistance(t, s) m, n = len(s), len(t) if m - n > 1: # case: abc, abcdefg, return false return False for i, c in enumerate(t): if c != s[i]: return s[i + 1 :] == t[i + 1 :] if m == n else s[i + 1 :] == t[i:] # case: abc, abcd. return true # case: abc, abc. the same 2 strings should return false # case: abc, abcdefg, return false return m == n + 1 ############ class Solution(object): def isOneEditDistance(self, s, t): """ :type s: str :type t: str :rtype: bool """ if len(s) >= len(t): i = 0 while i < len(t) and s[i] == t[i]: i += 1 return s != t and (s[i + 1:] == t[i:] if len(s) != len(t) else s[i + 1:] == t[i + 1:]) else: return self.isOneEditDistance(t, s)
-
func isOneEditDistance(s string, t string) bool { m, n := len(s), len(t) if m < n { return isOneEditDistance(t, s) } if m-n > 1 { return false } for i := range t { if s[i] != t[i] { if m == n { return s[i+1:] == t[i+1:] } return s[i+1:] == t[i:] } } return m == n+1 }
-
function isOneEditDistance(s: string, t: string): boolean { const [m, n] = [s.length, t.length]; if (m < n) { return isOneEditDistance(t, s); } if (m - n > 1) { return false; } for (let i = 0; i < n; ++i) { if (s[i] !== t[i]) { return s.slice(i + 1) === t.slice(i + (m === n ? 1 : 0)); } } return m === n + 1; }