Try an interactive version of this dialog: Sign up at solve.it.com, click Upload, and pass this URL.

Code: 61 ()

import sys
sys.path.append('.')
from leet_utils import lc_setup, get_leetcode_problem, lc_export
lc_setup("https://leetcode.com/problems/valid-anagram/", add_cells=False)

Output: 34

✓ Problem loaded: 242. Valid Anagram

Note: 10

242. Valid Anagram

Note: 25

  • URL: https://leetcode.com/problems/valid-anagram/
  • Difficulty: Easy

Code: 43 ()

from IPython.display import HTML
problem = get_leetcode_problem("https://leetcode.com/problems/valid-anagram/")
HTML(problem["content"])

Output: 534

Given two strings s and t, return true if t is an anagram of s, and false otherwise.

 

Example 1:

Input: s = "anagram", t = "nagaram"

Output: true

Example 2:

Input: s = "rat", t = "car"

Output: false

 

Constraints:

  • 1 <= s.length, t.length <= 5 * 104
  • s and t consist of lowercase English letters.

 

Follow up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case?

Note: 6

Step 1

Note: 139

実装1

  • アルゴリズムの選択
    • 文字種ごとの登場回数をs, tに対し数え、同じ分布か調べる。
  • 実装
    • lowercase English lettersなので、長さ26の配列でカウントする。
  • 計算量
    • Time: O(n)
    • Extra Space: O(1)

Code: 171 ()

import string


class Solution:
    NUM_CHARS = len(string.ascii_lowercase)
    BASE_ORD = ord("a")

    def count_lowers(self, s: str) -> list[int]:
        counter = [0] * self.NUM_CHARS
        for ch in s:
            counter[ord(ch) - self.BASE_ORD] += 1
        return counter

    def isAnagram(self, s: str, t: str) -> bool:
        return self.count_lowers(s) == self.count_lowers(t)
        

Note: 163

実装2

  • Follow up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case?

    • こうなったら辞書を使う方が可読性・保守性で好ましい。
    • せっかくなのでdefaultdictやCounterは使わずに実装する。
  • 計算量
    • 文字の種類数をmとして、
    • Time: O(n)
    • Extra Space: O(m)

Code: 130 ()

class Solution:
    def count_chars(self, s: str) -> dict[str, int]:
        counter = {}
        for ch in s:
            if ch not in counter:
                counter[ch] = 0
            counter[ch] += 1
        return counter

    def isAnagram(self, s: str, t: str) -> bool:
        return self.count_chars(s) == self.count_chars(t)

Note: 145

実装3

  • early returnを導入できないか考え、作ってみた。
  • 文字数・文字種が多く、anagramが来ることがレアな状況では輝きそう。
  • 通常の用途ではこの可読性の悪化は割に合わないが、他言語で低レイヤーで実装するならこのくらいしても良いだろう。

Code: 199 ()

