[英]How to count the number of distinct characters in common between two strings?
程序如何計算兩個字符串之間共有的不同字符數?
例如,如果s1="connect"
和s2="rectangle"
,則計數顯示為5,但正確答案為4; 重復字符只能計數一次。 如何修改此代碼,以便計數正確?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,j,count=0;
char s1[100],s2[100];
scanf("%s",s1);//string 1 is inputted
scanf("%s",s2);//string 2 is taken as input
for(i=1;i<strlen(s1);i++)
{
for(j=1;j<strlen(s2);j++)
{
if(s1[i]==s2[j])//compare each char of both the strings to find common letters
{
count++;//count the common letters
break;
}
}
}
printf("%d",count);//display the count
}
該程序將兩個字符串作為輸入,並顯示這些字符串中常見字符的計數。 請讓我知道這段代碼有什么問題。
如果必須忽略重復字符,則程序必須“記住”已經遇到的字符。 您可以通過將已處理的字符存儲到字符數組中,然后在處理其他字符時查詢該數組來做到這一點。
您可以使用計數器變量來跟蹤常見字符的數量,例如
int ctr=0;
char s1[100]="connect", s2[100]="rectangle", t[100]="";
此處, t
是將存儲檢查的字符的字符數組。 使它的大小與其他2個字符數組中最大字符的大小相同。
現在使用像
for(int i=0; s1[i]; ++i)
{
if(strchr(t, s1[i])==NULL && strchr(s2, s1[i])!=NULL)
{
t[ctr++]=s1[i];
t[ctr]=0;
}
}
t
最初有一個空字符串。 通過循環的主體將t
中以前不存在的字符添加到循環中,只有當被檢查的字符(即s1[i]
)不在t
但存在於另一個字符串(即s2
)中時,才會執行該循環)。
strchr()
是帶有原型的函數
char *strchr( const char *str, int c );
strchr()
在由str
指向的字符串中找到c的第一個匹配項。 如果str
不存在c
則返回NULL
。
您使用scanf()
可能會引起麻煩。
采用
scanf("%99s",s1);
(其中99比數組s1
的大小小s1
)而不是
scanf("%s",s1);
以防止溢出問題。 並檢查scanf()
的返回值,看看它是否為1
。 scanf()
返回成功進行分配的次數。
或使用fgets()
讀取字符串。
閱讀這篇文章以了解更多信息。
並注意數組索引從0
開始。 因此,在循環中,不會檢查字符串的第一個字符。
所以應該是這樣的
for(i=0;i<strlen(s1);i++)
代替
for(i=1;i<strlen(s1);i++)
這是一種避免二次O(N²)或三次O(N³)時間算法的解決方案-它是線性時間,需要對每個輸入字符串中的每個字符進行一次訪問。 該代碼使用一對常量字符串,而不要求用戶輸入。 另一種選擇是從命令行獲取兩個參數,然后進行比較。
#include <limits.h>
#include <stdio.h>
int main(void)
{
int count = 0;
char bytes[UCHAR_MAX + 1] = { 0 };
char s1[100] = "connect";
char s2[100] = "rectangle";
for (int i = 0; s1[i] != '\0'; i++)
bytes[(unsigned char)s1[i]] = 1;
for (int j = 0; s2[j] != '\0'; j++)
{
int k = (unsigned char)s2[j];
if (bytes[k] == 1)
{
bytes[k] = 0;
count++;
}
}
printf("%d\n",count);
return 0;
}
第一回路記錄哪些字符在本s1
通過的適當元素設置bytes
陣列1
。 字符串中是否有重復的字符並不重要。
第二個循環檢測s2
中的字符何時在s1
並且之前在s2
中s2
,然后通過將bytes
的條目設置回0
來遞增count
並將該字符標記為“不再相關”。
最后,它顯示計數4
(末尾有換行符)。
如果平台上的普通char
類型是帶符號類型,並且輸入字符串中的任何字節在0x80..0xFF范圍內(如果-128..-1
則等於-128..-1
(unsigned char)
則必須使用(unsigned char)
轉換char
類型已簽名)。 使用否定下標不會帶來幸福。 該代碼還假定您使用的是單字節代碼集,而不是多字節代碼集(例如UTF-8)。 如果您要處理多字節字符,則計數將關閉。
問題中的代碼至少是二次算法,因為對於s1
每個字符,它可以逐步遍歷s2
所有字符,只是發現它沒有發生。 僅此一項就需要O(N²)時間。 這兩個循環還使用基於strlen(s1)
或strlen(s2)
,並且如果優化器無法識別每次返回的值相同,則代碼可以在每個循環的每次迭代中掃描每個字符串。
類似地,我鍵入的其他兩個答案中的代碼( 答案1和答案2 )也由於它們的循環結構而二次冪或更差。
在每個字符串100個字符的范圍內,您可能不會輕易發現差異,尤其是在單次計數迭代中。 如果字符串更大(數千或數百萬個字節),並且重復執行計數,那么線性算法和二次(或更差)算法之間的差異將更大並且更容易檢測到。
我還使用Big-O標記略微加快了速度。 我假設N是字符串的大小,並且它們的大小足夠相似,以至於將N₁( s1
的長度)近似等於N 2( s2
的長度)不會是一個主要問題。 。 “二次”算法可以更正式地表示為O(N₁•N 2),而線性算法為O(N₁+ N 2)。
根據您期望的輸出,您應該跟蹤第二個字符串中使用的字符。 您可以按照以下步驟實現:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, j, count = 0, skeep;
char s1[100], s2[100], s2Used[100]{0};
scanf("%s", s1); //string 1 is inputted
scanf("%s", s2); //string 2 is taken as input
for (i = 0; i<strlen(s1); i++)
{
skeep = 0;
for (j = 0; j < i; j++)
{
if (s1[j] == s1[i])
{
skeep = 1;
break;
}
}
if (skeep)
continue;
for (j = 0; j<strlen(s2); j++)
{
if (s1[i] == s2[j] && s2Used[j] == 0) //compare each char of both the strings to find common letters
{
//printf("%c\n", s1[i]);
s2Used[j] = 1;
count++;//count the common letters
break;
}
}
}
printf("%d", count);//display the count
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.