リートコード
383. 身代金の手紙
難易度:と简单
の 2 つの文字列を与え、その中の文字で構成できるかどうかを。ransomNote
magazine
ransomNote
magazine
はいの場合は戻りtrue
、そうでない場合は戻りますfalse
。
magazine
の各文字はransomNote
で。
例 1:
入力: ransomNote = "a"、magazine = "b"
出力: false
例 2:
入力: ransomNote = "aa"、magazine = "ab"
出力: false
例 3:
入力: ransomNote = "aa"、magazine = "aab"
出力: true
ヒント:
1 <= ransomNote.length、magazine.length <= 105
ransomNote 和マガジン由小写英文字母组成
出典: LeetCode
リンク: https://leetcode.cn/problems/ransom-note
方法 1: 文字の統計
このトピックでは、 magazine
新しい string を構築するために文字列内の文字を使用する必要があります ransomNote
。文字列内の各英語文字の統計が同じ文字の統計以上である限りransomNote
、各文字は 1 回だけ使用できます。カンで。magazine
(’a’-’z’)
ransomNote
文字列magazine
の、マガジンは ransomNote を形成できず、この時点で直接戻ることができないと確信できます false
。
まずmagazine
、の各英文字 a
の回数を数えます cnt[a]
。次に、統計の数が統計の数よりも特定の英文字があること ransomNote
が判明した場合、 の各英文字の回数をたどって数えます。の文字の統計がある場合は、この時点で直接戻ります。
ransomNote
c
magazine
cnt[c]
false
著者: LeetCode-Solution
リンク: https://leetcode.cn/problems/ransom-note/solution/shu-jin-xin-by-leetcode-solution-ji8a/
出典: LeetCode
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
// 如果ransomNote的长度大于magazine的长度,显然无法构造
if (ransomNote.size() > magazine.size()) {
return false;
}
// 定义一个大小为26的计数数组cnt,记录magazine中每个字符出现的次数
vector<int> cnt(26);
for (auto & c : magazine) {
cnt[c - 'a']++;
}
// 遍历ransomNote中的每个字符,如果cnt中对应字符的计数器小于0,则无法构造
for (auto & c : ransomNote) {
cnt[c - 'a']--;
if (cnt[c - 'a'] < 0) {
return false;
}
}
// 如果ransomNote中的每个字符在magazine中都能找到,则可以构造
return true;
}
};
説明
vector<int> cnt(26);
for (auto & c : magazine) {
cnt[c - 'a']++;
}
このコードは、文字列を走査しmagazine
、各文字の出現数をカウントするために使用されます。
ループ ステートメントとカウントの配列を使用してcnt
、文字列magazine
内のc
。各文字 についてc
、 の操作c - 'a'
によって、cnt
カウント配列内の添え字に対応する要素の値に 1 を加算して、文字が 1 回c
出現する。
このうち、 は'a'
ASCIIコード表におけるアルファベットの小文字の最初の文字を表しc
、'a'
その文字を引いた結果がアルファベットでの位置となるため、カウンティング配列の添え字として使用できます。
このコードの目的は、後の文字列が の文字で構成できるransomNote
かどうかを準備magazine
であり、 の各文字の出現回数をカウントすることで、の各文字が文字で構成されているかどうかを判断するのに便利です。magazine
ransomNote
magazine
文字列を走査する、 count 配列が次のように変更されるとmagazine
仮定します。"aabbcdd"
magazine
cnt
cnt[0] = 2 // 'a' 出现了两次
cnt[1] = 2 // 'b' 出现了两次
cnt[2] = 0 // 'c' 没有出现
cnt[3] = 2 // 'd' 出现了两次
cnt[4] = 0 // 'e' 没有出现
...
このうち、配列の添字は 0 から始まるのでcnt[0]
、'a'
アルファベットの小文字の最初の文字の出現数、cnt[1]
アルファベットの小文字の 2 番目の文字の'b'
出現などを表します。
cnt[c - 'a']++;
現在スキャンされている文字c
が'b'
小文字であると仮定すると、配列の添字に変換できますc - 'a'
。つまり'b' - 'a' = 1
、ステートメントの実行はcnt[c - 'a']++
、cnt[1]++
カウント配列cnt
内要素の値に 1 を加算することと同じです。
文字列magazine
を、複数の文字がある場合'b'
、cnt[c - 'a']++
この、count 配列内の添え字が 1 である要素の値が毎回 1 ずつ増加します。最終的に、配列cnt
内の'b'
文字列magazine
内の文字の出現数と等しくなります。
// 遍历ransomNote中的每个字符,如果cnt中对应字符的计数器小于0,则无法构造
for (auto & c : ransomNote) {
cnt[c - 'a']--;
if (cnt[c - 'a'] < 0) {
return false;
}
}
このコードは、文字列ransomNote
内の、magazine
文字列内の文字で構成できるかどうかを判断するために使用されます。
まず、ループ ステートメントを使用して stringransomNote
内のc
、count 配列cnt
内の1 減算され、文字が使用されていることを示します。ここでは、c - 'a'
の、文字を対応する添え字に変換し、cnt
カウント配列内の対応する添え字の要素値から 1 を減算します。
次に、カウント配列cnt
内の、0 より小さい場合は、magazine
文字列を構成するのに十分な文字が存在しないことを意味しransomNote
、直接 false を返します。
最後に、 の各文字を走査してransomNote
も、ransomNote
の文字magazine
で意味します。
このコードの機能は、文字列ransomNote
がmagazine
文字列内の文字で構成できるかどうかを判断することです。前回のmagazine
走査、count 配列は内のcnt
各文字の出現回数をカウントします。magazine
次に、 の各文字ransomNote
をカウント配列内の対応する文字のカウンタを 1 ずつ減分します。ransomNote
走査の過程で特定の文字が十分なmagazine
回数、つまり、カウンタが 0 未満であることが判明した場合、これは、magazine
内の文字で構成できないことを意味しransomNote
、直接 false を返します。
二
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
// 定义一个大小为26的数组hash,用来记录magazine中每个字符出现的次数
std::array<int, 26> hash = {
0};
// 使用 C++ 11 的范围 for 循环可以使代码更加简洁明了
for (auto c : magazine) {
// 遍历magazine中的每个字符,将对应字符的计数器加1
hash[c - 'a']++;
}
for (auto c : ransomNote) {
// 遍历ransomNote中的每个字符,将对应字符的计数器减1
hash[c - 'a']--;
// 如果hash中对应字符的计数器小于0,则无法构造
if (hash[c - 'a'] < 0) {
return false;
}
}
// 如果ransomNote中的每个字符在magazine中都能找到,则可以构造
return true;
}
};
std::array<int, 26> hash
と はvector<int> cnt(26)
どちらもサイズ 26 の配列を作成するために使用されますが、それらの間にはいくつかの違いがあります。
- 固定サイズと可変サイズ:
std::array
固定サイズの配列で、そのサイズはコンパイル時に決定され、変更できません。むしろ、vector
これは実行時にサイズを動的に調整できる動的配列です。 - スペース占有: サイズ
std::array
が、配列の作成時に固定サイズのメモリが割り当てられるため、vector
スペース占有の点でより効率的です。ただし、実行時に動的にメモリを割り当てるvector
必要があるため、スペースが無駄になる可能性があります。 - 要素へのアクセス:どちらも
std::array
添字を使用した要素へのアクセスをサポートしていますが、アクセス速度は の方が高速です。これは、 の要素が連続したメモリ空間に格納されるのに対し、の要素は分散して異なるメモリ ブロックに格納される可能性があるためです。vector
std::array
std::array
vector
要約すると、固定サイズの配列を作成する必要がある場合は、std::array
スペースの占有とアクセス速度の点でより効率的であるため、固定サイズの配列を使用することをお勧めします。配列のサイズを動的に調整する必要がある場合は、これを使用することをお勧めしますvector
。