Algorithm for finding the lexicographically smallest string of unique characters satisfying given order

大憨熊 提交于 2021-02-04 21:56:26

问题


How to find the lexicographically smallest string and has unique characters that satisfies the order given in the form of a string filled with '>' and '<'.For example, answer for the string '<<<<' is 'abcde' because 'a<b<c<d<e.How to go about it?


回答1:


For string length N make a graph with N+1 nodes and N directed edges, where p[i] < p[j] denotes edge from i-th to j-th node.

Then perform topological sort for this graph.

Make the smallest result swapping neighbor pairs that violate natural order and have no edge between them (see section Uniqueness)

Assign alphabet chars to nodes in sorted order

1<2<3>4
graph:

1 -> 2 -> 3
          ^
         /  
        4
           
1 4 2 3  //one of the possible topologic orderings

1 2 4 3  //after 2/4 swap 
| | | |  
a b c d  //assign letters

a<b<d>c 




 



回答2:


If I understand correctly your input string would have one character less than the expected output string, since each character describes a relationship between two consecutive characters. And it also seems you want the output to consist of lowercase Latin letters only.

I would extend that input string, so it gets an extra "<" at its end.

We can make some observations now: if we find a "<" at position k in the input string, then we should output the kth letter from the Latin alphabet.

If however we find a ">" at position k, we should look for the end of this series of ">", up to the next "<". There is always a "<" following, since we added an extra one at the end. Let the position of the next "<" be at position m.

For those m-k positions we now produce the mth letter from the Latin alphabet first, then the (m-1)th, ...etc, down to the kth letter of the alphabet.

Here is an implementation in pseudo code:

solve(str):
    letters := "abcdefghijklmnopqrstuvwxyz"
    str.append("<")
    output := ""
    i := 0    
    while i < len(str) do
        if str[i] is "<" then
            output.append(letters[i])
        else
            start := i
            while str[i] is ">" do
                i := i + 1
            j := i
            while j >= start do
                output.append(letters[j])
                j := j - 1
        i := i + 1
    return output



回答3:


The problem is to fill an array with numbers from 0 to n-1, such that the local inegalities are respected, and such that the lowest numbers are localised at the beginning of the array as much as possible.

A simple solution consists in reading the input string in the reverse order, trying first to place n-1, then n-2 etc.

When a < is encountered, the current value is written in a stack. If not, the stack is read.

Output:

>>    -> cba
<<<<  -> abcde
<<><  -> abdce
>>>>  -> edcba
><>>  -> baedc

The code in C++:

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <algorithm>
#include <numeric>

std::string smallest_s (const std::string &s_in) {
    int n = s_in.size() + 1;
    std::string s;
    s.resize(n);
    std::vector<int> ans (n);
    int index = n-1;
    std::stack<int> qu;
    qu.push (n-1);
    for (int j = n-2; j >= 0; j--) {
        if (s_in[j] == '<') {
            while (!qu.empty()) {
                ans[index--] = qu.top();
                qu.pop();
            }
        } 
        qu.push (j);
    }
    while (!qu.empty()) {
        ans[index--] = qu.top();
        qu.pop();
    }
    for (int i = 0; i < n; ++i)
        s[i] = 'a' + ans[i];
    return s;
}


int main() {
    
    for (const std::string &s_in: {">>", "<<<<", "<<><", ">>>>", "><>>"}) {
        std::cout << s_in << " -> " << smallest_s(s_in) << '\n';
    }
}


来源:https://stackoverflow.com/questions/63933388/algorithm-for-finding-the-lexicographically-smallest-string-of-unique-characters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!