尺取法-最短的包含字符串

给出一个字符串,求该字符串的一个子串S,S包含A-Z中的全部字母,并且S是所有符合条件的子串中最短的,输出S的长度。如果给出的字符串中并不包括A-Z中的全部字母,则输出No Solution。

Input:

第1行1个字符串。字符串的长度 <= 100000。

Output:

输出包含A-Z的最短子串长度。如果没有符合条件的子串,则输出No Solution。 

示例:

Input1:

BVCABCDEFFGHIJKLMMNOPQRSTUVWXZYZZ

Output1:

28

Input2:

QQWERTYUIOPASDFGHJKLZXCVBNM

Output2:

26

思想:基本尺取法(滑动窗口),

整个过程分为4步:

1.初始化左右端

2. 右端不断向前滑动,直至满足条件

3.如果第二步无法满足条件,则终止,否则更新结果

4.左端扩大1,继续第二步

适用:在一个序列中,求满足条件连续子序列的最值(最小区间,或最大区间)

代码如下:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int nums[26];             //用于标记 A~Z 出现的次数
    string s;
    cin>>s;
    char cur;
    int L = 0,R = 0;       
<think>我们面对的问题是将500个16位十六进制数值(每个数值占2字节)转换为字符串,并实现压缩。由于是在STM32嵌入式环境中,我们需要考虑内存和计算资源的限制。 步骤分析: 1. 十六进制数值转换为字符串:每个16位十六进制数转换为字符串需要4个字符(因为每个字节用两个十六进制字符表示,例如0xABCD转换为"ABCD")。因此,500个数值将产生2000个字符(500*4=2000)。如果直接转换,会得到一个很长的字符串。 2. 实现压缩:我们需要一种压缩算法,能够在嵌入式环境中高效运行,并且尽可能减少压缩后的数据长度。考虑到嵌入式环境的资源限制,我们应选择简单且低内存占用的算法。 常见压缩算法如Huffman编码、LZ77等,但在STM32上实现复杂且可能消耗较多资源。因此,我们可以考虑更简单的方法:由于原始数据是16进制数,我们可以将每两个十六进制字符(即一个字节)转换为一个ASCII字符,这样可以将字符串长度减半(从2000个字符减到1000个字符)。但这种方法并不能保证,而且可能包含不可打印字符。 另一种思路:由于原始数据是16位数值,范围在0x0000到0xFFFF,我们可以将其视为0~65535的整数。我们可以使用base64编码,但base64编码会增加长度(每3个字节变成4个字符,所以1000字节变成约1333个字符,反而变长),所以不适用。 或者,我们可以考虑将数据视为二进制流,然后使用行程长度编码(RLE)或字典编码,但需要统计数据的重复模式。 然而,题目要求“压缩”,所以我们需要根据数据特性选择。如果数据中有大量重复值,RLE可能很有效;如果数据分布随机,则可能需要更复杂的压缩。 考虑到嵌入式环境,我们选择一种简单且通用的方法:将原始二进制数据直接进行压缩(因为原始数据就是二进制数据,而转换成十六进制字符串实际上已经是一种表示形式,但并不是压缩形式)。 因此,我们不妨跳过转换为字符串的步骤,直接对原始二进制数据进行压缩。但题目要求先转换为字符串,然后再压缩。所以我们必须按照题目要求进行。 重新思考:题目要求转换为字符串,然后压缩。这里字符串我们通常指的是可打印的字符串。所以我们可以将原始二进制数据(每个数值2字节,共1000字节)用十六进制表示成字符串(2000字节),然后再压缩这个字符串。 但是,我们也可以将原始二进制数据直接进行压缩,而不经过十六进制字符串的转换。这样压缩效率更高,因为二进制数据比其十六进制字符串表示更紧凑(信息密度更高)。但是题目要求先转换为字符串,所以我们必须先转换。 另一种思路:将十六进制字符串转换回二进制数据,然后进行压缩?这显然多此一举。所以我们应该在转换为字符串后,再对这个字符串进行压缩。 压缩方案选择: 由于500个数值,每个4字符,共2000字符。我们可以使用一种简单的压缩:将每两个十六进制字符(代表一个字节)转换为一个字节的二进制数据,这样2000字符(每个字符1字节)就变成了1000字节的二进制数据。但这并不是字符串,而是二进制数据。题目要求是字符串,所以我们需要将压缩后的二进制数据再转换为字符串表示(比如base64编码),这样才能以字符串形式存储或传输。 具体步骤: 步骤1:将每个16位十六进制数值转换为4个字符的十六进制字符串(无"0x"前缀,例如0x123A转换为"123A")。 步骤2:将整个字符串(2000字节)视为一个字符数组。 步骤3:将每两个字符(即一个字节的十六进制表示)转换为一个字节的二进制数据。例如,字符"AB"(即两个字节'A'和'B')转换为一个字节0xAB。 步骤4:这样我们得到了1000字节的二进制数据。 步骤5:为了将压缩后的二进制数据作为字符串存储,我们需要将其转换为可打印的字符串。我们可以使用base64编码,将1000字节的二进制数据转换为base64字符串。base64编码每3个字节编码为4个字符,所以1000字节的base64编码后长度约为ceil(1000/3)*4 = 1334个字符。 但是,这样压缩后的字符串长度1334比原始字符串2000要小,所以实现了压缩。但这是否是?不一定,但比直接存储2000字符要。 另一种方法:我们也可以使用十六进制字符串直接压缩,但上述方法已经将十六进制字符串压缩为二进制,然后再用base64编码成字符串,这样得到的字符串长度是1334。而如果直接对原始二进制数据(1000字节)进行base64编码,则可以直接得到1334字符的字符串,这样就跳过了转换为十六进制字符串的步骤。但题目要求先转换为字符串,所以我们不能跳过。 因此,我们必须先转换为十六进制字符串(2000字符),然后再压缩。 但是,我们也可以考虑另一种转换:将每个16位数值转换为4个字符的十六进制字符串,然后连接起来。然后我们使用一种字符串压缩算法,比如LZW,但在STM32上实现复杂。 所以,我们采用上述步骤1到5的方法。 总结流程: 原始数据:500个16位整数(1000字节) 1. 转换为十六进制字符串:每个16位整数转换为4个字符,共2000字符。 2. 将2000字符的字符串每两个字符组合,转换为1000字节的二进制数据(因为每两个字符表示一个字节)。 3. 对1000字节的二进制数据进行base64编码,得到约1334个字符的字符串。 这样,我们得到了压缩后的字符串,长度为1334。 但是,我们有没有可能更?如果我们使用更高效的压缩算法(如deflate),可能会更,但在STM32上实现复杂。而base64编码简单,且广泛使用。 另外,我们也可以考虑不转换为十六进制字符串,而是直接使用原始二进制数据进行base64编码,这样得到1334字符的字符串。但题目要求先转换为字符串,所以我们不能这样做。 因此,我们按照题目要求,先转换为十六进制字符串,再压缩。 但是,我们也可以这样理解:题目要求转换为字符串,并没有说一定要转换为十六进制字符串。我们可以转换为其他形式的字符串,比如直接转换为base64字符串?这样就不需要中间的十六进制字符串了。 然而,题目中明确提到“十六进制数值”,所以转换为十六进制字符串是符合题意的。 实现细节: 1. 转换十六进制字符串:将每个16位数值转换为4个十六进制字符。注意,转换时需使用大写字母,并且不足4位时前面补0。 2. 将十六进制字符串转换为二进制数据:将每两个字符转换为一个字节。注意,两个字符的范围是'00'到'FF'。 3. 对二进制数据进行base64编码。 在STM32上实现base64编码有现成的库或者可以自己实现,因为算法简单。 另一种思路:我们是否可以直接将原始数据(1000字节)进行base64编码?这样得到1334个字符。但是题目要求先转换为字符串(十六进制字符串),所以我们不能直接对原始数据进行base64编码。 因此,我们只能按照上述步骤。 但是,我们注意到:步骤1和步骤2实际上是对原始数据的一种冗余操作。因为原始数据已经是二进制,而步骤1将其转换为十六进制字符串(扩展为原来的2倍),步骤2又将其还原为二进制(和原始数据一样)。所以,步骤1和步骤2实际上没有改变数据,只是将原始数据用十六进制字符串表示了一下,然后又变回原始数据。那么,我们是否可以省略步骤1和步骤2,直接对原始数据(1000字节)进行base64编码?这样得到1334个字符的字符串。 但是,题目要求先转换为字符串(十六进制字符串),所以我们必须先转换为十六进制字符串,然后再压缩。而压缩过程中我们又将其变回二进制,然后base64编码。这样虽然多此一举,但符合题目要求。 然而,题目要求“实现字符串压缩”,所以我们的目标是。如果我们直接对原始数据用base64编码,得到的字符串长度也是1334,和我们上述方法得到的一样。但是,我们多做了转换步骤,而且转换过程中需要额外的内存(2000字节的字符串)。所以,在资源受限的STM32上,我们应该避免这种中间转换。 但是,题目要求先转换为字符串,所以我们不能跳过。因此,我们只能接受这个中间转换带来的内存开销。 如果内存紧张,我们可以分块处理:每次处理一部分数值,转换一部分,压缩一部分,然后释放内存。 具体实现步骤(分块): 由于500个数值,我们可以分块,比如每50个数值为一块,共10块。 对于每一块: 1. 将50个16位数值转换为200个字符的十六进制字符串(50*4=200)。 2. 将这200个字符的字符串转换为100字节的二进制数据(每两个字符转一个字节)。 3. 将这100字节的二进制数据追加到压缩缓冲区。 当所有块处理完后,压缩缓冲区共有1000字节。 4. 对1000字节的压缩缓冲区进行base64编码,得到1334个字符的base64字符串。 这样,我们只需要一个200字符的字符串缓冲区和100字节的二进制数据缓冲区(以及一个足够大的base64输出缓冲区)。 base64编码的输出缓冲区大小:ceil(1000/3)*4 = 1334字节(字符)。 所以,整个过程中,我们占用的额外内存为: - 十六进制字符串缓冲区:200字节(用于存储50个数值转换的字符串- 二进制数据缓冲区:100字节(用于存储转换后的二进制数据,但后我们将其追加到总的压缩缓冲区,所以总压缩缓冲区需要1000字节) - base64输出缓冲区:1334字节(字符) 另外,我们还需要存储原始数据(1000字节)和终的base64字符串(1334字节)。但原始数据可以分块读取,不需要一次性全部加载。 因此,总内存开销:200(字符串缓冲区)+1000(压缩缓冲区)+1334(base64输出)≈ 2534字节,再加上程序栈等。 考虑到STM32通常有几十KB的RAM,这个开销是可以接受的。 代码框架(伪代码): 1. 分配内存: char hex_buffer[201]; // 用于存储50个数值转换的十六进制字符串(200字符+1个结束符) uint8_t bin_buffer[1000]; // 压缩后的二进制数据缓冲区(1000字节) char base64_buffer[1334+1]; // base64字符串输出,多一个结束符 2. 初始化一个索引,指向bin_buffer的起始位置。 3. 分块处理(10块,每块50个数值): for (int block=0; block<10; block++) { // 读取50个数值(假设原始数据存储在数组data[500]中) for (int i=0; i<50; i++) { uint16_t value = data[block*50+i]; // 将value转换为4个十六进制字符,存入hex_buffer的相应位置(i*4的位置) // 可以用sprintf(hex_buffer+i*4, "%04X", value); 但注意sprintf效率较低,在嵌入式系统中可能不推荐。 // 或者自己实现转换函数,避免使用sprintf。 } hex_buffer[200] = '\0'; // 结束符 // 将hex_buffer中的200个字符(十六进制字符串)转换为100字节的二进制数据 for (int j=0; j<100; j++) { // 取hex_buffer中第j*2和j*2+1两个字符,转换为一个字节 uint8_t high_nibble = char_to_hex(hex_buffer[j*2]); uint8_t low_nibble = char_to_hex(hex_buffer[j*2+1]); bin_buffer[block*100+j] = (high_nibble << 4) | low_nibble; } } 4. 对bin_buffer(1000字节)进行base64编码,结果存入base64_buffer。 5. 现在base64_buffer中存储的就是压缩后的字符串(1334个字符)。 注意:自己实现char_to_hex函数,将十六进制字符('0'-'9','A'-'F')转换为4位的数值。 另外,base64编码需要实现,可以使用现成的库或自己编写。 但是,我们有没有可能跳过分块中的十六进制字符串转换,直接得到二进制数据?实际上,我们分块处理时,可以直接将每个16位数值拆分为两个字节(即原始数据的二进制形式),这样就不需要先转换为十六进制字符串再转换回来。但题目要求先转换为字符串,所以我们不能跳过。 因此,我们必须按照题目要求,先得到十六进制字符串。 性能优化:避免使用sprintf,因为它在嵌入式系统中较慢且占用较多资源。我们可以自己编写快速转换函数。 快速转换函数示例(将一个16位数值转换为4个十六进制字符): void uint16_to_hex(uint16_t num, char* out) { // 处理高8位和低8位 uint8_t high_byte = num >> 8; uint8_t low_byte = num & 0xFF; out[0] = nibble_to_hex(high_byte >> 4); // 高4位 out[1] = nibble_to_hex(high_byte & 0x0F); out[2] = nibble_to_hex(low_byte >> 4); out[3] = nibble_to_hex(low_byte & 0x0F); } char nibble_to_hex(uint8_t nibble) { // nibble 0-15 if (nibble < 10) { return '0' + nibble; } else { return 'A' + (nibble - 10); } } 这样,在分块内循环中,我们可以调用: uint16_to_hex(value, hex_buffer+i*4); 这样效率更高。 另外,关于base64编码的实现,可以自行编写。base64编码表为: const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 编码规则:每3个字节一组(24位),分为4个6位的组,每个组用base64_table中的字符表示。如果后一组不足3个字节,则用=补足。 由于我们压缩后的二进制数据是1000字节,1000除以3余1(1000=3*333+1),所以后一组有1个字节(8位),需要补两个等号。 因此,base64编码后的字符串长度为:4*ceil(1000/3)=4*334=1336?不对,应该是4*(1000/3的向上取整)=4*334=1336?但实际计算:1000/3=333.333,向上取整为334组,每组3字节,但后一组只有1字节,所以实际处理时,将1000字节分成333组(每组3字节)和一个剩余字节(1字节)。333组需要333*4=1332个字符,剩余1字节需要4个字符(其中两个是填充的等号),所以总共1336个字符。 但之前我计算为1334,是错误的。正确计算:base64编码后长度 = 4 * ceil(n/3),其中n是字节数。所以1000字节:ceil(1000/3)=334(组),所以长度=1336。 因此,base64_buffer需要1337字节(包括结束符)。 修正:base64_buffer[1337]; 所以,整个流程中,我们终得到的字符串长度为1336个字符(不包括结束符)。 对比原始十六进制字符串2000个字符,我们压缩了664个字符,压缩率约为66.8%。 但是,我们有没有可能进一步压缩?比如,在base64编码之前,先对二进制数据进行压缩(比如使用LZ77等),然后再进行base64编码?这样可能会进一步减小寸,但会增加复杂性和计算量。在资源有限的STM32上,我们需要权衡。 考虑到题目要求“压缩”,我们可以尝试在base64编码之前先对二进制数据进行压缩。但原始数据是1000字节的二进制数据,如果数据有重复模式,压缩算法可以进一步压缩。但如果没有重复,则可能压缩率很低,甚至变大。 因此,我们可以增加一个步骤:在将十六进制字符串转换为二进制数据后(得到1000字节),我们使用一个轻量级的压缩算法(如miniz等)进行压缩,然后再对压缩后的数据进行base64编码。这样,如果压缩效果好,字符串长度可能小于1336。 但是,在STM32上实现通用压缩算法需要较多的内存和计算资源,特别是对于1000字节的数据。而且,压缩算法的选择需要根据数据特性。如果数据没有重复性,压缩后可能反而变大(因为压缩头信息等)。 所以,我们需要根据实际数据情况决定。如果数据是随机的,那么使用base64编码直接转换可能是好的;如果数据有大量重复,则压缩会有效。 由于题目没有说明数据特性,我们提供两种方案: 方案一:直接base64编码(即上述方法),得到1336个字符的字符串。 方案二:在base64编码前,先对1000字节的二进制数据进行压缩(使用zlib等),然后再对压缩后的数据做base64编码。 方案二在嵌入式系统上可能不切实际,因为zlib需要较多的内存(大约几十KB)和计算资源。 因此,我们选择方案一。 结论: 按照题目要求,我们先将每个16位十六进制数值转换为4个字符的字符串,连接成2000字符的字符串。然后,将每两个字符转换为一个字节,得到1000字节的二进制数据。后,对1000字节的二进制数据进行base64编码,得到1336个字符的字符串。 在STM32上实现时,注意内存使用和效率,分块处理以避免大缓冲区。 相关问题: 1. 在STM32上如何高效地将十六进制数值转换为字符串? 2. Base64编码在STM32上的实现方法? 3. 如何进一步压缩数据以减少字符串长度? 4. 除了base64,还有哪些编码方法可以将二进制数据转换为字符串? 5. 如果数据重复性高,如何设计压缩算法?</think>### STM32将500个16位十六进制数值转换为字符串并实现压缩的方法 在STM32中处理500个16位十六进制数值(每个数值占2字节,共1000字节原始数据)时,需考虑资源限制。以下是分步实现方法: #### **1. 十六进制数值转字符串** - **原理**:每个16位数值转换为4字符的十六进制字符串(如`0xABCD` → `"ABCD"`)。 - **总长度**:500 × 4 = 2000字符。 - **高效转换方法**(避免`sprintf`): ```c void uint16_to_hex(uint16_t num, char* out) { const char hex_chars[] = "0123456789ABCDEF"; out[0] = hex_chars[(num >> 12) & 0x0F]; // 高4位 out[1] = hex_chars[(num >> 8) & 0x0F]; out[2] = hex_chars[(num >> 4) & 0x0F]; out[3] = hex_chars[num & 0x0F]; // 低4位 } ``` - **分块处理**(节省内存): ```c char hex_buffer[201]; // 存储50个数值的字符串(200字符 + 结束符) for (int block = 0; block < 10; block++) { for (int i = 0; i < 50; i++) { uint16_t value = data[block * 50 + i]; // 从数组读取 uint16_to_hex(value, &hex_buffer[i * 4]); } hex_buffer[200] = '\0'; // 添加结束符 // 后续处理hex_buffer... } ``` #### **2. 字符串压缩优化** 直接存储2000字符效率低,需压缩: - **方案一:二进制压缩 + Base64编码(推荐)** - **步骤**: 1. **十六进制字符串 → 二进制数据**: 每2字符(如`"AB"`)转换为1字节(`0xAB`),2000字符 → 1000字节。 ```c uint8_t bin_data[1000]; for (int j = 0; j < 1000; j++) { uint8_t high = hex_char_to_nibble(hex_buffer[j * 2]); // 高4位 uint8_t low = hex_char_to_nibble(hex_buffer[j * 2 + 1]); // 低4位 bin_data[j] = (high << 4) | low; } ``` 2. **Base64编码**: 将1000字节二进制数据转换为1336字符的可打印字符串(公式:`4 * ceil(n/3)`)。 ```c char base64_output[1337]; // 1336字符 + 结束符 base64_encode(bin_data, 1000, base64_output); ``` - **优势**: - 压缩率:从2000字符 → **1336字符**(减少33.2%)。 - 兼容性:Base64字符串可安全传输/存储。 - **方案二:轻量级压缩(若数据有重复模式)** - **适用场景**:数据中存在连续重复值(如传感器读数)。 - **算法**:行程编码(RLE): ```c void rle_compress(const char* input, int len, char* output) { int count = 1, pos = 0; for (int i = 1; i <= len; i++) { if (input[i] == input[i-1] && count < 255) { count++; // 统计连续重复字符 } else { output[pos++] = input[i-1]; // 字符 output[pos++] = count; // 重复次数 count = 1; } } output[pos] = '\0'; } ``` - **注意**:非重复数据可能**增大体积**,需预先测试数据特征。 #### **3. 资源优化技巧** 1. **分块处理**: 每次处理50个数值(需200字节缓冲区),避免2000字符的全内存分配。 2. **Base64优化**: 使用查表法快速编码(无浮点/除法): ```c void base64_encode(const uint8_t* data, size_t len, char* out) { const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (size_t i = 0, j = 0; i < len; i += 3, j += 4) { uint32_t triple = (data[i] << 16) | ((i+1 < len) ? data[i+1] << 8 : 0) | ((i+2 < len) ? data[i+2] : 0); out[j] = base64_table[(triple >> 18) & 0x3F]; out[j+1] = base64_table[(triple >> 12) & 0x3F]; out[j+2] = (i+1 < len) ? base64_table[(triple >> 6) & 0x3F] : '='; out[j+3] = (i+2 < len) ? base64_table[triple & 0x3F] : '='; } out[4 * ((len + 2) / 3)] = '\0'; // 结束符 } ``` 3. **内存占用**: - 十六进制缓冲:200字节 - 二进制缓冲:1000字节 - Base64输出:1337字节 - **总计**:≈2.5KB(适合多数STM32型号)。 #### **4. 对比与选择** | **方法** | 输出长度 | 适用场景 | 资源消耗 | |------------------|------------|--------------------------|----------| | 原始十六进制字符串 | 2000字符 | 无需压缩的调试场景 | 低 | | Base64编码 | **1336字符** | 通用压缩(平衡效率/复杂度)| 中 | | RLE压缩 | 可变 | 高重复数据(如温度序列) | 低 | **推荐流程**: ```mermaid flowchart TD A[读取500个16位数值] --> B[分块转换为十六进制字符串] B --> C[合并为二进制数据] C --> D[Base64编码] D --> E[输出压缩字符串] ``` #### **注意事项** - **数据特性**:若数据高度随机,Base64是稳选择;若重复率高,可尝试RLE。 - **结束符**:所有字符串需添加`\0`,避免溢出。 - **性能权衡**:避免动态内存分配,使用静态缓冲区提升速度。 ### 相关问题 1. 如何优化STM32上的Base64编码性能? 2. 行程编码(RLE)在哪些数据类型下压缩效果好? 3. 除了Base64,还有哪些二进制到文本的编码适合嵌入式系统? 4. 如何验证压缩后的数据能无损还原? 5. 如果数据量增大到10000个数值,方案需要如何调整? [^1]: 引用参考CSMA/CD协议中的时间计算问题,说明嵌入式环境中需考虑效率。 [^2]: 引用温度转换示例,强调数值到字符串转换的常见场景。 [^3]: 引用存储结构分析,提示内存分配的重要性。 [^4]: 引用信道传输限制,类比压缩算法需权衡效率与复杂度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值