最小表示法字符串

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小表示法字符串相关的知识,希望对你有一定的参考价值。

最小表示法

1️⃣ 简介

最小表示法就是找 字符串S的循环同构串中字典序最小的一个 的算法,属于是字符串算法。

循环同构串:

例子:字符串S : bcad, 则S的循环同构串为bcad, cadb, adbc, dbca

故循环同构串可以有多个,它是原字符串循环移位产生的字符串

2️⃣ 实现方法

最小表示法其实就是找到位置i,从这个位置输出S,使得到的同构串字典序最小

可以参考的链接:
https://oi-wiki.org/string/minimal-string/

暴力解法

关键是如何找:需要先知道暴力的简单方法,然后再对暴力做一些优化即可。

每次比较的是 i i i j j j开始的循环同构,把当前比较的位置记为 k k k.

int k = 0, i = 0, j = 1;
while (k < n && i < n && j < n)

  if (a[(i + k) % n] == a[(j + k) % n])
    ++k;
  else
  
    if (sec[(i + k) % n] > sec[(j + k) % n]) ++i;
    else  ++j;
    k = 0;
    if (i == j) i++;
  

i = min(i, j);

优化后的算法(最小表示法)

优化后的代码:

int i = 0, j = 1, k = 0;
while(i < n and j < n and k < n)

    if(a[(i + k) % n] == a[(j + k) % n])
        k++;
    else
    
        a[(i + k) % n] > a[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
        if(i == j) 
            i++;
        k = 0;
     

i = min(i, j);

模板题目

题目链接

https://www.luogu.com.cn/problem/P1368

找数组所有的循环同构中最小的字典序的数组

#include<bits/stdc++.h>
using namespace std;
using ll = long long ;

void solve()

	int n;
	cin >> n;
	vector<int> a(n + 1);
	for(int i = 0; i < n; i++)
		cin >> a[i];

	int i = 0, j = 1, k = 0;
	while(i < n and j < n and k < n)
	
		if(a[(i + k) % n] == a[(j + k) % n])
			k++;
		else
		
			a[(i + k) % n] > a[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
			if(i == j) 
				i++;
			k = 0;
		 
	
	i = min(i, j);
	for(int x = 0; x < n; x++)
		cout << a[(x + i) % n] << " \\n"[x == n - 1];


int main()

	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	// cin >> t;
	t = 1;
	while(t--)
		solve();
	return 0;

以上是关于最小表示法字符串的主要内容,如果未能解决你的问题,请参考以下文章

关于LIS和LCS问题的o(nlogn)解法

AcWing1048 鸡蛋的硬度(浅谈两种解法的思考方向)

判定最大值/最小值的两种解法!

LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)

最少交换次数

最小表示法字符串