字符串最小表示

题目地址http://zju.acmclub.com/index.php?app=problem_title&id=1&problem_id=1056

输出字符串最小表示的第一个字母在原字符串的位置。

思路是:

1.预处理,复制原字符串的2倍作为新的字符串,例如,str=“abc”变成str=“abcabc”

2.取双指针p1、p2,p1初始指向新字符串的首字符,p2指向第二个字符

3.每次首先找到位移k,使str[p1+k]!=str[p2+k],并比较str[p1+k]与str[p2+k],

如果str[p1+k]>str[p2+k],更新p1+=k+1;如果p1移到了和p2相同的位置,则p1再移一位;反之则更新p2并移动p2。

输出:

1.如果k等于原字符串的长度,说明循环同构,输出min(p1,p2)

2.如果p1、p2两者中的任何一个移到了原字符串长度之外,则输出另一方即可。

python代码:

#coding=utf-8
t = input()
while t:
    [n,s] = raw_input().split()
    #init point
    p1 = 0
    p2 = 1
    s = s*2
    #print len(s)
    while True:
        k = 0
        while s[p1+k]==s[p2+k] and k!=int(n):
            k+=1
        if k==int(n):
            print min(p1,p2)
            break
        if s[p1+k]>s[p2+k]:
            p1+=k+1
            if p1==p2:p1+=1
        elif s[p1+k]<s[p2+k]:
            p2+=k+1
            if p1==p2:p2+=1
        if p1>=int(n):
            print p2
            break
        if p2>=int(n):
            print p1
            break
    t -= 1
    if t==0:break

    
用python可能时间超限,可以考虑用c++重写

c++代码:

#include<iostream>
#include<cstring>
#define MAXN 200010
using namespace std;
int min_string(int num,char *s)
{
    char str[MAXN];
    int p1 = 0,p2 = 1,k;
    strcpy(str,s);
    strcat(s,str);
    while(1)
    {
        k = 0;
        while(s[p1+k]==s[p2+k]&&k!=num) k++;
        if (k==num)return min(p1,p2);
        if (s[p1+k]>s[p2+k])
        {
            p1+=k+1;
            if(p1==p2)p1++;
        }
        else if (s[p1+k]<s[p2+k])
        {
            p2+=k+1;
            if(p1==p2)p2++;
        }
        if (p1>=num) return p2;
        if (p2>=num) return p1;
    }
    return -1;
}

int main()
{
    int t,n;
    cin>>t;
    char s[MAXN];
    while(t--)
    {
        cin>>n>>s;
        cout<<min_string(n,s)<<endl;
    }
    return 0;
}
ps:数组MAXN尽量要开的大一点,开小了总提示段错误~!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值