我最近遇到了这个问题:
Given two strings, return true if they are one edit away from each other,else return false.
An edit is insert/replace/delete a character.
Ex. {"abc","ab"}->true, {"abc","adc"}->true, {"abc","cab"}->false
解决此问题的一种方法是使用动态编程找到两个字符串之间的编辑距离,并检查它是否为1.这将花费O(N2)时间。有没有办法在线性时间内完成此操作,因为我们只检查它们是否是1次编辑?
我在下面写的代码适用于大多数情况,但是对于像{" m",""}
这样的情况却失败了public boolean isOneEditDistance(String s1,String s2){
if(s1==null || s2==null)
return true;
if(s1.equals(s2))
return false;
if (Math.abs(s1.length() - s2.length()) > 1)
return false;
int i = -1;
int j = -1;
while (true)
{
i++;
j++;
if (i == s1.length())
return true;
if (s1.charAt(i) == s2.charAt(j))
continue;
if (i != j)
return false;
if (s1.length() < s2.length())
i--;
else
j--;
}
}
答案 0 :(得分:7)
这是在O(n)中找到一个编辑的解决方案。以下是我已在实施中介绍的方案。
private static boolean isOneEdit(String first, String second) {
// if the input string are same
if (first.equals(second))
return false;
int len1 = first.length();
int len2 = second.length();
// If the length difference of the stings is more than 1, return false.
if ((len1 - len2) > 1 || (len2 - len1) > 1 ) {
return false;
}
int i = 0, j = 0;
int diff = 0;
while (i<len1 && j<len2) {
char f = first.charAt(i);
char s = second.charAt(j);
if (f != s) {
diff++;
if (len1 > len2)
i++;
if (len2 > len1)
j++;
if (len1 == len2)
i++; j++;
}
else{
i++; j++;
}
if (diff > 1) {
return false;
}
}
// If the length of the string is not same. ex. "abc" and "abde" are not one edit distance.
if (diff == 1 && len1 != len2 && (i != len1 || j != len2)) {
return false;
}
return true;
}
答案 1 :(得分:3)
在动态编程方法中,经常使用矩阵。行对应一个字符串,列对应另一个字符串。重点是找到从左上角单元到右下角最便宜的路径。在任何时候,水平或垂直过渡都代表插入。
您的问题是一样的,但路径受到限制。使用 k 插入/删除时,路径被限制在 k - 对角线中。除此之外,经典的DP算法应该可行。复杂性是线性的。
答案 2 :(得分:1)
我在 C ++ 中解决了该问题,它是Khalid Habib试图在this答案中说的正确版本。这是下面的解决方案(我也在Github上添加了该解决方案,您可以点击链接here)。
#include<bits/stdc++.h>
using namespace std;
// checks if there is only one one different in both arrays
bool oneReplaceAway(string s1, string s2){
bool firstChangeDone = false;
int l1 = s1.length();
// l1 == l2 already
// int l2 = s2.length();
int l2 = l1;
int i=0, j=0;
while(i<l1 && j<l2){
if(s1[i] != s2[j]){
// if first change is already checked then return false as there are more than one dissimilarities
if(firstChangeDone){
//cout<<"IGI@"<< i<<" "<<j<<"\n";
return false;
}
firstChangeDone = true;
}
i++;
j++;
}
return true;
}
// checks if one word can be added to one string to create the other one
bool oneInsertAway(string s1, string s2){
bool firstChangeDone = false;
int l1 = s1.length();
int l2 = s2.length();
int i=0, j=0;
while(i<l1 && j<l2){
if(s1[i]!=s2[j]){
// if the chars at i and j are not equal and i!=j, that means one change is already checked, i.e., it is the second change
if(i!=j)
return false;
j++;
}
else{
i++;
j++;
}
}
return true;
}
// checks of two strings are One Edit Away
bool oneEditAway(string s1, string s2) {
int l1 = s1.length();
int l2 = s2.length();
// cout<<s1<<" - "<<l1<<"\n"<<s2<<" - "<<l2<<"\n"<<(l1==l2)<<"\n";
if(l1 == l2){
return oneReplaceAway(s1, s2);
}
else if(l1+1 == l2){
return oneInsertAway(s1, s2);
}
else if(l2+1 == l1){
return oneInsertAway(s2, s1);
}
else
return false;
}
int main(){
int t;
cin>>t;
while(t--){
string s1,s2;
cin>>s1>>s2;
// cout<<oneEditAway(s1, s2)<<"\n";
string ans = oneEditAway(s1, s2)==1?"One Edit Awway":"Not one Edit Away";
cout<<ans<<"\n";
}
return 0;
}
答案 3 :(得分:1)
在C#中有一种简单的方法。
static bool OneEdit(string s1, string s2)
{
var diff = s1.Length > s2.Length
? s1.Except(s2).ToList()
: s2.Except(s1).ToList();
return diff.Count() == 1;
}
答案 4 :(得分:1)
static boolean isEditDistanceOne(String s1, String s2)
{
// Find lengths of given strings
int m = s1.length(), n = s2.length();
// If difference between lengths is more than
// 1, then strings can't be at one distance
if (Math.abs(m - n) > 1)
return false;
int count = 0; // Count of edits
int i = 0, j = 0;
while (i < m && j < n)
{
// If current characters don't match
if (s1.charAt(i) != s2.charAt(j))
{
if (count == 1)return false;
// If length of one string is
// more, then only possible edit
// is to remove a character
if (m > n) i++;
else if (m< n) j++;
else //Iflengths of both strings is same
{
i++;
j++;
}
// Increment count of edits
count++;
}
else // If current characters match
{
i++;
j++;
}
}
// If last character is extra in any string
if (i < m || j < n)
count++;
return count == 1;
}
答案 5 :(得分:0)
boolean oneEditAway(String first, String second) {
if (first.length() == second.length()) {
//call a function which replce the character from the string
} else if (first.length() + 1 == second.length()) {
//call a function which remove the character from string
} else if (first.length() - 1 == second.length()) {
//call a function which insert the character in the string
}
return false;
}
答案 6 :(得分:0)
这是Ruby实现:
def one_away(s1, s2)
return false if (s1.size - s2.size).abs > 1
missed_count = 0
counter = 0
s1.each_char do |c|
if !s2[counter].nil? && (s2[counter] != c)
missed_count += 1
end
counter += 1
return false if missed_count > 1
end
true
end
p one_away('pale', 'bake') #=> false
答案 7 :(得分:0)
逐步解释 Swift 中的答案:
func isOneEdit(str1: String, str2: String) -> Bool {
// check if they are the same
if str1 == str2 {
return true
}
let difference = abs(str1.count - str2.count)
// check if the difference between then is bigger than 1
if difference > 1 {
return false
}
// lets iterate over the words
var i = 0
var j = 0
var changes = 0
while i < str1.count && j < str2.count {
let char1 = str1[str1.index(str1.startIndex, offsetBy: i)]
let char2 = str2[str1.index(str2.startIndex, offsetBy: j)]
// if the difference is 1 we need to move just one index (the one from the bigger word)
// this is just necessary when the char1 and char2 are different
if difference == 1 && char1 != char2 {
if str1.count > str2.count {
i += 1
} else {
j += 1
}
changes += 1
} else {
// if chars are equal (in this step we don't care about the difference)
// we move both indexes.
i += 1
j += 1
if char1 != char2 {
changes += 1
}
}
}
return changes <= 1
}
答案 8 :(得分:0)
Java版本可能如下:
public static boolean oneEdit(String w1, String w2)
{
char[] word1= w1.trim().toCharArray();
char[] word2 = w2.trim().toCharArray();
int length1=word1.length;
int length2=word2.length;
if(Math.abs(length2-length1) > 1) return false;
Arrays.sort(word1);
Arrays.sort(word2);
int length = word1.length >= word2.length? word2.length:word1.length; //take the minimum length
int falseCounter=0;
for(int i=0; i < length; i++ ) {
if(word1[i] != word2[i] && ++falseCounter > 1){
return false;
}
}
return true;
}
答案 9 :(得分:0)
C#版本
static bool IsOneEditAway(string word1, string word2)
{
if (string.IsNullOrEmpty(word1) && string.IsNullOrEmpty(word2))
return false;
ActionType actionToPerform;
if (word1.Length == word2.Length)
{
actionToPerform = ActionType.Replace;
}
else if (word1.Length < word2.Length)
{
actionToPerform = ActionType.Delete;
}
else
actionToPerform = ActionType.Insert;
int i = 0, j = 0;
var numOfEdits = 0;
var chrWord1 = word1.ToCharArray();
var chrWord2 = word2.ToCharArray();
while (numOfEdits <= 1)
{
if (i >= chrWord1.Length && j >= chrWord2.Length)
break;
if (i >= chrWord1.Length && j < chrWord2.Length)
{
j++;
numOfEdits++;
continue;
}
if (j >= chrWord2.Length && i < chrWord1.Length)
{
i++;
numOfEdits++;
continue;
}
if (chrWord1[i] == chrWord2[j])
{
i++; j++;
}
else
{
switch(actionToPerform)
{
case ActionType.Insert:
i++;
break;
case ActionType.Delete:
j++;
break;
case ActionType.Replace:
i++;j++;
break;
}
numOfEdits++;
}
}
return numOfEdits == 1 ? true : false;
}
public enum ActionType
{
Insert=0,
Delete=1,
Replace=2
}
答案 10 :(得分:0)
这是我在C#
的O(n)时间中的解决方案。几种情况:
我们将仅考虑小写英文字母
public static bool IsStringOneAway(string s1, string s2)
{
//we will consider lower-case English alphabets only
int[] engArray = new int[26];
var tmp = 0;
var editCount = 0;
//if string lengths differ by more than 1, then return
if (Math.Abs(s1.Length - s2.Length) > 1)
{
Console.WriteLine("Length difference is more than 1, One Away edit doesn't exist");
return false;
}
//append the english alphabet array from String 1
for (int i = 0; i < s1.Length; i++)
{
tmp = (int)s1[i];
engArray[tmp - 97]++;
}
//deduct the english alphabet arry from String 2
for (int i = 0; i < s2.Length; i++)
{
tmp = (int)s2[i];
engArray[tmp - 97]--;
}
//now check the count of edits; if count > 1, break
for (int i = 0; i < engArray.Length; i++)
{
if (engArray[i] != 0)
{
editCount++;
if (editCount > 2)
{
Console.WriteLine("One Away edit doesn't exist");
return false;
}
}
}
Console.WriteLine("One Away edit exist");
return true;
}
答案 11 :(得分:0)
这是我的python实现。我为每个字符串使用两个数组
import unittest
# Assume characters stored in 8 bits. 256 possible characters
MAX_CHARS = 256
def is_edit(string1, string2):
"""Given two strings, return if they are one or zero edits away.
Insert, remove or replace a character."""
# If the absolute difference in length is more than one
# return false
string1_len = len(string1)
string2_len = len(string2)
if string1_len != string2_len and abs(string1_len - string2_len) > 1:
return False
# Initialize two arrays, each for each string
count1 = [0] * MAX_CHARS
count2 = [0] * MAX_CHARS
# For each character in input strings get unicode representation
# and increment counter in corresponding array
for i in string1:
count1[ord(i)] += 1
for i in string2:
count2[ord(i)] += 1
edit = 0
# compare the arrays
# If number of edits required is more than 2 return false
# This will handle replacement when given words of the same length
for i in range(MAX_CHARS):
if count1[i] != count2[i]:
edit += 1
if edit > 2:
return False
# Return false if string1 is the same as string2 (No edit required) e.g pale, pale
if not edit:
return False
return True
class EditCheckTestCase(unittest.TestCase):
"""Tests for is_edit method."""
def test_insert_missing_character(self):
"""Test insertion of character is valid."""
self.assertEqual(is_edit('pale', 'ple'), True)
def test_insert_more_than_one_character(self):
"""Test insertion of more than one character is invalid"""
self.assertEqual(is_edit('pale', 'pe'), False)
def test_append_one_character(self):
"""Test the append of one character is valid."""
self.assertEqual(is_edit('pales', 'pale'), True)
def test_append_more_than_one_character(self):
"""Test append more than one character is invalid."""
self.assertEqual(is_edit('paless', 'pale'), False)
def test_replace_one_character(self):
"""Test replacement of one character is valid"""
self.assertEqual(is_edit('pale', 'bale'), True)
def test_no_edit_character(self):
"""Test no edit required is valid."""
self.assertEqual(is_edit('pale', 'bake'), False)
self.assertEqual(is_edit('pale', 'pale'), False)
if __name__ == "__main__":
unittest.main()
答案 12 :(得分:0)
diameter = float(input("Enter a diameter: "))
print (diameter)
radius = (diameter/2)
print("The radius is equal to : ", radius)
答案 13 :(得分:0)
这将花费o(n)运行时间
public static boolean isOneEditDistance(String str1 ,String str2 ){
if(Math.abs(str1.length() - str2.length()) > 1){
return false;
}
String s1 = str1.length() < str2.length() ? str1 : str2; // smallest
String s2 = str1.length() < str2.length() ? str2 : str1; // biggest
int index1 = 0, index2 = 0;
boolean isMoreThanOneEdit = false;
while (index1 < s1.length() && index2 < s2.length()){
if(s1.charAt(index1) != s2.charAt(index2)){
if(isMoreThanOneEdit)
return false;
isMoreThanOneEdit = true;
if(s1.length() == s2.length()) // if replace
index1++;
}else {
index1++; // if match
}
index2++; // always longer string index
}
return true;
}
答案 14 :(得分:0)
C.this.type#T
答案 15 :(得分:0)
在这里,您可以在Swift中找到解决方案。
func isOneEdit(str1: String, str2: String) -> Bool {
//The length difference between two input strings should not be more than 1.
let diff = abs(str1.characters.count - str2.characters.count)
if diff > 1 {
return false
}
//When the length of the strings is same, the number of different chars should not be more than 1.
if diff == 0 {
var numberOfEdits = 0
for (char1, char2) in zip(str1.characters, str2.characters) {
if char1 != char2 {
numberOfEdits++
}
}
return numberOfEdits < 2
}
//If the length difference is 1.
//then either one char can be inserted in the short string or deleted from the longer string.
//Considering that, the number of different char should not be more than 1.
return str1.rangeOfString(str2) != nil || str2.rangeOfString(str1) != nil
//return str1.isSubstring(str2) || str2.isSubstring(str1)
}
此函数需要O(n)时间和恒定空间。
答案 16 :(得分:0)
Java版本
public class Test {
public static void main(String[] args) {
System.out.println(fun("car", "cart"));
System.out.println(fun("cat", "bat"));
System.out.println(fun("balck", "back"));
}
/*
* Modifications : add, delete, update
*
* i/p Example Add: a = car b = cart
*
* delete : a = balck b = back
*
* update: a = cat b = bat
*
*/
public static boolean fun(String a, String b) {
Boolean isTestPositive = Boolean.FALSE;
if (a == null || b == null) {
return isTestPositive;
}
if (a.equals(b)) {
// No Modifications required
return isTestPositive;
}
// Start comparing
char[] arrayForA = a.toCharArray();
char[] arrayForB = b.toCharArray();
return testCase(arrayForA, arrayForB);
}
public static boolean testCase(char[] a, char[] b) {
int correctionCount = 0;
int aLen = a.length;
int bLen = b.length;
if (Math.abs(aLen - bLen) > 1) {
return Boolean.FALSE;
}
int minLen = Math.min(aLen, bLen);
for (int i = 0; i < minLen; i++) {
if (a[i] != b[i]) {
++correctionCount;
if (correctionCount > 1) {
return Boolean.FALSE;
}
// Test Delete case
if (b.length > i + 1 && a[i] == b[i + 1]) {
return testDeleteCase(Arrays.copyOfRange(a, i, a.length - 1),
Arrays.copyOfRange(b, i + 1, b.length - 1));
} else if (a.length > i + 1 && b[i] == a[i + 1]) {
return testDeleteCase(Arrays.copyOfRange(a, i + 1, a.length - 1),
Arrays.copyOfRange(b, i, b.length - 1));
}
}
}
return Boolean.TRUE;
}
public static boolean testDeleteCase(char[] a, char[] b) {
int aLen = a.length;
int bLen = b.length;
if (Math.abs(aLen - bLen) >= 1) {
return Boolean.FALSE;
}
int minLen = Math.min(aLen, bLen);
for (int i = 0; i < minLen; i++) {
if (a[i] != b[i]) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}}
答案 17 :(得分:0)
Java 中的通用实现,在 O(N) 中运行所需的编辑次数。它确定两个字符串应该小于或等于 edits
。
public boolean isEditsAway(String s1, String s2, int edits) {
int abs = Math.abs(s1.length() - s2.length());
if (abs > edits)
return false;
int edit = 0;
for (int i = 0; i < s1.length() && i < s2.length(); i++) {
if (s1.charAt(i) != s2.charAt(i))
edit++;
if (edit == edits + 1)
return false;
}
return abs + edit <= edits;
}