m1une's library

This documentation is automatically generated by online-judge-tools/verification-helper

View on GitHub

:heavy_check_mark: Minimum Rotation
(string/minimum_rotation.hpp)

Overview

minimum_cyclic_shift finds where the lexicographically smallest rotation of a sequence begins. If several starting positions produce the same minimum rotation, it returns the smallest index.

#include "string/minimum_rotation.hpp"

The function is in m1une::string and uses the same Duval-style linear scan as the previous implementation in lyndon_factorization.hpp.

Interface

template <class Sequence>
int minimum_cyclic_shift(const Sequence& sequence);
Function Description Complexity
minimum_cyclic_shift(sequence) Returns the earliest starting index of a lexicographically minimum cyclic shift. $O(N)$ time and $O(1)$ additional memory

Sequence must provide size() and random access through operator[]. Its elements are compared using operator<. Strings, vectors, and arrays are supported.

The empty sequence returns 0. The function does not construct or modify a rotation; it only returns its starting index.

lyndon_factorization.hpp includes this header, preserving the old include behavior. New code that only needs minimum rotation can include this smaller header directly.

Example

#include "string/minimum_rotation.hpp"

#include <iostream>
#include <string>

int main() {
    std::string text = "banana";
    int start = m1une::string::minimum_cyclic_shift(text);
    std::string rotation = text.substr(start) + text.substr(0, start);

    std::cout << start << '\n';     // 5
    std::cout << rotation << '\n';  // abanan
}

Required by

Verified with

Code

#ifndef M1UNE_STRING_MINIMUM_ROTATION_HPP
#define M1UNE_STRING_MINIMUM_ROTATION_HPP 1

namespace m1une {
namespace string {

// Returns the smallest starting index of a lexicographically minimum cyclic shift.
template <class Sequence>
int minimum_cyclic_shift(const Sequence& sequence) {
    const int size = int(sequence.size());
    if (size == 0) return 0;

    auto less = [&](int left, int right) {
        return sequence[left < size ? left : left - size] <
               sequence[right < size ? right : right - size];
    };

    int answer = 0;
    int start = 0;
    while (start < size) {
        answer = start;
        int scan = start + 1;
        int matched = start;
        while (scan < 2 * size && !less(scan, matched)) {
            if (less(matched, scan)) {
                matched = start;
            } else {
                matched++;
            }
            scan++;
        }

        const int period = scan - matched;
        while (start <= matched) start += period;
    }
    return answer;
}

}  // namespace string
}  // namespace m1une

#endif  // M1UNE_STRING_MINIMUM_ROTATION_HPP
#line 1 "string/minimum_rotation.hpp"



namespace m1une {
namespace string {

// Returns the smallest starting index of a lexicographically minimum cyclic shift.
template <class Sequence>
int minimum_cyclic_shift(const Sequence& sequence) {
    const int size = int(sequence.size());
    if (size == 0) return 0;

    auto less = [&](int left, int right) {
        return sequence[left < size ? left : left - size] <
               sequence[right < size ? right : right - size];
    };

    int answer = 0;
    int start = 0;
    while (start < size) {
        answer = start;
        int scan = start + 1;
        int matched = start;
        while (scan < 2 * size && !less(scan, matched)) {
            if (less(matched, scan)) {
                matched = start;
            } else {
                matched++;
            }
            scan++;
        }

        const int period = scan - matched;
        while (start <= matched) start += period;
    }
    return answer;
}

}  // namespace string
}  // namespace m1une
Back to top page