【程序员面试题】翻转句子中单词的顺序

翻转句子中单词的顺序。

题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。

句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。

例如输入“I am a student.”,则输出“student. a am I”。


一开始看到这题其实可以很容易地想到将每个单词保存在一个字符串里面,整个句子用一个二维字符串数组来保存,然后反转这个二维数组就可以了。事实上,若真的根据这个想法来写代码,感觉真的是费力不讨好,特别还是在用C/C++的字符串、指针的情况下(当然也可以用STL中的vector、string,那样会容易很多,这里就先自虐一下),不过其实看看写好的代码也不是很繁琐,如下所示:

解法一

void reverseWord1(char* p)
{
	int wordcount = 100;
	int wordlen = 15;
	char** rvWord = new char*[wordcount];
	char* wordstart = p;
	char* wordend = p;
	int i = 0;
	for (i=0; *wordend != '\0'; i++) {
		while( *wordend != '\0' && *wordend != ' ')
			++wordend;
		rvWord[i] = new char[wordlen];
		char* r = rvWord[i];
		while(wordstart<wordend)
			*r++ = *wordstart++;
		*r = '\0';
		if(*wordend != '\0')
			wordstart = ++wordend;
	}
	wordcount = i--;
	for (int j=0; j<i;j++,i--) {
		char* temp = rvWord[j];
		rvWord[j] = rvWord[i];
		rvWord[i] = temp;
	}
	for (int j=0; j<wordcount; ++j)
		cout << rvWord[j] << " ";
	for (int j=0; j<wordcount; ++j)
		delete [] rvWord[j];
	delete [] rvWord;
}

上面的代码其实不太简洁明了,而且用到了额外的空间,所以说费力不讨好。那就来看看其他的方法。

如果真的要一个一个单词来看呢,说到反转你能想到到什么数据结构呢?先顺着一个单词一个单词地读,再反过来一个单词一个单词地读,这样子的特点你应该能够跟栈联系起来吧!没错,我们可以先将单词按顺序一个一个进栈,单词全部进栈之后再一个一个出栈,这样就实现了翻转句子中单词的顺序。这次就不用蛋疼的C字符串指针之流的了,用用C++高大上的STL:

解法二

void reverseWord2(char* p)
{
	char* wordstart = p;
	char* wordend = p;
	stack<string> wordstack;
	while(*wordend != '\0') {
		while( *wordend != '\0' && *wordend != ' ')
			++wordend;
		string s(wordstart,wordend);
		wordstack.push(s);
		if(*wordend != '\0')
			wordstart = ++wordend;
	}
	while(!wordstack.empty()) {
		string s = wordstack.top();
		cout << s;
		wordstack.pop();
		if(!wordstack.empty()) cout << " ";
	}
}

另外我们也可以从句尾开始着手,从句尾到举手将单词一个一个搬到一个新的字符串上面,从而实现句子到此的翻转:

解法三:

void reverseWord3(char* p)
{
	int slen = strlen(p);
	char* rvWord = new char[slen];
	char* temp = rvWord;
	char* wordstart = p+slen-1;
	char* wordend = p+slen-1;
	while(wordstart != p-1) {
		while(wordstart != p-1 && *wordstart != ' ')
			--wordstart;
		int wlen = wordend-wordstart;
		strncpy(temp,wordstart+1,wlen);
		temp += wlen;
		*(temp++) = ' ';
		if(wordstart != p-1)
			wordend = --wordstart;
	}
	rvWord[slen] = '\0';
	cout << rvWord << endl;
	delete [] rvWord;
}

以上三种方法其实都是先找出单词然后再进行操作。联想到如果对一个字符串翻转两次还是得到原来的字符串,我们也可以先翻转整个句子,这样单词内字符的顺序也改变了,然后我们再翻转每个单词中字符的顺序,这样就得到原来的单词了,整个过程如下面的例子所示:

E.g. “I am a student.”—>“.tneduts a ma I”—>“student. a am I”

代码写起来也很简单:

解法四

void Reverse(char* s, int n)
{
	if (s ==NULL) return;
	char* begin = s;
	char* end = s+n-1;
	while(begin<end) {
		char temp = *begin;
		*begin = *end;
		*end = temp;
		begin++, end--;
	}
}

void reverseWord4(char* p)
{
	Reverse(p, strlen(p));
	char* wordstart = p;
	char* wordend = p;
	while(*wordend != '\0') {
		while( *wordend != '\0' && *wordend != ' ')
			++wordend;
		Reverse(wordstart, wordend-wordstart);
		if(*wordend != '\0')
			wordstart = ++wordend;
	}
	cout << p << endl;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elwin Wong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值