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:
| Manfaat | Cara Memanfaatkan |
|---|---|
| Lihat pola umum | Identifikasi algoritma inti yang dipakai mayoritas |
| Variasi idiom | Adaptasi idiom bahasa yang lebih efisien |
| Trade-off | Pahami kapan time > space dan sebaliknya |
| Edge case handling | Pelajari cara orang lain handle input aneh |
| Code golf vs readability | Pilih keseimbangan yang sesuai gaya kita |
Strategi Analisis Solusi #
Proses analisis yang baik bukan sekadar membaca kode, tetapi membandingkan dan menggeneralisasi:
| Langkah | Pertanyaan | Output |
|---|---|---|
| 1. Identifikasi pola | Algoritma apa yang dipakai? | Tag pola (hash map, 2 ptr, …) |
| 2. Kompleksitas | Time dan space Big-O? | Tabel perbandingan |
| 3. Edge case | Bagaimana input kosong, n=1, duplikat? | Daftar handling |
| 4. Idiom bahasa | Apa trik C++/Python yang dipakai? | Snippet untuk reuse |
| 5. Trade-off | Lebih cepat tapi boros memori? | Decision matrix |
| 6. Generalisasi | Pola ini berlaku untuk soal apa lagi? | Daftar soal serupa |
Kode: Solution Analyzer #
#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:
=== 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' pribadiBedah Kode Baris-per-Baris #
struct Solution { string author; string approach; string time_complexity; ... }: model data solusi dengan semua metrik relevan. Pemisahan field memungkinkan sorting berdasarkan dimensi berbeda.vector<Solution> solutions_;: simpan solusi sebagai vector (bukan map) karena key tidak unik dan order input penting untuk display. Vector juga efisien untuk iterasi.cout << left << setw(15) << "Author" << ...: header tabel dengan format alignment.leftuntuk rata kiri,setwmengatur lebar kolom. Konsistensi lebar kolom menghasilkan tabel yang rapi.void rankBy(string metric): fungsi generik untuk ranking berdasarkan metrik berbeda. Pemilihanstring(bukan enum) untuk kemudahan demo; pada produksi, gunakan enum untuk type safety.sort(sorted.begin(), sorted.end(), [metric](const Solution& a, const Solution& b) { ... }): sorting dengan lambda comparator. Lambda menangkapmetricby value — cukup untuk kasus sederhana.vector<Solution> sorted = solutions_;: copy untuk sorting — menjaga urutan aslisolutions_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:
| Aspek | Hash Map (one-pass) | Sort + Two Pointers |
|---|---|---|
| Time | O(n) | O(n log n) |
| Space | O(n) | O(n) untuk simpan pasangan (val, idx) |
| Cocok jika | Input unsorted | Input sudah sorted, atau boleh modifikasi |
| Kelebihan | Cepat | Lebih hemat memori bila input sorted |
| Kekurangan | Overhead hash function | Sort mengubah indeks asli |
| Edge case | Duplikat key perlu hati-hati | Tidak bisa langsung kembalikan indeks asli |
Sumber Solusi untuk Dibandingkan #
| Platform | Karakteristik | Cocok untuk |
|---|---|---|
| Codeforces submissions | Banyak top user, format ICPC | Belajar idiom competitive |
| LeetCode Discuss | Komentar menjelaskan, multi-bahasa | Belajar berbagai pendekatan |
| AtCoder editorial | Solusi resmi + user submission | Konteks problem-setting |
| GitHub (private repo) | Snippet pribadi | Reuse idiom |
Membangun Snippets Library #
Setiap solusi yang menarik harus dicatat sebagai snippet reusable. Format yang berguna:
[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 sumLibrary ini menjadi aset pribadi yang lebih bernilai daripada tutorial generik — karena berisi konteks spesifik dan catatan personal.
Hal yang Harus Diperhatikan Saat Membaca #
| Aspek | Apa yang Dilihat |
|---|---|
| Tipe data | int vs long long? unsigned? |
| Header | #include apa yang dipakai? |
| Konstanta | const int MOD = 1e9+7;? |
| Macro | #define all(x) x.begin(), x.end()? |
| Template | Apakah ada template khusus (mis. fast I/O)? |
| Edge case | n=0, n=1, duplikat, overflow? |
| Readability | Variabel self-documenting atau cryptic? |
| Comment | Apakah ada komentar penjelasan? |
Bahaya “Worship Top Coder” #
Saat membaca solusi top user (mis. tourist, Benq), ada risiko mengasumsikan mereka selalu benar. Padahal:
| Jebakan | Kenyataan |
|---|---|
| “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.