Pemenang Codeforces bukan hanya mereka yang tahu banyak algoritma, tetapi yang tahu kapan menggunakan algoritma mana. Setelah soal selesai (atau stuck), membaca submission user lain memperlihatkan variasi pendekatan dengan trade-off berbeda. Hash map mungkin tercepat tetapi boros memori; sort + two pointers lebih lambat tetapi lebih simple. Pada Chapter ini kita akan membangun solution analyzer yang membandingkan beberapa solusi untuk soal yang sama — kompleksitas, runtime, memory, dan lines of code. Setiap solusi punya pelajaran unik yang membentuk “snippets library” mental kita untuk soal-soal berikutnya.

Mengapa Membaca Solusi Orang Lain? #

Saat kita hanya melihat satu solusi (milik kita), kita terjebak dalam satu cara berpikir. Membaca 3–5 solusi alternatif memberi tiga manfaat:

ManfaatCara Memanfaatkan
Lihat pola umumIdentifikasi algoritma inti yang dipakai mayoritas
Variasi idiomAdaptasi idiom bahasa yang lebih efisien
Trade-offPahami kapan time > space dan sebaliknya
Edge case handlingPelajari cara orang lain handle input aneh
Code golf vs readabilityPilih keseimbangan yang sesuai gaya kita

Strategi Analisis Solusi #

Proses analisis yang baik bukan sekadar membaca kode, tetapi membandingkan dan menggeneralisasi:

LangkahPertanyaanOutput
1. Identifikasi polaAlgoritma apa yang dipakai?Tag pola (hash map, 2 ptr, …)
2. KompleksitasTime dan space Big-O?Tabel perbandingan
3. Edge caseBagaimana input kosong, n=1, duplikat?Daftar handling
4. Idiom bahasaApa trik C++/Python yang dipakai?Snippet untuk reuse
5. Trade-offLebih cepat tapi boros memori?Decision matrix
6. GeneralisasiPola ini berlaku untuk soal apa lagi?Daftar soal serupa

Kode: Solution Analyzer #

cpp
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>
using namespace std;

struct Solution {
    string author;
    string approach;        // mis. "Two pointers", "Hash map", "Sort + 2 ptr"
    string time_complexity;
    string space_complexity;
    int lines_of_code;
    int runtime_ms;
    int memory_kb;
    string notes;
};

class SolutionAnalyzer {
public:
    void addSolution(const Solution& s) {
        solutions_.push_back(s);
    }

    void compareTable() {
        cout << "=== Tabel Perbandingan Solusi ===\n\n";
        cout << left << setw(15) << "Author"
             << setw(20) << "Approach"
             << setw(15) << "Time"
             << setw(15) << "Space"
             << setw(7)  << "LOC"
             << setw(9)  << "Run(ms)"
             << setw(11) << "Mem(kb)" << "\n";
        cout << "---------------|--------------------|---------------|---------------|-------|---------|----------\n";
        for (const auto& s : solutions_) {
            cout << left << setw(15) << s.author
                 << setw(20) << s.approach
                 << setw(15) << s.time_complexity
                 << setw(15) << s.space_complexity
                 << setw(7)  << s.lines_of_code
                 << setw(9)  << s.runtime_ms
                 << setw(11) << s.memory_kb << "\n";
        }
    }

    void rankBy(string metric) {
        cout << "\n=== Rank by " << metric << " (ascending) ===\n";
        vector<Solution> sorted = solutions_;
        if (metric == "runtime") {
            sort(sorted.begin(), sorted.end(),
                 [](const Solution& a, const Solution& b) {
                     return a.runtime_ms < b.runtime_ms;
                 });
        } else if (metric == "memory") {
            sort(sorted.begin(), sorted.end(),
                 [](const Solution& a, const Solution& b) {
                     return a.memory_kb < b.memory_kb;
                 });
        } else if (metric == "loc") {
            sort(sorted.begin(), sorted.end(),
                 [](const Solution& a, const Solution& b) {
                     return a.lines_of_code < b.lines_of_code;
                 });
        }
        for (size_t i = 0; i < sorted.size(); ++i) {
            cout << "  " << (i+1) << ". " << left << setw(15) << sorted[i].author
                 << " (" << sorted[i].approach << ")\n";
        }
    }

    void lessons() {
        cout << "\n=== Pelajaran dari Perbandingan ===\n";
        for (const auto& s : solutions_) {
            cout << "- [" << s.author << "] " << s.notes << "\n";
        }
    }

private:
    vector<Solution> solutions_;
};

int main() {
    SolutionAnalyzer analyzer;

    // 4 solusi berbeda untuk soal Two Sum (unsorted)
    analyzer.addSolution({"tourist", "Hash map one-pass",
                          "O(n)", "O(n)", 8, 4, 10240,
                          "Hash map memberi lookup O(1); satu pass cukup"});
    analyzer.addSolution({"neal_wu", "Hash map two-pass",
                          "O(n)", "O(n)", 12, 5, 10240,
                          "Lebih jelas; pass 1 build map, pass 2 lookup. Cost: 2x iterasi."});
    analyzer.addSolution({"Benq",    "Sort + two pointers",
                          "O(n log n)", "O(n)", 18, 8, 8192,
                          "Sort mengubah indeks asli; perlu simpan pasangan (val, idx)."});
    analyzer.addSolution({"abc_dude","Brute force",
                          "O(n^2)", "O(1)", 6, 45, 1024,
                          "Tidak praktis untuk n>10^4, tapi baseline penting."});

    analyzer.compareTable();
    analyzer.rankBy("runtime");
    analyzer.rankBy("memory");
    analyzer.rankBy("loc");
    analyzer.lessons();

    cout << "\n=== Strategi Analisis ===\n";
    cout << "1. Identifikasi pola: hash map, two pointers, sort, dll\n";
    cout << "2. Bandingkan time/space complexity - pahami trade-off\n";
    cout << "3. Cek edge case: bagaimana duplikat, input kosong, n=1?\n";
    cout << "4. Pelajari idiom bahasa: mis. C++ unordered_map vs map\n";
    cout << "5. Adaptasi ke konteks lain: mis. bila sorted, ganti hash map jadi 2 ptr\n";
    cout << "6. Catat idiom baru ke 'snippets library' pribadi\n";
    return 0;
}

Output yang Dihasilkan:

text
=== Tabel Perbandingan Solusi ===

Author         Approach            Time           Space          LOC    Run(ms)  Mem(kb)
---------------|--------------------|---------------|---------------|-------|---------|----------
tourist        Hash map one-pass   O(n)           O(n)           8      4        10240
neal_wu        Hash map two-pass   O(n)           O(n)           12     5        10240
Benq           Sort + two pointers O(n log n)     O(n)           18     8        8192
abc_dude       Brute force         O(n^2)         O(1)           6      45       1024

=== Rank by runtime (ascending) ===
  1. tourist         (Hash map one-pass)
  2. neal_wu         (Hash map two-pass)
  3. Benq            (Sort + two pointers)
  4. abc_dude        (Brute force)

=== Rank by memory (ascending) ===
  1. abc_dude        (Brute force)
  2. Benq            (Sort + two pointers)
  3. tourist         (Hash map one-pass)
  4. neal_wu         (Hash map two-pass)

=== Rank by loc (ascending) ===
  1. abc_dude        (Brute force)
  2. tourist         (Hash map one-pass)
  3. neal_wu         (Hash map two-pass)
  4. Benq            (Sort + two pointers)

=== Pelajaran dari Perbandingan ===
- [tourist] Hash map memberi lookup O(1); satu pass cukup
- [neal_wu] Lebih jelas; pass 1 build map, pass 2 lookup. Cost: 2x iterasi.
- [Benq] Sort mengubah indeks asli; perlu simpan pasangan (val, idx).
- [abc_dude] Tidak praktis untuk n>10^4, tapi baseline penting.

=== Strategi Analisis ===
1. Identifikasi pola: hash map, two pointers, sort, dll
2. Bandingkan time/space complexity - pahami trade-off
3. Cek edge case: bagaimana duplikat, input kosong, n=1?
4. Pelajari idiom bahasa: mis. C++ unordered_map vs map
5. Adaptasi ke konteks lain: mis. bila sorted, ganti hash map jadi 2 ptr
6. Catat idiom baru ke 'snippets library' pribadi

Bedah Kode Baris-per-Baris #

  1. struct Solution { string author; string approach; string time_complexity; ... }: model data solusi dengan semua metrik relevan. Pemisahan field memungkinkan sorting berdasarkan dimensi berbeda.
  2. vector<Solution> solutions_;: simpan solusi sebagai vector (bukan map) karena key tidak unik dan order input penting untuk display. Vector juga efisien untuk iterasi.
  3. cout << left << setw(15) << "Author" << ...: header tabel dengan format alignment. left untuk rata kiri, setw mengatur lebar kolom. Konsistensi lebar kolom menghasilkan tabel yang rapi.
  4. void rankBy(string metric): fungsi generik untuk ranking berdasarkan metrik berbeda. Pemilihan string (bukan enum) untuk kemudahan demo; pada produksi, gunakan enum untuk type safety.
  5. sort(sorted.begin(), sorted.end(), [metric](const Solution& a, const Solution& b) { ... }): sorting dengan lambda comparator. Lambda menangkap metric by value — cukup untuk kasus sederhana.
  6. vector<Solution> sorted = solutions_;: copy untuk sorting — menjaga urutan asli solutions_ tetap utuh saat ranking berbeda. Copy vector adalah O(n) tetapi acceptable untuk ukuran kecil.

Trade-Off: Hash Map vs Sort + Two Pointers #

Perbandingan dua pendekatan populer untuk Two Sum:

AspekHash Map (one-pass)Sort + Two Pointers
TimeO(n)O(n log n)
SpaceO(n)O(n) untuk simpan pasangan (val, idx)
Cocok jikaInput unsortedInput sudah sorted, atau boleh modifikasi
KelebihanCepatLebih hemat memori bila input sorted
KekuranganOverhead hash functionSort mengubah indeks asli
Edge caseDuplikat key perlu hati-hatiTidak bisa langsung kembalikan indeks asli

Sumber Solusi untuk Dibandingkan #

PlatformKarakteristikCocok untuk
Codeforces submissionsBanyak top user, format ICPCBelajar idiom competitive
LeetCode DiscussKomentar menjelaskan, multi-bahasaBelajar berbagai pendekatan
AtCoder editorialSolusi resmi + user submissionKonteks problem-setting
GitHub (private repo)Snippet pribadiReuse idiom

Membangun Snippets Library #

Setiap solusi yang menarik harus dicatat sebagai snippet reusable. Format yang berguna:

text
[Topic: Hash Map]
[Problem: Two Sum]
[Pattern: One-pass hash map]

Code:
  unordered_map<int,int> seen;
  for (int i = 0; i < nums.size(); ++i) {
      auto it = seen.find(target - nums[i]);
      if (it != seen.end()) return {it->second, i};
      seen[nums[i]] = i;
  }

When to use:
  - Input unsorted
  - Need O(n) lookup
  - Memory O(n) acceptable

Variations:
  - Two Sum II (sorted): two pointers, O(n) time O(1) space
  - Three Sum: sort + two pointers per elemen
  - Four Sum: nested two pointers atau hash map pair sum

Library ini menjadi aset pribadi yang lebih bernilai daripada tutorial generik — karena berisi konteks spesifik dan catatan personal.

Hal yang Harus Diperhatikan Saat Membaca #

AspekApa yang Dilihat
Tipe dataint vs long long? unsigned?
Header#include apa yang dipakai?
Konstantaconst int MOD = 1e9+7;?
Macro#define all(x) x.begin(), x.end()?
TemplateApakah ada template khusus (mis. fast I/O)?
Edge casen=0, n=1, duplikat, overflow?
ReadabilityVariabel self-documenting atau cryptic?
CommentApakah ada komentar penjelasan?

Bahaya “Worship Top Coder” #

Saat membaca solusi top user (mis. tourist, Benq), ada risiko mengasumsikan mereka selalu benar. Padahal:

JebakanKenyataan
“Tourist pakai macro, saya juga harus”Macro adalah preferensi gaya, bukan keharusan
“Solusi pendek pasti lebih baik”Kadang readability > brevity
“AC = optimal”AC hanya berarti lulus test case, bukan paling optimal
“Top user tidak pernah brute force”Mereka brute force bila cukup untuk constraint

Ringkasan #

  • Membaca 3–5 solusi alternatif memperluas wawasan dan membangun snippets library.
  • Bandingkan time/space complexity, lines of code, runtime, dan memory.
  • Setiap solusi punya trade-off — pahami kapan satu pendekatan unggul atas yang lain.
  • Catat snippet dengan konteks: kapan dipakai, variasi, edge case.
  • Review snippets library secara berkala agar tetap relevan.
  • Jangan worship top coder — pilih idiom yang sesuai gaya pribadi.