亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++變位詞問題分析

2020-01-26 15:24:38
字體:
來源:轉載
供稿:網友

在《編程珠璣》一書的第二章提到了一個變位詞問題,變位詞指的是一個單詞可以通過改變其他單詞中字母的順序來得到,也叫做兄弟單詞,如army->mary。由變位詞可以引申出幾個算法問題,包括字符串包含問題,比較兩個字符串是否是變位詞,以及找出字典中變位詞集合的問題。

一、字符串包含問題

(1) 問題描述:存在字符串1和字符串2,假設字符串2相對較短,如何快速地判定字符串2中的字符都存在于字符串1里(假定字符串只包含字母)?

(2) 舉例:字符串1為ABCDEFGHIJK,字符串2為ABCDE,則字符串1包含字符串2,因為字符串2中包含的字母在字符串1中也都有。

(3) 解決方案:

思路一

最直接的思路就是針對字符串2中的每個字符,輪詢字符串1進行比較,看是否在字符串1里面。很明顯這種的時間效率為O(n*m)。

/*************************************************************************   > File Name: test.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<string> using namespace std;  void Compare(string long_str, string short_str) {   int i,j;   for(i=0; i<short_str.size(); ++i)   {     for(j=0; j<long_str.size(); ++j)     {       if(long_str[j] == short_str[i])       {         break;       }     }     if(j == long_str.size())     {       cout << "false" << endl;       return;     }   }   cout << "true" << endl;   return; }  int main() {   string l = "ABCDEFGHIJK";   string s = "ABCDEF";   Compare(l, s);   return 0; }

思路二

這里由于假定了字符串只包含字母,所以我們可以用一個額外的數組flag[26]作為26個字符標識位,先遍歷長字符串將對應的標識位置1,再遍歷短字符串,如果對應的標示位都是1,則包含;否則不包含。這種方法的時間復雜度為O(n+m),為了提高空間效率,這里不使用數組而使用26個bit位來作為標示位(bitset容器)。

/*************************************************************************   > File Name: test1.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<bitset> #include<string> using namespace std;  bool Compare(string long_str, string short_str) {   bitset<26> flag;   for(int i=0; i<long_str.size(); ++i)   {     // flag.set(n)置第n位為1     flag.set(long_str[i]-'A');   }   for(int i=0; i<short_str.size(); ++i)   {     // flag.test(n)判斷第n位是否為1     if(!flag.test(short_str[i]-'A'))       return false;   }   return true; }  int main() {   string l = "ABCDEFGHIJK";   string s = "ABCDEZ";   if(Compare(l, s))     cout << "true" << endl;   else     cout << "false" << endl;   return 0; }

這種方法還可以進行優化,例如如果長字串的前綴就為短字串,那么我們可以不需要n+m次,而只需要2m次。具體實現請自己思考。

思路三

給每個字母分配一個素數,從2開始到3,5,7...遍歷長字串,求得每個字符對應素數的乘積。然后遍歷短字串,判斷該乘積能否被短字符串中的字符對應的素數整除,如果除的結果存在余數,則說明有不匹配的字母;如果整個過程都沒有余數,則說明短字串中的字母在長字串里都有。這種方法的時間復雜度也是O(n+m),需要26個額外空間存素數,但是這種方法有一個缺點就是需要跟大整數打交道,因為乘積可能非常大。(這里我們使用<cstdint>頭文件中定義的int64_t和uint64_t)

/*************************************************************************   > File Name: test2.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<string> #include<stdint.h> //#include<cstdint> // C++11 using namespace std;  bool Compare(string long_str, string short_str) {   unsigned int primeNum[26] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,             53,59,61,67,71,73,79,83,89,97,101};   /* int64_t和uint64_t分別表示64位的有符號和無符號整形數 */   /* 在不同位數機器的平臺下通用,都是64位 */   uint64_t ch = 1;      for(int i=0; i<long_str.size(); ++i)   {     ch = ch*primeNum[long_str[i]-'A'];   }    for(int i=0; i<short_str.size(); ++i)   {     if(ch%primeNum[short_str[i]-'A'] != 0)       return false;   }   return true; }  int main() {   string l = "ABCDEFGHIJK";   string s = "ABCDEK";   if(Compare(l, s))     cout << "true" << endl;   else     cout << "false" << endl;   return 0; } 

