Passward

本文介绍了一个有趣的问题:在一个字符串中找到既是前缀也是后缀且出现在中间的最长子串。通过一种非传统的搜索算法实现了解决方案,并与KMP算法进行了对比。

题面

  题目描述

  你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s。

  传说打开庙门的密码是这个字符串的一个子串 t,并且 t 既是 s 的前缀又是 s 的后缀并且还在 s 的中间位置出现过一次。

  如果存在这样的串,请你输出这个串,如有多个满足条件的串,输出最长的那一个。

  如果不存在这样的串,输出”Just a legend”(去掉引号)。

  输入格式:

  仅一行,字符串 s。

  输出格式:

  如题所述

  样例输入

  fixprefixsuffix

  样例输出:

  fix

  数据范围:

  对于 60%的数据,1s 的长度100

  对于 100%的数据,1 s 的长度100000


思路

  考场想出下面这个算法,时间复杂度什么的都没有保证。但数据都很水, 所以大胆搜索。

  先定义结构体,num为原数组下标, step为当前以此下标匹配成功的长度。

struct Step
{
    int num;
    int step;
}tmp;

  b数组维护值为首字母的位置的下标:

for (int i = 0;i < y;i ++)
        if (ch[x] == ch[i])
            b.push(Step{i, 0});

  若队列大小小于2,则必无解:

if (b.size() <= 2)
    {
        printf("Just a legend");
        return 0;
    }

  然后每次将匹配长度向后推进一个,比较判断此时队列中所有元素是否仍然可行;将可行解再push进队列:

while (b.size() >= 3)
    {
        tmpb = b.front(); b.pop();
        if (tmpb.step >= now)
            now ++;
        if (ch[tmpb.num + now - 1] == ch[x + now - 1])
        {
            b.push(Step{tmpb.num, now});
            if (tmpb.num + now - 1 == y - 1 && b.size() >= 3)
                ans = max(ans, now);
        }
    }

  这里可以更新答案:若此时的匹配存在已经匹配到末位的元素(因为从首位开始匹配,所以匹配到末位一定为原串的后缀)并且当前已经匹配成功的元素,那么就将答案更新为此元素的step:

if (ch[tmpb.num + now - 1] == ch[x + now - 1])
        {
            b.push(Step{tmpb.num, now});
            if (tmpb.num + now - 1 == y - 1 && b.size() >= 3)
                ans = max(ans, now);
        }

  如果结果未被更新,便无解:

if (ans == -1)
    {
        printf("Just a legend");
        return ;
    }

  其实听说正解为KMP,但考场实测24MS,只比KMP慢8MS。

但其实还是很好构造出卡这个算法的数据。
如若有一连串的“aaaaaaaaaaaaaaaaaaa”,那每次都会只否定一组,接近Θ(n2) 的时间复杂度。

代码

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <queue>
#include <iostream>
#define LL long long
using namespace std;
const size_t MN = 100005;

struct Step
{
    int num;
    int step;
}tmp;

char ch[MN];
int x, y;
queue < Step > b;

void solve()
{
    Step tmpb;
    int now = 0, ans = -1;
    while (b.size() >= 3)
    {
        tmpb = b.front(); b.pop();
        if (tmpb.step >= now)
            now ++;
        if (ch[tmpb.num + now - 1] == ch[x + now - 1])
        {
            b.push(Step{tmpb.num, now});
            if (tmpb.num + now - 1 == y - 1 && b.size() >= 3)
                ans = max(ans, now);
        }
    }
    if (ans == -1)
    {
        printf("Just a legend");
        return ;
    }
    for (int i = 0;i < ans;i ++)
        putchar(ch[i]);
}


