对于最小表示法——一个比较容易的字符串算法

最小表示法,其实就是给你一个字符串s,让你求从一个点i开始数n个字符(n=|s|),若是最后一个字符,就转到第一个字符数起,让这个数法所得出的字符串s'比其它任意数法的字典序小.

也就像这么个字符串:"SSASBBAS".

那么它的最小表示就是"ASBBASSS",最小表示的第一个字符在第2位(设字符串最前面的字符是第0位).

那么设计一个算法很简单,暴力比较,时间复杂度为O(n^2).

很容易想到破环成链,这样更好处理.

代码如下:

inline int small(string s){      //返回的是第一个字符的位置
  int n=s.size(),minn=0;
  s=s+s;
  for (int i=1;i+n-1<=s.size();i++){
    for (int j=0;j<n;j++)
      if (s[i+j]>s[minn+j]) break;
      else if (s[i+j]<s[minn+j]){
        minn=i;
        break;
      }
  }
  return minn;
}

那么有没有优化方案呢?

我们考虑,若s[i+j]>s[minn+j],那么s[i+1],s[i+2],...,s[i+j]作为起点的字符串还有没有可能成为最小表示呢?

没有,因为肯定有一个s[minn+1],s[minn+2],...,s[minn+j]更小.

所以算法就好写了.

算法步骤:

1.初始化两个指针i,j,i=0,j=1.

2.比较它们两个串,直到,s[i+p]≠s[j+p].(若跑了p=n=|s|是还相等,说明这是只由一个字符组成的字符串).

3.若s[i+p]>s[j+p],则i=i+p+1,为了保证i≠j,在i=j的时候i++;若s[i+p]<s[j+p],对j进行差不多的操作.

4.若i>=n,返回j;若j>=n,返回i;否则重复2、3两步.

那么代码如下:

inline int small(string s){      //返回的是第一个字符的位置
  int i=0,j=1,n=s.size();
  s=s+s;
  while (i<n&&j<n){
    for (k=0;k<=n&&s[i+k]==s[j+k];k++);
    if  (k==n) break;
    if (s[i+k]<s[j+k]){
      j=j+k+1;
      if (j==i) j++;
    }else if (s[i+k]>s[j+l]){
      i=i+k+1;
      if (i==j) i++;
    }
  }
  return min(i,j);
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80148384
今日推荐