Given a string array words, return an array of all characters that show up in all strings within the words (including duplicates). You may return the answer in any order.
Example 1:
Input: words = ["bella","label","roller"]
Output: ["e","l","l"]
Example 2:
Input: words = ["cool","lock","cook"]
Output: ["c","o"]
Constraints:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] consists of lowercase English letters.
Thought:
class Solution {
public:
vector<string> commonChars(vector<string>& A) {
vector<string> result;
if (A.size() == 0) return result;
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
hash[A[0][i] - 'a']++;
}
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
for (int i = 1; i < A.size(); i++) {
memset(hashOtherStr, 0, 26 * sizeof(int));
for (int j = 0; j < A[i].size(); j++) {
hashOtherStr[A[i][j] - 'a']++;
}
// 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数
for (int k = 0; k < 26; k++) {
hash[k] = min(hash[k], hashOtherStr[k]);
}
}
// 将hash统计的字符次数,转成输出形式
for (int i = 0; i < 26; i++) {
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
string s(1, i + 'a'); // char -> string
result.push_back(s);
hash[i]--;
}
}
return result;
}
};
看了下官方题解
AC:
/*
* @lc app=leetcode.cn id=1002 lang=cpp
*
* [1002] 查找共用字符
*/
// @lc code=start
class Solution {
public:
vector<string> commonChars(vector<string>& words) {
vector<int> minfreq(26, INT_MAX);
vector<int> freq(26);
for(const string& word : words)
{
fill(freq.begin(), freq.end(), 0);
for(char ch : word)
{
freq[ch - 'a']++;
}
for(int i = 0; i < 26; i++)
{
minfreq[i] = min(minfreq[i], freq[i]);
}
}
vector<string> ans;
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < minfreq[i]; j++)
{
ans.emplace_back(1, i + 'a');
}
}
return ans;
}
};
// @lc code=end
std::fill
函数用于填充指定范围的元素,即用给定的值替换指定范围的所有元素。其语法如下:
template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );
其中,first
和 last
参数指定了要填充的元素范围,value
参数则是要赋给每个元素的值。
例如,以下代码将整个数组 arr
中的元素都置为 0:
int arr[10];
std::fill(std::begin(arr), std::end(arr), 0);
如果要填充的元素类型是类对象,则需要确保该类具有有效的赋值运算符。std::fill
函数用于填充指定范围的元素,即用给定的值替换指定范围的所有元素。其语法如下:
template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );
其中,first
和 last
参数指定了要填充的元素范围,value
参数则是要赋给每个元素的值。
例如,以下代码将整个数组 arr
中的元素都置为 0:
int arr[10];
std::fill(std::begin(arr), std::end(arr), 0);
如果要填充的元素类型是类对象,则需要确保该类具有有效的赋值运算符。
emplace_back是C++11引入的新特性之一,用于在容器的尾部添加新元素。与push_back相比,emplace_back可以直接在容器中构造新元素,而不是通过对象的拷贝或移动构造函数构造新元素,从而提高了性能。
使用emplace_back时,需要在括号中传递构造函数所需的参数,其语法与直接调用构造函数类似,如下所示:
std::vector vec;
// 使用push_back
vec.push_back(1);
// 使用emplace_back
vec.emplace_back(1);
如果需要添加自定义类型的元素,则需要在类中定义对应的构造函数和移动构造函数,以便emplace_back能够正确地构造新元素。例如:
class Person {
public:
Person(const std::string& name, int age) : name_(name), age_(age) { }
Person(std::string&& name, int age) : name_(std::move(name)), age_(age) { }
private:
std::string name_;
int age_;
};
std::vector persons;
// 使用push_back
persons.push_back(Person("Alice", 20));
// 使用emplace_back
persons.emplace_back("Alice", 20);
在上面的例子中,定义了两个构造函数,用于构造Person类型的元素。第一个构造函数接受了一个常量引用,第二个构造函数接受了一个右值引用。在使用emplace_back时,可以直接传递参数,使用移动构造函数构造新元素。emplace_back是C++11引入的新特性之一,用于在容器的尾部添加新元素。与push_back相比,emplace_back可以直接在容器中构造新元素,而不是通过对象的拷贝或移动构造函数构造新元素,从而提高了性能。
使用emplace_back时,需要在括号中传递构造函数所需的参数,其语法与直接调用构造函数类似,如下所示:
std::vector vec;
// 使用push_back
vec.push_back(1);
// 使用emplace_back
vec.emplace_back(1);
如果需要添加自定义类型的元素,则需要在类中定义对应的构造函数和移动构造函数,以便emplace_back能够正确地构造新元素。例如:
class Person {
public:
Person(const std::string& name, int age) : name_(name), age_(age) { }
Person(std::string&& name, int age) : name_(std::move(name)), age_(age) { }
private:
std::string name_;
int age_;
};
std::vector persons;
// 使用push_back
persons.push_back(Person("Alice", 20));
// 使用emplace_back
persons.emplace_back("Alice", 20);
在上面的例子中,定义了两个构造函数,用于构造Person类型的元素。第一个构造函数接受了一个常量引用,第二个构造函数接受了一个右值引用。在使用emplace_back时,可以直接传递参数,使用移动构造函数构造新元素。