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

Finding the lexicographically largest rotations in the string

本文关键字:旋转 排列 顺序 字符串 字典 查找      更新时间:2023-10-16

我需要从给定的输入字符串中找到词法上最大的字符串。因此,如果输入是

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]]='';
    }
    cout<<str[i]<<"n";
}
return 0;
}

但是,这个代码只对最大的数字进行编码,而对旁边的数字不进行编码,因此对i/p 失败

blowhowler

o/p应该是wlerblowho,但我得到的o/p是whowlerblo
如何跟踪每一个包含最大字符的元素,以便获得正确的输出?

为了在平均情况下获得良好的性能(实际上是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。关键行是循环的第一行。其思想是,它在l.perm-th排列的字母深度处添加词典学值。通过这种方式,它更新了所有的可能性,同时跟踪最佳可能性的水平。然后你做第二次传球,删除任何可能达不到最佳水平的可能性。值得注意的是,我编码的方式可能与循环排列的标准约定相反。也就是说,我的程序中的perm字段表示你循环移位的左边有多少个点,而通常正数是循环右移。你可以在某个地方用减号来解决这个问题。

至于运行时间分析,它与Quickselect基本上是相同的参数。每次while循环迭代所花费的时间与L的长度成比例。第一次迭代,L的长度总是=N(其中N是字符串的长度,与代码中的可变长度相同)。下一轮,我们通常只期望1/26的数据通过,下一轮是1/26。。。所以我们有N(1+1/26+2/26^2…),它是O(N)。

这个问题可以在O(n log n)时间内解决,方法是先将字符串附加到它本身,然后用它构建后缀数组。找到相应的条目,就可以得到你想要的结果。执行作为练习。

您可以:1.生成旋转2.将所有旋转放在map中<>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;
}
//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];

 }

经过校正后,您的算法归结为:

  1. 将当前最佳旋转设置为标识(旋转字符串的开头为当前索引0)
  2. 对于每个可能的旋转(所有其他起始索引):
    1. 与下面类似wrapcmp的当前最佳旋转进行比较
    2. 如果我们有更好的候选人,请设置当前的最佳轮换

时间复杂度: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
把它放在普通算法中,留给读者练习。

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

#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';
}

作为解释。它会找到字符串中最高的字符值,并旋转字符串以使该字符位于第一位。如果然后在字符串的剩余部分中查找重复的最高字符,以跟踪最高尝试。也许还有优化的空间。

此挑战用于活动比赛,我要求在9月18日至9月9日下午IST之前不提供答案。因为代码是可见的,我们可能不得不禁止用户参与我们的任何比赛。