1 条题解

  • 0
    @ 2025-4-29 21:09:32

    题意分析

    题目要求找出环形字符串的最小字典序起始位置。关键点包括:

    1. 输入为环形字符串,需要在任意位置断开
    2. 找出所有可能断开方式中字典序最小的字符串
    3. 若有多个解,选择起始位置编号最小的

    解题思路

    1. 环形处理:将原字符串复制一份拼接,模拟环形结构
    2. 双指针比较:使用指针iijj分别指向两个候选起始位置
    3. 字典序比较:通过逐个字符比较确定最小字典序起始点
    4. 优化处理:跳过已比较的相同前缀部分

    实现步骤

    1. 输入处理:
      • 读取测试用例数nn
      • 对每个字符串复制一份(长度2×len2 \times len
    2. 双指针初始化:
      • 初始化指针i=0i=0j=1j=1
    3. 字典序比较:
      • 比较s[i+k]s[i+k]s[j+k]s[j+k]
      • 根据比较结果移动指针
    4. 结果输出:
      • iijj中的较小值加11(转换为1-based索引)

    C++实现

    #include<iostream>
    #include<cstring>
    using namespace std;
    
    char s[20002]; // 两倍长度存储环形字符串
    
    int main() {
        int n;
        cin >> n;
        while(n--) {
            cin >> s;
            int len = strlen(s);
            // 环形处理:复制字符串
            for(int i=0; i<len; i++) s[len+i] = s[i];
            
            int i=0, j=1, k;
            while(i<len && j<len) {
                // 比较从i和j开始的前缀
                for(k=0; k<len && s[i+k]==s[j+k]; k++);
                if(k == len) break; // 完全相同的字符串
                
                if(s[i+k] > s[j+k]) 
                    i += k+1; // i开始的字符串更大,跳过
                else 
                    j += k+1; // j开始的字符串更大,跳过
                
                if(i == j) j++; // 避免指针重合
            }
            cout << min(i,j)+1 << endl; // 输出1-based索引
        }
        return 0;
    }
    

    代码说明

    1. 数据结构
      • 字符数组s存储原始字符串及其复制
    2. 核心算法
      • 双指针iijj维护候选起始位置
      • 通过kk比较相同前缀长度
    3. 优化处理
      • 跳过已比较的相同前缀(k+1k+1
      • 处理指针重合情况
    4. 复杂度分析
      • 时间复杂度:O(n)O(n),其中nn为字符串长度
      • 空间复杂度:O(n)O(n)
    5. 示例分析
      • 输入"helloworld"时,最小字典序起始位置为第1010个字符'd'
      • 输入"aaabaaa"时,最小字典序起始位置为第55个字符'a'
    • 1

    信息

    ID
    510
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者