我正在编码我们需要计算两个字符串中常见字符数的问题。计数的主要部分就像这样
for(i=0; i < strlen(s1); i++) {
for(j = 0; j < strlen(s2); j++) {
if(s1[i] == s2[j]) {
count++;
s2[j] = '*';
break;
}
}
}
这与O(n ^ 2)逻辑有关。但是,我想不出比这更好的解决方案。任何人都可以用O(n)逻辑帮助我编码。
答案 0 :(得分:9)
这很简单。取两个int
数组freq1
和freq2
。将其所有元素初始化为0
。然后读取您的字符串并将字符的频率存储到这些数组中。然后比较数组freq1
和freq2
以找到常见字符。
答案 1 :(得分:5)
可以在O(n)时间内以恒定的空间完成。
伪代码如下:
int map1[26], map2[26];
int common_chars = 0;
for c1 in string1:
map1[c1]++;
for c2 in string2:
map2[c2]++;
for i in 1 to 26:
common_chars += min(map1[i], map2[i]);
答案 2 :(得分:3)
由于O(n)strlen
s,您当前的代码为O(n ^ 3)并产生不正确的结果,例如“aa”,“aa”(您的代码将返回4)。
此代码在O(n)中计算共同的字母(每个字母最多计算一次)。
int common(const char *a, const char *b) {
int table[256] = {0};
int result = 0;
for (; *a; a++)table[*a]++;
for (; *b; b++)result += (table[*b]-- > 0);
return result;
}
根据您如何定义“共同字母”,您可能有不同的逻辑。这里是我正在使用的定义的一些测试用例(这是multiset交集的大小)。
int main(int argc, char *argv[]) {
struct { const char *a, *b; int want; } cases[] = {
{"a", "a", 1},
{"a", "b", 0},
{"a", "aa", 1},
{"aa", "a", 1},
{"ccc", "cccc", 3},
{"aaa", "aaa", 3},
{"abc", "cba", 3},
{"aasa", "asad", 3},
};
int fail = 0;
for (int i = 0; i < sizeof(cases) / sizeof(*cases); i++) {
int got = common(cases[i].a, cases[i].b);
if (got != cases[i].want) {
fail = 1;
printf("common(%s, %s) = %d, want %d\n",
cases[i].a, cases[i].b, got, cases[i].want);
}
}
return fail;
}
答案 3 :(得分:1)
你可以用2n:
来做int i,j, len1 = strlen(s1), len2 = strlen(s2);
unsigned char allChars[256] = { 0 };
int count = 0;
for( i=0; i<len1; i++ )
{
allChars[ (unsigned char) s1[i] ] = 1;
}
for( i=0; i<len2; i++ )
{
if( allChars[ (unsigned char) s1[i] ] == 1 )
{
allChars[ (unsigned char) s2[i] ] = 2;
}
}
for( i=0; i<256; i++ )
{
if( allChars[i] == 2 )
{
cout << allChars[i] << endl;
count++;
}
}
答案 4 :(得分:1)
以下代码仅遍历每个sting一次。所以复杂性是O(n)。其中一个假设是上下案例被认为是相同的。
#include<stdio.h>
int main() {
char a[] = "Hello world";
char b[] = "woowrd";
int x[26] = {0};
int i;
int index;
for (i = 0; a[i] != '\0'; i++) {
index = a[i] - 'a';
if (index > 26) {
//capital char
index = a[i] - 'A';
}
x[index]++;
}
for (i = 0; b[i] != '\0'; i++) {
index = b[i] - 'a';
if (index > 26) {
//capital char
index = b[i] - 'A';
}
if (x[index] > 0)
x[index] = -1;
}
printf("Common characters in '%s' and '%s' are ", a, b);
for (i = 0; i < 26; i++) {
if (x[i] < 0)
printf("%c", 'a'+i);
}
printf("\n");
}
答案 5 :(得分:1)
int count(string a, string b)
{
int i,c[26]={0},c1[26]={};
for(i=0;i<a.length();i++)
{
if(97<=a[i]&&a[i]<=123)
c[a[i]-97]++;
}
for(i=0;i<b.length();i++)
{
if(97<=b[i]&&b[i]<=123)
c1[b[i]-97]++;
}
int s=0;
for(i=0;i<26;i++)
{
s=s+abs(c[i]+c1[i]-(c[i]-c1[i]));
}
return (s);
}
这是更容易和更好的解决方案
答案 6 :(得分:0)
for (std::vector<char>::iterator i = s1.begin(); i != s1.end(); ++i)
{
if (std::find(s2.begin(), s2.end(), *i) != s2.end())
{
dest.push_back(*i);
}
}
取自here
答案 7 :(得分:0)
C实现在O(n)时间和常量空间中运行。
var update = require('react-addons-update');
this.setState(function(previousState, currentProps) {
var newState = update(previousState,{
order: {
brand: {
$set: 'some new value'
}
}
});
return newState;
});
}
答案 8 :(得分:0)
首先,你的代码不能在O(n ^ 2)中运行,它在O(nm)中运行,其中n和m是每个字符串的长度。
你可以在O(n + m)中完成,但不是更好,因为你必须经历每个字符串,至少一次,看看两个字符是否同时存在。
C ++中的一个例子,假设:
std::vector<char> strIntersect(std::string const&s1, std::string const&s2){
std::vector<bool> presents(256, false); //Assuming ASCII
std::vector<char> intersection;
for (auto c : s1) {
presents[c] = true;
}
for (auto c : s2) {
if (presents[c]){
intersection.push_back(c);
presents[c] = false;
}
}
return intersection;
}
int main() {
std::vector<char> result;
std::string s1 = "El perro de San Roque no tiene rabo, porque Ramon Rodriguez se lo ha cortado";
std::string s2 = "Saint Roque's dog has no tail, because Ramon Rodriguez chopped it off";
//Expected: "S a i n t R o q u e s d g h l , b c m r z p"
result = strIntersect(s1, s2);
for (auto c : result) {
std::cout << c << " ";
}
std::cout << std::endl;
return 0;
}
答案 9 :(得分:0)
它们是c ++中更好的版本: C ++位集及其应用 位集是布尔数组,但是每个布尔值都没有单独存储,而是通过位空间优化空间,使得每个布尔仅占用1位空间,因此位集bs占用的空间小于布尔bs [N]和向量bs( N)。但是,位集的限制是,在编译时必须知道N,即常量(矢量和动态数组没有此限制)
由于位集以压缩方式存储相同的信息,因此对位集的操作比对数组和向量的操作要快。我们可以借助数组索引运算符[]来单独访问位集的每个位,即bs [3]就像简单数组一样显示位集bs的索引3处的位。请记住,bitset开始向后索引,即10110,0位于第0和第3个索引,而1位于第1第2和第4索引。 我们可以通过构造函数使用整数和二进制字符串构造一个位集,如下面的代码所示。位集的大小在编译时是固定的,即无法在运行时更改。 有关位集的更多信息,请访问网站:https://www.geeksforgeeks.org/c-bitset-and-its-application
代码如下:
// considering the strings to be of lower case.
int main()
{
string s1,s2;
cin>>s1>>s2;
//Declaration for bitset type variables
bitset<26> b_s1,b_s2;
// setting the bits in b_s1 for the encountered characters of string s1
for(auto& i : s1)
{
if(!b_s1[i-'a'])
b_s1[i-'a'] = 1;
}
// setting the bits in b_s2 for the encountered characters of string s2
for(auto& i : s2)
{
if(!b_s2[i-'a'])
b_s2[i-'a'] = 1;
}
// counting the number of set bits by the "Logical AND" operation
// between b_s1 and b_s2
cout<<(b_s1&b_s2).count();
}
答案 10 :(得分:0)
无需初始化并保留26个元素的数组(字母中每个字母的数字)。只需执行以下操作:
这些步骤是在考虑Java编程语言的情况下编写的。
答案 11 :(得分:0)
Python代码:
>>>s1='abbc'
>>>s2='abde'
>>>p=list(set(s1).intersection(set(s2)))
>>print(p)
['a','b']
希望这对您有帮助,快乐编码!
答案 12 :(得分:-1)
可以使用“捕获”的概念轻松完成,这是一种散列的子算法。