【程序员面试金典】01.05. 一次编辑

一次编辑

字符串有三种编辑操作:插入一个英文字符、删除一个英文字符或者替换一个英文字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。

示例 1:

输入:
first = “pale”
second = “ple”
输出: True

示例 2:

输入:
first = “pales”
second = “pal”
输出: False

示例 3:

输入:
first = “pale”
second = “bale”
输出: True

示例 4:

输入:
first = “pale”
second = “bake”
输出: False

题目解法

解法 1

该题目可借助蛮力法,通过移除每一个字符(并比较),替换每一个字符(并比较),插入每一个字符(并比较)等方法,得到所有可能的字符串,然后检查只需一次编辑的字符串。(该算法运行时间过于缓慢,因此不用费尽心思来实现)

对于此类问题,思考一下每种操作的“意义”大有裨益。两个字符串之间需要一次插入、替换或删除操作意味着什么?

  • 替换。 设想一下诸如balepale这样的两个字符串,它们之间相差一次替换操作。这确实意味着你可以通过替换bale中的一个字母来获得pale,但是更精确的说法是,这两个字符仅在一个位置上有所不同。
  • 插入。 字符串appleaple之间相差一次插入操作。这意味着,如果你对比两个字符串,会发现除了在字符串的某一位置需要整体移动一次以外,它们是完全相同的。
  • 删除。 字符串appleaple之间同样也可以表示为相差一次删除操作,因为删除操作只是“插入”操作的相反操作而已。

实现算法时,会把插入和删除合并为一个步骤,而让替换操作成为一个单独的步骤。

算法实现(JAVA)
public class Solution {
    public boolean oneEditAway(String first, String second) {
        if (first.length() == second.length()) {
            // 替换
            return oneEditReplace(first, second);
        } else if (first.length() + 1 == second.length()) {
            // 删除
            return oneEditInsert(first, second);
        } else if (first.length() - 1 == second.length()){
            // 插入
            return oneEditInsert(second, first);
        }
        return false;
    }

    private boolean oneEditReplace(String first, String second) {
        boolean foundDifference = false;
        for (int i = 0; i < first.length(); i++) {
            if (first.charAt(i) != second.charAt(i)) {
                if (foundDifference) {
                    return false;
                }
                foundDifference = true;
            }
        }
        return true;
    }

    private boolean oneEditInsert(String first, String second) {
        int index1 = 0;
        int index2 = 0;
        while (index2 < second.length() && index1 < first.length()) {
            if (first.charAt(index1) != second.charAt(index2)) {
                if (index1 != index2) {
                    return false;
                }
            } else {
                index1++;
            }
            index2++;
        }
        return true;
    }

    public static void main(String[] args) {
        Solution1 solution = new Solution1();
        String first = "islander";
        String second = "slander";
        // true
        System.out.println(solution.oneEditAway(first, second));
    }
}

解法 2

解法1中方法oneEditReplace和oneEditInsert代码相差无几。因此,可以将二者合并为一个方法。

为达到该目的,请注意这两种方法的解题思路大体相似,即对比每个字符并确保两个字符串只相差一个字符。两种方法的不同之处在于如何处理不同的字符。oneEditReplace方法除了标出不同的字符之外不做任何操作,oneEditInsert方法则将较长字符串的指针向前移动。可以用同一种方法处理这两种情况。

算法实现(JAVA)
public class Solution {
    public boolean oneEditAway(String first, String second) {
        // 检查长度
        if (Math.abs(first.length() - second.length()) > 1) {
            return false;
        }

        // 获取较长和较短的字符串
        String s1 = first.length() < second.length() ? first : second;
        String s2 = first.length() < second.length() ? second : first;

        int index1 = 0;
        int index2 = 0;
        boolean foundDifference = false;
        while (index1 < s1.length() && index2 < s2.length()) {
            if (s1.charAt(index1) != s2.charAt(index2)) {
                // 确保此处为发现的第一处不同
                if (foundDifference) {
                    return false;
                }
                foundDifference = true;
                if (s1.length() == s2.length()) {
                    index1++;
                }
            } else {
                index1++; // 如果相匹配,就移动较短字符串的指针
            }
            index2++; // 总是移动较长字符串的指针
        }
        return true;
    }
}

[1] 盖尔.拉克曼.麦克道尔.程序员面试金典(第6版)[M].北京:人民邮电出版社,2019.9:162-164
[2] leetcode.面试题 01.05. 一次编辑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值