算法日记0003-句子逆序

上次已经说了句子中的单词逐个逆序,那么,单词内部不变,整个句子逆序又如何呢?面试的时候经常会考到这两题,前者是考思维的缜密,后者是考数据结构(链表)了,当然,不用链表也可以做,我将在一会给大家贴出不用链表的简单方法~
先看题:
将一个句子逆序
例如:
输入:
This is a cat, I like it.
输出:
it. like I cat, a is This
下面这个例子是相对来说比较常规的算法,即将每个单词依次存入链表中,然后将整个链表逆序,再将逆序后的链表中的各个单词取出来,自然是逆序后的句子了。

#include<iostream>
#include<string>
#include<cstdlib>
#include<string>
#include<cassert>
using namespace std;

struct Node
{
    string str;
    Node * next;
};

bool is_letter(char c)
{
    return (isalpha(c)||c == '.'||c==',');
}

void sen_rev(string & str)
{
    Node * pHead;
    Node * pCur;
    pCur = pHead = new Node;
    int word_index = 0;
    int word_size = 0;
    string word_cur;
    bool is_first_node = true;
    for(int i = 0; i < str.length(); i++)
    {
        if((i == 0 && str[i] != ' ')||(str[i-1] == ' ' && is_letter(str[i])))
        {
            word_index = i;
            for(int j = i; j < str.length() && is_letter(str[j]); j++)
            {
                word_size ++;
            }
            word_cur.resize(word_size);
            for(int j = word_index; j < word_index + word_size; j++)
            {
                word_cur[j - word_index] = str[j];
            }
            if(is_first_node == false)
            {
                pCur -> next = new Node;
                pCur = pCur -> next;
            }

            pCur -> str = word_cur;
            pCur -> next = NULL;
            is_first_node = false;
            word_size = 0;
        }
    }
    Node * pNext, * pNextNext;
    pCur = pHead;
    pNext = pCur -> next;
    while(pNext)
    {
        pNextNext = pNext -> next;
        pNext -> next = pCur;
        pCur = pNext;
        pNext = pNextNext;
    }
    pHead -> next = NULL;
    pHead = pCur;
    pCur = pHead;
    string result;
    while(pCur->next)
    {
            cout<<pCur->str<<endl;
        result += pCur->str;
        result += ' ';
        pCur = pCur->next;
    }
    result += pCur->str;
    str = result;
    return;
}

int main(int argc, char ** argv)
{
    string str = "This is a cat, I like it.";
    sen_rev(str);
    cout << str << endl;
    system("pause");
    return 0;
}

本例子将标点也算在单词中了,当然读者不喜欢的话可以去掉标点,当然这对于理解整个算法来说并不重要,代码中isalpha( )函数是判断字符是否是大小写字母的函数。
另外,本例中是有坑的:链表的基础是结构,但是结构的存储空间是固定的,然而string是个不定长的东西,怎么办呢?
解决方法如下:

word_cur.resize(word_size);

确定单词长度后,将相应的节点中string 的大小resize一下,变成我们需要的长度,这样的话就可以了,否则在大部分编译器中会报错的哦。

另外,还有一种方法,但这种方法就比较重技巧而轻数据结构了:

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;

bool is_letter(char c)
{
    return (isalpha(c)||c == '.'||c==',');
}

void sen_rev(string & str)
{
    string result;
    string word_cur;
    int word_index = 0;
    int word_size = 0;
    for(int i = str.size() -1; i >= 0; i--)
    {
        if((i == str.size() - 1 && str[i] != ' ')||(str[i+1] == ' ' && is_letter(str[i])))
        {
            word_index = i;
            for(int j = i; j >=0 && is_letter(str[j]); j--)
            {
                word_size ++;
            }
            word_cur.resize(word_size);

            for(int j = word_index; j > word_index - word_size; j--)
            {
                word_cur[word_size - (word_index - j) - 1] = str[j];
            }
            result += word_cur;
            result += " ";
            word_size = 0;
        }
    }
    str = result;
}

int main(int argc, char ** argv)
{
    string str = "This is a cat, I like it.";
    sen_rev(str);
    cout << str << endl;
    system("pause");
    return 0;
}

可见这段代码的长度比上一段短了很多,思路是从句子末尾开始向前查找单词,找到了就把这个单词放到result追加到字符串的后面,并加一个空格。在句子中从末尾找到开头找出所有的单词,在此过程中,result也生成了,就是我们想要的结果。

展开阅读全文

没有更多推荐了,返回首页