int main()
{
    scanf("%s", ch);
    y = strlen(ch);
    if (y <= 2)
    {
        printf("Just a legend");
        return 0;
    }
    tmp.step = 1;
    for (int i = 0;i < y;i ++)
    {
        if (ch[x] == ch[i])
            b.push(Step{i, 0});
    }
    if (b.size() <= 2)
    {
        printf("Just a legend");
        return 0;
    }
    solve();
    return 0;
}
void MQTT_Connect(char *clientid, char *username, char *passward) { char data[256] = {0}; /* 报文缓存数组 */ int len = 0; /* 报文长度计数变量 */ int remaining_length = 0; /* 剩余长度(可变报头 + 有效载荷) */ char flags = 0; /* 连接标志 */ int clientid_length = strlen(clientid); int will_topic_length = strlen(WILL_TOPIC); int will_message_length = strlen(WILL_MESSAGE); int username_length = strlen(username); int passward_length = strlen(passward); /*------------------ 连接标志配置 -----------------------*/ /* bit1 是否清除会话 */ if (CLEAN_SESSION) flags |= 0x02; /* bit2 是否使用遗嘱消息 */ if (WILL_FLAG) { flags |= 0x04; /* bit3、bit4 遗嘱QoS等级, 默认 QoS0 */ if (WILL_QOS == 1) flags |= 0x08; if (WILL_QOS == 2) flags |= 0x10; /* bit5 是否保留本次会话 */ if (WILL_RETAIN) flags |= 0x20; } /* bit6、bit7 是否使用账号、密码 */ if (USER_NAME_FLAG && PASS_WORD_FLAG) flags |= 0xC0; /* 0x80 | 0x40 */ /*------------------ 连接标志配置 END -------------------*/ /* 剩余长度 = 可变报头 + 负载的数据 */ remaining_length = 10 + (2 + clientid_length); if (WILL_FLAG) remaining_length += (2 + will_topic_length) + (2 + will_message_length); if (USER_NAME_FLAG) remaining_length += (2 + username_length) + (2 + passward_length); /* 1. Connect固定报头(Fixed header) */ data[len++] = 0x10; /* MQTT Message Type CONNECT */ /* 1.2 剩余长度编码 */ do { char encodedbyte = remaining_length % 128; remaining_length = remaining_length / 128; if (remaining_length > 0) { encodedbyte |= 128; } data[len++] = encodedbyte; } while (remaining_length > 0); /* 2. 可变报头(Variable header) */ data[len++] = 0; /* Protocol Name MSB */ data[len++] = 4; /* Protocol Name LSB */ data[len++] = 'M'; data[len++] = 'Q'; data[len++] = 'T'; data[len++] = 'T'; data[len++] = 4; /* Protocol Level */ data[len++] = flags; /* Connect Flags */ data[len++] = KEEP_ALIVE / 256; /* Keep Alive MSB */ data[len++] = KEEP_ALIVE % 256; /* Keep Alive LSB */ /* 3. 有效载荷(Payload) */ /* 3.1 客户端ID */ data[len++] = clientid_length / 256; data[len++] = clientid_length % 256; memcpy(&data[len], clientid, clientid_length); len += clientid_length; if (WILL_FLAG) { /* 3.2 遗嘱主题 */ data[len++] = will_topic_length / 256; data[len++] = will_topic_length % 256; memcpy(&data[len], WILL_TOPIC, will_topic_length); len += will_topic_length; /* 3.3 遗嘱消息 */ data[len++] = will_message_length / 256; data[len++] = will_message_length % 256; memcpy(&data[len], WILL_MESSAGE, will_message_length); len += will_message_length; } if (USER_NAME_FLAG && PASS_WORD_FLAG) { /* 3.4 用户名 */ data[len++] = username_length / 256; data[len++] = username_length % 256; memcpy(&data[len], username, username_length); len += username_length; /* 3.5 密码 */ data[len++] = passward_length / 256; data[len++] = passward_length % 256; memcpy(&data[len], passward, passward_length); len += passward_length; } Write_MQTT_TxDataBuff(data, len); /* 数据写入发送缓冲区 */ mqtt_debug(data, len, "\r\n* 1、CONNECT - 连接服务端 *: \r\n"); } 检查错误,单独封装剩余长度,并给出完整代码
03-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值