哈希(最大/最小表示法)

How many

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6487 Accepted Submission(s): 2983

Problem Description
Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100,tell me
How many kinds of necklaces total have.(if two necklaces can equal by rotating ,we say the two necklaces are some).
For example 0110 express a necklace, you can rotate it. 0110 -> 1100 -> 1001 -> 0011->0110.

Input
The input contains multiple test cases.
Each test case include: first one integers n. (2<=n<=10000)
Next n lines follow. Each line has a equal length character string. (string only include ‘0’,‘1’).

Output
For each test case output a integer , how many different necklaces.

有一个首位相连的字符串,我们要寻找一个位置,从这个位置向后形成一个新字符串,我们需要使这个字符串字典序最小。

算法解释

我们这里要i = 0,j = 1,k = 0,表示从i开始k长度和从j开始k长度的字符串相同(i,j表示当前判断的位置)

当我们str[i] == str[j]时,根据上面k的定义,我们的需要进行k+1操作

当str[i] > str[j]时,我们发现i位置比j位置上字典序要大,那么不能使用i作为开头了,我们要将i向后移动,移动多少呢?有因为i开头和j开头的有k个相同的字符,那么就执行 i = i + k +1

相反str[i] < str[j]时,执行:j = j + k +1

最终i和j中较小的值就是我们最终开始的位置

相反如果是最大表示法的话,我们就要求解字典序最大的字符串,那么我们只需要在执行第二或第三个操作时选择较大的那个位置较好了

Sample Input

4
0110
1100
1001
0011
4
1010
0101
1000
0001

Sample Output

1
2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <set>

using namespace std;
string str;
int len;
int getmin(){
    int i=0,j=1,k=0;// i , j 表示位置,k 表示两个位置之后相同字符的个数
    while(i<len&&j<len&&k<len){
        int t=str[(i+k)%len]-str[(j+k)%len];//比较两个位置字符的大小
        if(t==0)k++;
        else{
            if(t>0)//最小表示法
                i+=k+1;//j+=k+1,最大表示法(注释处)
            else
                j+=k+1;//i+=k+1
            if(i==j)j++;
            k=0;
        }
    }
    return i>j ? j : i;
}
int main()
{
    int n;
    while(cin >> n){
        set<string>q;
        q.clear();
        for(int i=0;i<n;i++){
            cin >> str;
            len=str.size();
            str+=str;//在两个字符串中一定可以截取最小字典树的字符串
            int t=getmin();//得到最小字典树的开始位置
            q.insert(str.substr(t,len));
        }
        cout << q.size() << endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值