二、比較兩個字符串是否為變位詞

(1) 問題描述:如果兩個字符串的字符一樣,但是順序不一樣,被認為是兄弟字符串,問如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。

(2) 注意:第一點中討論了字符串包含問題,但是不要以為兩個字符串互相包含就是(變位詞)兄弟字符串了,例如aabcde和edcba互相包含,但它們不是變位詞。

(3) 解決方案:

思路一

給每個字母分配一個素數,可以通過判斷兩個字符串的素數乘積是否相等。跟上述素數法一樣,時間復雜度也是O(n+m),需要跟大整數打交道。

/*************************************************************************   > File Name: test3.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<string> #include<stdint.h> //#include<cstdint> // C++11 using namespace std;  bool Compare(string s1, string s2) {   unsigned int primeNum[26] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,             53,59,61,67,71,73,79,83,89,97,101};   uint64_t ch = 1;    for(int i=0; i<s1.size(); ++i)   {     ch = ch*primeNum[s1[i]-'a'];   }    for(int i=0; i<s2.size(); ++i)   {     ch = ch/primeNum[s2[i]-'a'];   }      if(ch == 1)     return true;   else     return false; }  int main() {   string s1 = "abandon";   string s2 = "banadon";   if(Compare(s1, s2))     cout << "They are brother words!" << endl;   else     cout << "They aren't brother words!" << endl;   return 0; } 

思路二

將兩個字符串按照字母表順序排序,看排序后的字符串是否相等,如果相等則是兄弟字符串(變位詞)。這種方法的時間效率根據你使用的排序算法不同而不同。當然,你可以自己寫排序算法,這里我們使用C++的STL中的sort()函數對字符串進行排序。

/*************************************************************************   > File Name: test4.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<algorithm> #include<string> using namespace std;  // 自定義序函數(二元謂詞) bool myfunction(char i, char j) {   return i > j; }  bool Compare(string s1, string s2) {   // 采用泛型算法對s1,s2排序,sort()采用的是快速排序算法   sort(s1.begin(), s1.end(), myfunction);   sort(s2.begin(), s2.end(), myfunction);   if(!s1.compare(s2)) // 相等返回0     return true;   else     return false; }  int main() {   string s1 = "abandon";   string s2 = "banadon";   if(Compare(s1, s2))     cout << "They are brother words!" << endl;   else     cout << "They aren't brother words!" << endl;   return 0; } 

三、字典找出所有變位詞集合(重點)

(1) 問題描述:給定一個英語字典,找出其中的所有變位詞集合。

(2) 解決方案:

思路一

對于這個問題,最快想到的最直接的方法就是針對每一個單詞跟字典中的其他單詞進行比較。然而,假設一次比較至少花費1微秒的時間,則擁有二十萬單詞的字典將花費:200000單詞 x 200000比較/單詞 x 1微秒/比較 = 40000x10^6秒 = 40000秒 ≈ 11.1小時。比較的次數太多了,導致效率低下,我們需要找出效率更高的方法。

思路二

標識字典中的每一個單詞,使得在相同變位詞類中的單詞具有相同的的標識,然后集中具有相同標識的單詞。將每個單詞按照字母表排序,排序后得到的字符串作為該單詞的標識。那么對于該問題的解題過程可以分為三步:第一步,讀入字典文件,對單詞進行排序得到標識;第二步,將所有的單詞按照其標識的順序排序;第三步,將同一個變位詞類中的各個單詞放到同一行中。

這里出現了標識-單詞(key-value)對,我們很容易想到C++中的關聯容器map,使用map的好處就是:

動態管理內存,容器大小動態改變;
單詞與它的標識一一對應,對于相同標識(key)的單詞直接加在值(value)后面;
無需根據標識排序,因為map會自動按關鍵字有序(默認升序)。
所以,在將每個單詞及其標識存入map以后,就可以直接遍歷輸出了,每一個map元素就是一個變位詞集合。

C++實現代碼如下:

/*************************************************************************   > File Name: test5.cpp   > Author: SongLee  ************************************************************************/ #include<iostream> #include<fstream>  // file I/O #include<map>    // map #include<string>   // string #include<algorithm> // sort using namespace std; /*  *map是C++中的關聯容器  *   按關鍵字有序  *   關鍵字不可重復  */ map<string, string> word;  /* 自定義比較函數(用于排序) */ bool myfunction(char i, char j) {   return i < j; }  /*  *對每個單詞排序  *排序后字符串作為關鍵字,原單詞作為值  *存入map中  */ void sign_sort(const char* dic) {   // 文件流   ifstream in(dic);   if(!in)   {     cout << "Couldn't open file: " + string(dic) << endl;     return;   }    string aword;   string asign;   while(in >> aword)   {     asign = aword;     sort(asign.begin(), asign.end(), myfunction);     // 若標識不存在,創建一個新map元素,若存在,加在值后面     word[asign] += aword + " ";   }   in.close(); }  /*  *寫入輸出文件  */ void write_file(const char* file) {   ofstream out(file);   if(!out)   {     cout << "Couldn't create file: " + string(file) << endl;     return;   }      map<string, string>::iterator begin = word.begin();   map<string, string>::iterator end = word.end();   while(begin != end)   {     out << begin->second << "/n";     ++begin;   }   out.close(); }  int main() {   string dic;    string outfile;    cout << "Please input dictionary name: ";   cin >> dic;   cout << "Please input output filename: ";   cin >> outfile;    sign_sort(dic.c_str());   write_file(outfile.c_str());    return 0; } 

