【383.身代金の手紙】

リートコード

383. 身代金の手紙

難易度:简单
の 2 つの文字列を与え、その中の文字で構成できるかどうかをransomNotemagazineransomNotemagazine

はいの場合は戻り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 cmagazinecnt[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であり、 の各文字の出現回数をカウントすることで、の各文字が文字で構成されているかどうかを判断するのに便利です。magazineransomNotemagazine

文字列を走査する、 count 配列が次のように変更されるとmagazine仮定します。"aabbcdd"magazinecnt

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で意味します。

このコードの機能は、文字列ransomNotemagazine文字列内の文字で構成できるかどうかを判断することです。前回の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 の配列を作成するために使用されますが、それらの間にはいくつかの違いがあります。

  1. 固定サイズと可変サイズ:std::array固定サイズの配列で、そのサイズはコンパイル時に決定され、変更できません。むしろ、vectorこれは実行時にサイズを動的に調整できる動的配列です。
  2. スペース占有: サイズstd::arrayが、配列の作成時に固定サイズのメモリが割り当てられるため、vectorスペース占有の点でより効率的です。ただし、実行時に動的にメモリを割り当てるvector必要があるため、スペースが無駄になる可能性があります。
  3. 要素へのアクセス:どちらもstd::array添字を使用した要素へのアクセスをサポートしていますが、アクセス速度は の方が高速です。これは、 の要素が連続したメモリ空間に格納されるのに対し、の要素は分散して異なるメモリ ブロックに格納される可能性があるためです。vectorstd::arraystd::arrayvector

要約すると、固定サイズの配列を作成する必要がある場合は、std::arrayスペースの占有とアクセス速度の点でより効率的であるため、固定サイズの配列を使用することをお勧めします。配列のサイズを動的に調整する必要がある場合は、これを使用することをお勧めしますvector

おすすめ

転載: blog.csdn.net/u013454780/article/details/130537656