leetcode
leetcode 2151 ~ 2200
追加字符以获得子序列

追加字符以获得子序列

难度:

标签:

题目描述

You are given two strings s and t consisting of only lowercase English letters.

Return the minimum number of characters that need to be appended to the end of s so that t becomes a subsequence of s.

A subsequence is a string that can be derived from another string by deleting some or no characters without changing the order of the remaining characters.

 

Example 1:

Input: s = "coaching", t = "coding"
Output: 4
Explanation: Append the characters "ding" to the end of s so that s = "coachingding".
Now, t is a subsequence of s ("coachingding").
It can be shown that appending any 3 characters to the end of s will never make t a subsequence.

Example 2:

Input: s = "abcde", t = "a"
Output: 0
Explanation: t is already a subsequence of s ("abcde").

Example 3:

Input: s = "z", t = "abcde"
Output: 5
Explanation: Append the characters "abcde" to the end of s so that s = "zabcde".
Now, t is a subsequence of s ("zabcde").
It can be shown that appending any 4 characters to the end of s will never make t a subsequence.

 

Constraints:

  • 1 <= s.length, t.length <= 105
  • s and t consist only of lowercase English letters.

代码结果

运行时间: 40 ms, 内存: 17.1 MB


/*
 * 思路:
 * 使用 Java Stream API 来解决这个问题。
 * 我们还是从 s 的开头和 t 的开头同时开始匹配,
 * 当匹配到 t 的结尾时,说明 t 已经是 s 的子序列。
 * 如果 s 遍历完都没有匹配到 t 的结尾,
 * 那么需要将 t 的剩余字符全部追加到 s 的末尾。
 */
import java.util.stream.IntStream;
public class Solution {
    public int appendCharacters(String s, String t) {
        int[] idx = {0};
        IntStream.range(0, s.length()).forEach(i -> {
            if (idx[0] < t.length() && s.charAt(i) == t.charAt(idx[0])) {
                idx[0]++;
            }
        });
        return t.length() - idx[0];
    }
}

解释

方法:

题解的核心思想是通过一个指针来遍历字符串t,同时遍历字符串s。对于s中的每一个字符,如果它与t中当前指针所指向的字符相同,则移动t的指针到下一个字符。这一过程继续,直到s被完全遍历或者t的指针移动到字符串t的末尾。如果在遍历完s后,t的指针已经到达t的末尾,说明t已经是s的子序列,此时无需追加任何字符。否则,需要追加的字符数就是t的剩余部分的长度,即len(t) - cur_t。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中提到,如果在遍历完s后t的指针未到达末尾,我们需要追加的字符数是t的剩余部分的长度。请问如果t的部分字符已经在s中出现过,但顺序不同,这种方法还有效吗?
该方法仅在t的字符顺序与s中的部分字符顺序一致时有效。如果t的字符虽然在s中出现过,但顺序不同,那么这种方法不足以将t转换为s的子序列。例如,如果t是'abc'而s是'cba',尽管t的所有字符都在s中,但由于顺序不同,无法通过简单地追加字符来使t成为s的子序列。因此,这种方法依赖于t的字符在s中的相对位置和顺序。
🦆
题解中使用的方法似乎假设s中的每个字符只考察一次,这种单次遍历s足以保证找到t中尽可能多的字符吗?
单次遍历s通常足够找到尽可能多的与t相匹配的字符,因为我们在遍历s的过程中逐步移动t的指针,并尽量匹配每一个字符。但这种方法假设了t中的字符在s中出现的顺序是一致的。如果t的字符在s中多次出现但顺序不同,单次遍历可能无法捕捉所有的匹配可能性。所以,这种方法最适用于t的字符顺序与s中字符的出现顺序相匹配的场景。
🦆
题解中提到,如果t的所有字符都已经匹配完毕,则返回0。这里的逻辑是否考虑了所有可能的边界条件,例如t是空字符串的情况?
如果t是空字符串,根据题解的逻辑,初始化时't_len'将为0,因此在for循环中不会执行任何匹配操作,'cur_t'始终为0,最终返回0。因此,此逻辑正确处理了t为空字符串的情况,符合预期结果,即t已经是s的子序列,不需要追加任何字符。
🦆
在题解的代码中,如果s中的字符与t中当前指针所指向的字符不同,是否有考虑到跳过s中的某些字符可能导致错过后续可能的匹配?
代码实现确实跳过了与t当前指针所指向字符不匹配的s中的字符。这个策略基于假设t中的字符必须按照特定的顺序出现在s中,而不考虑s中字符的多次出现可能带来的多种匹配序列。这种方法在t的字符顺序与s中相应字符顺序严格匹配时最有效。如果存在多种顺序的匹配可能性,该策略可能不会找到所有可能的子序列,但对于确定t是否为s的子序列来说是足够的。

相关问题