在字符串中查找按字典顺序排列最大的旋转

时间:2014-09-17 22:54:17

标签: c++ string lexicographic

我需要从给定的输入字符串中找到按字典顺序排列的最大字符串。 所以如果输入是

enjoy

o / p应该是

yenjo

我试过的代码是......

int n;
cout<<"Enter the number of strings";
cin>>n;
int len[n];
char str[n][1000];
for(int i=0;i<n;i++)
{
    cin>>str[i];
    len[i]=strlen(str[i]);
}
int num,pos[n];
for(int i=0;i<n;i++)
{
    pos[i]=0;
    num=int(str[i][0]);
    for(int j=1;j<len[i];j++)
    {
       if(int(str[i][j])>num)
        {
           num=int(str[i][j]);
           pos[i]=j;
       }   
    }    
}
int i,j,k;
char temp[1];
for(i=0;i<n;i++)
{
    for(j=0;j<pos[i];j++)
        {
        temp[0]=str[i][0];
        for(k=0;k<len[i];k++)
         {
            str[i][k]=str[i][k+1];
        }
        strcat(str[i],temp);
        str[i][len[i]]='\0';
    }
    cout<<str[i]<<"\n";
}
return 0;
}

但是这段代码只有最大数量的ckecks而不是它旁边的数字,因此i / p

失败
blowhowler

o / p应为wlerblowho,但我将o / p视为whowlerblo
如何跟踪最大字符前面的每个元素以获得正确的输出?

7 个答案:

答案 0 :(得分:1)

为了在平均情况下获得良好的性能(实际上是O(N)),但在最差的情况下仍然是O ^ 2(并且总是正确的),您可以跟踪可能性,并随时随地消除它们。基本上是这样的。

struct PermSum
{
  int sum;
  int perm;
}

LinkedList<PermSum> L;

for(int i = 0; i != input.size(); ++i) L.append(PermSum{0,i});

int depth = 0;
int max = 0;
const int length = input.size()
while(L.size() > 1 && depth < length)
{
  for(l in L)
  {
    l.sum += input[(l.perm + depth) % length]
    if (l.sum > max) max = l.sum
  }

  for(l in L)
  {
    if (l.sum < max) L.delete(l)
  }
  depth ++;
}

if (L.size() == 1)
  return L.front().perm
else
  return -1

我在某些部分使用c ++代码有点懒,但我确定你可以在l中找出l。关键是第一个for循环。这个想法是它在l.perm-th排列的深度字母处添加了词典值。通过这种方式,它可以更新所有可能性,同时跟踪最佳可能性的级别。然后你做第二遍以删除任何不符合最佳状态的可能性。值得注意的是,我对其进行编码的方式,它可能使用与循环排列的标准约定相反的方式。也就是说,我的程序中的perm字段表示向左移动多少个点,而通常正数是向右移动的。你可以用某个减号来解决这个问题。

至于运行时间分析,它与Quickselect基本相同。每次while循环迭代都需要与L的长度成比例的时间。第一次迭代,L将始终具有length = N(其中N是字符串的长度,与代码中的变量长度相同)。下一轮,我们通常只期望1/26的数据通过,再次在1/26之后的回合...所以我们有N(1 + 1/26 + 2/26 ^ 2 ...)是O(N)。

答案 1 :(得分:1)

你可以: 1.产生旋转 2.将所有旋转放在地图中&lt;&gt; 3.找到地图的最后一个元素。 这是C ++中的实现。

#include <iostream>
#include <cstring>
#include <map>
using namespace std;

int main() {
    // your code goes here
    string str;int len,i=0,j=0,k=0;char temp;
    cin>>str;
    len = str.length();
    map<string,int>m;
    while(i<len)
    {
        temp = str[0];
        while(j<len-1)
        {
            str[j] = str[j+1];
            j++;
        }
        str[j] = temp;
        m[str] = k;
        k++;
        i++;j=0;
    }
    str = m.rbegin()->first;
    cout<<str;
    return 0;
}

