Это был вопрос интервью:
Как конвертировать
Dogs like cats
вcats like Dogs
?
Мой код показывает: cats like cats
. Где я делаю ошибки?
#include <iostream>
using namespace std;
int main()
{
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--)
{
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--)
{
str[words] = reverse[m];
words++;
}
}
}
cout << str;
return 0;
}
Я знаю, что вы можете сделать это, используя указатели, стек, векторы … но интервьюер не интересовался этим!
Это фиксированная версия вашего примера кода:
' '
или же '\0'
Вы копируете байты обратной строки от начала до этой точки. Пример в loop 5
вы копируете из индекса 0-5 (stac
) от reverse
в str
в обратном порядке, но в loop 10
вы копируете из индекса 0-10 (stac ekil
) от reverse
в str
в обратном порядке, пока здесь у вас уже не будет напечатана строка результата («кошки как кошки»), и то же самое в loop 15
все это увеличивает индекс str
, в последнем цикле вы пишете передать конец действительной памяти str
(и из-за этого не печатается как вывод).cats like\0dogs
Предоставлен модифицированный пример кода:
#include <iostream>
using namespace std;
int main() {
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
// change here added last_l to track the end of the last word reversed, moved
// the check of the end condition to the end of loop body for handling the \0
// case
for (int l = 0, last_l = 0; ; l++) {
if (reverse[l] == ' ' || reverse[l] == '\0')
{
for (int m = l - 1; m >= last_l; m--) { // change here, using last_t to
str[words] = reverse[m]; // only reverse the last word
words++; // without the split character
}
last_l = l + 1; // update the end of the last
// word reversed
str[words] = reverse[l]; // copy the split character
words++;
}
if (reverse[l] == '\0') // break the loop
break;
}
cout << str << endl;
return 0;
}
Некоторый код, написанный с ограничением использования самых простых функций языка.
#include <iostream>
// reverse any block of text.
void reverse(char* left, char* right) {
while (left < right) {
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main() {
char sentence[] = "dogs like cats";
std::cout << sentence << std::endl;
// The same length calculation as sample code.
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
std::cout << len << std::endl;
// reverse all the text (ex: 'stac ekil sgod')
reverse(sentence, sentence + len - 1);
// reverse word by word.
char* end = sentence;
char* begin = sentence;
while (end < sentence + len) {
if (*end != ' ')
end++;
if (end == sentence + len || *end == ' ') {
reverse(begin, end - 1);
begin = end + 1;
end = begin;
}
}
std::cout << sentence << std::endl;
return 0;
}
Рассекать ваш алгоритм по частям. Во-первых, вы найдете длину строки, не считая нулевого символьного терминатора. Это правильно, хотя может быть упрощено.
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
Это можно легко записать просто как:
size_t len = 0;
while (sentence[len])
++len;
Затем вы переворачиваете всю строку, но появляется первый дефект. VLA (массив переменной длины), который вы объявляете здесь (который вам не нужен и не должен использоваться, поскольку он является расширением C ++ и нестандартным), не учитывает и не устанавливает завершающий нулевой символ.
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
Эта временная буферная строка совсем не нужен. Нет причины, по которой вы не можете выполнить всю эту операцию на месте. Как только мы рассчитаем len
правильно, вы просто делаете что-то вроде следующего, чтобы полностью изменить последовательность, которая сохраняет нулевой символ-символ в правильном положении:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
Далее мы переходим к тому месту, где вы пытаетесь изменить каждое внутреннее слово. Опять же, как и раньше, длина буфера не является правильной. Так должно быть len+1
, Хуже (трудно представить), вы никогда не помните, где вы остановился при поиске конечной точки слова. Это место должно быть следующий точка, которую вы начинаете проверять и пропускаете пробелы. Не сохраняя, что вы копируете из текущей точки обратно в начало строки. который по существу взрывает cats
над dogs
,
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
Еще раз, это может быть сделано на месте без затруднений вообще. Один из таких алгоритмов выглядит следующим образом (и обратите внимание, что цикл, обращающий реальное слово, не совпадает с алгоритмом обращения всего нашего буфера):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
Собираем все вместе
Хотя использовать указатели значительно проще, чем все эти индексные переменные, следующее будет делать то, что вы пытаетесь, на месте.
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
Выход
dogs like cats
cats like dogs
Я бы посоветовал разбить исходную строку на массив слов, перевернуть этот массив. Затем добавьте эти слова в обратное предложение с пробелом между ними.
Так как они попросили никаких библиотек, я предположил, что нет std::string
нет vectors
, ничего вообще, и поэтому я написал это на C .. единственное, что используется printf
, Все остальное с нуля: l
Идея состоит в том, чтобы сначала перевернуть массив. Затем разделите массив на пробел и поменяйте местами каждое слово.
Пример: http://ideone.com/io6Bh9
Код:
#include <stdio.h>
int strlen(const char* s)
{
int l = 0;
while (*s++) ++l;
return l;
}void reverse(char* str)
{
int i = 0, j = strlen(str) - 1;
for(; i < j; ++i, --j)
{
str[i] ^= str[j];
str[j] ^= str[i];
str[i] ^= str[j];
}
}
void nulltok(char* str, char tok, int* parts)
{
int i = 0, len = strlen(str);
*parts = 1;
for (; i < len; ++i)
{
if (str[i] == tok)
{
str[i] = '\0';
++(*parts);
}
}
}
char* reverse_sentence(char* str)
{
char* tmp = str;
reverse(str);
int i = 0, parts = 0, len = strlen(str);
nulltok(str, 0x20, &parts);
while(parts--)
{
reverse(str);
str += strlen(str) + 1;
}
for(; i < len; ++i)
if (tmp[i] == '\0')
tmp[i] = 0x20;
return tmp;
}int main(void)
{
char str[] = "dogs like cats";
printf("%s", reverse_sentence(str));
return 0;
}
Мое решение
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cout<<"enter the sentence"<<endl;
getline(cin,str);
char* pch;
pch = strtok((char*)str.c_str()," ");
string rev = "";
while(NULL != pch)
{
rev.insert(0,pch);
rev.insert(0," ");
pch = strtok(NULL," ");
}
cout<<"the reversed string is :"<<rev<<endl;
return 0;
}