LeetCode 899.有序队列|字符串最小表示法的使用|求循环字符串的最小值

Tags: #String

For a string s, each time you can choose one of first k letters and put it the end of string s. What is the lexicographically smallest string you can obtain?

Example1:

Input: s="dbbca", k=1
Output: s="adbbc"
Explanation:
Continuously put the first letter to end of s till 'a' is the first letter.

Example2:

Input: s="baaca", k=3
Output: s="aaabc"
Explanation:
First move: 'b' to end, now s="aacab"
Second move: 'c' to end, now s="aaabc"

Let’s divide this problem into two situations:

k>1(Simple)

Let’s consider k=2, we can move either the first letter or second letter to the end. If we move the second letter to the end, that is equal to move the letter advance one space in the string cycle: "bacc", move "a", then the string becomes "bcca", which is equal to ” abcc“(just cycle 3 times). So that means we can move any character to any where in the string. Then we can always obtain a sorted lexicographically smallest string.

Any other case where k>2 is also the same.

    // if k>1
    char[] arr=s.toCharArray();
    Arrays.sort(arr);
    return String.valueOf(arr);

k=1(Interesting)

Each time we can only move one character to string end. That is Cyclic isomorphism(循环同构):

[S_i=S[i,n]+S[0,i]=T ]

(S) and (T) are called cyclic isomorphism.

To find the smallest cyclic isomorphism, we just need to index where the answer string starts in the string s. So we need to compare those n=s.length() strings.

Choose the i=0, j=1 as two strings’ beginning, compare them.

Compare each letter at same position of them. If s[i+k]<s[j+k]< code>, <span class="math inline">\(k\in(0,n)\)</span>, them string <span class="math inline">\(S_j\)</span> must bigger than string <span class="math inline">\(S_i\)</span>. For example:<br><code>s="aaabc", i=0, j=1</code>:</s[j+k]<>

  • k=0,1, s[i+k]=s[j+k]='a'
  • k=2, s[i+k]='a' < s[j+k]='b', so string (S_i) start with i=0: "aaabc" is smaller than (S_j) "aabca" which is start with j=1.

So string (S_j) j=1 must not be the answer. Then we should j start next?

Consider string (A) and (B), they are (S_i) and (S_j) of string s, which means they start at (i) and (j). The first (k) letters of them are equal:

[S[i,i+k-1]=S[j,j+k-1] ]

W.o.l.g, consider (S[i+k]

We only need to go through the string one time(till the bigger one of i or j reach the end). So the time complexity is (O(n)), that’s quick!

Code:

public String orderlyQueue(String s, int m) {
    if (m == 1) {
        int i = 0, j = 1, k = 0, n = s.length();
        while (i < n && j < n && k < n) {
            char iCh = s.charAt((i + k) % n), jCh = s.charAt((j + k) % n);
            if (iCh == jCh)
                k++;
            else {
                if (iCh > jCh) {
                    i += k + 1;
                } else {
                    j += k + 1;
                }
                if (i == j)
                    ++i;
                k = 0;
            }
        }
        i = Math.min(i, j);
        return s.substring(i) + s.substring(0, i);
    } else {
        char[] arr = s.toCharArray();
        Arrays.sort(arr);
        return String.valueOf(arr);
    }
}

Original: https://www.cnblogs.com/liuzhch1/p/16555486.html
Author: liuzhch1
Title: LeetCode 899.有序队列|字符串最小表示法的使用|求循环字符串的最小值

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606692/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球