附:(2012.5.6百度實習筆試題)一個單詞交換字母位置,可得另一個單詞,如army->mary,成為兄弟單詞。提供一個單詞,在字典中找到它的兄弟。描述數據結構和查詢過程。

解題思路:如果不允許進行預處理,那么我們只能順序遍歷整個字典,計算每個單詞的標識與給定單詞的標識比較。如果允許進行預處理,我們可以如上述思路二將所有單詞加入一個map,然后輸出關鍵字(給定單詞的標識)對應的值,值中就包含了該單詞的所有兄弟單詞。

相信本文所述實例有助于讀者更好的掌握C++下數據結構與算法的實現技巧。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本久久精品视频| 国产精品va在线| 中文字幕日韩电影| 亚洲视频专区在线| 97视频色精品| 亚洲天堂2020| 米奇精品一区二区三区在线观看| 日韩在线观看成人| 成人免费视频网| 亚洲精品动漫100p| 欧美日韩国产中文字幕| 亚洲精品国偷自产在线99热| 国产精品欧美在线| 亚洲毛片在线观看.| 亚洲欧美另类人妖| 中文字幕少妇一区二区三区| 亚洲国产精彩中文乱码av在线播放| 国产精品三级久久久久久电影| 国产精品免费视频久久久| 96pao国产成视频永久免费| 久久精品国产2020观看福利| 亚洲一区二区免费| 日产精品久久久一区二区福利| 国产精品专区h在线观看| 亚洲国内精品在线| 国产va免费精品高清在线| 久久久久久国产精品| 国产精品美女网站| 日韩免费高清在线观看| 亚洲欧洲美洲在线综合| 亚洲国产私拍精品国模在线观看| 免费91在线视频| 中文字幕精品—区二区| 精品性高朝久久久久久久| 高清在线视频日韩欧美| 国产精品偷伦视频免费观看国产| 国产精品极品美女在线观看免费| 色先锋资源久久综合5566| 日韩av在线播放资源| 黄网动漫久久久| 欧美日韩成人免费| 国产精选久久久久久| 国产精品无av码在线观看| 日韩大片在线观看视频| 国产精品第一区| 日韩黄色高清视频| 97在线看免费观看视频在线观看| 国产精品嫩草影院一区二区| 亚洲男人天堂手机在线| 国产亚洲人成a一在线v站| 色香阁99久久精品久久久| 亚洲欧美日韩精品久久奇米色影视| 久久久久久高潮国产精品视| 国语自产精品视频在线看抢先版图片| 97不卡在线视频| 操人视频在线观看欧美| 久久久精品久久久| 97激碰免费视频| 69影院欧美专区视频| 国产精品视频内| 欧美亚洲国产日本| 国产精品亚洲自拍| 亚洲国产精品人人爽夜夜爽| 国产69精品久久久久久| 伊人久久免费视频| 亚洲欧美日韩国产中文| 国产成人精品一区| 国产午夜精品美女视频明星a级| 亚洲在线视频观看| 日本三级韩国三级久久| 亚洲最大的免费| 欧美国产精品人人做人人爱| 久久久91精品| 亚洲а∨天堂久久精品喷水| 国产人妖伪娘一区91| 国产一区私人高清影院| 不卡中文字幕av| 国产97在线视频| 北条麻妃99精品青青久久| 中文字幕精品网| 久久精品国产久精国产一老狼| 久久6精品影院| 欧美一级大胆视频| 亚洲精品一区久久久久久| 久久久久久亚洲精品不卡| 日本a级片电影一区二区| www.欧美精品| 亚洲中国色老太| 欧美激情综合亚洲一二区| 九九九久久久久久| 97国产suv精品一区二区62| 69久久夜色精品国产7777| 欧美亚洲第一区| 亚洲视频第一页| 欧美一级大片在线观看| 日韩在线不卡视频| 欧美日韩一区二区免费视频| 精品日本高清在线播放| 国产成人亚洲精品| 欧美激情xxxx| 91精品视频播放| 国产精品欧美激情在线播放| 欧美电影免费观看大全| 国产精品电影网| 久久中文字幕在线视频| 欧美性猛交xxxx免费看漫画| 国产成人亚洲综合91精品| 欧美激情va永久在线播放| 92看片淫黄大片欧美看国产片| 最近的2019中文字幕免费一页| 在线日韩第一页| 国模精品系列视频| 日本精品在线视频| 色999日韩欧美国产| 成人欧美一区二区三区黑人| 亚洲91av视频| 国产91九色视频| 国产精品久久久久久久久免费| 国产日韩欧美在线观看| 欧美专区在线视频| 久久久久久久影视| 亚洲精品国产精品乱码不99按摩| 97欧美精品一区二区三区| 久久av在线看| 国产精品久久久久久久久久| 久久综合国产精品台湾中文娱乐网| 亚洲激情在线观看| 国产精品第一区| 国产成人av网址| 亚洲精品视频中文字幕| 久久福利网址导航| 久久久成人精品| 日本19禁啪啪免费观看www| 亚洲国语精品自产拍在线观看| 亚洲乱亚洲乱妇无码| 国产精品av网站| 亚洲国产高潮在线观看| 亚洲一二在线观看| 亚洲sss综合天堂久久| 国产一区玩具在线观看| 国产精品久久久久免费a∨大胸| 深夜福利国产精品| 一区二区欧美激情| 91久久嫩草影院一区二区| 午夜精品理论片| 久久精品成人欧美大片| 欧美电影在线观看完整版| 亚洲欧美日韩精品| xvideos亚洲人网站| 国产精品久久久久久五月尺| 一区二区三区无码高清视频| 色综合久久久久久中文网| 日韩美女免费视频| 国产精品日韩在线观看| 日韩av电影在线播放| 国产精品激情av电影在线观看| 久久国产精品首页| 欧美激情第1页| 色综合色综合久久综合频道88| 成年无码av片在线| 国产精品一区专区欧美日韩| 国产精品视频午夜| 久久久亚洲福利精品午夜| 97在线精品视频|