0Pricing
DSA Interview Prep · Pelajaran

Anagram dan Peta Frekuensi Karakter

Selesaikan group-anagrams, valid-anagram, dan permutation-in-string menggunakan array frekuensi serta hash map untuk solusi O(n).

Anagram dan Peta Frekuensi Karakter adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar DSA Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Apa Itu Anagram?

Dua teks disebut anagram jika keduanya berisi karakter yang sama dengan frekuensi yang sama, hanya urutannya berbeda. ‘batu’ dan ‘buat’ adalah anagram. Pemeriksaan kebenaran paling sederhana adalah mengurutkan kedua teks lalu membandingkannya: O(n log n). Untuk solusi O(n), bandingkan peta frekuensi karakter. Masalah anagram sering muncul dalam wawancara tentang teks karena menguji beberapa teknik: pencincangan, pengurutan, dan larik frekuensi.

def is_anagram_sort(s, t):
    return sorted(s) == sorted(t)  # O(n log n)

def is_anagram_counter(s, t):
    from collections import Counter
    return Counter(s) == Counter(t)  # O(n)

def is_anagram_array(s, t):
    if len(s) != len(t): return False
    freq = [0] * 26
    for a, b in zip(s, t):
        freq[ord(a) - ord('a')] += 1
        freq[ord(b) - ord('a')] -= 1
    return all(f == 0 for f in freq)  # O(n)

print(is_anagram_array('anagram', 'nagaram'))  # True
print(is_anagram_array('rat', 'car'))           # False

Larik Frekuensi untuk Huruf Kecil

Ketika himpunan karakter terbatas (misalnya, hanya huruf kecil a-z), gantilah peta hash dengan larik frekuensi berukuran 26. Pengindeksan berdasarkan ord(c) - ord('a') memetakan 'a'→0, 'b'→1, ..., 'z'→25. Dalam praktiknya, larik lebih cepat daripada kamus karena lokalitas tembolok dan tidak adanya biaya pencincangan. Trik ini muncul dalam masalah anagram valid, permutasi anagram dalam teks, dan permutasi palindrom.

def build_freq(s):
    freq = [0] * 26
    for c in s:
        freq[ord(c) - ord('a')] += 1
    return freq

def is_anagram_fast(s, t):
    return len(s) == len(t) and build_freq(s) == build_freq(t)

# Palindrome permutation: at most one odd-count character
def can_form_palindrome(s):
    freq = build_freq(s)
    odd_count = sum(1 for f in freq if f % 2 == 1)
    return odd_count <= 1

print(can_form_palindrome('carerace'))  # True ('racecar')
print(can_form_palindrome('hello'))     # False

Mengelompokkan Anagram

Kelompokkan daftar teks sehingga semua anagram muncul bersama. Solusi kanonis O(n×m log m) menggunakan teks yang sudah diurutkan sebagai kunci peta hash. Semua anagram menghasilkan kunci terurut yang sama, sehingga masuk ke wadah yang sama. Variasi O(n×m) menggunakan tupel hitungan karakter sebagai kunci — lebih lambat saat menghitungnya, tetapi sama sekali tidak memerlukan pengurutan. Pendekatan berbasis kunci terurut hampir selalu lebih disukai karena lebih jelas.

from collections import defaultdict

def group_anagrams(strs):
    groups = defaultdict(list)
    for s in strs:
        key = tuple(sorted(s))  # or ''.join(sorted(s))
        groups[key].append(s)
    return list(groups.values())

words = ['eat','tea','tan','ate','nat','bat']
result = group_anagrams(words)
for g in sorted(result, key=len, reverse=True):
    print(sorted(g))
# ['ate', 'eat', 'tea']
# ['nat', 'tan']
# ['bat']

Kunci Anagram dengan Tupel Hitungan

Untuk variasi pengelompokan anagram O(n×m), representasikan frekuensi setiap teks sebagai tupel berisi 26 hitungan: tuple(freq_array). Cara ini menghindari pengurutan, tetapi memerlukan pekerjaan O(26×n×m) untuk membangun semua kunci. Tupel dapat dicincang di Python, sehingga dapat digunakan sebagai kunci kamus. Variasi ini layak disebutkan ketika pewawancara meminta “solusi O(n×m) apa pun” — ini menunjukkan pemahaman tentang berbagai kompromi.

from collections import defaultdict

def group_anagrams_count(strs):
    groups = defaultdict(list)
    for s in strs:
        freq = [0] * 26
        for c in s:
            freq[ord(c) - ord('a')] += 1
        key = tuple(freq)  # tuple is hashable
        groups[key].append(s)
    return list(groups.values())

print(group_anagrams_count(['eat','tea','tan','ate','nat','bat']))

K Elemen dengan Frekuensi Tertinggi

