• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            life02

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              197 隨筆 :: 3 文章 :: 37 評論 :: 0 Trackbacks

            字符串面試題(一)字符串逆序

            幾點說明

            1. 所有題目全部來自網(wǎng)絡,書籍,或者我自己的面試經(jīng)歷,本人只是負責搜集整理。在此對原作者表示感謝!

            http://www.cnblogs.com/graphics/archive/2011/03/09/1977717.html
            2. 我已經(jīng)盡力確保文字及程序的正確性,但我畢竟是凡人,如果您發(fā)現(xiàn)了文章中的錯誤,或者有更好的解法,請一定留言相告,以免誤導大家!

            3. 所有代碼都采用C/C++編寫

            很早就準備寫一個字符串系列的面試題,本來已經(jīng)寫好了,大概有十幾道題,但是寫完才發(fā)現(xiàn),文章好長,連我自己都沒有耐心讀下去了,索性就將其拆分成幾個系列,一來分開后篇幅變小,看起來比較方便。二來也更有針對性,便于精雕細作。比如這篇,在原來的文章中只占很小的篇幅,但是獨立出來才發(fā)現(xiàn),東西也不少。既然是第一篇,就來個最最簡單的字符串逆序吧。

            字符串逆序可以說是最經(jīng)常考的題目。這是一道入門級的題目,相信80%的程序員經(jīng)歷過這道題。給定一個字符串s,將s中的字符順序顛倒過來,比如s="abcd",逆序后變成s="dcba"。

            普通逆序

            基本上沒有這么考的,放在這里主要是為了和后面的原地逆序做個對比。很簡單,直接分配一個與原字符串等長的字符數(shù)組,然后反向拷貝一下即可,

            char *Reverse(char *s)
            {
            //將q指向字符串最后一個字符
            char *q = s ;
            while(*q++)
            ;
            q
            -= 2 ;

            //分配空間,存儲逆序后的字符串。
            char *p = new char[sizeof(char) * (q - s + 2)] ;
            char *r = p ;

            // 逆序存儲
            while(q >= s)
            *p++ = *q-- ;
            *p = '\0' ;

            return r ;
            }

            原地逆序

            英文叫做in-place reverse。這是最常考的,原地逆序意味著不允額外分配空間,主要有以下幾種方法,思想都差不多,就是將字符串兩邊的字符逐個交換,如下圖。給定字符串"abcdef",逆序的過程分別是交換字符a和f,交換字符b和e,交換字符c和d。

            一 設置兩個指針,分別指向字符串的頭部和尾部,然后交換兩個指針所指的字符,并向中間移動指針直到交叉。

            char *Reverse(char *s)
            {
            // p指向字符串頭部
            char *p = s ;

            // q指向字符串尾部
            char *q = s ;
            while(*q)
            ++q ;
            q
            -- ;

            // 交換并移動指針,直到p和q交叉
            while(q > p)
            {
            char t = *p ;
            *p++ = *q ;
            *q-- = t ;
            }

            return s ;
            }

            二 用遞歸的方式,需要給定逆序的區(qū)間,調(diào)用方法:Reverse(s, 0, strlen(s)) ;

            // 對字符串s在區(qū)間left和right之間進行逆序,遞歸法
            char *Reverse( char *s, int left, int right )
            {
            if(left >= right)
            return s ;

            char t = s[left] ;
            s[left]
            = s[right] ;
            s[right]
            = t ;

            Reverse(s, left
            + 1, right - 1) ;
            }

            三 非遞歸法,同樣指定逆序區(qū)間,和方法一沒有本質(zhì)區(qū)別,一個使用指針,一個使用下標。

            // 對字符串str在區(qū)間left和right之間進行逆序
            char *Reverse( char *s, int left, int right )
            {
            while( left < right )
            {
            char t = s[left] ;
            s[left
            ++] = s[right] ;
            s[right
            --] = t ;
            }

            return s ;
            }

            不允許臨時變量的原地逆序

            上面的原地逆序雖然沒有額外分配空間,但還是使用了臨時變量,嚴格的說也算是額外的空間吧,如果再嚴格一點,連臨時變量也不允許的話,主要有下面兩種方法。一是異或操作,因為異或操作可以交換兩個變量而無需借助第三個變量,二是使用字符串的結(jié)束符'\0'所在的位置作為交換空間,這樣有個局限,就是只適合以'\0'結(jié)尾的字符串,對于不支持這種字符串格式的語言,就不能使用了。

            使用字符串結(jié)束符'\0'所在的位置作為交換空間

            // 使用字符串結(jié)束符'\0'所在的位置作為交換空間
            char* Reverse(char* s)
            {
            char* r = s ;

            // 令p指向結(jié)束符
            char* p = s;
            while (*p != '\0')
            ++p ;

            // 令q指向字符串最后一個字符
            char* q = p - 1;

            // 使用p作為交換空間逐個交換字符
            while (q > s)
            {
            *p = *q ;
            *q-- = *s ;
            *s++ = *p ;
            }

            *p = '\0' ; // 恢復結(jié)束符

            return r ;
            }

            使用異或操作

            // 使用異或操作對字符串s進行逆序
            char* Reverse(char* s)
            {
            char* r = s ;

            //令p指向字符串最后一個字符
            char* p = s;
            while (*(p + 1) != '\0')
            ++p ;

            // 使用異或操作進行交換
            while (p > s)
            {
            *p = *p ^ *s ;
            *s = *p ^ *s ;
            *p = *p-- ^ *s++ ;
            }

            return r ;
            }

            按單詞逆序

            給定一個字符串,按單詞將該字符串逆序,比如給定"This is a sentence",則輸出是"sentence a is This",為了簡化問題,字符串中不包含標點符號。

            分兩步

            1 先按單詞逆序得到"sihT si a ecnetnes"

            2 再整個句子逆序得到"sentence a is This"

            對于步驟一,關(guān)鍵是如何確定單詞,這里以空格為單詞的分界。當找到一個單詞后,就可以使用上面講過的方法將這個單詞進行逆序,當所有的單詞都逆序以后,將整個句子看做一個整體(即一個大的包含空格的單詞)再逆序一次即可,如下圖所示,第一行是原始字符換,第二行是按單詞逆序后的字符串,最后一行是按整個句子逆序后的字符串。

            代碼

            // 對指針p和q之間的所有字符逆序
            void ReverseWord(char* p, char* q)
            {
            while(p < q)
            {
            char t = *p ;
            *p++ = *q ;
            *q-- = t ;
            }
            }

            // 將句子按單詞逆序
            char* ReverseSentence(char *s)
            {
            // 這兩個指針用來確定一個單詞的首尾邊界
            char *p = s ; // 指向單詞的首字符
            char *q = s ; // 指向空格或者 '\0'

            while(*q != '\0')
            {
            if (*q == ' ')
            {
            ReverseWord(p, q
            - 1) ;
            q
            ++ ; // 指向下一個單詞首字符
            p = q ;
            }
            else
            q
            ++ ;
            }

            ReverseWord(p, q
            - 1) ; // 對最后一個單詞逆序
            ReverseWord(s, q - 1) ; // 對整個句子逆序

            return s ;
            }

            逆序打印

            還有一類題目是要求逆序輸出,而不要求真正的逆序存儲。這題很簡單,有下面幾種方法,有的方法效率不高,這里僅是提供一個思路而已。

            先求出字符串長度,然后反向遍歷即可。

            void ReversePrint(const char* s)
            {
            int len = strlen(s) ;
            for (int i = len - 1; i >= 0; --i)
            cout
            << s[i];
            }

            如果不想求字符串的長度,可以先遍歷到末尾,然后在遍歷回來,這要借助字符串的結(jié)束符'\0'。

            void ReversePrint(const char* s)
            {
            const char* p = s ;

            while (*p)
            *p++ ;

            --p ; //while結(jié)束時,p指向'\0',這里讓p指向最后一個字符

            while (p >= s)
            {
            cout
            << *p ;
            --p ;
            }
            }

            對于上面第二種方法,也可以使用遞歸的方式完成。

            void ReversePrint(const char* s)
            {
            if(*(s + 1) != '\0')
            ReversePrint(s
            + 1) ;
            cout
            << *s ;
            }

            關(guān)于數(shù)組的面試題,請看這里

            == THE END==

            Happy coding!

            作者:zdd
            出處:http://www.cnblogs.com/graphics/
            本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權(quán)利.
            posted on 2012-02-21 16:26 life02 閱讀(594) 評論(0)  編輯 收藏 引用 所屬分類: 筆試
            久久亚洲中文字幕精品一区| 99蜜桃臀久久久欧美精品网站| 青青青国产精品国产精品久久久久| 久久精品国产欧美日韩99热| 亚洲国产另类久久久精品黑人 | 国内精品久久久久久久coent| 久久综合伊人77777麻豆| 久久亚洲精品无码VA大香大香| 伊人色综合久久天天人手人婷| 香蕉久久夜色精品国产小说| 无码八A片人妻少妇久久| 久久国产精品成人免费| 久久久久久国产精品美女| 国产精品久久久久…| 久久亚洲sm情趣捆绑调教| 7国产欧美日韩综合天堂中文久久久久 | 99久久综合狠狠综合久久止| 18禁黄久久久AAA片| 精品久久久久久国产免费了| 久久久久国产精品熟女影院| 色妞色综合久久夜夜| 久久毛片免费看一区二区三区| 久久久久人妻精品一区二区三区 | 狠狠狠色丁香婷婷综合久久俺| 伊人久久大香线蕉成人| 日本道色综合久久影院| 欧美熟妇另类久久久久久不卡| 久久久久亚洲av成人无码电影| 国产一级做a爰片久久毛片| 亚洲国产欧美国产综合久久| 久久亚洲AV无码精品色午夜| 亚洲精品tv久久久久| 久久国产美女免费观看精品 | 久久久精品人妻无码专区不卡| 99久久99久久| 午夜不卡888久久| 品成人欧美大片久久国产欧美...| 精品久久久久久| 99久久精品国产一区二区三区 | 久久久精品国产Sm最大网站| 久久精品亚洲乱码伦伦中文|