3456. 找出长度为 K 的特殊子字符串

问题描述

给你一个字符串 s 和一个整数 k。

判断是否存在一个长度 恰好 为 k 的子字符串,该子字符串需要满足以下条件:

该子字符串 只包含一个唯一字符(例如,"aaa" 或 "bbb")。
如果该子字符串的 前面 有字符,则该字符必须与子字符串中的字符不同。
如果该子字符串的 后面 有字符,则该字符也必须与子字符串中的字符不同。
如果存在这样的子串,返回 true;否则,返回 false。

子字符串 是字符串中的连续、非空字符序列。

问题分析

如果搜索特定字符,可以考虑使用string类中的find函数。
然而,不确定到底是哪个字符,所以只能手动实现搜索方法。滑动窗口或者双指针均可。

  1. 滑动窗口
    长度为k,则每次滑动判断窗口内字符是否相同,并且窗口相邻元素是否与窗口内元素一样即可。
  2. 双指针
    快慢指针,快指针尽量向右走,走到最后一个相同的元素,然后判断r-l是否==k即可,若不等,令l=r,继续走。

法一、朴素滑动窗口,O(n^2)

class Solution {
public:
    bool hasSpecialSubstring(string s, int k) {
        int n = s.size();
        for (int l = 0, r = k-1; r < n; ) {
            bool win_same = true;
            for (int i = l+1; i <= r; i++) {
                if (s[i] != s[i-1]) {
                    win_same = false;
                }
            }
            if (win_same) {
                if ((l == 0 || s[l] != s[l-1]) && (r == n-1 || s[r] != s[r+1])) {
                    return true;
                }
            }
            l++; r++;
        }
        return false;
    }
};

法二、双指针,O(n)

错误代码:

class Solution {
public:
    bool hasSpecialSubstring(string s, int k) {
        int n = s.size();
        for (int l = 0, r = 0; r < n; ) {
            // 先找到连续的一个序列
            while (r - l + 1 < k && r < n) {
                if (s[r] != s[l]) {
                    l = r;
                }
                r++;
            }
            if (r - l + 1 == k) {
                if ((l == 0 || s[l-1] != s[l]) && 
                (r == n-1 || s[r] != s[r+1])) {
                    return true;
                }
                l = r;
            }
        }
        return false;
    }
};

当k=1且下一个字符一样,会导致无限循环。

这里使用for-while结构更好,代码如下:

class Solution {
public:
    bool hasSpecialSubstring(string s, int k) {
        int n = s.size();
        for (int l = 0, r = 0; r < n; ) {
            // 移动 r,直到找到不同的字符或到达字符串末尾
            while (r < n && s[r] == s[l]) {
                r++;
            }
            if (r - l == k) {
                return true;
            }
            // 找下一个子串
            l = r;
        }
        return false;
    }
};

该写法本质是左开右闭区间。思路清晰,简洁明了,很好。

法三、使用一层for循环控制双指针,便于控制各种逻辑,O(n)

class Solution {
public:
    bool hasSpecialSubstring(string s, int k) {
        int n = s.size();
        for (int l = 0, r = 0; l < n && r < n; ) {
            if (s[l] == s[r]) {
                if (r-l+1 == k) {
                    if ((l == 0 || s[l-1] != s[l]) && (r == n-1 || s[r] != s[r+1])) {
                        return true;
                    } else {
                        l = r; r++; continue;
                    }
                } else {
                    r++; continue;
                }
            } else {
                l = r; continue;
            }
        }
        return false;
    }
};
posted @   saulstavo  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示