答案 2 :(得分:1)

通过首先将字符串附加到自身并从中构建后缀数组,可以在O(n log n)时间内解决问题。找到相应的条目,并找到您想要的结果。实施留作练习。

答案 3 :(得分:1)

//Here the index with greater value is selected,
//if the same char occurs again the next characters
// of prev and curr characters is checked:-Prev=maxIndex,curr=i    
#include<bits/stdc++.h>
using namespace std;
int getIndex(char *str){
int max=INT_MIN,maxIndex;
int n=strlen(str);
int j,p;
for(int i=0;i<n;i++)
{
    if(str[i]>max)
    {
        max=str[i];
        maxIndex=i;
    }
    else if(str[i]==max)
    {
        j=maxIndex+1;
        p=(i+1)%n;
        while(j<n && p<n && str[j]==str[p]){
         j++;
         p=(p+1)%n;
        }
        maxIndex=str[p]>str[j]?i:maxIndex;
    }
}
return maxIndex;
}
int main(void)
{
char str[4000008];
scanf("%s",str);
int i=getIndex(str);
for(int j=i;j<strlen(str);j++)
cout<<str[j];
for(int j=0;j<i;j++)
cout<<str[j];



 }

答案 4 :(得分:0)

您的算法已更正,可归结为:

  1. 将当前最佳旋转设置为identity(旋转字符串的开头是当前索引0)。
  2. 对于每个可能的轮换(所有其他起始索引):
    1. 与当前最佳轮播比较,如下面的wrapcmp
    2. 如果我们有更好的候选人,请设置当前最佳轮换。
  3. 时间复杂度:O(n * n)
    空间复杂性:就地

    // Function to do ordinal-comparison on two rotations of a buffer
    // buffer: The buffer containing the string
    // n: The buffers size (string-length)
    // a: Index where the first buffer starts pre-rotation
    // b: Index where the second buffer starts pre-rotation
    int wrapcmp(const void* buffer, size_t n, size_t a, size_t b) {
        auto x = (const unsigned char*)buffer;
        auto m = n - std::max(a, b);
        int ret = memcmp(x+a, x+b, m);
        if(ret) return ret;
        auto left = n - m;
        a = (a + m) % n;
        b = (b + m) % n;
        m = left - std::max(a, b);
        ret = memcmp(x+a, x+b, m);
        if(ret) return ret;
        a = (a + m) % n;
        b = (b + m) % n;
        return memcmp(x+a, x+b, left - m);
    }
    

    用于coliru:http://coliru.stacked-crooked.com/a/4b138a6394483447
    把它放到一般的算法中留下作为读者的练习。

答案 5 :(得分:0)

这太诱人了,所以我不妨发表我的努力。不确定它如何评价效率wize。就我测试它似乎有效:

#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

std::string max_rot(const std::string& s)
{
    std::string tmp;
    std::string max;

    std::string::const_iterator m = std::max_element(s.begin(), s.end());
    if(m != s.end())
        for(char c = *m; (m = std::find(m, s.end(), c)) != s.end(); ++m)
            if(max < tmp.assign(m, s.end()).append(s.begin(), m))
                max = tmp;

    return max;
}


int main()
{
    size_t times = 0;
    std::string text;

    do { std::cout << "\nHow many words? : "; }
    while(std::getline(std::cin, text) && !(std::istringstream(text) >> times));

    std::vector<std::string> words;
    while(times-- && (std::cin >> text))
        words.push_back(text);

    for(const auto& s: words)
        std::cout << max_rot(s) << '\n';

}

作为解释。它在字符串中找到最高字符值,并旋转字符串以使该字符成为第一个。如果然后在字符串的其余部分中查找重复的最高字符,则跟踪最高尝试次数。可能还有优化空间。

答案 6 :(得分:0)

这项挑战在积极的比赛中使用,我请求在9月18日晚上9点之前提供答案。由于代码可见,我们可能必须禁止用户参与我们未来的任何竞赛。