算法-在字符串中刪除特定的字符或字符串


面試中經常會考到算法,下面分別講如何刪除一個字符串里的特定字符或特定字符串

一、

題目:輸入兩個字符串,從第一字符串中刪除第二個字符串中所有的字符。

例如, 輸入”i want to be a excellent programmers”和”aem”,則刪除之后的第一個字符串變成”i wnt to b  xcllnt progrrs"

分析:要編程完成這道題要求的功能可能並不難。畢竟,這道題的基本思路就是在第一 個字符串中拿到一個字符,在第二個字符串中查找一下,看它是不是在第二個字符串中。如果在的話,就從第一個字符串中刪除。但如何能夠把效率優化到讓人 滿意的程度,卻也不是一件容易的事情。也就是說,如何在第一個字符串中刪除 一個字符,以及如何在第二字符串中查找一個字符,都是需要一些小技巧的。

首先我們考慮如何在字符串中刪除一個字符。由於字符串的內存分配方式是連續 分配的。我們從字符串當中刪除一個字符,需要把后面所有的字符往前移動一個 字節的位置。但如果每次刪除都需要移動字符串后面的字符的話,對於一個長度 為 n 的字符串而言,刪除一個字符的時間復雜度為 O(n)。而對於本題而言,有可 能要刪除的字符的個數是 n,因此該方法就刪除而言的時間復雜度為 O(n2)。

事實上,我們並不需要在每次刪除一個字符的時候都去移動后面所有的字符。我 們可以設想,當一個字符需要被刪除的時候,我們把它所占的位置讓它后面的字 符來填補,也就相當於這個字符被刪除了。在具體實現中,我們可以定義兩個指 針(psou和 pkey),初始的時候都指向第一字符的起始位置。當 psou 指向的字符是需要刪除的字符,則 psou 直接跳過,指向下一個字符。如果 psou 指向的字符是不需要刪除的字符,那么把 psou 指向的字符賦值給 pkey 指向的字符, 並且 psou 和 pkey同時向后移動指向下一個字符。這樣,前面被psou 跳過的字符相當於被刪除了。用這種方法,整個刪除在 O(n)時間內就可以完成。

接下來我們考慮如何在一個字符串中查找一個字符。當然,最簡單的辦法就是從 頭到尾掃描整個字符串。顯然,這種方法需要一個循環,對於一個長度為 n 的字 符串,時間復雜度是 O(n)。 由於字符的總數是有限的。對於八位的 char 型字符而言,總共只有 28=256 個字 符。我們可以新建一個大小為 256 的數組,把所有元素都初始化為 0。然后對於 字符串中每一個字符,把它的 ASCII 碼映射成索引,把數組中該索引對應的元素 設為1。這個時候,要查找一個字符就變得很快了:根據這個字符的 ASCII 碼, 在數組中對應的下標找到該元素,如果為 0,表示字符串中沒有該字符,否則字符串中包含該字符。此時,查找一個字符的時間復雜度是 O(1)。其實,這個數組 就是一個 hash 表。

基於上述分析,我們可以寫出如下代碼:

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 char *  deleteStr(char *source, char *key)  6 {  7 
 8     int hashTable[256];  9     memset(hashTable, 0, sizeof(hashTable)); 10     char *point_sou, *point_key; 11     point_sou = key; 12     while (*point_sou != '\0')//待刪除字符在哈希表里賦值為1
13  { 14         hashTable[*point_sou] = 1; 15         point_sou++; 16  } 17     point_sou = source; 18     point_key = source; 19     while (*point_sou != '\0') 20  { 21         if (!hashTable[*point_sou])//哈希表不為1時不是待刪除字符,將sou指針指向的字符賦給key指針指向的字符,將兩指針同時向后移
22  { 23             *point_key = *point_sou; 24             point_key++; 25  } 26         point_sou++;  //是待刪除字符,sou指針繼續向前移,key指針停留在待刪除字符前 27     //下一次循環判斷是不是待刪除字符,不是,將sou指針指向的字符賦給key指針指向的字符,souce也就相當於刪除了前面的字符
28 
29  } 30     *point_key = '\0'; 31     return source; 32 
33 } 34 
35 int main() 36 { 37     char p[] = "i want to be a excellent programmers"; 38     char key[] = "aem"; 39     printf("%s\n", deleteStr(p, key)); 40 }

 

二、

問題描述: 在給定字符串中查找所有特定子串並刪除,如果沒有找到相應子串,則不作任何操作。

要求實現函數:int delete_sub_str(const char *str, const char *sub_str, char *result_str)

【輸入】str:輸入的被操作字符串  sub_str:需要查找並刪除的特定子字符串

【輸出】result_str:在str字符串中刪除所有sub_str子字符串后的結果

【返回】刪除的子字符串的個數

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 
 6 int Mysubstring(char* str_in, char* str_sub, char* str_out)  7 {  8     int start = 0;    /* 記錄開始比較下標 */
 9     int count = 0;    /* 記錄子串個數 */
10     int j = 0;        /* 記錄子串的下標 */
11     int k = 0;        /* 記錄結果字符串的下標 */
12 
13     for (int i = 0; str_in[i] != '\0'; i++) 14  { 15         start = i;      /* 臨時保存比較下標 */
16         j = 0;          /* 每次開始比較的時候,子串都從0開始,如果第一個字符相等, 17  那么就接着比較下一個字符,否則進入下一輪循環 */
18 
19         while ((str_in[i] != '\0') && (str_sub[j] != '\0') && (str_in[i] == str_sub[j])) 20  { 21             i++; 22             j++; 23  } 24 
25         if (str_sub[j] != '\0')                /* 如果不是子串 */
26  { 27             str_out[k++] = str_in[start];   i = start;   /* 將當前比較的這個字符存入結果 */
28  } 29         else                         /* 如果是子串 */
30  { 31             count++; 32             i--;           /* 因為返回for循環之后,進行下一次循環的時候還要進行i++的運算的 */
33  } 34  } 35 
36     return count; 37 } 38 
39 
40 int main() 41 { 42     char* str_in = "i want to be a excellent programmers "; 43     char* str_sub = "want"; 44     char str_out[100] = { 0 }; 45 
46     int   count = Mysubstring(str_in, str_sub, str_out); 47 
48     printf("子串:%s\n", str_sub); 49     printf("個數:%d\n", count); 50     printf("原串:%s\n", str_in); 51     printf("結果:%s\n", str_out); 52 
53     return 0; 54 
55 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM