0Pricing
Coding Interview Prep · Pelajaran

Permutasi dan Kombinasi

Enumerasikan semua permutasi dari sebuah daftar, baik dengan maupun tanpa elemen duplikat, lalu hasilkan semua kombinasi-k dan variasi jumlah kombinasi

Permutasi dan Kombinasi adalah pelajaran Coding 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 Coding Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Coding Interview Prep mencakup 4 pelajaran total.

Permutasi vs Kombinasi

Permutasi adalah susunan yang memperhatikan urutan: [1,2,3] dan [3,2,1] berbeda. Jumlah permutasi dari n elemen adalah n!. Kombinasi adalah pemilihan yang tidak memperhatikan urutan: memilih {1,2} sama dengan {2,1}. Jumlah kombinasi-k dari n elemen adalah C(n,k) = n! / (k! × (n-k)!). Keduanya merupakan pola penting dalam soal wawancara tentang penghitungan, enumerasi, dan pemilihan.

import math

# Permutations
n = 4
print(f'Permutations of {n} items: {math.factorial(n)}')
# 4! = 24

# Combinations
for k in range(n+1):
    print(f'C({n},{k}) = {math.comb(n,k)}')
# C(4,0)=1, C(4,1)=4, C(4,2)=6, C(4,3)=4, C(4,4)=1
# Sum = 2^4 = 16 (total subsets)

Menghasilkan Semua Permutasi

Gunakan larik Boolean used untuk melacak elemen mana yang berada dalam jalur saat ini. Pada setiap langkah, coba setiap elemen yang belum digunakan. Setelah selesai menjelajah, tandai kembali elemen tersebut sebagai belum digunakan. Berbeda dari subhimpunan, tidak ada indeks start karena permutasi menggunakan elemen dalam urutan apa pun. Rekursi berakhir ketika len(path) == n.

def permutations(nums):
    result = []
    used = [False] * len(nums)
    def backtrack(path):
        if len(path) == len(nums):
            result.append(list(path))
            return
        for i, num in enumerate(nums):
            if not used[i]:
                used[i] = True         # CHOOSE
                path.append(num)
                backtrack(path)        # EXPLORE
                path.pop()             # UNCHOOSE
                used[i] = False
    backtrack([])
    return result

print(permutations([1, 2, 3]))
# [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

Permutasi Berbasis Pertukaran

Sebagai alternatif, tukarkan elemen pada posisi start dengan setiap elemen dari start hingga n-1, lakukan rekursi, lalu tukarkan kembali. Cara ini mengubah larik secara langsung tanpa larik used. Inti pentingnya adalah bahwa pada setiap tingkat, semua elemen di sebelah kiri start sudah tetap, dan kita memilih elemen yang akan ditempatkan pada posisi start. Pendekatan ini sedikit lebih hemat memori dan menjadi dasar algoritme Heap.

def permutations_swap(nums):
    result = []
    def backtrack(start):
        if start == len(nums):
            result.append(list(nums))
            return
        for i in range(start, len(nums)):
            nums[start], nums[i] = nums[i], nums[start]  # CHOOSE (swap)
            backtrack(start + 1)                          # EXPLORE
            nums[start], nums[i] = nums[i], nums[start]  # UNCHOOSE (swap back)
    backtrack(0)
    return result

print(permutations_swap([1, 2, 3]))
# Same 6 permutations, different order

Permutasi II: Menangani Duplikat

Ketika masukan memiliki duplikat, misalnya [1, 1, 2], pendekatan dengan larik used menghasilkan permutasi duplikat. Perbaikannya: urutkan larik, lalu lewati duplikat jika elemen identik sebelumnya belum digunakan dalam pemanggilan rekursif ini. Kondisinya: if i > 0 and nums[i] == nums[i-1] and not used[i-1]: continue. Dengan demikian, duplikat selalu dipilih dari kiri ke kanan.

def permutations_unique(nums):
    nums.sort()
    result = []
    used = [False] * len(nums)
    def backtrack(path):
        if len(path) == len(nums):
            result.append(list(path))
            return
        for i in range(len(nums)):
            if used[i]: continue
            # Skip if this num is a duplicate and the previous dup was not used
            if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
                continue
            used[i] = True
            path.append(nums[i])
            backtrack(path)
            path.pop()
            used[i] = False
    backtrack([])
    return result

print(permutations_unique([1, 1, 2]))
# [[1,1,2],[1,2,1],[2,1,1]] — 3, not 6

Permutasi Berikutnya (Secara Leksikografis)

Permutasi Berikutnya (LeetCode 31) mengubah larik menjadi permutasi berikutnya yang lebih besar secara leksikografis secara langsung. Algoritmenya: (1) Temukan indeks paling kanan i dengan kondisi nums[i] < nums[i+1]. (2) Temukan indeks paling kanan j dengan kondisi nums[j] > nums[i]. (3) Tukarkan nums[i] dan nums[j]. (4) Balikkan sufiks setelah indeks i. Jika tidak ada i seperti itu, balikkan seluruh larik (kembali ke permutasi terkecil).

def next_permutation(nums):
    n = len(nums)
    # Step 1: find rightmost i where nums[i] < nums[i+1]
    i = n - 2
    while i >= 0 and nums[i] >= nums[i+1]:
        i -= 1
    if i >= 0:
        # Step 2: find rightmost j where nums[j] > nums[i]
        j = n - 1
        while nums[j] <= nums[i]:
            j -= 1
        # Step 3: swap
        nums[i], nums[j] = nums[j], nums[i]
    # Step 4: reverse suffix after i
    nums[i+1:] = nums[i+1:][::-1]
    return nums

print(next_permutation([1, 2, 3]))  # [1,3,2]
print(next_permutation([3, 2, 1]))  # [1,2,3] (wraps)
print(next_permutation([1, 1, 5]))  # [1,5,1]

Penelusuran Mundur untuk Kombinasi k

Hasilkan semua kombinasi k elemen dari n elemen (LeetCode 77). Gunakan indeks awal, seperti pada subhimpunan, untuk menghindari pengunjungan kembali elemen dan mempertahankan urutan terurut. Lakukan pemangkasan ketika elemen yang tersisa lebih sedikit daripada k - len(path): if len(nums) - i + 1 < k - len(path): break. Ini setara dengan combine(n, k) sebelumnya, tetapi beroperasi pada larik nyata.

def combinations(nums, k):
    result = []
    def backtrack(start, path):
        if len(path) == k:
            result.append(list(path))
            return
        for i in range(start, len(nums)):
            # Pruning: not enough elements left
            if len(nums) - i < k - len(path):
                break
            path.append(nums[i])
            backtrack(i + 1, path)
            path.pop()
    backtrack(0, [])
    return result

print(combinations([1,2,3,4,5], 3))
# 10 combinations: C(5,3)
import math
print(math.comb(5,3))  # 10

Jumlah Kombinasi: Penggunaan Ulang Tanpa Batas

Jumlah Kombinasi (LeetCode 39) memungkinkan setiap angka digunakan berkali-kali tanpa batas. Perbedaannya dari kombinasi standar: alih-alih memajukan start ke i+1, teruskan i (indeks yang sama) agar elemen saat ini dapat digunakan kembali. Pemangkasan: jika sasaran yang tersisa menjadi 0, catat jalurnya; jika menjadi negatif, berhentilah. Pengurutan memungkinkan penghentian dini ketika semua kandidat yang tersisa melebihi sasaran yang tersisa.

def combination_sum(candidates, target):
    candidates.sort()
    result = []
    def backtrack(start, path, remaining):
        if remaining == 0:
            result.append(list(path))
            return
        for i in range(start, len(candidates)):
            c = candidates[i]
            if c > remaining: break  # all remaining are too big
            path.append(c)
            backtrack(i, path, remaining - c)  # reuse allowed: pass i, not i+1
            path.pop()
    backtrack(0, [], target)
    return result

print(combination_sum([2, 3, 6, 7], 7))
# [[2,2,3],[7]]

Jumlah Kombinasi II: Tanpa Penggunaan Ulang, dengan Duplikat

Jumlah Kombinasi II (LeetCode 40) menggunakan setiap angka paling banyak satu kali, tetapi masukan dapat mengandung duplikat. Gunakan gabungan dua teknik: majukan start ke i+1 (tanpa penggunaan ulang), lalu lewati duplikat pada tingkat yang sama (if i > start and nums[i] == nums[i-1]: continue) setelah pengurutan. Ini merupakan perpaduan antara penanganan duplikat dari subhimpunan II dan batasan tanpa penggunaan ulang dari kombinasi.

def combination_sum_ii(candidates, target):
    candidates.sort()
    result = []
    def backtrack(start, path, remaining):
        if remaining == 0:
            result.append(list(path))
            return
        for i in range(start, len(candidates)):
            if candidates[i] > remaining: break
            # Skip duplicates at same level
            if i > start and candidates[i] == candidates[i-1]:
                continue
            path.append(candidates[i])
            backtrack(i + 1, path, remaining - candidates[i])  # no reuse: i+1
            path.pop()
    backtrack(0, [], target)
    return result

print(combination_sum_ii([10,1,2,7,6,1,5], 8))
# [[1,1,6],[1,2,5],[1,7],[2,6]]

Kombinasi Huruf dari Nomor Telepon

Kombinasi Huruf (LeetCode 17) memetakan setiap digit ke huruf pada papan tombol telepon dan menghasilkan semua kombinasi huruf yang mungkin untuk suatu teks digit. Ini adalah masalah penelusuran mundur: pada setiap posisi, kita memilih satu huruf dari pemetaan digit tersebut lalu melakukan rekursi. Untuk teks dengan panjang n dan rata-rata k huruf per digit, kompleksitas waktunya adalah O(kⁿ).

def letter_combinations(digits):
    if not digits: return []
    phone = {
        '2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl',
        '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'
    }
    result = []
    def backtrack(index, path):
        if index == len(digits):
            result.append(''.join(path))
            return
        for letter in phone[digits[index]]:
            path.append(letter)
            backtrack(index + 1, path)
            path.pop()
    backtrack(0, [])
    return result

print(letter_combinations('23'))
# ['ad','ae','af','bd','be','bf','cd','ce','cf']

Membandingkan Permutasi dan Kombinasi

Perbedaan struktural utama: Permutasi — tidak memiliki indeks awal, menggunakan larik used atau pertukaran untuk menghindari penggunaan ulang, pohonnya memiliki n pilihan pada setiap tingkat, dan memiliki total n! daun. Kombinasi — menggunakan indeks awal untuk mempertahankan urutan, dengan C(n,k) daun. Jumlah Kombinasi — tidak memajukan indeks awal agar dapat digunakan ulang, dan melakukan pemangkasan berdasarkan sasaran. Dengan memetakan masalah baru ke salah satu dari tiga bentuk ini, Anda dapat langsung memilih pola yang tepat.

# Pattern summary:
# Permutations: for i in range(n); if not used[i]; no start advancement
# Combinations: for i in range(start, n); advance start → i+1
# Combo Sum (reuse): for i in range(start, n); advance start → i (same)

# Quick reference:
import math
n = 5
print(f'Perm({n})   = n! = {math.factorial(n)}')
print(f'Comb({n},2) = C(n,k) = {math.comb(n,2)}')
print(f'Comb({n},3) = {math.comb(n,3)}')
# Also: subsets = sum(C(n,k) for k=0..n) = 2^n
print(f'Subsets({n}) = 2^n = {2**n}')

Kompleksitas dan Kiat Wawancara

Kompleksitas waktu untuk enumerasi: Permutasi O(n × n!), Kombinasi O(k × C(n,k)), Jumlah Kombinasi O(n^(T/min_val)). Ruang yang digunakan adalah O(n) untuk kedalaman rekursi ditambah O(keluaran) untuk hasil. Kiat penting: (1) Selalu pastikan apakah urutan penting (permutasi atau kombinasi). (2) Jelaskan penanganan duplikat sebelum ditanya. (3) Selalu nyatakan kondisi pemangkasan secara eksplisit. (4) Untuk n yang besar, ingat bahwa keluarannya sendiri bersifat eksponensial — algoritme tersebut optimal untuk tugas ini.

import math

# Complexity for n=10
n = 10
print(f'Permutations(10): {math.factorial(n):,} results')
print(f'Combinations(10,5): {math.comb(n,5):,} results')
print(f'Subsets(10): {2**n:,} results')

# For interview: state which pattern
# 'This is a combinations problem because order doesnt matter'
# 'I will use a start index to avoid revisiting elements'
# 'Pruning: when sum exceeds target, break (after sorting)'

Uji Singkat

Uji pemahaman Anda tentang konsep Struktur Data & Algoritme — Persiapan Wawancara Pemrograman dari pelajaran ini.

Ringkasan Pelajaran

Dalam pelajaran ini Anda mempelajari: permutasi menggunakan larik penanda penggunaan dan tidak memiliki indeks awal, sehingga menghasilkan n! susunan, kombinasi menggunakan indeks awal yang terus maju untuk menghindari penggunaan ulang, sehingga menghasilkan C(n,k) pilihan, serta duplikat dalam kedua masalah ditangani dengan mengurutkan dan melewati nilai berulang pada tingkat rekursi yang sama. Berikutnya kita akan menerapkan penelusuran mundur pada masalah N-Ratu dan mempelajari propagasi kendala.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Permutasi dan Kombinasi” gratis?

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

Apa yang akan aku pelajari di “Permutasi dan Kombinasi”?

Enumerasikan semua permutasi dari sebuah daftar, baik dengan maupun tanpa elemen duplikat, lalu hasilkan semua kombinasi-k dan variasi jumlah kombinasi Kamu berlatih Coding 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 Coding Interview Prep?

Tidak diperlukan pengalaman sebelumnya. Coding 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 “Permutasi dan Kombinasi” 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 Coding Interview Prep ini?

Ya. Setiap pelajaran Coding 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. Templat Backtracking: Pilih, Jelajahi, Batalkan Pilihan
  2. Himpunan Bagian dan Himpunan Kuasa
  3. Permutasi dan Kombinasi
  4. N-Queens dan Propagasi Kendala
← Kembali ke Coding Interview Prep