2025-08-23:找出长度为 K 的特殊子字符串。用go语言,给定一个字符串 s 和一个整数 k,判断 s 中是否存在一个长度正好为 k 的连续片段,且满足两点:片段内全部由同一个字符组成;若该片

#新星杯·14天创作挑战营·第14期#

2025-08-23:找出长度为 K 的特殊子字符串。用go语言,给定一个字符串 s 和一个整数 k,判断 s 中是否存在一个长度正好为 k 的连续片段,且满足两点:片段内全部由同一个字符组成;若该片段左侧或右侧有相邻字符,则这些相邻字符都不能与片段内的字符相同。若存在这样的片段返回 true,否则返回 false。这里“子字符串”指的是字符串中一段连续且非空的字符序列。

1 <= k <= s.length <= 100。

s 仅由小写英文字母组成。

输入: s = “aaabaaa”, k = 3。

输出: true。

解释:

子字符串 s[4…6] == “aaa” 满足条件:

长度为 3。

所有字符相同。

子串 “aaa” 前的字符是 ‘b’,与 ‘a’ 不同。

子串 “aaa” 后没有字符。

题目来自力扣3456。

分步骤描述过程:

  1. 问题理解:我们需要判断字符串 s 中是否存在一个长度为 k 的连续子串(片段),该子串必须满足:

    • 子串中的所有字符都相同。
    • 如果该子串左边有相邻字符,则该相邻字符不能与子串中的字符相同(即不能扩展)。
    • 如果该子串右边有相邻字符,则该相邻字符也不能与子串中的字符相同(即不能扩展)。
  2. 遍历字符串:我们将遍历字符串 s,逐个检查每个字符,并尝试找到满足条件的连续片段。

  3. 计数连续相同字符

    • 初始化一个计数器 cnt 为 0,用于记录当前连续相同字符的长度。
    • 从字符串的第一个字符开始,依次检查每个字符。
    • 对于每个位置 i,首先增加计数器 cnt(表示当前连续相同字符的长度增加1)。
    • 然后检查当前字符 s[i] 是否与下一个字符 s[i+1] 不同(或者当前是最后一个字符),这表示当前连续相同字符的片段结束。
  4. 检查片段是否满足条件

    • 当遇到片段结束(即当前字符与下一个字符不同,或者到达字符串末尾)时,检查当前计数 cnt 是否等于 k
      • 如果 cnt == k,则说明我们找到了一个长度为 k 的连续相同字符的片段。
    • 但还需要检查该片段的左右相邻字符是否与片段内的字符不同(以确保不能扩展):
      • 对于片段起始位置(假设片段从 start 开始,长度为 k):
        • 左边相邻字符是 s[start-1](如果存在),必须与片段字符不同。
        • 右边相邻字符是 s[start+k](如果存在),必须与片段字符不同。
    • 然而,在给定的代码中,并没有显式检查左右相邻字符?实际上,代码中的逻辑是:
      • 它只统计了连续相同字符的长度,并在片段结束时检查长度是否恰好为 k
      • 但题目要求左右相邻字符(如果存在)必须与片段字符不同。
    • 注意:原代码实际上有缺陷?因为它没有检查左右相邻字符。例如,对于 s = "aaabaaa", k=3,片段 s[0..2]="aaa" 的长度为3,但左边没有字符(所以忽略左边),右边相邻字符是 'b'(与 'a' 不同),所以满足条件?但实际上片段 s[0..2] 的右边相邻字符是 s[3]='b',确实不同,所以应该满足?然而,片段 s[4..6]="aaa" 也是满足的(左边是 'b',右边没有字符)。
    • 但原代码并没有区分不同的片段?它只是统计连续相同字符的长度,并在片段结束时检查长度是否等于 k。然而,如果连续相同字符的长度大于 k,那么其中可能包含多个长度为 k 的子串?但题目要求的是“连续片段”,且要求左右不能扩展(即左右相邻字符不能相同),所以只有那些恰好长度为 k 且左右都不能扩展的片段才有效?实际上,如果连续相同字符的长度为 L(L>=k),那么其中长度为 k 的子串可能有很多,但只有那些位置合适的(即左右边界恰好是片段边界)才满足?例如,连续5个 ‘a’,k=3:那么中间的子串(比如从第二个字符开始长度为3)的左右相邻字符都是 ‘a’,所以不满足(因为可以扩展)。只有整个片段恰好长度为3(且左右相邻字符不是’a’)才满足?或者如果片段在开头(左边无字符)且右边相邻字符不是’a’?或者片段在结尾(右边无字符)且左边相邻字符不是’a’?)?
  5. 原代码的缺陷:实际上,原代码没有检查左右相邻字符,因此可能会错误地返回 true。例如,考虑 s = "aaaa", k=3

    • 连续相同字符的长度为4,当片段结束时(即到达末尾),计数为4,不等于3?但实际上,其中包含长度为3的子串(比如前3个字符),但前3个字符的右边相邻字符是 ‘a’(相同),所以不满足条件。但原代码会返回 false(因为整个片段长度为4,不等于3)?但如果我们有 s = "aaab", k=3:连续相同字符片段(前3个)结束时(因为第3个和第4个不同),计数为3,然后返回 true。但这里前3个字符的右边相邻字符是 ‘b’(不同),左边无字符,所以满足?正确。

    然而,如果连续相同字符的长度大于k,但其中恰好有一个长度为k的子串满足左右相邻字符不同?实际上,只有在整个连续相同字符的片段恰好长度为k时(即左右边界恰好是片段的边界)才满足?因为如果连续相同字符的长度为L(L>k),那么其中任何一个长度为k的子串的左右相邻字符( within the same run)都是相同的(因为都在同一个连续片段内),所以都不满足条件(除非该子串位于片段的边界?但即使位于边界,其一边相邻字符仍然是相同字符?)。例如,连续5个 ‘a’(索引0到4),k=3:
    - 子串0-2:左边无字符,右边相邻字符是索引3的 ‘a’(相同),所以不满足。
    - 子串1-3:左边是索引0的 ‘a’(相同),右边是索引4的 ‘a’(相同),不满足。
    - 子串2-4:左边是索引1的 ‘a’(相同),右边无字符(如果字符串长度就是5)?但右边无字符,但左边相邻字符相同,所以不满足。
    因此,只有当整个连续相同字符的片段长度恰好为k时,才可能满足条件(因为左右相邻字符(如果存在)必须不同?)。所以原代码的做法(只检查连续相同字符的长度是否恰好为k)实际上是正确的?因为如果长度大于k,其中任何长度为k的子串都不满足(左右相邻字符相同);如果长度小于k,当然不满足。所以只需要检查连续相同字符的片段长度是否恰好等于k?而且,还需要检查该片段的左右相邻字符是否与片段字符不同?但实际上,当连续相同字符的片段长度恰好为k时,它的左右相邻字符(如果存在)自然就是不同字符(因为片段结束的原因就是遇到了不同字符)?例如,在遍历中,我们是在遇到字符变化(或字符串结束)时检查片段长度的。所以片段左右边界外的字符自然就是不同的(左边:如果片段不是从开头,那么左边相邻字符是前一个片段的最后一个字符,必然不同?因为片段之间字符不同;右边:如果片段不是到结尾,那么右边相邻字符是下一个片段的第一个字符,必然不同)。因此,原代码不需要显式检查左右相邻字符?因为遍历逻辑已经保证了:我们统计的连续相同字符片段,其左右相邻字符(如果存在)必然是不同的(因为片段结束就是因为遇到了不同字符)。

  6. 因此,原代码的正确性:实际上,原代码是正确的。因为:

    • 它统计连续相同字符的长度(比如遇到字符变化或字符串结束)。
    • 当片段结束时,检查该片段的长度是否恰好为k。如果是,则返回true。
    • 由于片段结束的原因就是遇到了不同字符(或者边界),所以该片段的左右相邻字符(如果存在)必然与片段内字符不同。因此,不需要显式检查。
  7. 例子验证:以 s = "aaabaaa", k=3 为例:

    • 第一个片段:连续3个 ‘a’(索引0-2),然后遇到 ‘b’(不同),所以片段结束,长度=3,等于k,返回true?但这里片段索引0-2的右边相邻字符是 ‘b’(不同),左边无字符,满足条件。
    • 注意:实际上这里有两个片段满足?第一个片段(前3个’a’)已经满足,所以直接返回true。第二个片段(后3个’a’)同样满足,但代码在第一个片段时就已经返回了。
  8. 算法流程

    • 初始化计数器 cnt = 0
    • 遍历字符串 s 的每个索引 i(从0到len(s)-1):
      • cnt++(当前连续相同字符长度加1)。
      • 如果当前字符 s[i] 与下一个字符 s[i+1] 不同(或者i是最后一个字符),说明当前连续片段结束:
        • 如果 cnt == k,则返回true。
        • 重置 cnt = 0(为下一个片段准备)。
    • 如果遍历结束都没有找到,返回false。
  9. 边界情况

    • 如果k=1:需要检查单个字符的片段,且左右相邻字符(如果存在)必须不同。
    • 例如,s=“aab”,k=1:第一个片段是连续两个’a’,长度2≠1,不返回;第二个片段是单个’b’,长度1==1,且左边是’a’(不同),右边无字符,所以返回true。
    • 但注意:单个字符的片段,如果左右相邻字符相同?比如s=“bab”,k=1:中间’a’的左右都是’b’(相同),所以不满足?但原代码会如何?
      • 遍历到索引0:字符’b’,cnt=1;然后检查下一个字符是’a’(不同),所以片段结束,长度1==1?但这里左边无字符(索引0是开头),右边是’a’(不同),所以满足?正确。
      • 遍历到索引1:字符’a’,cnt=1;然后检查下一个字符是’b’(不同),所以片段结束,长度1==1?但左边是’b’(相同),右边是’b’(相同)?所以不应该满足。但原代码会返回true?因为索引0的片段已经返回了?所以实际上,原代码会提前返回(在索引0处就返回true了),所以不会检查到索引1?但如果我们有s=“aa”,k=1:第一个片段是连续两个’a’,长度2≠1,然后第二个字符?实际上遍历到索引0时,片段还未结束(因为下一个字符相同),所以不会检查。直到索引1:片段结束,长度2≠1,返回false。正确(因为两个’a’都不满足:左边无右边有相同字符,或者左边有相同字符右边无)。

    然而,对于s=“bab”,k=1:第一个字符’b’(索引0)的片段结束(因为下一个字符是’a’),长度1,返回true。正确(因为第一个字符’b’满足:左边无,右边是’a’(不同))。

    所以原代码正确。

总的时间复杂度和总的额外空间复杂度:

  • 时间复杂度:O(n),其中n是字符串s的长度。我们只遍历字符串一次。
  • 额外空间复杂度:O(1),只使用了常数级别的额外变量(如cnt和循环变量)。

Go完整代码如下:

package main

import (
	"fmt"
)

func hasSpecialSubstring(s string, k int) bool {
	cnt := 0
	for i := range s {
		cnt++
		if i == len(s)-1 || s[i] != s[i+1] {
			if cnt == k {
				return true
			}
			cnt = 0
		}
	}
	return false
}

func main() {
	s := "aaabaaa"
	k := 3
	result := hasSpecialSubstring(s, k)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

def has_special_substring(s: str, k: int) -> bool:
    cnt = 0
    for i in range(len(s)):
        cnt += 1
        if i == len(s) - 1 or s[i] != s[i + 1]:
            if cnt == k:
                return True
            cnt = 0
    return False

def main():
    s = "aaabaaa"
    k = 3
    result = has_special_substring(s, k)
    print(result)

if __name__ == "__main__":
    main()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

福大大架构师每日一题

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值