Temukan k elemen yang paling sering muncul dalam sebuah larik. Penghitung + tumpukan-min: bangun peta frekuensi dalam O(n), lalu ambil k frekuensi terbesar menggunakan tumpukan-min berukuran k atau Counter.most_common(k). Pendekatan pengurutan berbasis wadah O(n) membuat wadah yang diindeks berdasarkan frekuensi (0 hingga n) dan mengumpulkan elemen dalam urutan frekuensi terbalik — elegan ketika k besar.

from collections import Counter
import heapq

def top_k_frequent_heap(nums, k):
    freq = Counter(nums)
    return heapq.nlargest(k, freq, key=freq.get)

def top_k_frequent_bucket(nums, k):
    freq = Counter(nums)
    buckets = [[] for _ in range(len(nums) + 1)]
    for num, cnt in freq.items():
        buckets[cnt].append(num)
    result = []
    for i in range(len(buckets)-1, -1, -1):
        result.extend(buckets[i])
        if len(result) >= k: break
    return result[:k]

print(top_k_frequent_heap([1,1,1,2,2,3], 2))   # [1, 2]
print(top_k_frequent_bucket([1,1,1,2,2,3], 2)) # [1, 2]

Peta Frekuensi untuk Permutasi dalam Teks

Tentukan apakah ada permutasi teks p yang muncul sebagai subteks dalam s. Peta frekuensi dari jendela sepanjang |p| harus sama dengan peta frekuensi p. Saat jendela bergeser, tambah hitungan karakter yang masuk dan kurangi hitungan karakter yang keluar. Membandingkan dua objek penghitung memerlukan O(26) setiap kali, sehingga totalnya O(n×26) = O(n). Lacak penghitung jumlah karakter yang terpenuhi untuk pemeriksaan kesamaan dalam O(1).

def check_inclusion_fast(p, s):
    if len(p) > len(s): return False
    need = [0] * 26
    have = [0] * 26
    for c in p:
        need[ord(c)-ord('a')] += 1
    for i in range(len(p)):
        have[ord(s[i])-ord('a')] += 1
    if need == have: return True
    for i in range(len(p), len(s)):
        have[ord(s[i])-ord('a')]         += 1
        have[ord(s[i-len(p)])-ord('a')] -= 1
        if need == have: return True
    return False

print(check_inclusion_fast('ab', 'eidbaooo'))  # True
print(check_inclusion_fast('ab', 'eidboaoo'))  # False

Jumlah Minimum Karakter untuk Membuat Anagram

Diberikan dua teks, temukan jumlah minimum penghapusan karakter agar salah satunya menjadi anagram dari yang lain. Hitung peta frekuensi untuk kedua teks; jawabannya adalah jumlah selisih mutlak frekuensi. Karakter yang ada dalam salah satu teks tetapi tidak ada dalam teks lainnya harus dihapus seluruhnya. Solusi O(n) ini menggunakan pola “menggabungkan dan menghitung selisih” pada peta frekuensi.

from collections import Counter

def min_steps_to_anagram(s, t):
    freq_s = Counter(s)
    freq_t = Counter(t)
    steps = 0
    # For each unique char across both strings:
    all_chars = set(freq_s) | set(freq_t)
    for c in all_chars:
        steps += abs(freq_s.get(c, 0) - freq_t.get(c, 0))
    return steps

# Or more concisely:
def min_steps_counter(s, t):
    diff = Counter(s) - Counter(t)
    return sum(diff.values())

print(min_steps_to_anagram('leetcode', 'practice'))  # 5
print(min_steps_counter('leetcode', 'practice'))      # 5

Peta Frekuensi untuk Catatan Tebusan

Periksa apakah semua karakter dalam note dapat disediakan oleh karakter dalam magazine (setiap karakter majalah hanya dapat digunakan sekali). Bangun peta frekuensi karakter majalah; lalu untuk setiap karakter dalam catatan, kurangi hitungannya. Jika ada hitungan yang menjadi negatif, kembalikan False. Waktunya O(n + m) dan ruangnya O(1) untuk masukan yang dibatasi pada huruf kecil dengan menggunakan larik 26 elemen, bukan kamus.

def can_construct(note, magazine):
    freq = [0] * 26
    for c in magazine:
        freq[ord(c) - ord('a')] += 1
    for c in note:
        freq[ord(c) - ord('a')] -= 1
        if freq[ord(c) - ord('a')] < 0:
            return False  # insufficient supply
    return True

print(can_construct('aa', 'aab'))    # True
print(can_construct('aa', 'ab'))     # False
print(can_construct('bg', 'efjbdfbdgbjjbghiklgdch'))  # True

Pencincangan Subteks Anagram Terpanjang

Untuk memeriksa apakah dua subteks dari teks yang sama merupakan anagram, gunakan hash polinomial dari frekuensi karakter yang bersifat komutatif (tidak bergantung pada urutan). XOR nilai karakter bersifat komutatif dan dapat diperbarui dalam O(1), tetapi memiliki kemungkinan tabrakan yang tinggi. Pendekatan yang lebih baik menggunakan pencincangan hasil kali bilangan prima (setiap karakter dipetakan ke bilangan prima yang berbeda; hasil kalinya tidak bergantung pada urutan). Ini adalah teknik khusus untuk wawancara tingkat lanjut.

