用双指针,判断子序列

历次做算法题目,今天耗时最短。题目原链接leetcode

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

示例 1:
s = "abc", t = "ahbgdc"
返回 true.

示例 2:
s = "axc", t = "ahbgdc"
返回 false.

解题逻辑,先用 s 的第一个字母和 t 的第一个字母比较,结果只有两种:
如果不一样,就拿 s 的第一个字母和 t 的下一个字母比较,
如果一样, 就拿s 的下一个字母和 t 的下一个字母比较

    public boolean isSubsequence(String s, String t) {
        char[] sChar = s.toCharArray();
        int sLen = s.length();
        char[] tChar = t.toCharArray();
        int tLen = t.length();
        int i = 0, j=0; // 初始下标
        while(i < sLen && j < tLen){
            if(sChar[i] == tChar[j]){
                i++; // 相同,s的下标后移一位
            }
            j++; // 不论相同与否,j 的下标都后移一位
        }
        return i == sLen; 
    }

官方题解中,除了双指针外,还给出了动态规划的解法,有兴趣的可以看一下。我觉得双指针已经完美解决问题,并且性能、内存消耗双百。动态规划有点大材小用了。
在这里插入图片描述

<think>嗯,我现在需要解决的是判断子序列的问题,题目是给定两个字符串s和t,判断s是否是t的子序列。用户提到要用双指针的思路来解题,而且用C++来实现。那我先得理解什么是子序列子序列的定义是不需要连续,但顺序必须一致。比如s="abc",t="ahbgdc",那s就是t的子序列,因为a在t的第一个位置,h之后是b,再后面有g、d、c,所以顺序是对的。 那双指针的思路应该是什么样的呢?可能是一个指针i指向s的当前字符,另一个指针j指向t的当前字符。然后逐个比较,如果s[i]等于t[j],那么i和j都往后移动一位;如果不相等,则只移动j指针,继续在t中寻找下一个可能的匹配字符。这样,当i遍历完整个s时,说明s是t的子序列;否则,如果j已经遍历完t但i还没遍历完s,则不是。 我需要考虑边界情况。比如,当s为空时,应该返回true,因为空字符串是任何字符串的子序列。当t为空而s不为空时,返回false。这些情况在代码中需要处理。 然后,C++的实现应该怎么写呢?函数可能是这样的:bool isSubsequence(string s, string t)。然后初始化i和j都为0,循环条件是i < s.size()且j < t.size()。在循环里比较s[i]和t[j],相等的话i++,不管是否相等,j都要++。循环结束后,检查i是否等于s.size(),如果是的话返回true,否则false。 测试一下这个逻辑。比如例子s="abc",t="ahbgdc",i开始是0,j是0。s[0]是a,t[0]是a,匹配,i变成1,j变成1。现在比较s[1]='b'和t[1]='h',不匹配,j增加到2。t[2]是b,这时匹配,i变成2,j变成3。接下来s[2]是c,和t[3]='g'不匹配,j增加到4,t[4]是d,也不匹配,j到5,t[5]是c,这时匹配,i变成3,此时i等于s.size(),循环结束,返回true。正确。 另一个例子,s="axc",t="ahbgdc"。i=0时,a匹配,i=1,j=1。现在s[1]是x,而t[1]是h,不匹配,j增加到2,t[2]是b,还是不行。j继续增加到3,t[3]是g,不行,j到4是d,还是不行,j到5是c,此时j是5,这时候i还是1,循环结束,i不等于s.size(),返回false。对的。 那这样的话,代码逻辑应该没问题。那时间复杂度是O(n+m),其中n和m是s和t的长度,因为每个指针最多遍历各自的字符串一次。空间复杂度是O(1),因为没有使用额外空间。 有没有其他可能的优化?比如,当s的长度大于t的时候,直接返回false。这应该在开始时判断,可以提前结束。比如,如果s.size() > t.size(),直接返回false。这样节省时间。是的,这个应该加上。 那最终的代码大概是这样: bool isSubsequence(string s, string t) { if (s.size() > t.size()) return false; int i = 0, j = 0; while (i < s.size() && j < t.size()) { if (s[i] == t[j]) { i++; } j++; } return i == s.size(); } 这样应该可以了。再测试一下s为空的情况,返回true,是对的。当t为空且s不为空时,返回false,也是对的。 有没有可能漏掉的情况?比如,s的最后一个字符刚好是t的最后一个字符,这时候j会增加到等于t.size(),循环结束,但i已经增加到s.size(),所以正确返回true。 总之,这个双指针的方法应该是正确的,而且效率很高。</think>判断子序列问题可以通过双指针算法高效解决。以下是详细的解题思路和C++实现步骤: ### 问题分析 **子序列定义**:若字符串`s`中所有字符按顺序出现在字符串`t`中(无需连续),则`s`是`t`的子序列。 **核心思路**:使用两个指针分别遍历`s`和`t`,逐个匹配字符。 --- ### 双指针算法步骤 1. **初始化指针**:`i`指向`s`的起始位置,`j`指向`t`的起始位置。 2. **同步遍历**: - 若`s[i] == t[j]`,则匹配成功,`i`和`j`均向后移动。 - 若不等,仅`j`向后移动(继续在`t`中查找匹配项)。 3. **终止条件**: - `i`遍历完`s`:说明全部字符匹配成功,返回`true`。 - `j`遍历完`t`但`i`未遍历完`s`:匹配失败,返回`false`。 --- ### 代码实现(C++) ```cpp bool isSubsequence(string s, string t) { // 提前判断:若s比t长,直接返回false if (s.size() > t.size()) return false; int i = 0, j = 0; while (i < s.size() && j < t.size()) { if (s[i] == t[j]) { i++; // 匹配成功,移动s的指针 } j++; // 无论是否匹配,t的指针都移动 } return i == s.size(); // 检查s是否全部匹配 } ``` --- ### 关键点解析 1. **时间复杂度**:$O(n + m)$ - 最坏情况下,两个指针各遍历完整个字符串。 2. **空间复杂度**:$O(1)$ - 仅使用常数级别的额外空间。 3. **边界条件处理**: - 若`s`为空,直接返回`true`(空串是任何字符串的子序列)。 - 提前判断`s.size() > t.size()`可减少不必要的遍历。 --- ### 示例验证 1. **示例1**: - 输入:`s = "abc"`, `t = "ahbgdc"` - 过程:`a`匹配`t[0]`,`b`匹配`t[2]`,`c`匹配`t[5]` - 输出:`true` 2. **示例2**: - 输入:`s = "axc"`, `t = "ahbgdc"` - 过程:`a`匹配`t[0]`,但`x`在`t`中无后续匹配 - 输出:`false` --- ### 总结 双指针法通过线性遍历高效解决了子序列判断问题,代码简洁且性能优异,适用于大规模字符串处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值