例题3-6 环状序列(Circular Sequence, ACM/ICPC Seoul 2004, UVa1584)

题目描述

在这里插入图片描述
在这里插入图片描述

大神分析

本题出现了一个新概念:字典序。所谓字典序,就是字符串在字典中的顺序。一般地, 对于两个字符串,从第一个字符开始比较,当某一个位置的字符不同时,该位置字符较小的 串,字典序较小(例如,abc比bcd小);如果其中一个字符串已经没有更多字符,但另一个 字符串还没结束,则较短的字符串的字典序较小(例如,hi比history小)。字典序的概念可 以推广到任意序列,例如,序列1, 2, 4, 7比1, 2, 5小。
学会了字典序的概念之后,本题就不难解决了:就像"求n个元素中的最小值"一样,用 变量ans表示目前为止,字典序最小串在输入串中的起始位置,然后不断更新ans。

代码注释(非常啰嗦)

#include <stdio.h>
#include <string.h>
#define maxn 105

// 环状串 s 的表示法 p 是否比表示法 q 的字典序小
// 比较第 p 个字符和第 q 个字符谁的字典序小
int less(const char * s, int p, int q) {
    // 当前字符串 s 的长为 n
    int n = strlen(s);
    // 接下来以 n 为一个周期,依次从该周期的第一个开始比较大小
    // 由题目分析,我们知道,每一个长度为 n 的环状串都有 n 种表示法(一般情况下)
    // 而所谓的 n 种方法,每一种都是以该串的一个字母开始,依次输出 n 个字母
    // 后得到的。
    // 现在就是先从每个表示方法的第一个字母开始比较。
    // 当调用这个函数时,传进来的 p 和 q 就是串 s 的两种表示方法中的首字母
    for(int i = 0; i < n; i++) {
        // 依次比较相对顺序上的字母,谁的字典序小
        // 当两个位置上的字母不同时,一定可以比较出大小
        if(s[(p + i) % n] != s[(q + i) % n])
            // 如果 s[(p + i) % n] < s[(q + i) % n] 成立
            // 该 return 值为 1
            // 否则 return 返回 0
            return s[(p + i) % n] < s[(q + i) % n];
        // 另外当 if 条件不成立,表示当前比较的两个字母一样,会通过 i++, 比较下一对
    }
    // 如果循环执行到这里,说明相对位置上的字母都是一样的,也 return 返回 0
    return 0; // 相等
}

int main() {
    // T 为 将要输入的串的个数
    int T;
    // 输入的串保存在 s 数组中
    char s[maxn];
    scanf("%d", &T);
    while(T--) {
        scanf("%s", s);
        // ans 用来记录,到目前位置,找到的最小串(字典序最小的串),在用户输入的串中
        // 的起始位置,之后会不断更新 ans
        int ans = 0;
        int n = strlen(s);
        for(int i = 1; i < n; i++) 
            // ans = 0 时,
            // i = 1
            // 即,从 s 串的第 ans 个字符后的第一个字符开始,依次与当前的 ans 项上的字符比较
            // 如果 less 返回值为 1, 说明以第 i 项开始的串的字典序相对较小
            // 则更新 ans,保存当前 “最小串” 首字母在 s 中的序号 i
            // 如果 less 返回 0,则表示用第 i 项作为首字母表示的串的字典序
            // 大于或等于相应的用 ans 表示的串
            // 所以不执行操作,即,不更新 ans
            if(less(s, i, ans)) ans = i;
        // 通过循环后找到了满足条件的 ans(ans储存者最小串首字母)
        for(int i = 0; i < n; i++) {
            // 依次输出(从第 ans 项开始,输出 n 个值)
            // 考虑到 会有输出到最后一位还没输出结束的情况,
            // 这个时候 ans + i 已经等于 n - 1 (即,ans + i 已经到了最后一项了)
            // 又要返回第 0 位,继续输出的话,
            // 用 取模(取余)的方法,可以很好解决这个问题。% 号为 取余的意思(罗里吧嗦……)
            putchar(s[(ans + i) % n]);
        }
        putchar('\n');
    }
    return 0;
}

启发启示

这里的 % 号取模是亮点。现在还处于欣赏阅读代码的阶段,自己不好写,再看看抄抄吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值