反转字符串中单词的位置,而不更改 O(1) 空格限制中特殊字符的顺序

Reversing the positions of words in a string without changing order of special characters in O(1) space limit

本文关键字:空格 顺序 特殊字符 单词 字符串 位置      更新时间:2023-10-16

在模拟面试中,我想出了这个问题。面试官首先问这个问题,没有任何篇幅限制。然后他继续使用空间有限的版本。要在同一页面上。在问题中,给出了由分隔符组成的字符串和容器类。这由您决定合适的容器类和响应语言。我认为示例输入和输出足以理解真正的问题是什么。

输入:

"Reverse#Strings Without%Changing-Delimiters"

输出:

"Delimiters#Changing Without%Strings-Reverse"

请注意:">#"、"%"、","-">的位置不会更改

我想出了以下解决方案:

string ChangeOrderWithoutSpecial(string s, unordered_set<char> delimiter)
{
stack<string> words; // since last words outs first
queue<char> limiter; // since first delimiter outs first
string response =""; //return value
int index=-1; // index of last delimiter visited
int len=s.length();
for (int i =0 ; i <len;i++)
{
if(delimiter.find(s[i]) != delimiter.end()) // i-th char is a delimiter character
{
string temp=s.substr(index+1,i-index-1);
words.push(temp);
char t =s.at(i);
limiter.push(t);
index=i;
}
// i realized that part after interview under assumption starting with word and no double delimiters ie, each word followed by one delimiter
if(index!=s.length()-1)
{
string temp=s.substr(index+1,s.length()-index-1);//until the end;
cout<<temp<<endl;
words.push(temp);
}
while(!limiter.empty())
{
response+=words.top()+limiter.front();
words.pop();
limiter.pop();
}
response+=words.top();
return response;  
} 

但是我找不到o(1(空间解决方案?有人知道怎么做吗?我也无法弄清楚是否有多个分隔符,这也适用。谢谢任何人花时间甚至阅读。

找到第一个单词和最后一个单词。将琴弦旋转length(last_word)-length(first_word):这会将中间部分置于正确的位置。在示例中,这将产生

ersReverse#Strings Without%Changing-Delimit

然后将字符串的第一部分和最后一部分旋转,跳过中间部分,按length(first_word)

Delimiters#Strings Without%Changing-Reverse

对两个最外层分隔符之间的子字符串重复此算法。

"按m旋转"操作可以在O(1)空间和O(n)时间内执行,其中n是正在旋转的序列的长度。

除了旋转字符串,还可以通过连续反转字符串来解决。

  • 反转整个字符串。这是O(n)操作。在您的情况下,字符串变为sretimileD-gnignahC%tuohtiW sgnirtS#esreveR.
  • 找到所有单词并反转每个单词。这是O(n)操作。字符串现在等于Delimiters-Changing%Without Strings#Reverse
  • 反向分隔符。这是O(n)操作。你会得到想要的结果:Delimiters#Changing Without%Strings-Reverse

这些操作中的每一个都可以就地完成,因此总内存复杂度O(1),时间复杂度O(n)

值得注意的是,使用这种方法,每个字符将被访问 4 次(第一次反向、查找单词、反向单词、反向分隔符(,因此(在一般情况下(它应该比 Igor Tandetnik 的答案更快,其中字符串中间的字符被多次访问。但是,在每个单词具有相同长度的特殊情况下,Igor的解决方案将更快,因为不存在第一个旋转操作。

编辑:

反向分隔符可以在O(n)中完成,无需额外的内存,方式与标准反向类似。只需遍历分隔符而不是整组字符:

  1. 向前迭代,直到达到分隔符;
  2. 反向迭代,直到从后面到达分隔符;
  3. 交换当前分隔符;
  4. 继续执行该过程,直到迭代器满足。

这是C++中的程序,可以完成这项工作

void reverseDelimiters(string& s, unordered_set<char>& delimiters)
{
auto i = s.begin(); auto j = s.end() - 1; auto dend = delimiters.end();
while (i < j) {
while (i < j && delimiters.find(*i) == dend) i++;
while (i < j && delimiters.find(*j) == dend) j--;
if (i < j) swap(*i, *j), i++, j--;      
}
}