leetcode
leetcode 1601 ~ 1650
句子相似性 III

句子相似性 III

难度:

标签:

题目描述

代码结果

运行时间: 26 ms, 内存: 16.0 MB


/**
 * 思路:
 * 我们可以通过比较两个句子的前缀和后缀来判断它们是否相似。
 * 如果 sentence1 可以通过在 sentence2 的某个部分插入一部分得到,那么
 * sentence1 和 sentence2 的前缀和后缀应该相同。
 */
import java.util.Arrays;

public class SentenceSimilarity {
    public boolean areSentencesSimilar(String sentence1, String sentence2) {
        String[] words1 = sentence1.split(" ");
        String[] words2 = sentence2.split(" ");
        int i = 0;

        // 比较前缀
        i = (int) Arrays.stream(words1)
                        .limit(words2.length)
                        .takeWhile(word -> word.equals(words2[i++]))
                        .count();

        int j = 0;
        // 比较后缀
        j = (int) Arrays.stream(words1, words1.length - i, words1.length)
                        .limit(words2.length - i)
                        .takeWhile(word -> word.equals(words2[words2.length - ++j]))
                        .count();

        return i + j == Math.min(words1.length, words2.length);
    }
}

解释

方法:

该题解的核心思路是通过检查两个句子的开头和结尾是否可以匹配来判断他们是否相似。首先,确保sentence1是较短的句子,如果不是,则递归调用函数交换两个句子的位置。接着,将两个句子分割成单词数组。使用两个指针i和k分别从句子的开始比较单词是否相同,若相同则同时向后移动。当遇到不同的单词时停止。然后,使用两个指针j和k从两个句子的末尾开始向前比较,若相同则同时向前移动。最后,若i大于j,则说明所有能匹配的单词都已匹配完毕,且中间的部分可以由插入得到,返回true,否则返回false。

时间复杂度:

O(n + m)

空间复杂度:

O(n + m)

代码细节讲解

🦆
为什么首先要确保sentence1是较短的句子,递归交换两个句子的位置对算法的正确性有什么影响?
首先确保sentence1是较短的句子,是为了简化代码逻辑,因为算法的目的是检查一个较长的句子是否可以通过插入方式得到较短的句子。如果sentence1是较长的,通过递归调用函数并交换两个句子的位置,可以统一处理逻辑,使得总是检查较短句子是否可以由较长的句子通过插入得到。这样做不影响算法的正确性,反而使得实现更加统一和简洁。
🦆
在算法中,如果两个句子的长度完全相同但单词顺序不同,例如'sentence1 = "Hello Jane"' 和 'sentence2 = "Jane Hello"',这种情况下算法的返回结果是什么?
在这种情况下,算法将返回false。因为算法通过从前向后和从后向前检查单词是否相同,如果单词顺序不同,则无法在句子的开头或结尾找到完全匹配的单词序列。例如在给定的例子中,从前向后和从后向前比较都会在第一个比较时遇到不同的单词,因此i和j的条件(i > j)无法满足,所以返回false。
🦆
算法中提到的指针i和j的初始和结束条件是怎样的?请详细说明其在算法中的作用。
在算法中,指针i和j用于比较两个句子中的单词是否相同。指针i从0开始,向后移动,直到达到数组a的长度或遇到不同的单词停止。指针j从数组a的最后一个元素开始,向前移动,直到索引小于0或遇到不同的单词停止。指针i和j的作用在于识别两个句子中相同的前缀和后缀,如果在i和j的指示范围之外的句子b的部分可以插入到句子a中,以形成句子b,那么算法返回true。i > j的条件检查是否所有a中的单词都已经在b中按顺序找到了对应的位置。
🦆
在从后向前比较单词时,为什么选择从len(b) - 1开始,而不是从len(a) - 1开始?这样做有什么特别的考虑吗?
之所以从len(b) - 1开始而不是从len(a) - 1开始,是因为算法需要检查句子b是否可以通过插入一些单词到句子a中来形成。由于句子b可能比句子a长,从b的末尾开始比较可以确保我们考虑到b中所有的单词。如果我们从len(a) - 1开始,那么当b比a长时,我们将无法比较b中超出a长度的部分,这可能会错过一些可以通过插入得到的正确匹配。

相关问题