class Solution:
    def count_chars(self, s: str) -> dict[str, int]:
        counter = {}
        for ch in s:
            if ch not in counter:
                counter[ch] = 0
            counter[ch] += 1
        return counter

    def isAnagram(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False
        
        remaining_counts = self.count_chars(s)
        for ch in t:
            if remaining_counts.get(ch, 0) == 0:
                return False
            remaining_counts[ch] -= 1
        return True 

Note: 39

  • 振り返り
    • まぁひとまず想像力の範囲ではこんな感じ。

Note: 6

Step 2

Prompt: 24

Step 1のコードをレビューして、改善点を教えてください。

Assistant: 610

🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠

3つの実装、どれもよく考えられていますね!いくつかコメントします。

実装1について

良い点:

  • 固定長配列を使うのは、この制約下では最適解
  • クラス変数で定数を定義しているのは良い習慣

改善案:

  • len(s) != len(t) の早期リターンを入れると、長さが違う場合にカウント処理をスキップできる
Copied!
def isAnagram(self, s: str, t: str) -> bool:
    if len(s) != len(t):
        return False
    return self.count_lowers(s) == self.count_lowers(t)

実装2について

良い点:

  • Unicode対応への拡張として適切な選択
  • Counterを使わず自前実装する練習、良いと思います

細かい点:

  • counter[ch] = counter.get(ch, 0) + 1 と1行で書くスタイルもある(好みの問題)

実装3について

良い点:

  • early returnの発想は実践的
  • 実際に「ほとんど不一致」なケースでは効果的

気になる点:

  • remaining_counts[ch] -= 1 で値が0になっても辞書に残る。問題はないが、メモリ的にはdelする選択肢もある(ただし可読性との兼ね合い)

全体として、問題の制約をよく理解した上で複数のアプローチを試しているのが素晴らしいです。何か特定の実装について深掘りしたい点はありますか?

Note: 298

  • LLMレビューの感想
    • counter[ch] = counter.get(ch, 0) + 1 も悪くないが、こう書くくらいならdefaultdictに変更して+= 1を維持したい。
  • コメント集:空
  • PR
    • https://github.com/ryosuketc/leetcode_grind75/pull/7
    • https://github.com/eito2002/LeetCode/pull/2
    • https://github.com/huyfififi/coding-challenges/pull/7
    • https://github.com/azriel1rf/leetcode-prep/pull/2
    • https://github.com/rihib/leetcode/pull/5
    • https://github.com/kzhra/Grind41/pull/8
    • https://github.com/NobukiFukui/Grind75-ProgrammingTraining/pull/21

Prompt: 67

上記に他の人が解いたPRをまとめています。それぞれのPRの代表的なソリューションとレビューコメントをチェックし、PRごとの内容を簡潔にまとめてください。

Assistant: 3,291

🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠

7つのPRを確認しますね。順番に読み込んでいきます。

Copied!
{
  "id": "toolu_011WpAKjrpDwSaJHSPfrM84P",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/ryosuketc/leetcode_grind75/pull/7"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_01VwxRFBFi6baLoSkfsoGk6b",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/eito2002/LeetCode/pull/2"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_012w15UWiPkXPK3uzX6Qiiir",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/huyfififi/coding-challenges/pull/7"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_01SCG5MfaKMnRkXkFv6kEDjP",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/azriel1rf/leetcode-prep/pull/2"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_01A5eeTL14cQxVwdBzZDkUPk",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/rihib/leetcode/pull/5"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_01Mvfch1JmDMbATmKKKCwxb1",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/kzhra/Grind41/pull/8"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}
Copied!
{
  "id": "toolu_01PU62DRUbvQersym7RzXxEP",
  "call": {
    "function": "read_url",
    "arguments": {
      "url": "https://github.com/NobukiFukui/Grind75-ProgrammingTraining/pull/21"
    }
  },
  "result": "'Skip to content\\n\\n## Navigation Menu\\n\\nToggle navigation\\n\\n[ ](/)\\n\\n[ Sign in ](/login?return_t<TRUNCATED>"
}

各PRの内容をまとめます。


1. ryosuketc/leetcode_grind75 PR #7 (C++)

  • 解法: unordered_mapでカウント
  • 主なコメント:
    • Structured binding (for (const auto& [s_char, s_char_count] : ...)) はC++17から(oda)
    • ソート後に s == t で比較する方法もある(Apo-Matchbox)
    • 参照渡し・RVO・ポインタに関する深い考察をメモに記載

2. eito2002/LeetCode PR #2 (C++)

  • 解法: hash map、ソート、固定長配列(26要素)
  • 主なコメント:
    • ぶら下がりif(if (...) return false;)は事故が起きやすいので避けるべき(huyfififi)
    • 変数名を dictchar_to_count のように説明的にすべき(huyfififi)
    • ++ii++ の違い(前置の方がコピーを避けられる)
    • EBCDICでは s[i] - 'a' が動かない可能性(nodchip)
    • CodeRabbit(AI)のレビューはこの勉強会では不要という議論

3. huyfififi/coding-challenges PR #7 (Python)

  • 解法: 配列カウント、defaultdictcollections.Counter
  • 主なコメント:
    • 同じ処理を2度したら関数にすることを考える(oda)
    • 引き算で解くとSpaceがn+mではなくnかmで済む(sasanquaneuf)
    • 早期リターンできるパターンに気を配る
    • cnt より count と省略しない方が良い(Google Style Guide)
    • Step3でも同じコードでも貼った方が良い

4. azriel1rf/leetcode-prep PR #2 (Python)

  • 解法: defaultdictでカウント、Counter
  • 主なコメント:
    • 変数名は lower_snake が標準(PEP8, Google Style Guide)
    • cnt ではなく count と略さず書く
    • return cnt1 == cnt2 で辞書比較可能(内部でearly returnされる)
    • Counter(s) == Counter(t) で1行で書ける
    • 引き算して負になったらFalseで抜ける方法も(liquo-rice)
    • 1ループで2つの文字列を処理するより、2ループに分けた方が良い(oda)

5. rihib/leetcode PR #5 (Go)

  • 解法: map[rune]intでカウント(Unicode対応)
  • 主なコメント:
    • Unicode/サロゲートペア/結合文字/合字 についての非常に詳細な調査(本人)
    • runeを使っても結合文字(例:「が」=「か」+濁点)は正しく処理できない(sasanquaneuf)
    • グラフィムクラスタを使えばほぼ対応可能だが、旗シーケンスなど例外あり
    • 文字コードは魔境(oda)

6. kzhra/Grind41 PR #8 (C++)

  • 解法: map / unordered_mapでカウント、ソート
  • 主なコメント:
    • return count_letter_1 == count_letter_2; で比較可能
    • 変数名は letter_to_count のようにkey→valueを表す命名が良い(nodchip)
    • unordered_map vs map:要素数が少ないとハッシュ化のオーバーヘッドで差がないことも
    • for (auto [letter, count] : ...) で回した方が読みやすい
    • if の後にスペースを入れる(Google Style Guide)

7. NobukiFukui/Grind75-ProgrammingTraining PR #21 (Python)

  • 解法: sorted() で比較、set + count()
  • 主なコメント:
    • count()sorted()を使わずに書けるか?という問いかけ(Kitaken0107)
    • 基本的な実装力を問うレビュー

全体的な傾向:

  • 変数名: char_to_countletter_to_count など説明的な命名が推奨
  • 比較: 辞書/mapは == で直接比較可能
  • 早期リターン: 長さチェックや負のカウントで早く抜ける
  • Unicode: 結合文字やサロゲートペアの問題は深い(特にrihib PR)
  • コーディング規約: PEP8、Google Style Guideへの言及多数

Prompt: 27

各トピックについて、さらに深掘りして詳しく解説してください。

Assistant: 2,262

🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠

では、PRレビューで出てきた主要トピックを深掘りしていきます。


1. 変数名の命名(char_to_count スタイル)

辞書/mapの変数名で key_to_value の形式が推奨される理由:

Copied!
# 悪い例
dict = {}        # 組み込み型を上書き
d = {}           # 意味不明
cnt = {}         # 何のカウント?

# 良い例
char_to_count = {}      # 文字 → 出現回数
letter_to_frequency = {}

この命名により:

  • 辞書のキーと値が何かが一目でわかる
  • char_to_count[ch] と書くと「文字chの出現回数」と自然に読める
  • コードレビューや後からの保守が楽になる

Google Style Guideでは略語を避けることも推奨されています(cntcount)。


2. 辞書/mapの == 比較

Python/C++/Goいずれでも、辞書型は == で直接比較可能です:

Copied!
# Python
{"a": 1, "b": 2} == {"b": 2, "a": 1}  # True(順序は関係ない)

# 内部的には:
# 1. len(d1) == len(d2) をチェック
# 2. 各キーの存在と値を比較
# → 不一致が見つかった時点でFalseを返す(early return)
Copied!
// C++
std::unordered_map<char, int> m1, m2;
m1 == m2;  // OK

つまり、自分でループを書いて比較する必要はありません。


3. 早期リターン(Early Return)

不一致を早く検出することで無駄な処理を省けます:

Copied!
def isAnagram(self, s: str, t: str) -> bool:
    # Level 1: 長さチェック
    if len(s) != len(t):
        return False
    
    # Level 2: カウントしながら検出
    char_to_count = {}
    for ch in s:
        char_to_count[ch] = char_to_count.get(ch, 0) + 1
    
    for ch in t:
        if ch not in char_to_count:
            return False  # sに無い文字が出現
        char_to_count[ch] -= 1
        if char_to_count[ch] < 0:
            return False  # sより多く出現
    
    return True

引き算アプローチ(sasanquaneufさんのコメント):

  • 2つの辞書を作る → Space: O(n + m)
  • 1つの辞書で引き算 → Space: O(n) または O(m)

4. Unicode・サロゲートペア・結合文字

これはrihib PRで非常に深く議論されていたトピックです。

レベル1: ASCII

Copied!
len("abc")  # 3 → 問題なし

レベル2: BMP(Basic Multilingual Plane)内のUnicode

Copied!
len("あいう")  # 3 → 問題なし

レベル3: サロゲートペア(BMP外の文字)

Copied!
len("𠮷")  # Python3では1(正しく処理)
# JavaScriptやJavaでは2になることがある(UTF-16の2つのコードユニット)

Goの rune はUnicodeコードポイント単位なので、サロゲートペアは正しく処理されます。

レベル4: 結合文字(ここが魔境)

Copied!
s1 = "が"           # 1文字として入力(U+304C)
s2 = "か" + "\u3099"  # 「か」+ 濁点(U+304B + U+3099)

len(s1)  # 1
len(s2)  # 2  ← 見た目は同じ「が」なのに!

s1 == s2  # False

これを正しく処理するには Unicode正規化 が必要:

Copied!
import unicodedata

s1_nfc = unicodedata.normalize('NFC', s1)
s2_nfc = unicodedata.normalize('NFC', s2)
s1_nfc == s2_nfc  # True

レベル5: グラフィムクラスタ(さらに深い)

絵文字の例:

Copied!
flag = "🇯🇵"  # 日本国旗
len(flag)  # 2(Regional Indicator Symbol 2つの組み合わせ)

family = "👨‍👩‍👧‍👦"  # 家族絵文字
len(family)  # 7(ZWJで結合された複数のコードポイント)

結論: 「文字」の定義は複雑。問題の制約が「lowercase English letters」なら気にしなくて良いが、「Unicode対応」と言われたら正規化まで考慮が必要。


5. コーディング規約

Python(PEP8 / Google Style Guide):

  • 変数名: lower_snake_case
  • 略語を避ける: cntcount
  • 行の長さ: 79文字(PEP8)/ 80文字(Google)

C++(Google Style Guide):

  • if の後にスペース: if (condition) ✓ / if(condition)
  • ぶら下がりif(braceなし)は避ける:
    Copied!
    // 危険
    if (condition)
        return false;
    
    // 安全
    if (condition) {
        return false;
    }
    
  • ++i vs i++: イテレータでは前置 ++i の方がコピーを避けられる

C++17 Structured Binding:

Copied!
// C++17以降
for (const auto& [key, value] : map) { ... }

// C++11/14
for (const auto& pair : map) {
    auto key = pair.first;
    auto value = pair.second;
}

どのトピックについてさらに詳しく知りたいですか?特にUnicode周りは奥が深いので、必要であればもっと掘り下げられます。

Prompt: 48

Unicode対応を熟練SWE並に本気でやった、可読性も維持されたコードを書いてみてほしいです。

Code: 690 ()

def run_tests():
    """Simple test runner for Jupyter."""
    
    passed = 0
    failed = 0
    
    def test(name: str, s: str, t: str, expected: bool):
        nonlocal passed, failed
        result = is_anagram(s, t)
        if result == expected:
            print(f"✓ {name}: is_anagram({s!r}, {t!r}) = {result}")
            passed += 1
        else:
            print(f"✗ {name}: is_anagram({s!r}, {t!r}) = {result}, expected {expected}")
            failed += 1
    
    # Basic ASCII
    test("basic_anagram", "listen", "silent", True)
    test("basic_not_anagram", "hello", "world", False)
    test("different_length", "ab", "abc", False)
    
    # Unicode normalization
    test("nfc_normalization (café)", "café", "cafe\u0301", True)
    test("japanese_combining (が)", "\u304C", "\u304B\u3099", True)
    test("japanese_anagram", "あいう", "ういあ", True)
    
    # Grapheme clusters
    if _HAS_GRAPHEME:
        test("emoji_flag (🇯🇵🇺🇸)", "🇯🇵🇺🇸", "🇺🇸🇯🇵", True)
        test("emoji_zwj_sequence", "👨‍👩‍👧", "👨‍👩‍👧", True)
        test("skin_tone_emoji", "👋🏽👋🏻", "👋🏻👋🏽", True)
    else:
        print("⚠ Skipping grapheme tests (install: pip install grapheme)")
    
    # Edge cases
    test("empty_strings", "", "", True)
    test("single_char", "a", "a", True)
    test("single_char_different", "a", "b", False)
    
    print(f"\n{passed} passed, {failed} failed")


run_tests()

Output: 669

✓ basic_anagram: is_anagram('listen', 'silent') = True
✓ basic_not_anagram: is_anagram('hello', 'world') = False
✓ different_length: is_anagram('ab', 'abc') = False
✓ nfc_normalization (café): is_anagram('café', 'café') = True
✓ japanese_combining (が): is_anagram('が', 'が') = True
✓ japanese_anagram: is_anagram('あいう', 'ういあ') = True
✓ emoji_flag (🇯🇵🇺🇸): is_anagram('🇯🇵🇺🇸', '🇺🇸🇯🇵') = True
✓ emoji_zwj_sequence: is_anagram('👨\u200d👩\u200d👧', '👨\u200d👩\u200d👧') = True
✓ skin_tone_emoji: is_anagram('👋🏽👋🏻', '👋🏻👋🏽') = True
✓ empty_strings: is_anagram('', '') = True
✓ single_char: is_anagram('a', 'a') = True
✓ single_char_different: is_anagram('a', 'b') = False

12 passed, 0 failed

Prompt: 64

結局実装的には、unicodedata.normalize('NFC', text)すれば、多くの合体文字が1字になり、あとはオプションでgraphemesって感じ?

Assistant: 625

🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠🧠

はい、その理解で正確です!整理すると:

NFC正規化で解決するもの:

  • 結合文字の統一: +
  • アクセント記号: e + ́é
  • 同じ見た目の異なる表現を統一

NFC正規化では解決しないもの(grapheme必要):

  • 国旗: 🇯🇵 = Regional Indicator J + P(2コードポイント、合成されない)
  • ZWJ絵文字: 👨‍👩‍👧 = 複数絵文字 + ZWJ(結合しても1コードポイントにならない)
  • 肌色修飾: 👋🏽 = 👋 + 🏽(修飾子は独立したコードポイント)
Copied!
import unicodedata

# NFCで解決 ✓
s = "か\u3099"  # か + 濁点
unicodedata.normalize('NFC', s)  # → "が" (1文字)

# NFCでは解決しない ✗
flag = "🇯🇵"
unicodedata.normalize('NFC', flag)  # → "🇯🇵" (まだ2コードポイント)
len(unicodedata.normalize('NFC', flag))  # → 2

結論:

ケース NFC grapheme
ASCII 不要 不要
日本語・アクセント 不要
絵文字・国旗 不十分

実用上は「NFC正規化だけで95%のケースは対応できる」という感じですね。絵文字をユーザー入力で扱うSNS系サービスなどではgraphemeまで必要になります。

Note: 58

実装4

  • Unicode対応をしっかりやる。
    • とはいえ、先人のやってくれた実装を使うだけ。

Code: 181 ()

from typing import Iterator
import unicodedata
from collections import Counter

import grapheme


class Solution:
    def iter_graphemes(self, s: str) -> Iterator[str]:
        normalized = unicodedata.normalize('NFC', s)
        return grapheme.graphemes(normalized)

    def isAnagram(self, s: str, t: str) -> bool:
        s_graphemes = self.iter_graphemes(s)
        t_graphemes = self.iter_graphemes(t)
        return Counter(s_graphemes) == Counter(t_graphemes)
        

Note: 6

Step 3

Note: 55

実装5

  • 何も見ずに書き直し
    • Unicodeの設定は忘れ、素朴な設定に取り組む。

Code: 186 ()

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False
        
        s_char_to_count = {}
        for ch in s:
            if ch not in s_char_to_count:
                s_char_to_count[ch] = 0 
            s_char_to_count[ch] += 1
        
        remaining_count = s_char_to_count
        for ch in t:
            if remaining_count.get(ch, 0) == 0:
                return False
            remaining_count[ch] -= 1
        return True

Note: 6

Step 4

Note: 18

自分のPR:(自分のPRへのリンク)

Prompt: 46

ここに、私が投稿したStep1-3のPRに対してレビューコメントがついています。それぞれチェックしてまとめてください。

Prompt: 25

それぞれのレビューコメントについて、もう少し詳しく教えてください。

Note: 37

実装6

  • レビューを受けて書き直し
    • (修正点)

Code: 7 ()

class Solution:
    pass

Code: 120 ()

from IPython.display import Markdown

md = lc_export(
    next_url="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/",
    dry_run=True,
    desc="",
    notebook_url="https://share.solve.it.com/d/31dccb7f2a9aa3998533a6acccf04c65"
)
# Markdown(md)

Output: 930

=== DRY RUN: 0242-valid-anagram/0242-valid-anagram.md ===

# 242. Valid Anagram

- URL: https://leetcode.com/problems/valid-anagram/
- Difficulty: Easy
- Tags: Hash Table, String, Sorting
- Notebook: https://share.solve.it.com/d/31dccb7f2a9aa3998533a6acccf04c65

## 問題文

<p>Given two strings <code>s</code> and <code>t</code>, return <code>true</code> if <code>t</code> is an <span data-keyword="anagram">anagram</span> of <code>s</code>, and <code>false</code> otherwise.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">s = &quot;anagram&quot;, t = &quot;nagaram&quot;</span></p>

<p><strong>Output:</strong> <span class="example-io">true</span></p>
</div>

<p><strong class="example">Example 2:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">s = &quot;rat&quot;, t = &quot;car&quot;</span></p>

<p><strong>Output:</strong> <span class="example-io">false</span></p>
</div>

<p>&nbsp;</p>
<p><strong>Constrain...

=== 22 cells would be exported ===
=== PR Title: 242. Valid Anagram ===
=== Notebook: https://share.solve.it.com/d/31dccb7f2a9aa3998533a6acccf04c65 ===