跳至主要內容

最小(大)表示法

大约 2 分钟

最小(大)表示法

题目难度
899. 有序队列open in new window困难最小
1163. 按字典序排在最后的子串open in new window困难最大
3403. 从盒子中找出字典序最大的字符串 Iopen in new window中等最大

定义

循环同构

当字符串 S 中可以选定一个位置 i 满足 S[i,n] + S[1,i-1] = T

则称 ST 循环同构。

最小表示

字符串 S 的最小表示为与 S 循环同构的所有字符串中字典序最小的字符串。

899. 有序队列

import java.util.Arrays;

public class Solution899 {
    public String orderlyQueue(String S, int k) {
        char[] s = S.toCharArray();
        if (k == 1) {
            int i = minimalString(s, true);
            return S.substring(i) + S.substring(0, i);
        } else {
            Arrays.sort(s);
            return new String(s);
        }
    }

    // 最小表示法
    private int minimalString(char[] s, boolean isMin) {
        int n = s.length;
        int k = 0, i = 0, j = 1;
        while (k < n && i < n && j < n) {
            int d = chr(s, i + k, isMin) - chr(s, j + k, isMin);
            if (d == 0) {
                k++;
            } else {
                if (d > 0 == isMin) i = i + k + 1;
                else j = j + k + 1;
                if (i == j) i++;
                k = 0;
            }
        }
        i = Math.min(i, j);
        return i;
    }

    private int chr(char[] s, int i, boolean isMin) {
        int n = s.length;
        if (i >= n) return isMin ? s[i % n] : 0;
        return s[i];
    }
}

1163. 按字典序排在最后的子串

public class Solution1163 {
    public String lastSubstring(String s) {
        return s.substring(minimalString(s.toCharArray(), false));
    }

    // 最小表示法
    private int minimalString(char[] s, boolean isMin) {
        int n = s.length;
        int k = 0, i = 0, j = 1;
        while (k < n && i < n && j < n) {
            int d = chr(s, i + k, isMin) - chr(s, j + k, isMin);
            if (d == 0) {
                k++;
            } else {
                if (d > 0 == isMin) i = i + k + 1;
                else j = j + k + 1;
                if (i == j) i++;
                k = 0;
            }
        }
        i = Math.min(i, j);
        return i;
    }

    private int chr(char[] s, int i, boolean isMin) {
        int n = s.length;
        if (i >= n) return isMin ? s[i % n] : 0;
        return s[i];
    }
}

3403. 从盒子中找出字典序最大的字符串 I

public class Solution3403 {
    public String answerString(String word, int numFriends) {
        if (numFriends == 1) return word;

        int n = word.length();
        // 取最大子串长度为 n - numFriends + 1 的前缀
        int i = minimalString(word.toCharArray(), false);
        int maxLen = Math.min(n + 1 - numFriends, n - i);
        return word.substring(i, i + maxLen);
    }

    // 最小表示法
    private int minimalString(char[] s, boolean isMin) {
        int n = s.length;
        int k = 0, i = 0, j = 1;
        while (k < n && i < n && j < n) {
            int d = chr(s, i + k, isMin) - chr(s, j + k, isMin);
            if (d == 0) {
                k++;
            } else {
                if (d > 0 == isMin) i = i + k + 1;
                else j = j + k + 1;
                if (i == j) i++;
                k = 0;
            }
        }
        i = Math.min(i, j);
        return i;
    }

    private int chr(char[] s, int i, boolean isMin) {
        int n = s.length;
        if (i >= n) return isMin ? s[i % n] : 0;
        return s[i];
    }
}

(全文完)