# Prime product hash: each char maps to a prime
PRIMES = [2,3,5,7,11,13,17,19,23,29,31,37,41,
          43,47,53,59,61,67,71,73,79,83,89,97,101]

def char_hash(s):
    h = 1
    for c in s:
        h *= PRIMES[ord(c) - ord('a')]
    return h

# Two windows with equal hash are likely anagrams
print(char_hash('listen'))  # same as:
print(char_hash('silent'))  # should match

Daftar Periksa Pola Peta Frekuensi

Kenali pola wawancara berbasis peta frekuensi berikut:

  • Anagram valid: panjang sama + frekuensi sama → kesamaan penghitung atau perbandingan larik
  • Mengelompokkan anagram: teks terurut atau tupel frekuensi sebagai kunci kamus
  • k elemen paling sering: penghitung + tumpukan atau pengurutan berbasis wadah
  • Permutasi dalam teks: jendela geser + perbandingan frekuensi
  • Catatan tebusan: peta frekuensi persediaan, kurangi untuk permintaan
  • Permutasi palindrom: paling banyak satu karakter dengan hitungan ganjil
Semuanya dapat direduksi menjadi gagasan inti yang sama: frekuensi sebagai sidik jari.

from collections import Counter

# Palindrome permutation
def palindrome_permutation(s):
    return sum(v % 2 for v in Counter(s).values()) <= 1

# First unique character
def first_unique(s):
    freq = Counter(s)
    for i, c in enumerate(s):
        if freq[c] == 1:
            return i
    return -1

# Character replacement for longest repeat
def char_replacement(s, k):
    freq = Counter()
    left = best = max_freq = 0
    for right, c in enumerate(s):
        freq[c] += 1
        max_freq = max(max_freq, freq[c])
        if (right - left + 1) - max_freq > k:
            freq[s[left]] -= 1
            left += 1
        best = max(best, right - left + 1)
    return best

print(palindrome_permutation('carerace'))  # True
print(first_unique('leetcode'))             # 0
print(char_replacement('AABABBA', 1))      # 4

Yang Berbeda: XOR untuk Frekuensi

XOR adalah alat yang ampuh untuk masalah frekuensi ketika tepat satu elemen memiliki frekuensi ganjil. XOR suatu angka dengan dirinya sendiri menghasilkan 0: a XOR a = 0. XOR semua elemen, ketika setiap nilai muncul sebanyak bilangan genap kecuali satu nilai, hanya menyisakan nilai yang frekuensinya ganjil. Cara ini memberikan waktu O(n) dan ruang O(1) — tidak memerlukan peta hash. Teknik ini dapat digeneralisasi untuk menemukan dua angka yang muncul dalam jumlah ganjil menggunakan sifat-sifat XOR.

def single_number(nums):
    result = 0
    for n in nums:
        result ^= n  # XOR cancels pairs
    return result

print(single_number([4,1,2,1,2]))   # 4
print(single_number([2,2,1]))       # 1

# Find the unique character in an anagram check:
def find_difference(s, t):
    result = 0
    for c in s + t:
        result ^= ord(c)
    return chr(result)

print(find_difference('abcd', 'abcde'))  # 'e'

Uji Singkat

Ujilah pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.

Rangkuman Pelajaran

Dalam pelajaran ini Anda mempelajari: peta frekuensi karakter adalah alat utama untuk mendeteksi anagram — gunakan larik 26 elemen untuk alfabet terbatas atau penghitung untuk karakter sembarang, kunci kamus berupa teks terurut atau tupel frekuensi mengelompokkan semua anagram dalam waktu O(n × m log m) atau O(n × m), dan XOR menghapus pasangan dengan rapi untuk masalah hitungan ganjil satu elemen, sehingga memberikan waktu O(n) dengan ruang O(1) ketika kamus tidak diperlukan. Selanjutnya kita akan mempelajari pengodean teks, pembalikan, dan teknik palindrom.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Anagram dan Peta Frekuensi Karakter” gratis?

Ya — teks lengkap “Anagram dan Peta Frekuensi Karakter” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DSA Interview Prep, upgrade ke CoddyKit PRO. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Anagram dan Peta Frekuensi Karakter”?

Selesaikan group-anagrams, valid-anagram, dan permutation-in-string menggunakan array frekuensi serta hash map untuk solusi O(n). Kamu berlatih DSA Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai DSA Interview Prep?

Tidak diperlukan pengalaman sebelumnya. DSA Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Anagram dan Peta Frekuensi Karakter” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran DSA Interview Prep ini?

Ya. Setiap pelajaran DSA Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. API String Python untuk Wawancara
  2. Sliding Window untuk Substring
  3. Anagram dan Peta Frekuensi Karakter
  4. Pengodean String, Pembalikan, dan Palindrome
← Kembali ke DSA Interview Prep