E卷-最长子字符串的长度(100分)

E卷-刷题笔记合集🔗

最长子字符串的长度

问题描述

LYA 最近在研究一种特殊的字符串问题。给定一个由小写字母组成的字符串 ,将该字符串首尾相连形成一个环形字符串。LYA 的任务是在这个环形字符串中找出一个最长的子串,使得子串中字符 'I'、'o' 和 'x' 都出现偶数次(包括 0 次)。

例如,对于字符串 "alolobo",最长的满足条件的子串是整个字符串本身,长度为 7。而对于字符串 "looxdolx",最长的满足条件的子串是 "oxdolxl",长度为 7。

输入格式

输入是一个字符串 ,由小写字母组成,长度在 范围内。

输出格式

输出一个整数,表示满足条件的最长子串的长度。

样例输入 1

alolobo

样例输出 1

6

样例解释 1

最长的满足条件的子串是 "alolobo" 本身,长度为 6。它包含 2 个 'I'、2 个 'o' 和 0 个 'x'。

样例输入 2

looxdolx

样例输出 2

7

样例解释 2

最长的满足条件的子串是 "oxdolxl",长度为 7。由于字符串是环形的,所以最后一个 'x' 和开头的 'l' 是相连的。该子串包含 2 个 'I'、2 个 'o' 和 2 个 'x'。

样例输入 3

bcbcbc

样例输出 3

6

样例解释 3

这个示例中,字符串 "bcbcbc" 本身就是最长的满足条件的子串,因为它不包含 'I'、'o' 和 'x'。

数据范围

  • ,其中 表示字符串 的长度。
  • 只包含小写字母。

题解

 滑动窗口

这个问题可以使用滑动窗口的思想来解决。我们可以将字符串 复制一遍,形成一个新的字符串 ,其长度为 。这样做的目的是为了处理环形字符串的情况。

接下来,我们使用一个状态码 来表示当前窗口中 'I'、'o' 和 'x' 出现的次数的奇偶性。具体来说,我们用二进制的三位来表示 'I'、'o' 和 'x' 的出现次数是奇数还是偶数,其中 1 表示奇数,0 表示偶数。例如,状态码 表示当前窗口中 'I' 出现奇数次,'o' 出现偶数次,'x' 出现奇数次。

我们使用一个队列 来维护当前状态码为 时所有可能的最长子串的起始位置。每次遇到一个新的字符时,我们更新状态码 ,并将当前位置 加入到对应的队列 中。同时,我们需要从队列的头部删除那些长度超过 的子串的起始位置,因为它们已经不可能是最长的满足条件的子串了。

最后,我们遍历所有的队列 ,找出其中最长的子串的长度,即为答案。

参考代码

  • Python
from collections import deque

def longest_substring(s):
    n = len(s)
    s = s + s  # 将字符串复制一遍,形成环形字符串
    ans = 0
    q = [deque() for _ in range(8)]  # 初始化 8 个队列,用于存储不同状态码下的子串起始位置
    x = 0  # 初始状态码为 0
    q[0].append(-1)  # 将 -1 加入到初始队列中,表示子串的起始位置可以从 0 开始

    for i in range(2 * n):
        # 更新状态码
        if s[i] == 'l':
            x ^= 1  # 更新状态码中 'l' 的位
        elif s[i] == 'o':
            x ^= 2  # 更新状态码中 'o' 的位
        elif s[i] == 'x':
            x ^= 4  # 更新状态码中 'x' 的位

        q[x].append(i)  # 将当前位置加入到对应的队列中

        # 从队列头部删除长度超过 n 的子串的起始位置
        while q[x][-1] - q[x][0] > n:
            q[x].popleft()

        ans = max(ans, q[x][-1] - q[x][0])  # 更新最长子串的长度

    return ans

# 读取输入
s = input().strip()

# 调用函数并输出结果
print(longest_substring(s))
  • C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_N 500000

// 定义队列结构
typedef struct {
    int* data;
    int front;
    int rear;
    int size;
} Queue;

// 初始化队列
void initQueue(Queue* q, int capacity) {
    q->data = (int*)malloc(sizeof(int) * capacity);
    q->front = q->rear = 0;
    q->size = capacity;
}

// 入队
void enqueue(Queue* q, int value) {
    q->data[q->rear] = value;
    q->rear = (q->rear + 1) % q->size;
}

// 出队
int dequeue(Queue* q) {
    int value = q->data[q->front];
    q->front = (q->front + 1) % q->size;
    return value;
}

// 获取队首元素
int front(Queue* q) {
    return q->data[q->front];
}

// 获取队尾元素
int back(Queue* q) {
    return q->data[(q->rear - 1 + q->size) % q->size];
}

// 判断队列是否为空
int isEmpty(Queue* q) {
    return q->front == q->rear;
}

int longest_substring(char* s) {
    int n = strlen(s);
    char* t = (char*)malloc(sizeof(char) * (2 * n + 1));
    strcpy(t, s);
    strcat(t, s);  // 将字符串复制一遍,形成环形字符串

    int ans = 0;
    Queue q[8];
    for (int i = 0; i < 8; i++) {
        initQueue(&q[i], 2 * n + 1);
    }

    int x = 0;  // 初始状态码为 0
    enqueue(&q[0

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务