[{"data":1,"prerenderedAt":106635},["ShallowReactive",2],{"search-navigation":3,"challenges-all":961,"challenges-fundamentals":90883},[4,54],{"title":5,"path":6,"stem":7,"children":8,"page":53},"Fundamentals","\u002Ffundamentals","fundamentals",[9,13,17,21,25,29,33,37,41,45,49],{"title":10,"path":11,"stem":12},"Ký hiệu Big-O và các lớp tăng trưởng","\u002Ffundamentals\u002Fbig-o-notation","fundamentals\u002Fbig-o-notation",{"title":14,"path":15,"stem":16},"Chiều dữ liệu và chiều tính toán","\u002Ffundamentals\u002Fchieu-du-lieu-va-tinh-toan","fundamentals\u002Fchieu-du-lieu-va-tinh-toan",{"title":18,"path":19,"stem":20},"Đệ quy: tư duy và cái giá","\u002Ffundamentals\u002Fde-quy","fundamentals\u002Fde-quy",{"title":22,"path":23,"stem":24},"Giải thuật ngẫu nhiên và độ chính xác","\u002Ffundamentals\u002Fgiai-thuat-ngau-nhien-va-do-chinh-xac","fundamentals\u002Fgiai-thuat-ngau-nhien-va-do-chinh-xac",{"title":26,"path":27,"stem":28},"Nguyên lý thiết kế hướng đối tượng","\u002Ffundamentals\u002Fnguyen-ly-thiet-ke-huong-doi-tuong","fundamentals\u002Fnguyen-ly-thiet-ke-huong-doi-tuong",{"title":30,"path":31,"stem":32},"Nhập môn design patterns","\u002Ffundamentals\u002Fnhap-mon-design-patterns","fundamentals\u002Fnhap-mon-design-patterns",{"title":34,"path":35,"stem":36},"P, NP và độ khó bài toán","\u002Ffundamentals\u002Fp-np-va-do-kho","fundamentals\u002Fp-np-va-do-kho",{"title":38,"path":39,"stem":40},"Mô hình RAM và chi phí tính toán","\u002Ffundamentals\u002Fram-model-va-chi-phi","fundamentals\u002Fram-model-va-chi-phi",{"title":42,"path":43,"stem":44},"Thiết kế và kiểm chứng thuật toán","\u002Ffundamentals\u002Fthiet-ke-va-kiem-chung-thuat-toan","fundamentals\u002Fthiet-ke-va-kiem-chung-thuat-toan",{"title":46,"path":47,"stem":48},"Thuật toán và môi trường phát triển","\u002Ffundamentals\u002Fthuat-toan-moi-truong-phat-trien","fundamentals\u002Fthuat-toan-moi-truong-phat-trien",{"title":50,"path":51,"stem":52},"Độ phức tạp thời gian và không gian","\u002Ffundamentals\u002Ftime-space-complexity","fundamentals\u002Ftime-space-complexity",false,{"title":55,"path":56,"stem":57,"children":58,"page":53},"Challenges","\u002Fchallenges","challenges",[59,64,69,74,79,84,89,94,99,104,109,114,119,124,129,134,139,144,149,154,159,164,169,174,179,184,189,194,199,204,209,214,219,224,229,234,239,244,249,254,259,264,269,274,279,284,289,294,299,304,309,314,319,324,329,334,339,344,349,354,359,364,369,374,379,384,389,394,399,404,409,414,419,424,429,434,439,444,449,454,459,464,469,474,479,484,489,494,499,504,509,514,519,524,529,534,539,544,549,554,559,564,569,574,579,584,589,594,599,604,609,614,619,624,629,634,639,644,649,654,659,664,669,674,679,684,689,694,699,704,709,714,719,724,729,734,739,744,749,754,759,764,769,774,779,786,791,796,801,806,811,816,821,826,831,836,841,846,851,856,861,866,871,876,881,886,891,896,901,906,911,916,921,926,931,936,941,946,951,956],{"title":60,"path":61,"stem":62,"day":63},"Dynamic Array: mảng động và cách tự cài đặt","\u002Fchallenges\u002Fmang-va-danh-sach","challenges\u002F1.mang-va-danh-sach",1,{"title":65,"path":66,"stem":67,"day":68},"Linked list đơn, đôi và so sánh với mảng","\u002Fchallenges\u002Flinked-list","challenges\u002F2.linked-list",2,{"title":70,"path":71,"stem":72,"day":73},"SOLID, Open-Closed và Dependency Inversion thực hành","\u002Fchallenges\u002Fsolid-thuc-hanh","challenges\u002F3.solid-thuc-hanh",3,{"title":75,"path":76,"stem":77,"day":78},"Stack, queue, deque: LIFO, FIFO và ứng dụng","\u002Fchallenges\u002Fstack-va-queue","challenges\u002F4.stack-va-queue",4,{"title":80,"path":81,"stem":82,"day":83},"Dictionary, set và ý tưởng băm","\u002Fchallenges\u002Fdictionary-va-set","challenges\u002F5.dictionary-va-set",5,{"title":85,"path":86,"stem":87,"day":88},"Strategy: đóng gói họ thuật toán bay và kêu của vịt","\u002Fchallenges\u002Fstrategy-pattern","challenges\u002F6.strategy-pattern",6,{"title":90,"path":91,"stem":92,"day":93},"Cây và binary search tree: thuật ngữ và bất biến","\u002Fchallenges\u002Fcay-va-bst","challenges\u002F7.cay-va-bst",7,{"title":95,"path":96,"stem":97,"day":98},"Thực hành đệ quy: base case, trace và memo","\u002Fchallenges\u002Fde-quy-thuc-hanh","challenges\u002F8.de-quy-thuc-hanh",8,{"title":100,"path":101,"stem":102,"day":103},"Observer: publisher-subscriber và loose coupling","\u002Fchallenges\u002Fobserver-co-ban","challenges\u002F9.observer-co-ban",9,{"title":105,"path":106,"stem":107,"day":108},"Bộ ba sắp xếp O(n²): bubble, selection, insertion","\u002Fchallenges\u002Fsap-xep-co-ban","challenges\u002F10.sap-xep-co-ban",10,{"title":110,"path":111,"stem":112,"day":113},"Sắp xếp hiệu quả: merge, shell, quick và cách chọn","\u002Fchallenges\u002Fsap-xep-hieu-qua","challenges\u002F11.sap-xep-hieu-qua",11,{"title":115,"path":116,"stem":117,"day":118},"Decorator: Starbuzz Coffee và chuỗi bọc","\u002Fchallenges\u002Fdecorator-co-ban","challenges\u002F12.decorator-co-ban",12,{"title":120,"path":121,"stem":122,"day":123},"Tìm kiếm: linear, binary và interpolation","\u002Fchallenges\u002Ftim-kiem-co-ban","challenges\u002F13.tim-kiem-co-ban",13,{"title":125,"path":126,"stem":127,"day":128},"Ma trận và bảng dữ liệu trong thuật toán","\u002Fchallenges\u002Fma-tran-va-du-lieu-bang","challenges\u002F14.ma-tran-va-du-lieu-bang",14,{"title":130,"path":131,"stem":132,"day":133},"Observer nâng cao: pull vs push và trạm thời tiết","\u002Fchallenges\u002Fobserver-nang-cao","challenges\u002F15.observer-nang-cao",15,{"title":135,"path":136,"stem":137,"day":138},"Brute-force và greedy nhập môn qua TSP","\u002Fchallenges\u002Fbrute-force-va-greedy","challenges\u002F16.brute-force-va-greedy",16,{"title":140,"path":141,"stem":142,"day":143},"Quy hoạch động: bài toán con gối nhau và memo","\u002Fchallenges\u002Fquy-hoach-dong-nhap-mon","challenges\u002F17.quy-hoach-dong-nhap-mon",17,{"title":145,"path":146,"stem":147,"day":148},"Simple Factory: đóng gói khởi tạo đối tượng pizza","\u002Fchallenges\u002Fsimple-factory","challenges\u002F18.simple-factory",18,{"title":150,"path":151,"stem":152,"day":153},"Singleton: Chocolate Factory và an toàn đa luồng","\u002Fchallenges\u002Fsingleton-pattern","challenges\u002F19.singleton-pattern",19,{"title":155,"path":156,"stem":157,"day":158},"Adapter: vịt-gà tây và object vs class adapter","\u002Fchallenges\u002Fadapter-pattern","challenges\u002F20.adapter-pattern",20,{"title":160,"path":161,"stem":162,"day":163},"Mini project 1: benchmark sắp xếp và cấu trúc cơ bản","\u002Fchallenges\u002Fmini-project-sort","challenges\u002F21.mini-project-sort",21,{"title":165,"path":166,"stem":167,"day":168},"Học không giám sát - vòng đời, khoảng cách, phân khúc","\u002Fchallenges\u002Funsupervised-tong-quan","challenges\u002F22.unsupervised-tong-quan",22,{"title":170,"path":171,"stem":172,"day":173},"Priority queue và binary heap: API và biểu diễn mảng","\u002Fchallenges\u002Fpriority-queue-va-heap","challenges\u002F23.priority-queue-va-heap",23,{"title":175,"path":176,"stem":177,"day":178},"Thao tác heap: BubbleUp, PushDown, Heapify, Top, Update","\u002Fchallenges\u002Fheap-operations","challenges\u002F24.heap-operations",24,{"title":180,"path":181,"stem":182,"day":183},"Factory Method: framework và creator song song product","\u002Fchallenges\u002Ffactory-method","challenges\u002F25.factory-method",25,{"title":185,"path":186,"stem":187,"day":188},"D-ary heap, branching factor và bài toán top-K","\u002Fchallenges\u002Fd-ary-heap-va-topk","challenges\u002F26.d-ary-heap-va-topk",26,{"title":190,"path":191,"stem":192,"day":193},"Mã Huffman: nén tham lam bằng heap","\u002Fchallenges\u002Fma-huffman","challenges\u002F27.ma-huffman",27,{"title":195,"path":196,"stem":197,"day":198},"Command: remote control và khe cắm lệnh","\u002Fchallenges\u002Fcommand-co-ban","challenges\u002F28.command-co-ban",28,{"title":200,"path":201,"stem":202,"day":203},"Treap: BST kết hợp heap và phép xoay","\u002Fchallenges\u002Ftreap-co-ban","challenges\u002F29.treap-co-ban",29,{"title":205,"path":206,"stem":207,"day":208},"Bloom filter: cơ chế bit, false positive và ứng dụng","\u002Fchallenges\u002Fbo-loc-bloom","challenges\u002F30.bo-loc-bloom",30,{"title":210,"path":211,"stem":212,"day":213},"Facade: rạp hát tại gia và Least Knowledge","\u002Fchallenges\u002Ffacade-pattern","challenges\u002F31.facade-pattern",31,{"title":215,"path":216,"stem":217,"day":218},"Disjoint set: bài toán distinct subsets và cài đặt naive","\u002Fchallenges\u002Fdisjoint-set-co-ban","challenges\u002F32.disjoint-set-co-ban",32,{"title":220,"path":221,"stem":222,"day":223},"Union-Find tối ưu và Kruskal tìm cây khung","\u002Fchallenges\u002Funion-find-va-kruskal","challenges\u002F33.union-find-va-kruskal",33,{"title":225,"path":226,"stem":227,"day":228},"Template Method: khung pha chế và Hollywood principle","\u002Fchallenges\u002Ftemplate-method","challenges\u002F34.template-method",34,{"title":230,"path":231,"stem":232,"day":233},"Trie: nút, cạnh, search, insert, remove, prefix","\u002Fchallenges\u002Ftrie-co-ban","challenges\u002F35.trie-co-ban",35,{"title":235,"path":236,"stem":237,"day":238},"Radix trie nén cạnh và ứng dụng autocomplete, spell-check","\u002Fchallenges\u002Fradix-trie-va-ung-dung","challenges\u002F36.radix-trie-va-ung-dung",36,{"title":240,"path":241,"stem":242,"day":243},"Iterator: sáp nhập quán ăn và single responsibility","\u002Fchallenges\u002Fiterator-pattern","challenges\u002F37.iterator-pattern",37,{"title":245,"path":246,"stem":247,"day":248},"Hash table nâng cao: hàm băm và xử lý xung đột","\u002Fchallenges\u002Fhash-table-nang-cao","challenges\u002F38.hash-table-nang-cao",38,{"title":250,"path":251,"stem":252,"day":253},"LRU cache: thứ tự thời gian và đuổi dữ liệu cũ","\u002Fchallenges\u002Flru-cache","challenges\u002F39.lru-cache",39,{"title":255,"path":256,"stem":257,"day":258},"Biểu diễn đồ thị và BFS tìm đường ngắn nhất","\u002Fchallenges\u002Fdo-thi-va-bfs","challenges\u002F40.do-thi-va-bfs",40,{"title":260,"path":261,"stem":262,"day":263},"DFS, ngăn xếp và so sánh với BFS","\u002Fchallenges\u002Fdfs-va-so-sanh","challenges\u002F41.dfs-va-so-sanh",41,{"title":265,"path":266,"stem":267,"day":268},"Dijkstra với heap cho đồ thị có trọng số","\u002Fchallenges\u002Fdijkstra-voi-heap","challenges\u002F42.dijkstra-voi-heap",42,{"title":270,"path":271,"stem":272,"day":273},"A* heuristic và Prim cây khung nhỏ nhất","\u002Fchallenges\u002Fa-star-va-prim","challenges\u002F43.a-star-va-prim",43,{"title":275,"path":276,"stem":277,"day":278},"Egonet và centrality - degree, betweenness, closeness, eigenvector","\u002Fchallenges\u002Fcentrality-va-egonet","challenges\u002F44.centrality-va-egonet",44,{"title":280,"path":281,"stem":282,"day":283},"K-d tree - luân phiên chiều, bất biến và cân bằng","\u002Fchallenges\u002Fkd-tree-co-ban","challenges\u002F45.kd-tree-co-ban",45,{"title":285,"path":286,"stem":287,"day":288},"Ứng dụng NN - nearest hub, giảm màu ảnh, hạt vật lý","\u002Fchallenges\u002Fung-dung-nn-search","challenges\u002F46.ung-dung-nn-search",46,{"title":290,"path":291,"stem":292,"day":293},"K-means - khởi tạo, hội tụ và curse of dimensionality","\u002Fchallenges\u002Fkmeans","challenges\u002F47.kmeans",47,{"title":295,"path":296,"stem":297,"day":298},"DBSCAN - density-reachable, lõi, biên, nhiễu","\u002Fchallenges\u002Fdbscan","challenges\u002F48.dbscan",48,{"title":300,"path":301,"stem":302,"day":303},"Đánh giá clustering - silhouette và diễn giải","\u002Fchallenges\u002Fdanh-gia-clustering","challenges\u002F49.danh-gia-clustering",49,{"title":305,"path":306,"stem":307,"day":308},"MapReduce - map, reduce qua ví dụ Donald Duck","\u002Fchallenges\u002Fmapreduce-co-ban","challenges\u002F50.mapreduce-co-ban",50,{"title":310,"path":311,"stem":312,"day":313},"Luật giỏ hàng - Apriori và FP-growth","\u002Fchallenges\u002Fluat-gio-hang","challenges\u002F51.luat-gio-hang",51,{"title":315,"path":316,"stem":317,"day":318},"Học có giám sát - pipeline, scaling và phân loại bài toán","\u002Fchallenges\u002Fsupervised-tong-quan","challenges\u002F52.supervised-tong-quan",52,{"title":320,"path":321,"stem":322,"day":323},"Decision tree - split, impurity và pruning","\u002Fchallenges\u002Fcay-quyet-dinh","challenges\u002F53.cay-quyet-dinh",53,{"title":325,"path":326,"stem":327,"day":328},"Naive Bayes và mô hình xác suất cho text","\u002Fchallenges\u002Fnaive-bayes","challenges\u002F54.naive-bayes",54,{"title":330,"path":331,"stem":332,"day":333},"Hồi quy tuyến tính, bội và logistic","\u002Fchallenges\u002Fhoi-quy","challenges\u002F55.hoi-quy",55,{"title":335,"path":336,"stem":337,"day":338},"Đánh giá mô hình - confusion matrix, precision, recall, overfitting","\u002Fchallenges\u002Fdanh-gia-mo-hinh","challenges\u002F56.danh-gia-mo-hinh",56,{"title":340,"path":341,"stem":342,"day":343},"NLP cơ bản: tokenize, BoW và TF-IDF","\u002Fchallenges\u002Fnlp-co-ban","challenges\u002F57.nlp-co-ban",57,{"title":345,"path":346,"stem":347,"day":348},"Gợi ý content-based và đồng xuất hiện","\u002Fchallenges\u002Frecsys-content","challenges\u002F58.recsys-content",58,{"title":350,"path":351,"stem":352,"day":353},"Collaborative filtering user-based và item-based","\u002Fchallenges\u002Frecsys-collaborative","challenges\u002F59.recsys-collaborative",59,{"title":355,"path":356,"stem":357,"day":358},"CAP theorem và lưu trữ phân tán","\u002Fchallenges\u002Fcap-va-luu-tru","challenges\u002F60.cap-va-luu-tru",60,{"title":360,"path":361,"stem":362,"day":363},"Nén dữ liệu: LZ77 và định dạng nâng cao","\u002Fchallenges\u002Fnen-du-lieu","challenges\u002F61.nen-du-lieu",61,{"title":365,"path":366,"stem":367,"day":368},"Mật mã cơ bản: thay thế, hoán vị, băm, đối xứng","\u002Fchallenges\u002Fcrypto-co-ban","challenges\u002F62.crypto-co-ban",62,{"title":370,"path":371,"stem":372,"day":373},"Explainability: hộp trắng, hộp đen và giảm bias","\u002Fchallenges\u002Fexplainability-dao-duc","challenges\u002F63.explainability-dao-duc",63,{"title":375,"path":376,"stem":377,"day":378},"Tổ chức patterns C\u002FS\u002FB và anti-patterns","\u002Fchallenges\u002Fto-chuc-anti-patterns","challenges\u002F64.to-chuc-anti-patterns",64,{"title":380,"path":381,"stem":382,"day":383},"Treap nâng cao: insert, delete và cân bằng kỳ vọng","\u002Fchallenges\u002Ftreap-nang-cao","challenges\u002F65.treap-nang-cao",65,{"title":385,"path":386,"stem":387,"day":388},"LFU, freshness, async và khóa đồng bộ trong cache","\u002Fchallenges\u002Flfu-va-chien-luoc-cache","challenges\u002F66.lfu-va-chien-luoc-cache",66,{"title":390,"path":391,"stem":392,"day":393},"Composite: thực đơn cây, trong suốt vs an toàn","\u002Fchallenges\u002Fcomposite-pattern","challenges\u002F67.composite-pattern",67,{"title":395,"path":396,"stem":397,"day":398},"Kết hợp Iterator và Composite duyệt cây đệ quy","\u002Fchallenges\u002Fiterator-composite","challenges\u002F68.iterator-composite",68,{"title":400,"path":401,"stem":402,"day":403},"Nearest neighbor và region search trên k-d tree","\u002Fchallenges\u002Fkd-tree-nang-cao","challenges\u002F69.kd-tree-nang-cao",69,{"title":405,"path":406,"stem":407,"day":408},"Bài toán nearest neighbor và R-tree indexing","\u002Fchallenges\u002Fnn-search-va-rtree","challenges\u002F70.nn-search-va-rtree",70,{"title":410,"path":411,"stem":412,"day":413},"Decorator thực tế: thư viện vào-ra và tự viết decorator","\u002Fchallenges\u002Fdecorator-io","challenges\u002F71.decorator-io",71,{"title":415,"path":416,"stem":417,"day":418},"Case study phát hiện gian lận bằng SNA và watchtower","\u002Fchallenges\u002Fgian-lan-watchtower","challenges\u002F72.gian-lan-watchtower",72,{"title":420,"path":421,"stem":422,"day":423},"PageRank lan truyền điểm số và damping","\u002Fchallenges\u002Fpagerank","challenges\u002F73.pagerank",73,{"title":425,"path":426,"stem":427,"day":428},"Abstract Factory: họ nguyên liệu và vùng miền","\u002Fchallenges\u002Fabstract-factory","challenges\u002F74.abstract-factory",74,{"title":430,"path":431,"stem":432,"day":433},"So sánh 3 factory và nghịch lý mở rộng","\u002Fchallenges\u002Ffactory-so-sanh","challenges\u002F75.factory-so-sanh",75,{"title":435,"path":436,"stem":437,"day":438},"Quy hoạch tuyến tính - hàm mục tiêu, ràng buộc, capacity planning","\u002Fchallenges\u002Fquy-hoach-tuyen-tinh","challenges\u002F76.quy-hoach-tuyen-tinh",76,{"title":440,"path":441,"stem":442,"day":443},"Quy hoạch động nâng cao - overlapping, tái cấu trúc nghiệm","\u002Fchallenges\u002Fquy-hoach-dong-nang-cao","challenges\u002F77.quy-hoach-dong-nang-cao",77,{"title":445,"path":446,"stem":447,"day":448},"TSP dưới 3 chiến lược - brute-force, greedy, DP","\u002Fchallenges\u002Ftsp-ba-chien-luoc","challenges\u002F78.tsp-ba-chien-luoc",78,{"title":450,"path":451,"stem":452,"day":453},"Đồ thị phẳng: nhúng và định lý Kuratowski","\u002Fchallenges\u002Fdo-thi-phang","challenges\u002F79.do-thi-phang",79,{"title":455,"path":456,"stem":457,"day":458},"Mini project 2 - tuyến giao hàng BFS, DFS, Dijkstra","\u002Fchallenges\u002Fmini-project-graph","challenges\u002F80.mini-project-graph",80,{"title":460,"path":461,"stem":462,"day":463},"Command: undo bằng state và macro mở tiệc","\u002Fchallenges\u002Fcommand-undo-macro","challenges\u002F81.command-undo-macro",81,{"title":465,"path":466,"stem":467,"day":468},"Command thực tế: hàng đợi, logging và ActionListener","\u002Fchallenges\u002Fcommand-queue-log","challenges\u002F82.command-queue-log",82,{"title":470,"path":471,"stem":472,"day":473},"OPTICS và phân cụm phân cấp","\u002Fchallenges\u002Foptics-phan-cap","challenges\u002F83.optics-phan-cap",83,{"title":475,"path":476,"stem":477,"day":478},"Giảm chiều PCA - vector riêng và PC1, PC2","\u002Fchallenges\u002Fgiam-chieu-pca","challenges\u002F84.giam-chieu-pca",84,{"title":480,"path":481,"stem":482,"day":483},"State: máy bán kẹo và ủy thác trạng thái","\u002Fchallenges\u002Fstate-co-ban","challenges\u002F85.state-co-ban",85,{"title":485,"path":486,"stem":487,"day":488},"State nâng cao: game 1\u002F10 và State vs Strategy","\u002Fchallenges\u002Fstate-nang-cao","challenges\u002F86.state-nang-cao",86,{"title":490,"path":491,"stem":492,"day":493},"MapReduce cho K-means và canopy clustering","\u002Fchallenges\u002Fmapreduce-kmeans-canopy","challenges\u002F87.mapreduce-kmeans-canopy",87,{"title":495,"path":496,"stem":497,"day":498},"MapReduce DBSCAN và khởi tạo centroid","\u002Fchallenges\u002Fmapreduce-dbscan","challenges\u002F88.mapreduce-dbscan",88,{"title":500,"path":501,"stem":502,"day":503},"Random forest, GBM và XGBoost","\u002Fchallenges\u002Frung-va-boosting","challenges\u002F89.rung-va-boosting",89,{"title":505,"path":506,"stem":507,"day":508},"SVM - margin, kernel và dữ liệu phi tuyến","\u002Fchallenges\u002Fsvm","challenges\u002F90.svm",90,{"title":510,"path":511,"stem":512,"day":513},"Matrix factorization, cold start và mô hình lai","\u002Fchallenges\u002Frecsys-nang-cao","challenges\u002F91.recsys-nang-cao",91,{"title":515,"path":516,"stem":517,"day":518},"Bridge và Builder còn lại nhưng quan trọng","\u002Fchallenges\u002Fbridge-builder","challenges\u002F92.bridge-builder",92,{"title":520,"path":521,"stem":522,"day":523},"Perceptron, XOR và kiến trúc mạng noron","\u002Fchallenges\u002Fperceptron-mang-noron","challenges\u002F93.perceptron-mang-noron",93,{"title":525,"path":526,"stem":527,"day":528},"Huấn luyện mạng: loss, backprop và hàm kích hoạt","\u002Fchallenges\u002Fhuan-luyen-mang","challenges\u002F94.huan-luyen-mang",94,{"title":530,"path":531,"stem":532,"day":533},"Mediator, Memento và Prototype","\u002Fchallenges\u002Fmediator-memento-prototype","challenges\u002F95.mediator-memento-prototype",95,{"title":535,"path":536,"stem":537,"day":538},"CNN: tích chập và gộp cho ảnh","\u002Fchallenges\u002Fcnn","challenges\u002F96.cnn",96,{"title":540,"path":541,"stem":542,"day":543},"GAN và transfer learning","\u002Fchallenges\u002Fgan-va-transfer","challenges\u002F97.gan-va-transfer",97,{"title":545,"path":546,"stem":547,"day":548},"Proxy: truy cập từ xa và virtual ảnh bìa","\u002Fchallenges\u002Fproxy-remote-virtual","challenges\u002F98.proxy-remote-virtual",98,{"title":550,"path":551,"stem":552,"day":553},"Word embedding và sentiment bằng Naive Bayes","\u002Fchallenges\u002Fembedding-sentiment","challenges\u002F99.embedding-sentiment",99,{"title":555,"path":556,"stem":557,"day":558},"Mô hình chuỗi và RNN với BPTT","\u002Fchallenges\u002Frnn-chuoi","challenges\u002F100.rnn-chuoi",100,{"title":560,"path":561,"stem":562,"day":563},"LSTM và GRU: cổng và trí nhớ dài hạn","\u002Fchallenges\u002Flstm-gru","challenges\u002F101.lstm-gru",101,{"title":565,"path":566,"stem":567,"day":568},"Attention, self-attention và Transformer","\u002Fchallenges\u002Fattention-transformer","challenges\u002F102.attention-transformer",102,{"title":570,"path":571,"stem":572,"day":573},"GPT vs BERT và Seq2Seq bottleneck","\u002Fchallenges\u002Fgpt-bert","challenges\u002F103.gpt-bert",103,{"title":575,"path":576,"stem":577,"day":578},"Chain of Responsibility và Flyweight","\u002Fchallenges\u002Fchain-flyweight","challenges\u002F104.chain-flyweight",104,{"title":580,"path":581,"stem":582,"day":583},"Stream processing thời gian thực và StreamSensing","\u002Fchallenges\u002Fstream-processing","challenges\u002F105.stream-processing",105,{"title":585,"path":586,"stem":587,"day":588},"Bất đối xứng, PKI, blockchain và chống MITM","\u002Fchallenges\u002Fcrypto-nang-cao","challenges\u002F106.crypto-nang-cao",106,{"title":590,"path":591,"stem":592,"day":593},"MVC: compound pattern điều khiển nhịp DJ","\u002Fchallenges\u002Fmvc-compound","challenges\u002F107.mvc-compound",107,{"title":595,"path":596,"stem":597,"day":598},"Đàn vịt compound: 4 patterns trong một app","\u002Fchallenges\u002Fcompound-ducks","challenges\u002F108.compound-ducks",108,{"title":600,"path":601,"stem":602,"day":603},"Spark, in-memory và elasticity hệ thống lớn","\u002Fchallenges\u002Fspark-large-scale","challenges\u002F109.spark-large-scale",109,{"title":605,"path":606,"stem":607,"day":608},"Hiệu năng tính toán: Amdahl, CUDA và data locality","\u002Fchallenges\u002Fhieu-nang-tinh-toan","challenges\u002F110.hieu-nang-tinh-toan",110,{"title":610,"path":611,"stem":612,"day":613},"Gradient descent: cost, step và local minima","\u002Fchallenges\u002Fgradient-descent","challenges\u002F111.gradient-descent",111,{"title":615,"path":616,"stem":617,"day":618},"Gradient cho hồi quy tuyến tính và graph embedding","\u002Fchallenges\u002Fgradient-ung-dung","challenges\u002F112.gradient-ung-dung",112,{"title":620,"path":621,"stem":622,"day":623},"Simulated annealing: leo lên để xuống đáy","\u002Fchallenges\u002Fsimulated-annealing","challenges\u002F113.simulated-annealing",113,{"title":625,"path":626,"stem":627,"day":628},"SA cho TSP: transition, 2-opt và tỉa cành","\u002Fchallenges\u002Fsa-tsp","challenges\u002F114.sa-tsp",114,{"title":630,"path":631,"stem":632,"day":633},"Giải thuật di truyền: chromosome, fitness, selection","\u002Fchallenges\u002Fgenetic-co-ban","challenges\u002F115.genetic-co-ban",115,{"title":635,"path":636,"stem":637,"day":638},"Project: refactor SimUDuck bằng Strategy và Observer","\u002Fchallenges\u002Fproject-simuduck","challenges\u002F116.project-simuduck",116,{"title":640,"path":641,"stem":642,"day":643},"Project: Pizza Store bằng Factory và Decorator","\u002Fchallenges\u002Fproject-pizza","challenges\u002F117.project-pizza",117,{"title":645,"path":646,"stem":647,"day":648},"Kể chuyện patterns và SOLID khi phỏng vấn","\u002Fchallenges\u002Fpatterns-phong-van","challenges\u002F118.patterns-phong-van",118,{"title":650,"path":651,"stem":652,"day":653},"SS-tree và similarity search gần đúng cho ảnh","\u002Fchallenges\u002Fss-tree-similarity","challenges\u002F119.ss-tree-similarity",119,{"title":655,"path":656,"stem":657,"day":658},"Planarity testing và crossing number tối thiểu","\u002Fchallenges\u002Fplanarity-crossing","challenges\u002F120.planarity-crossing",120,{"title":660,"path":661,"stem":662,"day":663},"SA vẽ đồ thị: force-directed và min edge crossing","\u002Fchallenges\u002Fsa-graph-drawing","challenges\u002F121.sa-graph-drawing",121,{"title":665,"path":666,"stem":667,"day":668},"Lai, đột biến và GA cho TSP, vertex cover","\u002Fchallenges\u002Fgenetic-nang-cao","challenges\u002F122.genetic-nang-cao",122,{"title":670,"path":671,"stem":672,"day":673},"Dynamic proxy, protection proxy và vườn thú proxy","\u002Fchallenges\u002Fproxy-dynamic","challenges\u002F123.proxy-dynamic",123,{"title":675,"path":676,"stem":677,"day":678},"Interpreter và Visitor cho ngôn ngữ và cấu trúc","\u002Fchallenges\u002Finterpreter-visitor","challenges\u002F124.interpreter-visitor",124,{"title":680,"path":681,"stem":682,"day":683},"Project: rạp hát Facade và Command macro","\u002Fchallenges\u002Fproject-hometheater","challenges\u002F125.project-hometheater",125,{"title":685,"path":686,"stem":687,"day":688},"App: autocomplete có Trie và cache LRU","\u002Fchallenges\u002Fapp-autocomplete","challenges\u002F126.app-autocomplete",126,{"title":690,"path":691,"stem":692,"day":693},"App: mini search engine với Trie, ranking và Bloom","\u002Fchallenges\u002Fapp-search-engine","challenges\u002F127.app-search-engine",127,{"title":695,"path":696,"stem":697,"day":698},"App: rate limiter bằng cache và hàng đợi","\u002Fchallenges\u002Fapp-rate-limiter","challenges\u002F128.app-rate-limiter",128,{"title":700,"path":701,"stem":702,"day":703},"App: top-K trên stream bằng heap","\u002Fchallenges\u002Fapp-topk-stream","challenges\u002F129.app-topk-stream",129,{"title":705,"path":706,"stem":707,"day":708},"App: pipeline phát hiện gian lận bằng đồ thị","\u002Fchallenges\u002Fapp-fraud-pipeline","challenges\u002F130.app-fraud-pipeline",130,{"title":710,"path":711,"stem":712,"day":713},"App: recommendation engine end-to-end","\u002Fchallenges\u002Fapp-recsys-pipeline","challenges\u002F131.app-recsys-pipeline",131,{"title":715,"path":716,"stem":717,"day":718},"App: pipeline clustering từ K-means tới OPTICS","\u002Fchallenges\u002Fapp-clustering-pipeline","challenges\u002F132.app-clustering-pipeline",132,{"title":720,"path":721,"stem":722,"day":723},"App: wordcount MapReduce và Spark job","\u002Fchallenges\u002Fapp-mapreduce-spark","challenges\u002F133.app-mapreduce-spark",133,{"title":725,"path":726,"stem":727,"day":728},"App: tuyến giao hàng so sánh BFS, Dijkstra, A*","\u002Fchallenges\u002Fapp-delivery-routes","challenges\u002F134.app-delivery-routes",134,{"title":730,"path":731,"stem":732,"day":733},"App: thiết kế mạng với Prim và Kruskal","\u002Fchallenges\u002Fapp-mst-network","challenges\u002F135.app-mst-network",135,{"title":735,"path":736,"stem":737,"day":738},"App: TSP so găng greedy, SA và GA","\u002Fchallenges\u002Fapp-tsp-showdown","challenges\u002F136.app-tsp-showdown",136,{"title":740,"path":741,"stem":742,"day":743},"App: nhúng và vẽ đồ thị force-directed","\u002Fchallenges\u002Fapp-graph-embedding","challenges\u002F137.app-graph-embedding",137,{"title":745,"path":746,"stem":747,"day":748},"App: tuning siêu tham số với gradient và eval","\u002Fchallenges\u002Fapp-tuning","challenges\u002F138.app-tuning",138,{"title":750,"path":751,"stem":752,"day":753},"App: sentiment từ tokenize tới Naive Bayes","\u002Fchallenges\u002Fapp-sentiment","challenges\u002F139.app-sentiment",139,{"title":755,"path":756,"stem":757,"day":758},"App: tìm ảnh với CNN và similarity search","\u002Fchallenges\u002Fapp-image-search","challenges\u002F140.app-image-search",140,{"title":760,"path":761,"stem":762,"day":763},"App: dự báo chuỗi với RNN và LSTM","\u002Fchallenges\u002Fapp-forecast","challenges\u002F141.app-forecast",141,{"title":765,"path":766,"stem":767,"day":768},"App: chat bảo mật với TLS handshake và PKI","\u002Fchallenges\u002Fapp-secure-chat","challenges\u002F142.app-secure-chat",142,{"title":770,"path":771,"stem":772,"day":773},"App: pipeline batch vs stream và CAP","\u002Fchallenges\u002Fapp-data-pipeline","challenges\u002F143.app-data-pipeline",143,{"title":775,"path":776,"stem":777,"day":778},"App: hệ thống cache LRU, LFU và locks","\u002Fchallenges\u002Fapp-cache-system","challenges\u002F144.app-cache-system",144,{"title":780,"path":781,"stem":782,"children":783,"day":785},"App: index DB với B-tree, hash và Bloom","\u002Fchallenges\u002Fapp-db-index","challenges\u002F145.app-db-index",[784],{"title":780,"path":781,"stem":782,"day":785},145,{"title":787,"path":788,"stem":789,"day":790},"App: spell checker với Trie và độ tương đồng","\u002Fchallenges\u002Fapp-spell-checker","challenges\u002F146.app-spell-checker",146,{"title":792,"path":793,"stem":794,"day":795},"App: AI game kẹo với State và Strategy","\u002Fchallenges\u002Fapp-game-ai","challenges\u002F147.app-game-ai",147,{"title":797,"path":798,"stem":799,"day":800},"App: text editor undo với stack, Command và Memento","\u002Fchallenges\u002Fapp-text-editor","challenges\u002F148.app-text-editor",148,{"title":802,"path":803,"stem":804,"day":805},"App: hệ thống thông báo với Observer và queue","\u002Fchallenges\u002Fapp-notification","challenges\u002F149.app-notification",149,{"title":807,"path":808,"stem":809,"day":810},"Ôn tập tổng hợp: từ sắp xếp tới tối ưu","\u002Fchallenges\u002Fon-tap-tong-hop","challenges\u002F150.on-tap-tong-hop",150,{"title":812,"path":813,"stem":814,"day":815},"Capstone: benchmark sort và graph traversal","\u002Fchallenges\u002Fcapstone-sort-graph","challenges\u002F151.capstone-sort-graph",151,{"title":817,"path":818,"stem":819,"day":820},"Capstone: autocomplete cache LRU và Trie nâng cao","\u002Fchallenges\u002Fcapstone-cache-trie","challenges\u002F152.capstone-cache-trie",152,{"title":822,"path":823,"stem":824,"day":825},"Capstone: clustering pipeline và báo cáo metric","\u002Fchallenges\u002Fcapstone-clustering","challenges\u002F153.capstone-clustering",153,{"title":827,"path":828,"stem":829,"day":830},"Capstone: recsys có đo cold start và sparsity","\u002Fchallenges\u002Fcapstone-recsys","challenges\u002F154.capstone-recsys",154,{"title":832,"path":833,"stem":834,"day":835},"Capstone: hệ thống lớn có mật mã và streaming","\u002Fchallenges\u002Fcapstone-crypto-scale","challenges\u002F155.capstone-crypto-scale",155,{"title":837,"path":838,"stem":839,"day":840},"Capstone: tối ưu TSP và vẽ đồ thị tổng hợp","\u002Fchallenges\u002Fcapstone-optimization","challenges\u002F156.capstone-optimization",156,{"title":842,"path":843,"stem":844,"day":845},"Capstone: SimUDuck refactor toàn diện","\u002Fchallenges\u002Fcapstone-patterns-duck","challenges\u002F157.capstone-patterns-duck",157,{"title":847,"path":848,"stem":849,"day":850},"Capstone: Pizza Store đa vùng và toppings","\u002Fchallenges\u002Fcapstone-patterns-pizza","challenges\u002F158.capstone-patterns-pizza",158,{"title":852,"path":853,"stem":854,"day":855},"Capstone: home theater Facade và macro","\u002Fchallenges\u002Fcapstone-patterns-home","challenges\u002F159.capstone-patterns-home",159,{"title":857,"path":858,"stem":859,"day":860},"Capstone: mạng xã hội mini với graph và feed","\u002Fchallenges\u002Fcapstone-social","challenges\u002F160.capstone-social",160,{"title":862,"path":863,"stem":864,"day":865},"Phỏng vấn 1: array, string và two pointers","\u002Fchallenges\u002Fphong-van-algo-1","challenges\u002F161.phong-van-algo-1",161,{"title":867,"path":868,"stem":869,"day":870},"Phỏng vấn 2: BST, heap và top-k","\u002Fchallenges\u002Fphong-van-algo-2","challenges\u002F162.phong-van-algo-2",162,{"title":872,"path":873,"stem":874,"day":875},"Phỏng vấn 3: BFS, DFS, Dijkstra trên ma trận","\u002Fchallenges\u002Fphong-van-graph","challenges\u002F163.phong-van-graph",163,{"title":877,"path":878,"stem":879,"day":880},"Phỏng vấn 4: DP kinh điển và greedy chứng minh","\u002Fchallenges\u002Fphong-van-dp","challenges\u002F164.phong-van-dp",164,{"title":882,"path":883,"stem":884,"day":885},"Phỏng vấn 5: cache, rate limiter và search","\u002Fchallenges\u002Fphong-van-system","challenges\u002F165.phong-van-system",165,{"title":887,"path":888,"stem":889,"day":890},"Phỏng vấn 6: kể chuyện patterns và SOLID","\u002Fchallenges\u002Fphong-van-patterns","challenges\u002F166.phong-van-patterns",166,{"title":892,"path":893,"stem":894,"day":895},"Dự án cuối 1: đặc tả và chia module","\u002Fchallenges\u002Fdu-an-cuoi-1","challenges\u002F167.du-an-cuoi-1",167,{"title":897,"path":898,"stem":899,"day":900},"Dự án cuối 2: benchmark và profiling","\u002Fchallenges\u002Fdu-an-cuoi-2","challenges\u002F168.du-an-cuoi-2",168,{"title":902,"path":903,"stem":904,"day":905},"Dự án cuối 3: dữ liệu lớn và evaluate","\u002Fchallenges\u002Fdu-an-cuoi-3","challenges\u002F169.du-an-cuoi-3",169,{"title":907,"path":908,"stem":909,"day":910},"Dự án cuối 4: áp dụng patterns và review chéo","\u002Fchallenges\u002Fdu-an-cuoi-4","challenges\u002F170.du-an-cuoi-4",170,{"title":912,"path":913,"stem":914,"day":915},"Tổng kết 180 ngày: bản đồ tri thức","\u002Fchallenges\u002Ftong-ket-180-ngay","challenges\u002F171.tong-ket-180-ngay",171,{"title":917,"path":918,"stem":919,"day":920},"Lộ trình sau 180 ngày: ML, systems, research","\u002Fchallenges\u002Flo-trinh-sau-180","challenges\u002F172.lo-trinh-sau-180",172,{"title":922,"path":923,"stem":924,"day":925},"Checklist năng lực: tự đánh giá 180 kỹ năng","\u002Fchallenges\u002Fchecklist-nang-luc","challenges\u002F173.checklist-nang-luc",173,{"title":927,"path":928,"stem":929,"day":930},"Bộ đề luyện thêm 50 bài tự ra đề","\u002Fchallenges\u002Fbo-de-luyen-them","challenges\u002F174.bo-de-luyen-them",174,{"title":932,"path":933,"stem":934,"day":935},"System design cơ bản: scale, ELB và sharding","\u002Fchallenges\u002Fsystem-design-co-ban","challenges\u002F175.system-design-co-ban",175,{"title":937,"path":938,"stem":939,"day":940},"Đọc whitepaper và viết blog kỹ thuật","\u002Fchallenges\u002Fdoc-paper-viet-blog","challenges\u002F176.doc-paper-viet-blog",176,{"title":942,"path":943,"stem":944,"day":945},"Ngày open source: đọc source và đóng góp","\u002Fchallenges\u002Fopen-source-day","challenges\u002F177.open-source-day",177,{"title":947,"path":948,"stem":949,"day":950},"Mock interview và peer review chéo","\u002Fchallenges\u002Fmock-interview","challenges\u002F178.mock-interview",178,{"title":952,"path":953,"stem":954,"day":955},"Hoàn thiện sản phẩm demo cuối khóa","\u002Fchallenges\u002Fsan-pham-demo","challenges\u002F179.san-pham-demo",179,{"title":957,"path":958,"stem":959,"day":960},"Demo day và tổng kết","\u002Fchallenges\u002Fle-tot-nghiep","challenges\u002F180.le-tot-nghiep",180,[962,3056,4674,5203,6439,7038,7555,8155,8805,9254,10192,11574,12059,13226,14060,14450,15150,15593,16074,16571,17020,17504,18476,19409,20616,21060,22232,22658,23087,23654,24343,24852,25482,26311,26805,27245,27650,28103,28662,29127,29789,30453,31169,31503,32326,33133,33724,34180,34742,35336,35751,36105,36494,37146,37982,38543,38889,39232,39584,39892,40275,40639,41007,41331,41705,42177,42563,43006,43346,43949,44316,44784,45096,46184,46644,47043,47535,48151,48825,49329,49651,50115,50538,50955,51289,51720,52076,52493,52871,53231,54270,54633,55132,55459,56132,56587,57318,57670,58104,58666,59289,60898,61254,61611,62063,62457,62859,63316,63781,64335,64972,65342,65749,66199,66545,66932,67351,67806,68139,68567,68960,69293,69645,70099,70512,70851,71482,71940,72345,72950,73257,73587,73868,74181,74486,74815,75093,75749,76056,76356,76637,76895,77170,77424,77701,78082,78473,78805,79141,79466,79777,80862,81149,81407,82100,82469,82740,83088,83387,83686,84029,84609,85499,85911,86372,86633,86881,87201,87474,87739,88002,88251,88538,88837,89255,89573,89822,90093,90400,90637],{"id":963,"title":60,"body":964,"category":3041,"day":63,"description":3042,"difficulty":3043,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":3046,"navigation":2723,"outcomes":3047,"path":61,"prerequisites":3048,"seo":3051,"stem":62,"tags":3052,"__hash__":3055},"challenges\u002Fchallenges\u002F1.mang-va-danh-sach.md",{"type":965,"value":966,"toc":3023},"minimark",[967,972,976,980,985,1012,1016,1094,1098,1347,1351,1391,1402,1405,1430,1434,1479,1483,1499,1503,1518,1545,1558,2190,2195,2223,2236,2244,2261,2265,2272,2415,2421,2515,2523,2536,2679,2695,2708,2712,2887,2891,3013,3016,3019],[968,969,971],"h2",{"id":970},"giới-thiệu","Giới thiệu",[973,974,975],"p",{},"Mảng động là vùng nhớ liên tục có dự trữ chỗ trống. Hết chỗ thì cấp vùng gấp đôi và sao chép sang. Bài này chỉ học một thứ: tự cài đặt Dynamic Array.",[968,977,979],{"id":978},"kiến-thức-cần-nhớ","Kiến thức cần nhớ",[981,982,984],"h3",{"id":983},"size-vs-capacity","Size vs capacity",[986,987,988,996,1002],"ul",{},[989,990,991,995],"li",{},[992,993,994],"code",{},"size",": số phần tử đang dùng.",[989,997,998,1001],{},[992,999,1000],{},"capacity",": số ô đã cấp phát.",[989,1003,1004,1007,1008,1011],{},[992,1005,1006],{},"size == capacity"," khi ",[992,1009,1010],{},"push"," → phải cấp phát lại.",[981,1013,1015],{"id":1014},"vì-sao-nhân-đôi","Vì sao nhân đôi",[973,1017,1018,1019,1021,1022,1093],{},"Cấp vùng mới gấp đôi, copy toàn bộ, rồi mới thêm. Nhờ dự trữ dư nên n lần ",[992,1020,1010],{}," chỉ tốn ",[1023,1024,1027,1062],"span",{"className":1025},[1026],"katex",[1023,1028,1031],{"className":1029},[1030],"katex-mathml",[1032,1033,1035],"math",{"xmlns":1034},"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML",[1036,1037,1038,1057],"semantics",{},[1039,1040,1041,1045,1050,1054],"mrow",{},[1042,1043,1044],"mi",{},"O",[1046,1047,1049],"mo",{"stretchy":1048},"false","(",[1051,1052,1053],"mn",{},"1",[1046,1055,1056],{"stretchy":1048},")",[1058,1059,1061],"annotation",{"encoding":1060},"application\u002Fx-tex","O(1)",[1023,1063,1067],{"className":1064,"ariaHidden":1066},[1065],"katex-html","true",[1023,1068,1071,1076,1082,1086,1089],{"className":1069},[1070],"base",[1023,1072],{"className":1073,"style":1075},[1074],"strut","height:1em;vertical-align:-0.25em;",[1023,1077,1044],{"className":1078,"style":1081},[1079,1080],"mord","mathnormal","margin-right:0.0278em;",[1023,1083,1049],{"className":1084},[1085],"mopen",[1023,1087,1053],{"className":1088},[1079],[1023,1090,1056],{"className":1091},[1092],"mclose"," trung bình.",[981,1095,1097],{"id":1096},"bảng-độ-phức-tạp","Bảng độ phức tạp",[1099,1100,1101,1117],"table",{},[1102,1103,1104],"thead",{},[1105,1106,1107,1111,1114],"tr",{},[1108,1109,1110],"th",{},"Thao tác",[1108,1112,1113],{},"Độ phức tạp",[1108,1115,1116],{},"Lý do",[1118,1119,1120,1177,1234,1292],"tbody",{},[1105,1121,1122,1129,1174],{},[1123,1124,1125,1128],"td",{},[992,1126,1127],{},"get\u002Fset"," theo chỉ số",[1123,1130,1131],{},[1023,1132,1134,1153],{"className":1133},[1026],[1023,1135,1137],{"className":1136},[1030],[1032,1138,1139],{"xmlns":1034},[1036,1140,1141,1151],{},[1039,1142,1143,1145,1147,1149],{},[1042,1144,1044],{},[1046,1146,1049],{"stretchy":1048},[1051,1148,1053],{},[1046,1150,1056],{"stretchy":1048},[1058,1152,1061],{"encoding":1060},[1023,1154,1156],{"className":1155,"ariaHidden":1066},[1065],[1023,1157,1159,1162,1165,1168,1171],{"className":1158},[1070],[1023,1160],{"className":1161,"style":1075},[1074],[1023,1163,1044],{"className":1164,"style":1081},[1079,1080],[1023,1166,1049],{"className":1167},[1085],[1023,1169,1053],{"className":1170},[1079],[1023,1172,1056],{"className":1173},[1092],[1123,1175,1176],{},"tính địa chỉ trực tiếp",[1105,1178,1179,1185,1231],{},[1123,1180,1181,1184],{},[992,1182,1183],{},"push\u002Fpop"," cuối",[1123,1186,1187,1230],{},[1023,1188,1190,1209],{"className":1189},[1026],[1023,1191,1193],{"className":1192},[1030],[1032,1194,1195],{"xmlns":1034},[1036,1196,1197,1207],{},[1039,1198,1199,1201,1203,1205],{},[1042,1200,1044],{},[1046,1202,1049],{"stretchy":1048},[1051,1204,1053],{},[1046,1206,1056],{"stretchy":1048},[1058,1208,1061],{"encoding":1060},[1023,1210,1212],{"className":1211,"ariaHidden":1066},[1065],[1023,1213,1215,1218,1221,1224,1227],{"className":1214},[1070],[1023,1216],{"className":1217,"style":1075},[1074],[1023,1219,1044],{"className":1220,"style":1081},[1079,1080],[1023,1222,1049],{"className":1223},[1085],[1023,1225,1053],{"className":1226},[1079],[1023,1228,1056],{"className":1229},[1092]," trung bình",[1123,1232,1233],{},"thỉnh thoảng copy khi đầy",[1105,1235,1236,1242,1289],{},[1123,1237,1238,1241],{},[992,1239,1240],{},"insert\u002Ferase"," giữa",[1123,1243,1244],{},[1023,1245,1247,1268],{"className":1246},[1026],[1023,1248,1250],{"className":1249},[1030],[1032,1251,1252],{"xmlns":1034},[1036,1253,1254,1265],{},[1039,1255,1256,1258,1260,1263],{},[1042,1257,1044],{},[1046,1259,1049],{"stretchy":1048},[1042,1261,1262],{},"n",[1046,1264,1056],{"stretchy":1048},[1058,1266,1267],{"encoding":1060},"O(n)",[1023,1269,1271],{"className":1270,"ariaHidden":1066},[1065],[1023,1272,1274,1277,1280,1283,1286],{"className":1273},[1070],[1023,1275],{"className":1276,"style":1075},[1074],[1023,1278,1044],{"className":1279,"style":1081},[1079,1080],[1023,1281,1049],{"className":1282},[1085],[1023,1284,1262],{"className":1285},[1079,1080],[1023,1287,1056],{"className":1288},[1092],[1123,1290,1291],{},"phải dồn phần tử giữ liên tục",[1105,1293,1294,1299,1344],{},[1123,1295,1296],{},[992,1297,1298],{},"reserve\u002Fshrink",[1123,1300,1301],{},[1023,1302,1304,1323],{"className":1303},[1026],[1023,1305,1307],{"className":1306},[1030],[1032,1308,1309],{"xmlns":1034},[1036,1310,1311,1321],{},[1039,1312,1313,1315,1317,1319],{},[1042,1314,1044],{},[1046,1316,1049],{"stretchy":1048},[1042,1318,1262],{},[1046,1320,1056],{"stretchy":1048},[1058,1322,1267],{"encoding":1060},[1023,1324,1326],{"className":1325,"ariaHidden":1066},[1065],[1023,1327,1329,1332,1335,1338,1341],{"className":1328},[1070],[1023,1330],{"className":1331,"style":1075},[1074],[1023,1333,1044],{"className":1334,"style":1081},[1079,1080],[1023,1336,1049],{"className":1337},[1085],[1023,1339,1262],{"className":1340},[1079,1080],[1023,1342,1056],{"className":1343},[1092],[1123,1345,1346],{},"cấp mới + copy một lần",[981,1348,1350],{"id":1349},"khung-struct","Khung struct",[1352,1353,1358],"pre",{"className":1354,"code":1355,"language":1356,"meta":1357,"style":1357},"language-c shiki shiki-themes github-light github-light github-dark","\u002F\u002F C\ntypedef struct {\n  int *data;\n  size_t size;\n  size_t capacity;\n} DynamicArray;\n","c","",[992,1359,1360,1366,1371,1376,1381,1386],{"__ignoreMap":1357},[1023,1361,1363],{"class":1362,"line":63},"line",[1023,1364,1365],{},"\u002F\u002F C\n",[1023,1367,1368],{"class":1362,"line":68},[1023,1369,1370],{},"typedef struct {\n",[1023,1372,1373],{"class":1362,"line":73},[1023,1374,1375],{},"  int *data;\n",[1023,1377,1378],{"class":1362,"line":78},[1023,1379,1380],{},"  size_t size;\n",[1023,1382,1383],{"class":1362,"line":83},[1023,1384,1385],{},"  size_t capacity;\n",[1023,1387,1388],{"class":1362,"line":88},[1023,1389,1390],{},"} DynamicArray;\n",[1352,1392,1396],{"className":1393,"code":1394,"language":1395,"meta":1357,"style":1357},"language-cpp shiki shiki-themes github-light github-light github-dark","\u002F\u002F C++: class DynamicArray với data_, size_, capacity_ + destructor\n","cpp",[992,1397,1398],{"__ignoreMap":1357},[1023,1399,1400],{"class":1362,"line":63},[1023,1401,1394],{},[973,1403,1404],{},"Quy tắc bắt buộc:",[986,1406,1407,1413,1420],{},[989,1408,1409,1412],{},[992,1410,1411],{},"realloc"," qua con trỏ tạm, thất bại thì mảng cũ còn nguyên.",[989,1414,1415,1416,1419],{},"Mọi ",[992,1417,1418],{},"get\u002Fset\u002Finsert\u002Ferase\u002Fpop"," kiểm tra biên, không crash.",[989,1421,1422,1425,1426,1429],{},[992,1423,1424],{},"destroy"," free đúng 1 lần, gán ",[992,1427,1428],{},"NULL",", không leak.",[968,1431,1433],{"id":1432},"ví-dụ","Ví dụ",[1352,1435,1437],{"className":1354,"code":1436,"language":1356,"meta":1357,"style":1357},"DynamicArray a; da_init(&a, 2);\nda_push(&a, 1); da_push(&a, 2); da_push(&a, 3);\n\u002F\u002F capacity: 2 -> 4, size = 3\nda_get(&a, 1);    \u002F\u002F = 2\nda_insert(&a, 1, 9); \u002F\u002F 1, 9, 2, 3\nda_erase(&a, 1);     \u002F\u002F 1, 2, 3\nda_pop(&a);          \u002F\u002F 1, 2\nda_destroy(&a);\n",[992,1438,1439,1444,1449,1454,1459,1464,1469,1474],{"__ignoreMap":1357},[1023,1440,1441],{"class":1362,"line":63},[1023,1442,1443],{},"DynamicArray a; da_init(&a, 2);\n",[1023,1445,1446],{"class":1362,"line":68},[1023,1447,1448],{},"da_push(&a, 1); da_push(&a, 2); da_push(&a, 3);\n",[1023,1450,1451],{"class":1362,"line":73},[1023,1452,1453],{},"\u002F\u002F capacity: 2 -> 4, size = 3\n",[1023,1455,1456],{"class":1362,"line":78},[1023,1457,1458],{},"da_get(&a, 1);    \u002F\u002F = 2\n",[1023,1460,1461],{"class":1362,"line":83},[1023,1462,1463],{},"da_insert(&a, 1, 9); \u002F\u002F 1, 9, 2, 3\n",[1023,1465,1466],{"class":1362,"line":88},[1023,1467,1468],{},"da_erase(&a, 1);     \u002F\u002F 1, 2, 3\n",[1023,1470,1471],{"class":1362,"line":93},[1023,1472,1473],{},"da_pop(&a);          \u002F\u002F 1, 2\n",[1023,1475,1476],{"class":1362,"line":98},[1023,1477,1478],{},"da_destroy(&a);\n",[968,1480,1482],{"id":1481},"bài-tập","💻 Bài tập",[973,1484,1485,1486,1490,1491,1494,1495,1498],{},"Ngôn ngữ: ",[1487,1488,1489],"strong",{},"C"," cho Bài 1-2, ",[1487,1492,1493],{},"C++"," cho Bài 3. Nộp vào thư mục ",[992,1496,1497],{},"day-001\u002F"," trong repo của bạn.",[981,1500,1502],{"id":1501},"bài-1-cài-đặt-dynamic-array-bằng-c","Bài 1: Cài đặt Dynamic Array bằng C",[973,1504,1505,1506,1509,1510,1513,1514,1517],{},"Viết ",[992,1507,1508],{},"dynamic_array.h"," và ",[992,1511,1512],{},"dynamic_array.c",". Mảng lưu phần tử kiểu ",[992,1515,1516],{},"int",".",[1352,1519,1521],{"className":1354,"code":1520,"language":1356,"meta":1357,"style":1357},"typedef struct {\n  int *data;\n  size_t size;      \u002F\u002F số phần tử đang dùng\n  size_t capacity;  \u002F\u002F số ô đã cấp phát\n} DynamicArray;\n",[992,1522,1523,1527,1531,1536,1541],{"__ignoreMap":1357},[1023,1524,1525],{"class":1362,"line":63},[1023,1526,1370],{},[1023,1528,1529],{"class":1362,"line":68},[1023,1530,1375],{},[1023,1532,1533],{"class":1362,"line":73},[1023,1534,1535],{},"  size_t size;      \u002F\u002F số phần tử đang dùng\n",[1023,1537,1538],{"class":1362,"line":78},[1023,1539,1540],{},"  size_t capacity;  \u002F\u002F số ô đã cấp phát\n",[1023,1542,1543],{"class":1362,"line":83},[1023,1544,1390],{},[973,1546,1547,1550,1551,1554,1555,1557],{},[1487,1548,1549],{},"API bắt buộc."," Mọi hàm trả ",[992,1552,1553],{},"bool"," đều trả ",[992,1556,1048],{}," khi lỗi và giữ mảng nguyên trạng.",[1099,1559,1560,1572],{},[1102,1561,1562],{},[1105,1563,1564,1567,1570],{},[1108,1565,1566],{},"Hàm",[1108,1568,1569],{},"Việc phải làm",[1108,1571,1113],{},[1118,1573,1574,1640,1706,1764,1825,1890,1950,2012,2070,2129],{},[1105,1575,1576,1581,1595],{},[1123,1577,1578],{},[992,1579,1580],{},"bool da_init(DynamicArray *a, size_t cap)",[1123,1582,1583,1584,1587,1588,1591,1592,1517],{},"Cấp ",[992,1585,1586],{},"cap"," ô (",[992,1589,1590],{},"cap == 0"," thì dùng 1). ",[992,1593,1594],{},"size = 0",[1123,1596,1597],{},[1023,1598,1600,1619],{"className":1599},[1026],[1023,1601,1603],{"className":1602},[1030],[1032,1604,1605],{"xmlns":1034},[1036,1606,1607,1617],{},[1039,1608,1609,1611,1613,1615],{},[1042,1610,1044],{},[1046,1612,1049],{"stretchy":1048},[1051,1614,1053],{},[1046,1616,1056],{"stretchy":1048},[1058,1618,1061],{"encoding":1060},[1023,1620,1622],{"className":1621,"ariaHidden":1066},[1065],[1023,1623,1625,1628,1631,1634,1637],{"className":1624},[1070],[1023,1626],{"className":1627,"style":1075},[1074],[1023,1629,1044],{"className":1630,"style":1081},[1079,1080],[1023,1632,1049],{"className":1633},[1085],[1023,1635,1053],{"className":1636},[1079],[1023,1638,1056],{"className":1639},[1092],[1105,1641,1642,1647,1661],{},[1123,1643,1644],{},[992,1645,1646],{},"void da_destroy(DynamicArray *a)",[1123,1648,1649,1652,1653,1656,1657,1660],{},[992,1650,1651],{},"free",", gán ",[992,1654,1655],{},"data = NULL",", ",[992,1658,1659],{},"size = capacity = 0",". Gọi 2 lần vẫn an toàn.",[1123,1662,1663],{},[1023,1664,1666,1685],{"className":1665},[1026],[1023,1667,1669],{"className":1668},[1030],[1032,1670,1671],{"xmlns":1034},[1036,1672,1673,1683],{},[1039,1674,1675,1677,1679,1681],{},[1042,1676,1044],{},[1046,1678,1049],{"stretchy":1048},[1051,1680,1053],{},[1046,1682,1056],{"stretchy":1048},[1058,1684,1061],{"encoding":1060},[1023,1686,1688],{"className":1687,"ariaHidden":1066},[1065],[1023,1689,1691,1694,1697,1700,1703],{"className":1690},[1070],[1023,1692],{"className":1693,"style":1075},[1074],[1023,1695,1044],{"className":1696,"style":1081},[1079,1080],[1023,1698,1049],{"className":1699},[1085],[1023,1701,1053],{"className":1702},[1079],[1023,1704,1056],{"className":1705},[1092],[1105,1707,1708,1713,1719],{},[1123,1709,1710],{},[992,1711,1712],{},"bool da_push(DynamicArray *a, int x)",[1123,1714,1715,1716,1718],{},"Thêm cuối. Đầy thì nhân đôi ",[992,1717,1000],{}," trước.",[1123,1720,1721,1230],{},[1023,1722,1724,1743],{"className":1723},[1026],[1023,1725,1727],{"className":1726},[1030],[1032,1728,1729],{"xmlns":1034},[1036,1730,1731,1741],{},[1039,1732,1733,1735,1737,1739],{},[1042,1734,1044],{},[1046,1736,1049],{"stretchy":1048},[1051,1738,1053],{},[1046,1740,1056],{"stretchy":1048},[1058,1742,1061],{"encoding":1060},[1023,1744,1746],{"className":1745,"ariaHidden":1066},[1065],[1023,1747,1749,1752,1755,1758,1761],{"className":1748},[1070],[1023,1750],{"className":1751,"style":1075},[1074],[1023,1753,1044],{"className":1754,"style":1081},[1079,1080],[1023,1756,1049],{"className":1757},[1085],[1023,1759,1053],{"className":1760},[1079],[1023,1762,1056],{"className":1763},[1092],[1105,1765,1766,1771,1780],{},[1123,1767,1768],{},[992,1769,1770],{},"bool da_pop(DynamicArray *a, int *out)",[1123,1772,1773,1774,1777,1778,1517],{},"Lấy phần tử cuối vào ",[992,1775,1776],{},"*out",". Rỗng thì trả ",[992,1779,1048],{},[1123,1781,1782],{},[1023,1783,1785,1804],{"className":1784},[1026],[1023,1786,1788],{"className":1787},[1030],[1032,1789,1790],{"xmlns":1034},[1036,1791,1792,1802],{},[1039,1793,1794,1796,1798,1800],{},[1042,1795,1044],{},[1046,1797,1049],{"stretchy":1048},[1051,1799,1053],{},[1046,1801,1056],{"stretchy":1048},[1058,1803,1061],{"encoding":1060},[1023,1805,1807],{"className":1806,"ariaHidden":1066},[1065],[1023,1808,1810,1813,1816,1819,1822],{"className":1809},[1070],[1023,1811],{"className":1812,"style":1075},[1074],[1023,1814,1044],{"className":1815,"style":1081},[1079,1080],[1023,1817,1049],{"className":1818},[1085],[1023,1820,1053],{"className":1821},[1079],[1023,1823,1056],{"className":1824},[1092],[1105,1826,1827,1832,1845],{},[1123,1828,1829],{},[992,1830,1831],{},"bool da_get(const DynamicArray *a, size_t i, int *out)",[1123,1833,1834,1835,1838,1839,1842,1843,1517],{},"Đọc ô ",[992,1836,1837],{},"i",". ",[992,1840,1841],{},"i >= size"," thì trả ",[992,1844,1048],{},[1123,1846,1847],{},[1023,1848,1850,1869],{"className":1849},[1026],[1023,1851,1853],{"className":1852},[1030],[1032,1854,1855],{"xmlns":1034},[1036,1856,1857,1867],{},[1039,1858,1859,1861,1863,1865],{},[1042,1860,1044],{},[1046,1862,1049],{"stretchy":1048},[1051,1864,1053],{},[1046,1866,1056],{"stretchy":1048},[1058,1868,1061],{"encoding":1060},[1023,1870,1872],{"className":1871,"ariaHidden":1066},[1065],[1023,1873,1875,1878,1881,1884,1887],{"className":1874},[1070],[1023,1876],{"className":1877,"style":1075},[1074],[1023,1879,1044],{"className":1880,"style":1081},[1079,1080],[1023,1882,1049],{"className":1883},[1085],[1023,1885,1053],{"className":1886},[1079],[1023,1888,1056],{"className":1889},[1092],[1105,1891,1892,1897,1905],{},[1123,1893,1894],{},[992,1895,1896],{},"bool da_set(DynamicArray *a, size_t i, int x)",[1123,1898,1899,1900,1902,1903,1517],{},"Ghi ô ",[992,1901,1837],{},". Ngoài biên thì trả ",[992,1904,1048],{},[1123,1906,1907],{},[1023,1908,1910,1929],{"className":1909},[1026],[1023,1911,1913],{"className":1912},[1030],[1032,1914,1915],{"xmlns":1034},[1036,1916,1917,1927],{},[1039,1918,1919,1921,1923,1925],{},[1042,1920,1044],{},[1046,1922,1049],{"stretchy":1048},[1051,1924,1053],{},[1046,1926,1056],{"stretchy":1048},[1058,1928,1061],{"encoding":1060},[1023,1930,1932],{"className":1931,"ariaHidden":1066},[1065],[1023,1933,1935,1938,1941,1944,1947],{"className":1934},[1070],[1023,1936],{"className":1937,"style":1075},[1074],[1023,1939,1044],{"className":1940,"style":1081},[1079,1080],[1023,1942,1049],{"className":1943},[1085],[1023,1945,1053],{"className":1946},[1079],[1023,1948,1056],{"className":1949},[1092],[1105,1951,1952,1957,1967],{},[1123,1953,1954],{},[992,1955,1956],{},"bool da_insert(DynamicArray *a, size_t i, int x)",[1123,1958,1959,1960,1962,1963,1966],{},"Chèn tại ",[992,1961,1837],{},", với ",[992,1964,1965],{},"0 \u003C= i \u003C= size",". Dồn phần sau sang phải.",[1123,1968,1969],{},[1023,1970,1972,1991],{"className":1971},[1026],[1023,1973,1975],{"className":1974},[1030],[1032,1976,1977],{"xmlns":1034},[1036,1978,1979,1989],{},[1039,1980,1981,1983,1985,1987],{},[1042,1982,1044],{},[1046,1984,1049],{"stretchy":1048},[1042,1986,1262],{},[1046,1988,1056],{"stretchy":1048},[1058,1990,1267],{"encoding":1060},[1023,1992,1994],{"className":1993,"ariaHidden":1066},[1065],[1023,1995,1997,2000,2003,2006,2009],{"className":1996},[1070],[1023,1998],{"className":1999,"style":1075},[1074],[1023,2001,1044],{"className":2002,"style":1081},[1079,1080],[1023,2004,1049],{"className":2005},[1085],[1023,2007,1262],{"className":2008},[1079,1080],[1023,2010,1056],{"className":2011},[1092],[1105,2013,2014,2019,2025],{},[1123,2015,2016],{},[992,2017,2018],{},"bool da_erase(DynamicArray *a, size_t i)",[1123,2020,2021,2022,2024],{},"Xóa ô ",[992,2023,1837],{},", dồn phần sau sang trái.",[1123,2026,2027],{},[1023,2028,2030,2049],{"className":2029},[1026],[1023,2031,2033],{"className":2032},[1030],[1032,2034,2035],{"xmlns":1034},[1036,2036,2037,2047],{},[1039,2038,2039,2041,2043,2045],{},[1042,2040,1044],{},[1046,2042,1049],{"stretchy":1048},[1042,2044,1262],{},[1046,2046,1056],{"stretchy":1048},[1058,2048,1267],{"encoding":1060},[1023,2050,2052],{"className":2051,"ariaHidden":1066},[1065],[1023,2053,2055,2058,2061,2064,2067],{"className":2054},[1070],[1023,2056],{"className":2057,"style":1075},[1074],[1023,2059,1044],{"className":2060,"style":1081},[1079,1080],[1023,2062,1049],{"className":2063},[1085],[1023,2065,1262],{"className":2066},[1079,1080],[1023,2068,1056],{"className":2069},[1092],[1105,2071,2072,2077,2084],{},[1123,2073,2074],{},[992,2075,2076],{},"bool da_reserve(DynamicArray *a, size_t cap)",[1123,2078,2079,2080,2083],{},"Đảm bảo ",[992,2081,2082],{},"capacity >= cap",". Không bao giờ giảm.",[1123,2085,2086],{},[1023,2087,2089,2108],{"className":2088},[1026],[1023,2090,2092],{"className":2091},[1030],[1032,2093,2094],{"xmlns":1034},[1036,2095,2096,2106],{},[1039,2097,2098,2100,2102,2104],{},[1042,2099,1044],{},[1046,2101,1049],{"stretchy":1048},[1042,2103,1262],{},[1046,2105,1056],{"stretchy":1048},[1058,2107,1267],{"encoding":1060},[1023,2109,2111],{"className":2110,"ariaHidden":1066},[1065],[1023,2112,2114,2117,2120,2123,2126],{"className":2113},[1070],[1023,2115],{"className":2116,"style":1075},[1074],[1023,2118,1044],{"className":2119,"style":1081},[1079,1080],[1023,2121,1049],{"className":2122},[1085],[1023,2124,1262],{"className":2125},[1079,1080],[1023,2127,1056],{"className":2128},[1092],[1105,2130,2131,2136,2145],{},[1123,2132,2133],{},[992,2134,2135],{},"bool da_shrink_to_fit(DynamicArray *a)",[1123,2137,2138,2139,2141,2142,1517],{},"Đưa ",[992,2140,1000],{}," về ",[992,2143,2144],{},"max(size, 1)",[1123,2146,2147],{},[1023,2148,2150,2169],{"className":2149},[1026],[1023,2151,2153],{"className":2152},[1030],[1032,2154,2155],{"xmlns":1034},[1036,2156,2157,2167],{},[1039,2158,2159,2161,2163,2165],{},[1042,2160,1044],{},[1046,2162,1049],{"stretchy":1048},[1042,2164,1262],{},[1046,2166,1056],{"stretchy":1048},[1058,2168,1267],{"encoding":1060},[1023,2170,2172],{"className":2171,"ariaHidden":1066},[1065],[1023,2173,2175,2178,2181,2184,2187],{"className":2174},[1070],[1023,2176],{"className":2177,"style":1075},[1074],[1023,2179,1044],{"className":2180,"style":1081},[1079,1080],[1023,2182,1049],{"className":2183},[1085],[1023,2185,1262],{"className":2186},[1079,1080],[1023,2188,1056],{"className":2189},[1092],[973,2191,2192],{},[1487,2193,2194],{},"Ràng buộc",[986,2196,2197,2211,2216],{},[989,2198,2199,2200,1656,2203,1656,2205,1656,2207,2210],{},"Chỉ dùng ",[992,2201,2202],{},"malloc",[992,2204,1411],{},[992,2206,1651],{},[992,2208,2209],{},"memmove",". Không dùng thư viện container.",[989,2212,2213,2215],{},[992,2214,1411],{}," luôn qua con trỏ tạm. Cấp phát thất bại thì dữ liệu cũ còn nguyên.",[989,2217,2218,2219,2222],{},"Thư viện không ",[992,2220,2221],{},"printf",". Lỗi báo qua giá trị trả về.",[973,2224,2225,2228,2229,2232,2233,1517],{},[1487,2226,2227],{},"Test mẫu."," Viết trong ",[992,2230,2231],{},"test_da.c"," bằng ",[992,2234,2235],{},"assert",[1352,2237,2242],{"className":2238,"code":2240,"language":2241,"meta":1357},[2239],"language-text","init(cap=2); push 1, 2, 3        -> size=3, capacity=4, [1, 2, 3]\nget(1)                           -> true, out=2\ninsert(1, 9)                     -> [1, 9, 2, 3]\ninsert(4, 7)                     -> [1, 9, 2, 3, 7]   (chèn cuối hợp lệ)\nerase(1)                         -> [1, 2, 3, 7]\npop                              -> true, out=7, [1, 2, 3]\nget(5) \u002F set(5, 0) \u002F erase(5)    -> false, mảng không đổi\ninsert(9, 0)                     -> false\npop 3 lần, rồi pop tiếp          -> lần thứ 4 trả false\nreserve(100); shrink_to_fit      -> capacity 100, rồi về 1\n","text",[992,2243,2240],{"__ignoreMap":1357},[2245,2246,2247],"tip",{},[973,2248,2249,2252,2253,2256,2257,2260],{},[992,2250,2251],{},"insert"," dùng ",[992,2254,2255],{},"memmove(&data[i+1], &data[i], (size-i) * sizeof(int))",". Không dùng ",[992,2258,2259],{},"memcpy"," vì hai vùng nhớ chồng nhau.",[981,2262,2264],{"id":2263},"bài-2-đo-vết-capacity-và-chi-phí-copy","Bài 2: Đo vết capacity và chi phí copy",[973,2266,2267,2268,2271],{},"Thêm vào struct biến đếm ",[992,2269,2270],{},"size_t copies",": tổng số phần tử bị sao chép khi cấp phát lại.",[2273,2274,2275,2290,2303],"ol",{},[989,2276,2277,2278,1656,2281,2283,2284,2286,2287,1517],{},"Khởi tạo ",[992,2279,2280],{},"cap = 1",[992,2282,1010],{}," 10 phần tử. In ra mỗi lần ",[992,2285,1000],{}," đổi. Kết quả phải là ",[992,2288,2289],{},"1 -> 2 -> 4 -> 8 -> 16",[989,2291,2292,2293,1509,2296,2299,2300,1517],{},"Viết thêm 2 chiến lược tăng: ",[992,2294,2295],{},"+1 ô",[992,2297,2298],{},"x1.5",". Chọn chiến lược qua tham số ở ",[992,2301,2302],{},"da_init",[989,2304,2305,2306,2308,2309,2414],{},"Với mỗi chiến lược, ",[992,2307,1010],{}," ",[1023,2310,2312,2338],{"className":2311},[1026],[1023,2313,2315],{"className":2314},[1030],[1032,2316,2317],{"xmlns":1034},[1036,2318,2319,2335],{},[1039,2320,2321,2323,2326],{},[1042,2322,1262],{},[1046,2324,2325],{},"=",[2327,2328,2329,2332],"msup",{},[1051,2330,2331],{},"10",[1051,2333,2334],{},"5",[1058,2336,2337],{"encoding":1060},"n = 10^5",[1023,2339,2341,2363],{"className":2340,"ariaHidden":1066},[1065],[1023,2342,2344,2348,2351,2356,2360],{"className":2343},[1070],[1023,2345],{"className":2346,"style":2347},[1074],"height:0.4306em;",[1023,2349,1262],{"className":2350},[1079,1080],[1023,2352],{"className":2353,"style":2355},[2354],"mspace","margin-right:0.2778em;",[1023,2357,2325],{"className":2358},[2359],"mrel",[1023,2361],{"className":2362,"style":2355},[2354],[1023,2364,2366,2370,2373],{"className":2365},[1070],[1023,2367],{"className":2368,"style":2369},[1074],"height:0.8141em;",[1023,2371,1053],{"className":2372},[1079],[1023,2374,2376,2380],{"className":2375},[1079],[1023,2377,2379],{"className":2378},[1079],"0",[1023,2381,2384],{"className":2382},[2383],"msupsub",[1023,2385,2388],{"className":2386},[2387],"vlist-t",[1023,2389,2392],{"className":2390},[2391],"vlist-r",[1023,2393,2396],{"className":2394,"style":2369},[2395],"vlist",[1023,2397,2399,2404],{"style":2398},"top:-3.063em;margin-right:0.05em;",[1023,2400],{"className":2401,"style":2403},[2402],"pstrut","height:2.7em;",[1023,2405,2411],{"className":2406},[2407,2408,2409,2410],"sizing","reset-size6","size3","mtight",[1023,2412,2334],{"className":2413},[1079,2410]," phần tử rồi in bảng:",[1352,2416,2419],{"className":2417,"code":2418,"language":2241,"meta":1357},[2239],"chien_luoc   n        copies      copies\u002Fn\nx2           100000   ...         ...\nx1.5         100000   ...         ...\n+1           100000   ...         ...\n",[992,2420,2418],{"__ignoreMap":1357},[973,2422,2423,2426,2427,2430,2431,2434,2435,2438,2439,2510,2511,2514],{},[1487,2424,2425],{},"Kiểm tra:"," nhân đôi cho ",[992,2428,2429],{},"copies \u003C 2n",". Chiến lược ",[992,2432,2433],{},"+1"," cho ",[992,2436,2437],{},"copies"," xấp xỉ ",[1023,2440,2442,2467],{"className":2441},[1026],[1023,2443,2445],{"className":2444},[1030],[1032,2446,2447],{"xmlns":1034},[1036,2448,2449,2464],{},[1039,2450,2451,2458,2462],{},[2327,2452,2453,2455],{},[1042,2454,1262],{},[1051,2456,2457],{},"2",[1042,2459,2461],{"mathvariant":2460},"normal","\u002F",[1051,2463,2457],{},[1058,2465,2466],{"encoding":1060},"n^2\u002F2",[1023,2468,2470],{"className":2469,"ariaHidden":1066},[1065],[1023,2471,2473,2477,2506],{"className":2472},[1070],[1023,2474],{"className":2475,"style":2476},[1074],"height:1.0641em;vertical-align:-0.25em;",[1023,2478,2480,2483],{"className":2479},[1079],[1023,2481,1262],{"className":2482},[1079,1080],[1023,2484,2486],{"className":2485},[2383],[1023,2487,2489],{"className":2488},[2387],[1023,2490,2492],{"className":2491},[2391],[1023,2493,2495],{"className":2494,"style":2369},[2395],[1023,2496,2497,2500],{"style":2398},[1023,2498],{"className":2499,"style":2403},[2402],[1023,2501,2503],{"className":2502},[2407,2408,2409,2410],[1023,2504,2457],{"className":2505},[1079,2410],[1023,2507,2509],{"className":2508},[1079],"\u002F2",". Viết 3 dòng trong ",[992,2512,2513],{},"README.md"," giải thích kết quả.",[981,2516,2518,2519,2522],{"id":2517},"bài-3-bản-c-vect-nâng-cao","Bài 3: Bản C++ ",[992,2520,2521],{},"Vec\u003CT>"," (nâng cao)",[973,2524,2525,2526,2528,2529,2532,2533,1517],{},"Viết class template ",[992,2527,2521],{}," trong ",[992,2530,2531],{},"vec.hpp",", tự quản lý bộ nhớ. Không dùng ",[992,2534,2535],{},"std::vector",[1099,2537,2538,2548],{},[1102,2539,2540],{},[1105,2541,2542,2545],{},[1108,2543,2544],{},"Thành phần",[1108,2546,2547],{},"Yêu cầu",[1118,2549,2550,2563,2573,2585,2593,2609,2619,2633,2645,2663],{},[1105,2551,2552,2560],{},[1123,2553,2554,1656,2557],{},[992,2555,2556],{},"Vec()",[992,2558,2559],{},"explicit Vec(size_t cap)",[1123,2561,2562],{},"Khởi tạo rỗng",[1105,2564,2565,2570],{},[1123,2566,2567],{},[992,2568,2569],{},"~Vec()",[1123,2571,2572],{},"Hủy đúng các phần tử đang dùng rồi giải phóng vùng nhớ",[1105,2574,2575,2578],{},[1123,2576,2577],{},"Copy constructor, copy assignment",[1123,2579,2580,2581,2584],{},"Deep copy. Tự gán ",[992,2582,2583],{},"v = v"," không hỏng",[1105,2586,2587,2590],{},[1123,2588,2589],{},"Move constructor, move assignment",[1123,2591,2592],{},"Chuyển con trỏ, để nguồn ở trạng thái rỗng hợp lệ",[1105,2594,2595,2606],{},[1123,2596,2597,1656,2600,1656,2603],{},[992,2598,2599],{},"push_back(const T&)",[992,2601,2602],{},"push_back(T&&)",[992,2604,2605],{},"pop_back()",[1123,2607,2608],{},"Như Bài 1",[1105,2610,2611,2616],{},[1123,2612,2613],{},[992,2614,2615],{},"T& operator[](size_t)",[1123,2617,2618],{},"Không kiểm tra biên",[1105,2620,2621,2626],{},[1123,2622,2623],{},[992,2624,2625],{},"T& at(size_t)",[1123,2627,2628,2629,2632],{},"Ném ",[992,2630,2631],{},"std::out_of_range"," khi ngoài biên",[1105,2634,2635,2643],{},[1123,2636,2637,1656,2640],{},[992,2638,2639],{},"insert(size_t i, const T&)",[992,2641,2642],{},"erase(size_t i)",[1123,2644,2608],{},[1105,2646,2647,2661],{},[1123,2648,2649,1656,2652,1656,2655,1656,2658],{},[992,2650,2651],{},"size()",[992,2653,2654],{},"capacity()",[992,2656,2657],{},"empty()",[992,2659,2660],{},"reserve(n)",[1123,2662,2608],{},[1105,2664,2665,2673],{},[1123,2666,2667,1656,2670],{},[992,2668,2669],{},"T* begin()",[992,2671,2672],{},"T* end()",[1123,2674,2675,2676],{},"Để dùng được ",[992,2677,2678],{},"for (auto &x : v)",[973,2680,2681,2252,2684,2687,2688,2691,2692,1517],{},[1487,2682,2683],{},"Test mẫu:",[992,2685,2686],{},"Vec\u003Cstd::string>",". Push 1000 chuỗi, copy sang ",[992,2689,2690],{},"Vec"," khác, sửa bản copy, kiểm tra bản gốc không đổi. Move sang biến mới, kiểm tra nguồn có ",[992,2693,2694],{},"size() == 0",[2245,2696,2697],{},[973,2698,2699,2700,2703,2704,2707],{},"Dùng ",[992,2701,2702],{},"::operator new(cap * sizeof(T))"," để cấp vùng nhớ thô, rồi placement ",[992,2705,2706],{},"new (&data[i]) T(x)"," để dựng phần tử. Như vậy capacity dư không gọi constructor thừa.",[981,2709,2711],{"id":2710},"tiêu-chí-hoàn-thành","✅ Tiêu chí hoàn thành",[986,2713,2716,2729,2739,2752,2758],{"className":2714},[2715],"contains-task-list",[989,2717,2720,2725,2726,2728],{"className":2718},[2719],"task-list-item",[2721,2722],"input",{"disabled":2723,"type":2724},true,"checkbox"," Toàn bộ test ",[992,2727,2235],{}," của Bài 1 pass.",[989,2730,2732,2734,2735,2738],{"className":2731},[2719],[2721,2733],{"disabled":2723,"type":2724}," Build với ",[992,2736,2737],{},"gcc -Wall -Wextra -g -fsanitize=address,undefined"," không có cảnh báo, không lỗi runtime.",[989,2740,2742,2308,2744,2747,2748,2751],{"className":2741},[2719],[2721,2743],{"disabled":2723,"type":2724},[992,2745,2746],{},"valgrind --leak-check=full .\u002Ftest_da"," báo ",[992,2749,2750],{},"0 bytes in 0 blocks"," bị leak.",[989,2753,2755,2757],{"className":2754},[2719],[2721,2756],{"disabled":2723,"type":2724}," Bảng đo Bài 2 có số thật và 3 dòng giải thích.",[989,2759,2761,2763,2764,2308,2766,2809,2810,2812,2813,1517],{"className":2760},[2719],[2721,2762],{"disabled":2723,"type":2724}," Nói được bằng lời: vì sao nhân đôi cho ",[992,2765,1010],{},[1023,2767,2769,2788],{"className":2768},[1026],[1023,2770,2772],{"className":2771},[1030],[1032,2773,2774],{"xmlns":1034},[1036,2775,2776,2786],{},[1039,2777,2778,2780,2782,2784],{},[1042,2779,1044],{},[1046,2781,1049],{"stretchy":1048},[1051,2783,1053],{},[1046,2785,1056],{"stretchy":1048},[1058,2787,1061],{"encoding":1060},[1023,2789,2791],{"className":2790,"ariaHidden":1066},[1065],[1023,2792,2794,2797,2800,2803,2806],{"className":2793},[1070],[1023,2795],{"className":2796,"style":1075},[1074],[1023,2798,1044],{"className":2799,"style":1081},[1079,1080],[1023,2801,1049],{"className":2802},[1085],[1023,2804,1053],{"className":2805},[1079],[1023,2807,1056],{"className":2808},[1092]," trung bình, còn ",[992,2811,2433],{}," cho tổng ",[1023,2814,2816,2840],{"className":2815},[1026],[1023,2817,2819],{"className":2818},[1030],[1032,2820,2821],{"xmlns":1034},[1036,2822,2823,2837],{},[1039,2824,2825,2827,2829,2835],{},[1042,2826,1044],{},[1046,2828,1049],{"stretchy":1048},[2327,2830,2831,2833],{},[1042,2832,1262],{},[1051,2834,2457],{},[1046,2836,1056],{"stretchy":1048},[1058,2838,2839],{"encoding":1060},"O(n^2)",[1023,2841,2843],{"className":2842,"ariaHidden":1066},[1065],[1023,2844,2846,2849,2852,2855,2884],{"className":2845},[1070],[1023,2847],{"className":2848,"style":2476},[1074],[1023,2850,1044],{"className":2851,"style":1081},[1079,1080],[1023,2853,1049],{"className":2854},[1085],[1023,2856,2858,2861],{"className":2857},[1079],[1023,2859,1262],{"className":2860},[1079,1080],[1023,2862,2864],{"className":2863},[2383],[1023,2865,2867],{"className":2866},[2387],[1023,2868,2870],{"className":2869},[2391],[1023,2871,2873],{"className":2872,"style":2369},[2395],[1023,2874,2875,2878],{"style":2398},[1023,2876],{"className":2877,"style":2403},[2402],[1023,2879,2881],{"className":2880},[2407,2408,2409,2410],[1023,2882,2457],{"className":2883},[1079,2410],[1023,2885,1056],{"className":2886},[1092],[968,2888,2890],{"id":2889},"câu-hỏi-ôn-tập","❓ Câu hỏi ôn tập",[986,2892,2893,2901,2998,3003],{},[989,2894,2895,2897,2898,2900],{},[992,2896,994],{}," khác ",[992,2899,1000],{}," ở điểm nào? Khi nào phải cấp phát lại?",[989,2902,2903,2904,2906,2907,2950,2951,2953,2954,2997],{},"Vì sao ",[992,2905,1010],{}," cuối là ",[1023,2908,2910,2929],{"className":2909},[1026],[1023,2911,2913],{"className":2912},[1030],[1032,2914,2915],{"xmlns":1034},[1036,2916,2917,2927],{},[1039,2918,2919,2921,2923,2925],{},[1042,2920,1044],{},[1046,2922,1049],{"stretchy":1048},[1051,2924,1053],{},[1046,2926,1056],{"stretchy":1048},[1058,2928,1061],{"encoding":1060},[1023,2930,2932],{"className":2931,"ariaHidden":1066},[1065],[1023,2933,2935,2938,2941,2944,2947],{"className":2934},[1070],[1023,2936],{"className":2937,"style":1075},[1074],[1023,2939,1044],{"className":2940,"style":1081},[1079,1080],[1023,2942,1049],{"className":2943},[1085],[1023,2945,1053],{"className":2946},[1079],[1023,2948,1056],{"className":2949},[1092]," trung bình nhưng ",[992,2952,2251],{}," giữa là ",[1023,2955,2957,2976],{"className":2956},[1026],[1023,2958,2960],{"className":2959},[1030],[1032,2961,2962],{"xmlns":1034},[1036,2963,2964,2974],{},[1039,2965,2966,2968,2970,2972],{},[1042,2967,1044],{},[1046,2969,1049],{"stretchy":1048},[1042,2971,1262],{},[1046,2973,1056],{"stretchy":1048},[1058,2975,1267],{"encoding":1060},[1023,2977,2979],{"className":2978,"ariaHidden":1066},[1065],[1023,2980,2982,2985,2988,2991,2994],{"className":2981},[1070],[1023,2983],{"className":2984,"style":1075},[1074],[1023,2986,1044],{"className":2987,"style":1081},[1079,1080],[1023,2989,1049],{"className":2990},[1085],[1023,2992,1262],{"className":2993},[1079,1080],[1023,2995,1056],{"className":2996},[1092],"?",[989,2999,2903,3000,3002],{},[992,3001,1411],{}," phải qua con trỏ tạm?",[989,3004,3005,3006,3009,3010,2997],{},"Khi nào dùng ",[992,3007,3008],{},"reserve",", khi nào dùng ",[992,3011,3012],{},"shrink_to_fit",[3014,3015],"hr",{},[973,3017,3018],{},"🌕 Bạn đã xong ngày 1. Cài đặt xong Dynamic Array chạy sạch thì sang Day 2.",[3020,3021,3022],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":1357,"searchDepth":68,"depth":68,"links":3024},[3025,3026,3032,3033,3040],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":3027},[3028,3029,3030,3031],{"id":983,"depth":73,"text":984},{"id":1014,"depth":73,"text":1015},{"id":1096,"depth":73,"text":1097},{"id":1349,"depth":73,"text":1350},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":3034},[3035,3036,3037,3039],{"id":1501,"depth":73,"text":1502},{"id":2263,"depth":73,"text":2264},{"id":2517,"depth":73,"text":3038},"Bài 3: Bản C++ Vec\u003CT> (nâng cao)",{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"data-structure","Hiểu size, capacity và cơ chế nhân đôi, tự cài đặt Dynamic Array bằng C\u002FC++.","de","md","2026-09-19",{},null,[3049,3050],"thuat-toan-moi-truong-phat-trien","big-o-notation",{"title":60,"description":3042},[3053,3054],"array","dynamic-array","N1PjOTaCKcLjI_zzgGWU-bdAWppI-vRzmr24BB7y3Bs",{"id":3057,"title":65,"body":3058,"category":3041,"day":68,"description":4666,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":4667,"navigation":2723,"outcomes":3047,"path":66,"prerequisites":4668,"seo":4670,"stem":67,"tags":4671,"__hash__":4673},"challenges\u002Fchallenges\u002F2.linked-list.md",{"type":965,"value":3059,"toc":4650},[3060,3062,3065,3067,3071,3088,3092,3109,3113,3213,3526,3528,3536,3558,3560,3572,3576,3591,4180,4184,4202,4207,4213,4217,4277,4282,4337,4343,4347,4438,4536,4582,4590,4592,4627,4629,4643,4645,4648],[968,3061,971],{"id":970},[973,3063,3064],{},"Bài này học nút, con trỏ và hai loại linked list. Bạn biết khi nào dùng list thay mảng.",[968,3066,979],{"id":978},[981,3068,3070],{"id":3069},"nút-và-list-đơn","Nút và list đơn",[986,3072,3073,3076,3079,3082,3085],{},[989,3074,3075],{},"Nút gồm dữ liệu và con trỏ next.",[989,3077,3078],{},"Next trỏ tới nút kế tiếp trong chuỗi.",[989,3080,3081],{},"Head là nút đầu, cửa vào duy nhất.",[989,3083,3084],{},"Ví dụ đời thường: đoàn tàu, mỗi toa nối toa sau.",[989,3086,3087],{},"Đọc phần tử thứ k phải duyệt từ head.",[981,3089,3091],{"id":3090},"list-đôi-và-list-vòng","List đôi và list vòng",[986,3093,3094,3097,3100,3103,3106],{},[989,3095,3096],{},"List đôi thêm con trỏ prev trỏ ngược.",[989,3098,3099],{},"Prev giúp duyệt hai chiều, xóa nhanh hơn.",[989,3101,3102],{},"List vòng cho nút cuối trỏ về head.",[989,3104,3105],{},"Ví dụ đời thường: lịch sử trình duyệt đi tới lui.",[989,3107,3108],{},"Giá phải trả là tốn thêm bộ nhớ.",[981,3110,3112],{"id":3111},"so-sánh-với-mảng","So sánh với mảng",[986,3114,3115,3161,3207,3210],{},[989,3116,3117,3118,1517],{},"Mảng truy xuất thứ k trong ",[1023,3119,3121,3140],{"className":3120},[1026],[1023,3122,3124],{"className":3123},[1030],[1032,3125,3126],{"xmlns":1034},[1036,3127,3128,3138],{},[1039,3129,3130,3132,3134,3136],{},[1042,3131,1044],{},[1046,3133,1049],{"stretchy":1048},[1051,3135,1053],{},[1046,3137,1056],{"stretchy":1048},[1058,3139,1061],{"encoding":1060},[1023,3141,3143],{"className":3142,"ariaHidden":1066},[1065],[1023,3144,3146,3149,3152,3155,3158],{"className":3145},[1070],[1023,3147],{"className":3148,"style":1075},[1074],[1023,3150,1044],{"className":3151,"style":1081},[1079,1080],[1023,3153,1049],{"className":3154},[1085],[1023,3156,1053],{"className":3157},[1079],[1023,3159,1056],{"className":3160},[1092],[989,3162,3163,3164,1517],{},"List chèn xóa đầu trong ",[1023,3165,3167,3186],{"className":3166},[1026],[1023,3168,3170],{"className":3169},[1030],[1032,3171,3172],{"xmlns":1034},[1036,3173,3174,3184],{},[1039,3175,3176,3178,3180,3182],{},[1042,3177,1044],{},[1046,3179,1049],{"stretchy":1048},[1051,3181,1053],{},[1046,3183,1056],{"stretchy":1048},[1058,3185,1061],{"encoding":1060},[1023,3187,3189],{"className":3188,"ariaHidden":1066},[1065],[1023,3190,3192,3195,3198,3201,3204],{"className":3191},[1070],[1023,3193],{"className":3194,"style":1075},[1074],[1023,3196,1044],{"className":3197,"style":1081},[1079,1080],[1023,3199,1049],{"className":3200},[1085],[1023,3202,1053],{"className":3203},[1079],[1023,3205,1056],{"className":3206},[1092],[989,3208,3209],{},"Mảng thân thiện cache hơn list.",[989,3211,3212],{},"Ví dụ đời thường: mảng như kệ sách đánh số.",[1099,3214,3215,3227],{},[1102,3216,3217],{},[1105,3218,3219,3221,3224],{},[1108,3220,1110],{},[1108,3222,3223],{},"Mảng",[1108,3225,3226],{},"List đơn",[1118,3228,3229,3324,3419,3515],{},[1105,3230,3231,3234,3279],{},[1123,3232,3233],{},"Đọc thứ k",[1123,3235,3236],{},[1023,3237,3239,3258],{"className":3238},[1026],[1023,3240,3242],{"className":3241},[1030],[1032,3243,3244],{"xmlns":1034},[1036,3245,3246,3256],{},[1039,3247,3248,3250,3252,3254],{},[1042,3249,1044],{},[1046,3251,1049],{"stretchy":1048},[1051,3253,1053],{},[1046,3255,1056],{"stretchy":1048},[1058,3257,1061],{"encoding":1060},[1023,3259,3261],{"className":3260,"ariaHidden":1066},[1065],[1023,3262,3264,3267,3270,3273,3276],{"className":3263},[1070],[1023,3265],{"className":3266,"style":1075},[1074],[1023,3268,1044],{"className":3269,"style":1081},[1079,1080],[1023,3271,1049],{"className":3272},[1085],[1023,3274,1053],{"className":3275},[1079],[1023,3277,1056],{"className":3278},[1092],[1123,3280,3281],{},[1023,3282,3284,3303],{"className":3283},[1026],[1023,3285,3287],{"className":3286},[1030],[1032,3288,3289],{"xmlns":1034},[1036,3290,3291,3301],{},[1039,3292,3293,3295,3297,3299],{},[1042,3294,1044],{},[1046,3296,1049],{"stretchy":1048},[1042,3298,1262],{},[1046,3300,1056],{"stretchy":1048},[1058,3302,1267],{"encoding":1060},[1023,3304,3306],{"className":3305,"ariaHidden":1066},[1065],[1023,3307,3309,3312,3315,3318,3321],{"className":3308},[1070],[1023,3310],{"className":3311,"style":1075},[1074],[1023,3313,1044],{"className":3314,"style":1081},[1079,1080],[1023,3316,1049],{"className":3317},[1085],[1023,3319,1262],{"className":3320},[1079,1080],[1023,3322,1056],{"className":3323},[1092],[1105,3325,3326,3329,3374],{},[1123,3327,3328],{},"Chèn xóa đầu",[1123,3330,3331],{},[1023,3332,3334,3353],{"className":3333},[1026],[1023,3335,3337],{"className":3336},[1030],[1032,3338,3339],{"xmlns":1034},[1036,3340,3341,3351],{},[1039,3342,3343,3345,3347,3349],{},[1042,3344,1044],{},[1046,3346,1049],{"stretchy":1048},[1042,3348,1262],{},[1046,3350,1056],{"stretchy":1048},[1058,3352,1267],{"encoding":1060},[1023,3354,3356],{"className":3355,"ariaHidden":1066},[1065],[1023,3357,3359,3362,3365,3368,3371],{"className":3358},[1070],[1023,3360],{"className":3361,"style":1075},[1074],[1023,3363,1044],{"className":3364,"style":1081},[1079,1080],[1023,3366,1049],{"className":3367},[1085],[1023,3369,1262],{"className":3370},[1079,1080],[1023,3372,1056],{"className":3373},[1092],[1123,3375,3376],{},[1023,3377,3379,3398],{"className":3378},[1026],[1023,3380,3382],{"className":3381},[1030],[1032,3383,3384],{"xmlns":1034},[1036,3385,3386,3396],{},[1039,3387,3388,3390,3392,3394],{},[1042,3389,1044],{},[1046,3391,1049],{"stretchy":1048},[1051,3393,1053],{},[1046,3395,1056],{"stretchy":1048},[1058,3397,1061],{"encoding":1060},[1023,3399,3401],{"className":3400,"ariaHidden":1066},[1065],[1023,3402,3404,3407,3410,3413,3416],{"className":3403},[1070],[1023,3405],{"className":3406,"style":1075},[1074],[1023,3408,1044],{"className":3409,"style":1081},[1079,1080],[1023,3411,1049],{"className":3412},[1085],[1023,3414,1053],{"className":3415},[1079],[1023,3417,1056],{"className":3418},[1092],[1105,3420,3421,3424,3469],{},[1123,3422,3423],{},"Chèn cuối",[1123,3425,3426],{},[1023,3427,3429,3448],{"className":3428},[1026],[1023,3430,3432],{"className":3431},[1030],[1032,3433,3434],{"xmlns":1034},[1036,3435,3436,3446],{},[1039,3437,3438,3440,3442,3444],{},[1042,3439,1044],{},[1046,3441,1049],{"stretchy":1048},[1051,3443,1053],{},[1046,3445,1056],{"stretchy":1048},[1058,3447,1061],{"encoding":1060},[1023,3449,3451],{"className":3450,"ariaHidden":1066},[1065],[1023,3452,3454,3457,3460,3463,3466],{"className":3453},[1070],[1023,3455],{"className":3456,"style":1075},[1074],[1023,3458,1044],{"className":3459,"style":1081},[1079,1080],[1023,3461,1049],{"className":3462},[1085],[1023,3464,1053],{"className":3465},[1079],[1023,3467,1056],{"className":3468},[1092],[1123,3470,3471,3514],{},[1023,3472,3474,3493],{"className":3473},[1026],[1023,3475,3477],{"className":3476},[1030],[1032,3478,3479],{"xmlns":1034},[1036,3480,3481,3491],{},[1039,3482,3483,3485,3487,3489],{},[1042,3484,1044],{},[1046,3486,1049],{"stretchy":1048},[1042,3488,1262],{},[1046,3490,1056],{"stretchy":1048},[1058,3492,1267],{"encoding":1060},[1023,3494,3496],{"className":3495,"ariaHidden":1066},[1065],[1023,3497,3499,3502,3505,3508,3511],{"className":3498},[1070],[1023,3500],{"className":3501,"style":1075},[1074],[1023,3503,1044],{"className":3504,"style":1081},[1079,1080],[1023,3506,1049],{"className":3507},[1085],[1023,3509,1262],{"className":3510},[1079,1080],[1023,3512,1056],{"className":3513},[1092]," nếu thiếu tail",[1105,3516,3517,3520,3523],{},[1123,3518,3519],{},"Bộ nhớ thêm",[1123,3521,3522],{},"Thấp",[1123,3524,3525],{},"1 con trỏ mỗi nút",[968,3527,1433],{"id":1432},[986,3529,3530,3533],{},[989,3531,3532],{},"Input: A -> B -> C, chèn X sau A. Output: A -> X -> B -> C.",[989,3534,3535],{},"Giải thích: chỉ nối lại 2 con trỏ nên không mất nút nào.",[1352,3537,3541],{"className":3538,"code":3539,"language":3540,"meta":1357,"style":1357},"language-python shiki shiki-themes github-light github-light github-dark","# Chèn sau nút đã biết\nnew_node.next = cur.next  # nút mới trỏ tới nút kế\ncur.next = new_node  # nút hiện tại trỏ sang nút mới\n","python",[992,3542,3543,3548,3553],{"__ignoreMap":1357},[1023,3544,3545],{"class":1362,"line":63},[1023,3546,3547],{},"# Chèn sau nút đã biết\n",[1023,3549,3550],{"class":1362,"line":68},[1023,3551,3552],{},"new_node.next = cur.next  # nút mới trỏ tới nút kế\n",[1023,3554,3555],{"class":1362,"line":73},[1023,3556,3557],{},"cur.next = new_node  # nút hiện tại trỏ sang nút mới\n",[968,3559,1482],{"id":1481},[973,3561,1485,3562,3564,3565,3568,3569,1517],{},[1487,3563,1489],{}," (hoặc C++ không dùng ",[992,3566,3567],{},"std::list","). Nộp vào ",[992,3570,3571],{},"day-002\u002F",[981,3573,3575],{"id":3574},"bài-1-singly-linked-list","Bài 1: Singly linked list",[1352,3577,3579],{"className":1354,"code":3578,"language":1356,"meta":1357,"style":1357},"typedef struct Node { int val; struct Node *next; } Node;\ntypedef struct { Node *head; Node *tail; size_t size; } SList;\n",[992,3580,3581,3586],{"__ignoreMap":1357},[1023,3582,3583],{"class":1362,"line":63},[1023,3584,3585],{},"typedef struct Node { int val; struct Node *next; } Node;\n",[1023,3587,3588],{"class":1362,"line":68},[1023,3589,3590],{},"typedef struct { Node *head; Node *tail; size_t size; } SList;\n",[1099,3592,3593,3603],{},[1102,3594,3595],{},[1105,3596,3597,3599,3601],{},[1108,3598,1566],{},[1108,3600,1569],{},[1108,3602,1113],{},[1118,3604,3605,3665,3720,3778,3835,3892,3950,4010,4070,4125],{},[1105,3606,3607,3612,3620],{},[1123,3608,3609],{},[992,3610,3611],{},"void sl_init(SList *l)",[1123,3613,3614,3615,1656,3618],{},"List rỗng: ",[992,3616,3617],{},"head = tail = NULL",[992,3619,1594],{},[1123,3621,3622],{},[1023,3623,3625,3644],{"className":3624},[1026],[1023,3626,3628],{"className":3627},[1030],[1032,3629,3630],{"xmlns":1034},[1036,3631,3632,3642],{},[1039,3633,3634,3636,3638,3640],{},[1042,3635,1044],{},[1046,3637,1049],{"stretchy":1048},[1051,3639,1053],{},[1046,3641,1056],{"stretchy":1048},[1058,3643,1061],{"encoding":1060},[1023,3645,3647],{"className":3646,"ariaHidden":1066},[1065],[1023,3648,3650,3653,3656,3659,3662],{"className":3649},[1070],[1023,3651],{"className":3652,"style":1075},[1074],[1023,3654,1044],{"className":3655,"style":1081},[1079,1080],[1023,3657,1049],{"className":3658},[1085],[1023,3660,1053],{"className":3661},[1079],[1023,3663,1056],{"className":3664},[1092],[1105,3666,3667,3672,3675],{},[1123,3668,3669],{},[992,3670,3671],{},"bool sl_push_front(SList *l, int x)",[1123,3673,3674],{},"Thêm đầu",[1123,3676,3677],{},[1023,3678,3680,3699],{"className":3679},[1026],[1023,3681,3683],{"className":3682},[1030],[1032,3684,3685],{"xmlns":1034},[1036,3686,3687,3697],{},[1039,3688,3689,3691,3693,3695],{},[1042,3690,1044],{},[1046,3692,1049],{"stretchy":1048},[1051,3694,1053],{},[1046,3696,1056],{"stretchy":1048},[1058,3698,1061],{"encoding":1060},[1023,3700,3702],{"className":3701,"ariaHidden":1066},[1065],[1023,3703,3705,3708,3711,3714,3717],{"className":3704},[1070],[1023,3706],{"className":3707,"style":1075},[1074],[1023,3709,1044],{"className":3710,"style":1081},[1079,1080],[1023,3712,1049],{"className":3713},[1085],[1023,3715,1053],{"className":3716},[1079],[1023,3718,1056],{"className":3719},[1092],[1105,3721,3722,3727,3733],{},[1123,3723,3724],{},[992,3725,3726],{},"bool sl_push_back(SList *l, int x)",[1123,3728,3729,3730],{},"Thêm cuối nhờ ",[992,3731,3732],{},"tail",[1123,3734,3735],{},[1023,3736,3738,3757],{"className":3737},[1026],[1023,3739,3741],{"className":3740},[1030],[1032,3742,3743],{"xmlns":1034},[1036,3744,3745,3755],{},[1039,3746,3747,3749,3751,3753],{},[1042,3748,1044],{},[1046,3750,1049],{"stretchy":1048},[1051,3752,1053],{},[1046,3754,1056],{"stretchy":1048},[1058,3756,1061],{"encoding":1060},[1023,3758,3760],{"className":3759,"ariaHidden":1066},[1065],[1023,3761,3763,3766,3769,3772,3775],{"className":3762},[1070],[1023,3764],{"className":3765,"style":1075},[1074],[1023,3767,1044],{"className":3768,"style":1081},[1079,1080],[1023,3770,1049],{"className":3771},[1085],[1023,3773,1053],{"className":3774},[1079],[1023,3776,1056],{"className":3777},[1092],[1105,3779,3780,3785,3790],{},[1123,3781,3782],{},[992,3783,3784],{},"bool sl_pop_front(SList *l, int *out)",[1123,3786,3787,3788],{},"Gỡ đầu. Rỗng trả ",[992,3789,1048],{},[1123,3791,3792],{},[1023,3793,3795,3814],{"className":3794},[1026],[1023,3796,3798],{"className":3797},[1030],[1032,3799,3800],{"xmlns":1034},[1036,3801,3802,3812],{},[1039,3803,3804,3806,3808,3810],{},[1042,3805,1044],{},[1046,3807,1049],{"stretchy":1048},[1051,3809,1053],{},[1046,3811,1056],{"stretchy":1048},[1058,3813,1061],{"encoding":1060},[1023,3815,3817],{"className":3816,"ariaHidden":1066},[1065],[1023,3818,3820,3823,3826,3829,3832],{"className":3819},[1070],[1023,3821],{"className":3822,"style":1075},[1074],[1023,3824,1044],{"className":3825,"style":1081},[1079,1080],[1023,3827,1049],{"className":3828},[1085],[1023,3830,1053],{"className":3831},[1079],[1023,3833,1056],{"className":3834},[1092],[1105,3836,3837,3842,3847],{},[1123,3838,3839],{},[992,3840,3841],{},"bool sl_insert_after(SList *l, Node *n, int x)",[1123,3843,3844,3845],{},"Chèn sau nút ",[992,3846,1262],{},[1123,3848,3849],{},[1023,3850,3852,3871],{"className":3851},[1026],[1023,3853,3855],{"className":3854},[1030],[1032,3856,3857],{"xmlns":1034},[1036,3858,3859,3869],{},[1039,3860,3861,3863,3865,3867],{},[1042,3862,1044],{},[1046,3864,1049],{"stretchy":1048},[1051,3866,1053],{},[1046,3868,1056],{"stretchy":1048},[1058,3870,1061],{"encoding":1060},[1023,3872,3874],{"className":3873,"ariaHidden":1066},[1065],[1023,3875,3877,3880,3883,3886,3889],{"className":3876},[1070],[1023,3878],{"className":3879,"style":1075},[1074],[1023,3881,1044],{"className":3882,"style":1081},[1079,1080],[1023,3884,1049],{"className":3885},[1085],[1023,3887,1053],{"className":3888},[1079],[1023,3890,1056],{"className":3891},[1092],[1105,3893,3894,3899,3905],{},[1123,3895,3896],{},[992,3897,3898],{},"bool sl_remove(SList *l, int x)",[1123,3900,3901,3902],{},"Xóa nút đầu tiên có giá trị ",[992,3903,3904],{},"x",[1123,3906,3907],{},[1023,3908,3910,3929],{"className":3909},[1026],[1023,3911,3913],{"className":3912},[1030],[1032,3914,3915],{"xmlns":1034},[1036,3916,3917,3927],{},[1039,3918,3919,3921,3923,3925],{},[1042,3920,1044],{},[1046,3922,1049],{"stretchy":1048},[1042,3924,1262],{},[1046,3926,1056],{"stretchy":1048},[1058,3928,1267],{"encoding":1060},[1023,3930,3932],{"className":3931,"ariaHidden":1066},[1065],[1023,3933,3935,3938,3941,3944,3947],{"className":3934},[1070],[1023,3936],{"className":3937,"style":1075},[1074],[1023,3939,1044],{"className":3940,"style":1081},[1079,1080],[1023,3942,1049],{"className":3943},[1085],[1023,3945,1262],{"className":3946},[1079,1080],[1023,3948,1056],{"className":3949},[1092],[1105,3951,3952,3957,3965],{},[1123,3953,3954],{},[992,3955,3956],{},"Node *sl_find(const SList *l, int x)",[1123,3958,3959,3960,3962,3963],{},"Trả nút đầu tiên có giá trị ",[992,3961,3904],{},", không thấy trả ",[992,3964,1428],{},[1123,3966,3967],{},[1023,3968,3970,3989],{"className":3969},[1026],[1023,3971,3973],{"className":3972},[1030],[1032,3974,3975],{"xmlns":1034},[1036,3976,3977,3987],{},[1039,3978,3979,3981,3983,3985],{},[1042,3980,1044],{},[1046,3982,1049],{"stretchy":1048},[1042,3984,1262],{},[1046,3986,1056],{"stretchy":1048},[1058,3988,1267],{"encoding":1060},[1023,3990,3992],{"className":3991,"ariaHidden":1066},[1065],[1023,3993,3995,3998,4001,4004,4007],{"className":3994},[1070],[1023,3996],{"className":3997,"style":1075},[1074],[1023,3999,1044],{"className":4000,"style":1081},[1079,1080],[1023,4002,1049],{"className":4003},[1085],[1023,4005,1262],{"className":4006},[1079,1080],[1023,4008,1056],{"className":4009},[1092],[1105,4011,4012,4017,4023],{},[1123,4013,4014],{},[992,4015,4016],{},"bool sl_get(const SList *l, size_t k, int *out)",[1123,4018,4019,4020],{},"Đọc phần tử thứ ",[992,4021,4022],{},"k",[1123,4024,4025],{},[1023,4026,4028,4048],{"className":4027},[1026],[1023,4029,4031],{"className":4030},[1030],[1032,4032,4033],{"xmlns":1034},[1036,4034,4035,4045],{},[1039,4036,4037,4039,4041,4043],{},[1042,4038,1044],{},[1046,4040,1049],{"stretchy":1048},[1042,4042,4022],{},[1046,4044,1056],{"stretchy":1048},[1058,4046,4047],{"encoding":1060},"O(k)",[1023,4049,4051],{"className":4050,"ariaHidden":1066},[1065],[1023,4052,4054,4057,4060,4063,4067],{"className":4053},[1070],[1023,4055],{"className":4056,"style":1075},[1074],[1023,4058,1044],{"className":4059,"style":1081},[1079,1080],[1023,4061,1049],{"className":4062},[1085],[1023,4064,4022],{"className":4065,"style":4066},[1079,1080],"margin-right:0.0315em;",[1023,4068,1056],{"className":4069},[1092],[1105,4071,4072,4077,4080],{},[1123,4073,4074],{},[992,4075,4076],{},"void sl_reverse(SList *l)",[1123,4078,4079],{},"Đảo ngược tại chỗ, không cấp nút mới",[1123,4081,4082],{},[1023,4083,4085,4104],{"className":4084},[1026],[1023,4086,4088],{"className":4087},[1030],[1032,4089,4090],{"xmlns":1034},[1036,4091,4092,4102],{},[1039,4093,4094,4096,4098,4100],{},[1042,4095,1044],{},[1046,4097,1049],{"stretchy":1048},[1042,4099,1262],{},[1046,4101,1056],{"stretchy":1048},[1058,4103,1267],{"encoding":1060},[1023,4105,4107],{"className":4106,"ariaHidden":1066},[1065],[1023,4108,4110,4113,4116,4119,4122],{"className":4109},[1070],[1023,4111],{"className":4112,"style":1075},[1074],[1023,4114,1044],{"className":4115,"style":1081},[1079,1080],[1023,4117,1049],{"className":4118},[1085],[1023,4120,1262],{"className":4121},[1079,1080],[1023,4123,1056],{"className":4124},[1092],[1105,4126,4127,4132,4135],{},[1123,4128,4129],{},[992,4130,4131],{},"void sl_clear(SList *l)",[1123,4133,4134],{},"Giải phóng mọi nút",[1123,4136,4137],{},[1023,4138,4140,4159],{"className":4139},[1026],[1023,4141,4143],{"className":4142},[1030],[1032,4144,4145],{"xmlns":1034},[1036,4146,4147,4157],{},[1039,4148,4149,4151,4153,4155],{},[1042,4150,1044],{},[1046,4152,1049],{"stretchy":1048},[1042,4154,1262],{},[1046,4156,1056],{"stretchy":1048},[1058,4158,1267],{"encoding":1060},[1023,4160,4162],{"className":4161,"ariaHidden":1066},[1065],[1023,4163,4165,4168,4171,4174,4177],{"className":4164},[1070],[1023,4166],{"className":4167,"style":1075},[1074],[1023,4169,1044],{"className":4170,"style":1081},[1079,1080],[1023,4172,1049],{"className":4173},[1085],[1023,4175,1262],{"className":4176},[1079,1080],[1023,4178,1056],{"className":4179},[1092],[973,4181,4182],{},[1487,4183,2194],{},[986,4185,4186,4191],{},[989,4187,4188,4190],{},[992,4189,3732],{}," luôn đúng sau mọi thao tác, kể cả khi list còn 0 hoặc 1 nút.",[989,4192,4193,4194,4197,4198,4201],{},"Viết thêm hàm ",[992,4195,4196],{},"void sl_print(const SList *l)"," in dạng ",[992,4199,4200],{},"[1 -> 2 -> 3]"," để debug.",[973,4203,4204],{},[1487,4205,4206],{},"Test mẫu",[1352,4208,4211],{"className":4209,"code":4210,"language":2241,"meta":1357},[2239],"push_back 1, 2, 3                 -> [1 -> 2 -> 3], size=3\ninsert_after(find(1), 9)          -> [1 -> 9 -> 2 -> 3]\nremove(3)                         -> [1 -> 9 -> 2], tail->val = 2\nreverse                           -> [2 -> 9 -> 1], tail->val = 1\npop_front x3, pop_front lần 4     -> lần 4 trả false, head = tail = NULL\npush_back 5 sau khi rỗng          -> [5], head == tail\n",[992,4212,4210],{"__ignoreMap":1357},[981,4214,4216],{"id":4215},"bài-2-doubly-linked-list-và-lịch-sử-trình-duyệt","Bài 2: Doubly linked list và lịch sử trình duyệt",[973,4218,1505,4219,4222,4223,1509,4226,4229,4230,4233,4234,1517],{},[992,4220,4221],{},"DList"," với nút có ",[992,4224,4225],{},"prev",[992,4227,4228],{},"next",". Cài thêm ",[992,4231,4232],{},"dl_remove_node(DList *l, DNode *n)"," chạy ",[1023,4235,4237,4256],{"className":4236},[1026],[1023,4238,4240],{"className":4239},[1030],[1032,4241,4242],{"xmlns":1034},[1036,4243,4244,4254],{},[1039,4245,4246,4248,4250,4252],{},[1042,4247,1044],{},[1046,4249,1049],{"stretchy":1048},[1051,4251,1053],{},[1046,4253,1056],{"stretchy":1048},[1058,4255,1061],{"encoding":1060},[1023,4257,4259],{"className":4258,"ariaHidden":1066},[1065],[1023,4260,4262,4265,4268,4271,4274],{"className":4261},[1070],[1023,4263],{"className":4264,"style":1075},[1074],[1023,4266,1044],{"className":4267,"style":1081},[1079,1080],[1023,4269,1049],{"className":4270},[1085],[1023,4272,1053],{"className":4273},[1079],[1023,4275,1056],{"className":4276},[1092],[973,4278,2699,4279,4281],{},[992,4280,4221],{}," làm lịch sử trình duyệt:",[1099,4283,4284,4293],{},[1102,4285,4286],{},[1105,4287,4288,4290],{},[1108,4289,1566],{},[1108,4291,4292],{},"Hành vi",[1118,4294,4295,4311,4325],{},[1105,4296,4297,4302],{},[1123,4298,4299],{},[992,4300,4301],{},"visit(url)",[1123,4303,4304,4305,4308,4309],{},"Xóa toàn bộ trang phía sau trang hiện tại, thêm ",[992,4306,4307],{},"url",", chuyển tới ",[992,4310,4307],{},[1105,4312,4313,4318],{},[1123,4314,4315],{},[992,4316,4317],{},"back(steps)",[1123,4319,4320,4321,4324],{},"Lùi tối đa ",[992,4322,4323],{},"steps"," bước, trả URL hiện tại",[1105,4326,4327,4332],{},[1123,4328,4329],{},[992,4330,4331],{},"forward(steps)",[1123,4333,4334,4335,4324],{},"Tiến tối đa ",[992,4336,4323],{},[1352,4338,4341],{"className":4339,"code":4340,"language":2241,"meta":1357},[2239],"visit a, b, c           -> hiện tại c\nback(2)                 -> a\nforward(1)              -> b\nvisit d                 -> d (trang c bị xóa)\nforward(1)              -> d (không còn trang sau)\nback(10)                -> a\n",[992,4342,4340],{"__ignoreMap":1357},[981,4344,4346],{"id":4345},"bài-3-đo-mảng-và-list-nâng-cao","Bài 3: Đo mảng và list (nâng cao)",[973,4348,4349,4350,4353,4354,4437],{},"Dùng Dynamic Array ngày 1 và ",[992,4351,4352],{},"SList"," Bài 1. Đo thời gian với ",[1023,4355,4357,4378],{"className":4356},[1026],[1023,4358,4360],{"className":4359},[1030],[1032,4361,4362],{"xmlns":1034},[1036,4363,4364,4376],{},[1039,4365,4366,4368,4370],{},[1042,4367,1262],{},[1046,4369,2325],{},[2327,4371,4372,4374],{},[1051,4373,2331],{},[1051,4375,2334],{},[1058,4377,2337],{"encoding":1060},[1023,4379,4381,4399],{"className":4380,"ariaHidden":1066},[1065],[1023,4382,4384,4387,4390,4393,4396],{"className":4383},[1070],[1023,4385],{"className":4386,"style":2347},[1074],[1023,4388,1262],{"className":4389},[1079,1080],[1023,4391],{"className":4392,"style":2355},[2354],[1023,4394,2325],{"className":4395},[2359],[1023,4397],{"className":4398,"style":2355},[2354],[1023,4400,4402,4405,4408],{"className":4401},[1070],[1023,4403],{"className":4404,"style":2369},[1074],[1023,4406,1053],{"className":4407},[1079],[1023,4409,4411,4414],{"className":4410},[1079],[1023,4412,2379],{"className":4413},[1079],[1023,4415,4417],{"className":4416},[2383],[1023,4418,4420],{"className":4419},[2387],[1023,4421,4423],{"className":4422},[2391],[1023,4424,4426],{"className":4425,"style":2369},[2395],[1023,4427,4428,4431],{"style":2398},[1023,4429],{"className":4430,"style":2403},[2402],[1023,4432,4434],{"className":4433},[2407,2408,2409,2410],[1023,4435,2334],{"className":4436},[1079,2410],":",[2273,4439,4440,4474,4505],{},[989,4441,4442,2308,4445,4473],{},[992,4443,4444],{},"push_back",[1023,4446,4448,4461],{"className":4447},[1026],[1023,4449,4451],{"className":4450},[1030],[1032,4452,4453],{"xmlns":1034},[1036,4454,4455,4459],{},[1039,4456,4457],{},[1042,4458,1262],{},[1058,4460,1262],{"encoding":1060},[1023,4462,4464],{"className":4463,"ariaHidden":1066},[1065],[1023,4465,4467,4470],{"className":4466},[1070],[1023,4468],{"className":4469,"style":2347},[1074],[1023,4471,1262],{"className":4472},[1079,1080]," phần tử.",[989,4475,4476,4477,4473],{},"Chèn đầu ",[1023,4478,4480,4493],{"className":4479},[1026],[1023,4481,4483],{"className":4482},[1030],[1032,4484,4485],{"xmlns":1034},[1036,4486,4487,4491],{},[1039,4488,4489],{},[1042,4490,1262],{},[1058,4492,1262],{"encoding":1060},[1023,4494,4496],{"className":4495,"ariaHidden":1066},[1065],[1023,4497,4499,4502],{"className":4498},[1070],[1023,4500],{"className":4501,"style":2347},[1074],[1023,4503,1262],{"className":4504},[1079,1080],[989,4506,4507,4508,4473],{},"Duyệt tính tổng ",[1023,4509,4511,4524],{"className":4510},[1026],[1023,4512,4514],{"className":4513},[1030],[1032,4515,4516],{"xmlns":1034},[1036,4517,4518,4522],{},[1039,4519,4520],{},[1042,4521,1262],{},[1058,4523,1262],{"encoding":1060},[1023,4525,4527],{"className":4526,"ariaHidden":1066},[1065],[1023,4528,4530,4533],{"className":4529},[1070],[1023,4531],{"className":4532,"style":2347},[1074],[1023,4534,1262],{"className":4535},[1079,1080],[973,4537,4538,4539,1517],{},"In bảng thời gian (ms). Viết 3 câu giải thích vì sao duyệt mảng nhanh hơn duyệt list dù cùng ",[1023,4540,4542,4561],{"className":4541},[1026],[1023,4543,4545],{"className":4544},[1030],[1032,4546,4547],{"xmlns":1034},[1036,4548,4549,4559],{},[1039,4550,4551,4553,4555,4557],{},[1042,4552,1044],{},[1046,4554,1049],{"stretchy":1048},[1042,4556,1262],{},[1046,4558,1056],{"stretchy":1048},[1058,4560,1267],{"encoding":1060},[1023,4562,4564],{"className":4563,"ariaHidden":1066},[1065],[1023,4565,4567,4570,4573,4576,4579],{"className":4566},[1070],[1023,4568],{"className":4569,"style":1075},[1074],[1023,4571,1044],{"className":4572,"style":1081},[1079,1080],[1023,4574,1049],{"className":4575},[1085],[1023,4577,1262],{"className":4578},[1079,1080],[1023,4580,1056],{"className":4581},[1092],[2245,4583,4584],{},[973,4585,2699,4586,4589],{},[992,4587,4588],{},"clock_gettime(CLOCK_MONOTONIC, ...)"," để đo. Chạy mỗi phép đo 5 lần, lấy trung vị.",[981,4591,2711],{"id":2710},[986,4593,4595,4603,4609,4615],{"className":4594},[2715],[989,4596,4598,4600,4601,1517],{"className":4597},[2719],[2721,4599],{"disabled":2723,"type":2724}," Mọi test mẫu pass bằng ",[992,4602,2235],{},[989,4604,4606,4608],{"className":4605},[2719],[2721,4607],{"disabled":2723,"type":2724}," AddressSanitizer và valgrind sạch: không leak, không use-after-free.",[989,4610,4612,4614],{"className":4611},[2719],[2721,4613],{"disabled":2723,"type":2724}," Bảng đo Bài 3 có số thật kèm giải thích về cache.",[989,4616,4618,4620,4621,1509,4624,1517],{"className":4617},[2719],[2721,4619],{"disabled":2723,"type":2724}," Vẽ tay được các con trỏ đổi thế nào khi ",[992,4622,4623],{},"insert_after",[992,4625,4626],{},"reverse",[968,4628,2890],{"id":2889},[986,4630,4631,4634,4637,4640],{},[989,4632,4633],{},"Nút gồm những gì, head là gì?",[989,4635,4636],{},"List đơn khác list đôi ở điểm nào?",[989,4638,4639],{},"Chèn đầu list tốn bao nhiêu bước?",[989,4641,4642],{},"Khi nào nên dùng mảng thay list?",[3014,4644],{},[973,4646,4647],{},"🌕 Bạn đã hoàn thành ngày 2. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,4649,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":4651},[4652,4653,4658,4659,4665],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":4654},[4655,4656,4657],{"id":3069,"depth":73,"text":3070},{"id":3090,"depth":73,"text":3091},{"id":3111,"depth":73,"text":3112},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":4660},[4661,4662,4663,4664],{"id":3574,"depth":73,"text":3575},{"id":4215,"depth":73,"text":4216},{"id":4345,"depth":73,"text":4346},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu nút, con trỏ next và prev, phân biệt linked list đơn với đôi, và biết khi nào danh sách liên kết thắng mảng.",{},[3050,4669],"time-space-complexity",{"title":65,"description":4666},[4672],"linked-list","_6K02fmxBWb97L_XC-S-kAsfaBI_IrV8Bsnlelk9ibk",{"id":4675,"title":70,"body":4676,"category":5189,"day":73,"description":5190,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":5192,"navigation":2723,"outcomes":3047,"path":71,"prerequisites":5193,"seo":5196,"stem":72,"tags":5197,"__hash__":5202},"challenges\u002Fchallenges\u002F3.solid-thuc-hanh.md",{"type":965,"value":4677,"toc":5173},[4678,4680,4683,4685,4689,4703,4707,4721,4725,4739,4784,4786,4794,4796,4812,4816,4822,4867,4873,4936,4942,4946,4952,4987,4991,5042,5048,5052,5107,5109,5150,5152,5166,5168,5171],[968,4679,971],{"id":970},[973,4681,4682],{},"Bài này ôn 5 nguyên lý SOLID qua ví dụ vịt và pizza. Bạn học cách thêm tính năng không sửa code cũ.",[968,4684,979],{"id":978},[981,4686,4688],{"id":4687},"s-đơn-trách-nhiệm","S — Đơn trách nhiệm",[986,4690,4691,4694,4697,4700],{},[989,4692,4693],{},"Một lớp chỉ có một lý do để đổi.",[989,4695,4696],{},"Lớp ôm nhiều việc rất dễ hỏng dây chuyền.",[989,4698,4699],{},"Ví dụ đời thường: một người chỉ làm một nghề.",[989,4701,4702],{},"Tách lớp in hóa đơn ra khỏi lớp lưu món ăn.",[981,4704,4706],{"id":4705},"o-mở-rộng-không-sửa-đổi","O — Mở rộng không sửa đổi",[986,4708,4709,4712,4715,4718],{},[989,4710,4711],{},"Thêm mới bằng cách thêm lớp mới.",[989,4713,4714],{},"Không mở lớp cũ ra vá mỗi lần thêm.",[989,4716,4717],{},"Ví dụ đời thường: cắm thêm ổ điện, không đục tường.",[989,4719,4720],{},"Vịt bay tên lửa là lớp mới, lớp Vịt giữ nguyên.",[981,4722,4724],{"id":4723},"l-i-d-còn-lại","L, I, D còn lại",[986,4726,4727,4730,4733,4736],{},[989,4728,4729],{},"L: vịt con phải dùng được như vịt cha.",[989,4731,4732],{},"I: đừng ép lớp dùng thứ nó không cần.",[989,4734,4735],{},"D: phụ thuộc vào giao diện, không phụ thuộc lớp cụ thể.",[989,4737,4738],{},"Ví dụ đời thường: remote chỉ cần nút bấm chung.",[1099,4740,4741,4751],{},[1102,4742,4743],{},[1105,4744,4745,4748],{},[1108,4746,4747],{},"Chữ",[1108,4749,4750],{},"Câu hỏi tự vấn",[1118,4752,4753,4761,4768,4776],{},[1105,4754,4755,4758],{},[1123,4756,4757],{},"S",[1123,4759,4760],{},"Lớp này có mấy lý do để đổi?",[1105,4762,4763,4765],{},[1123,4764,1044],{},[1123,4766,4767],{},"Thêm mới có phải sửa cũ không?",[1105,4769,4770,4773],{},[1123,4771,4772],{},"L",[1123,4774,4775],{},"Lớp con có gây bất ngờ không?",[1105,4777,4778,4781],{},[1123,4779,4780],{},"D",[1123,4782,4783],{},"Đang phụ thuộc vào cụ thể hay trừu tượng?",[968,4785,1433],{"id":1432},[986,4787,4788,4791],{},[989,4789,4790],{},"Input: thêm kiểu bay tên lửa cho đàn vịt. Output: tạo lớp mới, lớp Vịt nguyên vẹn.",[989,4792,4793],{},"Giải thích: đúng chữ O vì mở rộng mà không sửa cũ.",[968,4795,1482],{"id":1481},[973,4797,1485,4798,4801,4802,4805,4806,1509,4809,1517],{},[1487,4799,4800],{},"C++17"," (hoặc Java). Nộp vào ",[992,4803,4804],{},"day-003\u002F",". Mỗi bài có thư mục ",[992,4807,4808],{},"before\u002F",[992,4810,4811],{},"after\u002F",[981,4813,4815],{"id":4814},"bài-1-tách-trách-nhiệm-s","Bài 1: Tách trách nhiệm (S)",[973,4817,4818,4819,4437],{},"Cho class sau, viết lại đúng như đề trong ",[992,4820,4821],{},"before\u002Forder.cpp",[1352,4823,4825],{"className":1393,"code":4824,"language":1395,"meta":1357,"style":1357},"class Order {\n public:\n  void addItem(std::string name, double price, int qty);\n  double total() const;                   \u002F\u002F tính tiền\n  std::string toInvoiceText() const;      \u002F\u002F định dạng hóa đơn\n  void saveToFile(const std::string &p);  \u002F\u002F ghi file\n  void sendEmail(const std::string &to);  \u002F\u002F gửi email (chỉ in ra console)\n};\n",[992,4826,4827,4832,4837,4842,4847,4852,4857,4862],{"__ignoreMap":1357},[1023,4828,4829],{"class":1362,"line":63},[1023,4830,4831],{},"class Order {\n",[1023,4833,4834],{"class":1362,"line":68},[1023,4835,4836],{}," public:\n",[1023,4838,4839],{"class":1362,"line":73},[1023,4840,4841],{},"  void addItem(std::string name, double price, int qty);\n",[1023,4843,4844],{"class":1362,"line":78},[1023,4845,4846],{},"  double total() const;                   \u002F\u002F tính tiền\n",[1023,4848,4849],{"class":1362,"line":83},[1023,4850,4851],{},"  std::string toInvoiceText() const;      \u002F\u002F định dạng hóa đơn\n",[1023,4853,4854],{"class":1362,"line":88},[1023,4855,4856],{},"  void saveToFile(const std::string &p);  \u002F\u002F ghi file\n",[1023,4858,4859],{"class":1362,"line":93},[1023,4860,4861],{},"  void sendEmail(const std::string &to);  \u002F\u002F gửi email (chỉ in ra console)\n",[1023,4863,4864],{"class":1362,"line":98},[1023,4865,4866],{},"};\n",[973,4868,4869,4872],{},[1487,4870,4871],{},"Yêu cầu:"," tách thành 4 lớp, mỗi lớp một lý do để đổi.",[1099,4874,4875,4885],{},[1102,4876,4877],{},[1105,4878,4879,4882],{},[1108,4880,4881],{},"Lớp",[1108,4883,4884],{},"Trách nhiệm",[1118,4886,4887,4900,4912,4924],{},[1105,4888,4889,4894],{},[1123,4890,4891],{},[992,4892,4893],{},"Order",[1123,4895,4896,4897],{},"Giữ danh sách món, tính ",[992,4898,4899],{},"total()",[1105,4901,4902,4907],{},[1123,4903,4904],{},[992,4905,4906],{},"InvoiceFormatter",[1123,4908,4909],{},[992,4910,4911],{},"std::string format(const Order&)",[1105,4913,4914,4919],{},[1123,4915,4916],{},[992,4917,4918],{},"OrderRepository",[1123,4920,4921],{},[992,4922,4923],{},"void save(const Order&, const std::string &path)",[1105,4925,4926,4931],{},[1123,4927,4928],{},[992,4929,4930],{},"EmailSender",[1123,4932,4933],{},[992,4934,4935],{},"void send(const std::string &to, const std::string &body)",[973,4937,4938,4939,4941],{},"Trong ",[992,4940,2513],{},", với mỗi lớp ghi 1 ví dụ thay đổi yêu cầu chỉ làm đổi lớp đó.",[981,4943,4945],{"id":4944},"bài-2-mở-rộng-không-sửa-o-và-đảo-phụ-thuộc-d","Bài 2: Mở rộng không sửa (O) và đảo phụ thuộc (D)",[973,4947,4948,4949,4437],{},"Code ban đầu tính giảm giá bằng chuỗi ",[992,4950,4951],{},"if",[1352,4953,4955],{"className":1393,"code":4954,"language":1395,"meta":1357,"style":1357},"double discount(const std::string &type, double total) {\n  if (type == \"none\") return 0;\n  if (type == \"percent10\") return total * 0.1;\n  if (type == \"fixed50\") return total > 50 ? 50 : 0;\n  return 0;\n}\n",[992,4956,4957,4962,4967,4972,4977,4982],{"__ignoreMap":1357},[1023,4958,4959],{"class":1362,"line":63},[1023,4960,4961],{},"double discount(const std::string &type, double total) {\n",[1023,4963,4964],{"class":1362,"line":68},[1023,4965,4966],{},"  if (type == \"none\") return 0;\n",[1023,4968,4969],{"class":1362,"line":73},[1023,4970,4971],{},"  if (type == \"percent10\") return total * 0.1;\n",[1023,4973,4974],{"class":1362,"line":78},[1023,4975,4976],{},"  if (type == \"fixed50\") return total > 50 ? 50 : 0;\n",[1023,4978,4979],{"class":1362,"line":83},[1023,4980,4981],{},"  return 0;\n",[1023,4983,4984],{"class":1362,"line":88},[1023,4985,4986],{},"}\n",[973,4988,4989],{},[1487,4990,4871],{},[2273,4992,4993,4999,5011,5028],{},[989,4994,4995,4996],{},"Tạo interface ",[992,4997,4998],{},"class DiscountPolicy { public: virtual double apply(double total) const = 0; virtual ~DiscountPolicy() = default; };",[989,5000,5001,5002,1656,5005,1656,5008,1517],{},"Viết 3 lớp: ",[992,5003,5004],{},"NoDiscount",[992,5006,5007],{},"PercentDiscount(double rate)",[992,5009,5010],{},"FixedDiscount(double amount, double minTotal)",[989,5012,5013,5016,5017,5020,5021,5023,5024,5027],{},[992,5014,5015],{},"Checkout"," nhận ",[992,5018,5019],{},"std::unique_ptr\u003CDiscountPolicy>"," qua constructor. ",[992,5022,5015],{}," không được ",[992,5025,5026],{},"#include"," lớp cụ thể nào.",[989,5029,5030,5031,5034,5035,5038,5039,5041],{},"Thêm ",[992,5032,5033],{},"BuyOver200Get15Percent"," mà ",[1487,5036,5037],{},"không sửa"," dòng nào của ",[992,5040,5015],{}," và 3 lớp cũ.",[1352,5043,5046],{"className":5044,"code":5045,"language":2241,"meta":1357},[2239],"total=100, NoDiscount             -> 100\ntotal=100, PercentDiscount(0.1)   -> 90\ntotal=40,  FixedDiscount(50, 50)  -> 40\ntotal=120, FixedDiscount(50, 50)  -> 70\ntotal=250, BuyOver200Get15Percent -> 212.5\n",[992,5047,5045],{"__ignoreMap":1357},[981,5049,5051],{"id":5050},"bài-3-phát-hiện-vi-phạm-l-và-i-nâng-cao","Bài 3: Phát hiện vi phạm L và I (nâng cao)",[2273,5053,5054,5084,5090],{},[989,5055,1505,5056,5059,5060,1656,5063,1656,5066,5069,5070,5073,5074,5076,5077,5080,5081,5083],{},[992,5057,5058],{},"Rectangle"," có ",[992,5061,5062],{},"setWidth",[992,5064,5065],{},"setHeight",[992,5067,5068],{},"area",". Cho ",[992,5071,5072],{},"Square"," kế thừa ",[992,5075,5058],{},". Viết hàm test ",[992,5078,5079],{},"void resize(Rectangle &r) { r.setWidth(5); r.setHeight(4); assert(r.area() == 20); }",". Chứng minh ",[992,5082,5072],{}," làm test fail.",[989,5085,5086,5087,1517],{},"Sửa thiết kế để test không còn fail. Ví dụ: tách interface ",[992,5088,5089],{},"Shape { virtual double area() const = 0; }",[989,5091,5092,5093,5096,5097,1656,5100,1656,5103,5106],{},"Cho interface ",[992,5094,5095],{},"IMachine { print(); scan(); fax(); }",". Máy in rẻ chỉ in được. Tách thành ",[992,5098,5099],{},"IPrinter",[992,5101,5102],{},"IScanner",[992,5104,5105],{},"IFax"," để máy in rẻ không phải cài hàm rỗng.",[981,5108,2711],{"id":2710},[986,5110,5112,5123,5133,5142],{"className":5111},[2715],[989,5113,5115,5117,5118,1509,5120,5122],{"className":5114},[2719],[2721,5116],{"disabled":2723,"type":2724}," Mỗi bài có ",[992,5119,4808],{},[992,5121,4811],{},", cả hai build và chạy được.",[989,5124,5126,5128,5129,5132],{"className":5125},[2719],[2721,5127],{"disabled":2723,"type":2724}," Bài 2: ",[992,5130,5131],{},"git diff"," khi thêm policy mới chỉ có file mới, không sửa file cũ.",[989,5134,5136,5138,5139,5141],{"className":5135},[2719],[2721,5137],{"disabled":2723,"type":2724}," Bài 3: có test cho thấy ",[992,5140,5072],{}," phá LSP, và bản sửa pass.",[989,5143,5145,2308,5147,5149],{"className":5144},[2719],[2721,5146],{"disabled":2723,"type":2724},[992,5148,2513],{}," trả lời câu tự vấn trong bảng SOLID cho từng bài.",[968,5151,2890],{"id":2889},[986,5153,5154,5157,5160,5163],{},[989,5155,5156],{},"S nghĩa là gì, cho ví dụ?",[989,5158,5159],{},"O nghĩa là gì, cho ví dụ?",[989,5161,5162],{},"D nghĩa là gì, cho ví dụ?",[989,5164,5165],{},"Dấu hiệu nào cho thấy code vi phạm SOLID?",[3014,5167],{},[973,5169,5170],{},"🌕 Bạn đã hoàn thành ngày 3. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,5172,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":5174},[5175,5176,5181,5182,5188],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":5177},[5178,5179,5180],{"id":4687,"depth":73,"text":4688},{"id":4705,"depth":73,"text":4706},{"id":4723,"depth":73,"text":4724},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":5183},[5184,5185,5186,5187],{"id":4814,"depth":73,"text":4815},{"id":4944,"depth":73,"text":4945},{"id":5050,"depth":73,"text":5051},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"design-pattern","Ôn lại năm nguyên lý SOLID qua các câu chuyện thực tế, đào sâu Open-Closed và Dependency Inversion với SimUDuck và Pizza Store.","trung-binh",{},[5194,5195],"nguyen-ly-thiet-ke-huong-doi-tuong","nhap-mon-design-patterns",{"title":70,"description":5190},[5198,5199,5200,5201],"principles","solid","ocp","dip","YKhws0zkPlb8gfYr9_a6hrtg4PMhgOQ-LqMX5SkbrnA",{"id":5204,"title":75,"body":5205,"category":3041,"day":78,"description":6431,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":6432,"navigation":2723,"outcomes":3047,"path":76,"prerequisites":6433,"seo":6434,"stem":77,"tags":6435,"__hash__":6438},"challenges\u002Fchallenges\u002F4.stack-va-queue.md",{"type":965,"value":5206,"toc":6415},[5207,5209,5212,5214,5218,5278,5282,5385,5389,5406,5550,5552,5560,5580,5582,5603,5607,5846,5860,5866,5870,5879,6072,6126,6132,6136,6257,6263,6272,6274,6349,6351,6408,6410,6413],[968,5208,971],{"id":970},[973,5210,5211],{},"Bài này học ngăn xếp LIFO và hàng đợi FIFO. Bạn biết khi nào dùng cấu trúc nào.",[968,5213,979],{"id":978},[981,5215,5217],{"id":5216},"stack-vào-sau-ra-trước","Stack — vào sau ra trước",[986,5219,5220,5223,5226,5229,5232],{},[989,5221,5222],{},"Quy tắc LIFO: mới vào thì ra trước.",[989,5224,5225],{},"push thêm lên đỉnh, pop lấy khỏi đỉnh.",[989,5227,5228],{},"peek chỉ nhìn đỉnh, không gỡ.",[989,5230,5231],{},"Ví dụ đời thường: chồng đĩa, lấy từ trên cùng.",[989,5233,5234,5235,1517],{},"Mọi thao tác đều ",[1023,5236,5238,5257],{"className":5237},[1026],[1023,5239,5241],{"className":5240},[1030],[1032,5242,5243],{"xmlns":1034},[1036,5244,5245,5255],{},[1039,5246,5247,5249,5251,5253],{},[1042,5248,1044],{},[1046,5250,1049],{"stretchy":1048},[1051,5252,1053],{},[1046,5254,1056],{"stretchy":1048},[1058,5256,1061],{"encoding":1060},[1023,5258,5260],{"className":5259,"ariaHidden":1066},[1065],[1023,5261,5263,5266,5269,5272,5275],{"className":5262},[1070],[1023,5264],{"className":5265,"style":1075},[1074],[1023,5267,1044],{"className":5268,"style":1081},[1079,1080],[1023,5270,1049],{"className":5271},[1085],[1023,5273,1053],{"className":5274},[1079],[1023,5276,1056],{"className":5277},[1092],[981,5279,5281],{"id":5280},"queue-vào-trước-ra-trước","Queue — vào trước ra trước",[986,5283,5284,5287,5290,5293,5339],{},[989,5285,5286],{},"Quy tắc FIFO: đến trước phục vụ trước.",[989,5288,5289],{},"enqueue xếp vào cuối, dequeue ra ở đầu.",[989,5291,5292],{},"Ví dụ đời thường: hàng vé, ai đến trước mua trước.",[989,5294,5295,5296,1517],{},"Mọi thao tác chuẩn đều ",[1023,5297,5299,5318],{"className":5298},[1026],[1023,5300,5302],{"className":5301},[1030],[1032,5303,5304],{"xmlns":1034},[1036,5305,5306,5316],{},[1039,5307,5308,5310,5312,5314],{},[1042,5309,1044],{},[1046,5311,1049],{"stretchy":1048},[1051,5313,1053],{},[1046,5315,1056],{"stretchy":1048},[1058,5317,1061],{"encoding":1060},[1023,5319,5321],{"className":5320,"ariaHidden":1066},[1065],[1023,5322,5324,5327,5330,5333,5336],{"className":5323},[1070],[1023,5325],{"className":5326,"style":1075},[1074],[1023,5328,1044],{"className":5329,"style":1081},[1079,1080],[1023,5331,1049],{"className":5332},[1085],[1023,5334,1053],{"className":5335},[1079],[1023,5337,1056],{"className":5338},[1092],[989,5340,5341,5342,1517],{},"Đừng cài queue bằng mảng chèn đầu vì bị ",[1023,5343,5345,5364],{"className":5344},[1026],[1023,5346,5348],{"className":5347},[1030],[1032,5349,5350],{"xmlns":1034},[1036,5351,5352,5362],{},[1039,5353,5354,5356,5358,5360],{},[1042,5355,1044],{},[1046,5357,1049],{"stretchy":1048},[1042,5359,1262],{},[1046,5361,1056],{"stretchy":1048},[1058,5363,1267],{"encoding":1060},[1023,5365,5367],{"className":5366,"ariaHidden":1066},[1065],[1023,5368,5370,5373,5376,5379,5382],{"className":5369},[1070],[1023,5371],{"className":5372,"style":1075},[1074],[1023,5374,1044],{"className":5375,"style":1081},[1079,1080],[1023,5377,1049],{"className":5378},[1085],[1023,5380,1262],{"className":5381},[1079,1080],[1023,5383,1056],{"className":5384},[1092],[981,5386,5388],{"id":5387},"deque-và-ứng-dụng","Deque và ứng dụng",[986,5390,5391,5394,5397,5400,5403],{},[989,5392,5393],{},"Deque thêm bớt được ở cả hai đầu.",[989,5395,5396],{},"Dùng một đầu thì thành stack.",[989,5398,5399],{},"Dùng hai đầu thì thành queue.",[989,5401,5402],{},"Ví dụ đời thường: hàng người cho chen hai đầu.",[989,5404,5405],{},"Ứng dụng: undo, lịch sử trình duyệt, BFS, DFS.",[1099,5407,5408,5421],{},[1102,5409,5410],{},[1105,5411,5412,5415,5418],{},[1108,5413,5414],{},"Tiêu chí",[1108,5416,5417],{},"Stack",[1108,5419,5420],{},"Queue",[1118,5422,5423,5434,5444,5539],{},[1105,5424,5425,5428,5431],{},[1123,5426,5427],{},"Quy tắc",[1123,5429,5430],{},"LIFO",[1123,5432,5433],{},"FIFO",[1105,5435,5436,5438,5441],{},[1123,5437,1110],{},[1123,5439,5440],{},"push, pop, peek",[1123,5442,5443],{},"enqueue, dequeue",[1105,5445,5446,5449,5494],{},[1123,5447,5448],{},"Chi phí",[1123,5450,5451],{},[1023,5452,5454,5473],{"className":5453},[1026],[1023,5455,5457],{"className":5456},[1030],[1032,5458,5459],{"xmlns":1034},[1036,5460,5461,5471],{},[1039,5462,5463,5465,5467,5469],{},[1042,5464,1044],{},[1046,5466,1049],{"stretchy":1048},[1051,5468,1053],{},[1046,5470,1056],{"stretchy":1048},[1058,5472,1061],{"encoding":1060},[1023,5474,5476],{"className":5475,"ariaHidden":1066},[1065],[1023,5477,5479,5482,5485,5488,5491],{"className":5478},[1070],[1023,5480],{"className":5481,"style":1075},[1074],[1023,5483,1044],{"className":5484,"style":1081},[1079,1080],[1023,5486,1049],{"className":5487},[1085],[1023,5489,1053],{"className":5490},[1079],[1023,5492,1056],{"className":5493},[1092],[1123,5495,5496],{},[1023,5497,5499,5518],{"className":5498},[1026],[1023,5500,5502],{"className":5501},[1030],[1032,5503,5504],{"xmlns":1034},[1036,5505,5506,5516],{},[1039,5507,5508,5510,5512,5514],{},[1042,5509,1044],{},[1046,5511,1049],{"stretchy":1048},[1051,5513,1053],{},[1046,5515,1056],{"stretchy":1048},[1058,5517,1061],{"encoding":1060},[1023,5519,5521],{"className":5520,"ariaHidden":1066},[1065],[1023,5522,5524,5527,5530,5533,5536],{"className":5523},[1070],[1023,5525],{"className":5526,"style":1075},[1074],[1023,5528,1044],{"className":5529,"style":1081},[1079,1080],[1023,5531,1049],{"className":5532},[1085],[1023,5534,1053],{"className":5535},[1079],[1023,5537,1056],{"className":5538},[1092],[1105,5540,5541,5544,5547],{},[1123,5542,5543],{},"Ví dụ dùng",[1123,5545,5546],{},"Undo, DFS",[1123,5548,5549],{},"Hàng in, BFS",[968,5551,1433],{"id":1432},[986,5553,5554,5557],{},[989,5555,5556],{},"Input: push Đỏ rồi Xanh, pop 1 lần. Output: lấy ra Xanh, còn Đỏ.",[989,5558,5559],{},"Giải thích: phần tử vào sau ra trước đúng LIFO.",[1352,5561,5563],{"className":3538,"code":5562,"language":3540,"meta":1357,"style":1357},"stack = []  # dùng list làm stack\nstack.append(\"Do\")  # push lên đỉnh\ntop = stack.pop()  # pop khỏi đỉnh\n",[992,5564,5565,5570,5575],{"__ignoreMap":1357},[1023,5566,5567],{"class":1362,"line":63},[1023,5568,5569],{},"stack = []  # dùng list làm stack\n",[1023,5571,5572],{"class":1362,"line":68},[1023,5573,5574],{},"stack.append(\"Do\")  # push lên đỉnh\n",[1023,5576,5577],{"class":1362,"line":73},[1023,5578,5579],{},"top = stack.pop()  # pop khỏi đỉnh\n",[968,5581,1482],{"id":1481},[973,5583,1485,5584,5586,5587,5589,5590,1656,5593,1656,5596,5599,5600,1517],{},[1487,5585,1489],{}," hoặc ",[1487,5588,1493],{}," không dùng ",[992,5591,5592],{},"std::stack",[992,5594,5595],{},"std::queue",[992,5597,5598],{},"std::deque",". Nộp vào ",[992,5601,5602],{},"day-004\u002F",[981,5604,5606],{"id":5605},"bài-1-stack-trên-mảng-động","Bài 1: Stack trên mảng động",[1099,5608,5609,5619],{},[1102,5610,5611],{},[1105,5612,5613,5615,5617],{},[1108,5614,1566],{},[1108,5616,1569],{},[1108,5618,1113],{},[1118,5620,5621,5676,5733,5788],{},[1105,5622,5623,5628,5631],{},[1123,5624,5625],{},[992,5626,5627],{},"bool st_push(Stack *s, int x)",[1123,5629,5630],{},"Đẩy lên đỉnh. Đầy thì nhân đôi",[1123,5632,5633,1230],{},[1023,5634,5636,5655],{"className":5635},[1026],[1023,5637,5639],{"className":5638},[1030],[1032,5640,5641],{"xmlns":1034},[1036,5642,5643,5653],{},[1039,5644,5645,5647,5649,5651],{},[1042,5646,1044],{},[1046,5648,1049],{"stretchy":1048},[1051,5650,1053],{},[1046,5652,1056],{"stretchy":1048},[1058,5654,1061],{"encoding":1060},[1023,5656,5658],{"className":5657,"ariaHidden":1066},[1065],[1023,5659,5661,5664,5667,5670,5673],{"className":5660},[1070],[1023,5662],{"className":5663,"style":1075},[1074],[1023,5665,1044],{"className":5666,"style":1081},[1079,1080],[1023,5668,1049],{"className":5669},[1085],[1023,5671,1053],{"className":5672},[1079],[1023,5674,1056],{"className":5675},[1092],[1105,5677,5678,5683,5688],{},[1123,5679,5680],{},[992,5681,5682],{},"bool st_pop(Stack *s, int *out)",[1123,5684,5685,5686],{},"Lấy đỉnh. Rỗng trả ",[992,5687,1048],{},[1123,5689,5690],{},[1023,5691,5693,5712],{"className":5692},[1026],[1023,5694,5696],{"className":5695},[1030],[1032,5697,5698],{"xmlns":1034},[1036,5699,5700,5710],{},[1039,5701,5702,5704,5706,5708],{},[1042,5703,1044],{},[1046,5705,1049],{"stretchy":1048},[1051,5707,1053],{},[1046,5709,1056],{"stretchy":1048},[1058,5711,1061],{"encoding":1060},[1023,5713,5715],{"className":5714,"ariaHidden":1066},[1065],[1023,5716,5718,5721,5724,5727,5730],{"className":5717},[1070],[1023,5719],{"className":5720,"style":1075},[1074],[1023,5722,1044],{"className":5723,"style":1081},[1079,1080],[1023,5725,1049],{"className":5726},[1085],[1023,5728,1053],{"className":5729},[1079],[1023,5731,1056],{"className":5732},[1092],[1105,5734,5735,5740,5743],{},[1123,5736,5737],{},[992,5738,5739],{},"bool st_peek(const Stack *s, int *out)",[1123,5741,5742],{},"Xem đỉnh, không gỡ",[1123,5744,5745],{},[1023,5746,5748,5767],{"className":5747},[1026],[1023,5749,5751],{"className":5750},[1030],[1032,5752,5753],{"xmlns":1034},[1036,5754,5755,5765],{},[1039,5756,5757,5759,5761,5763],{},[1042,5758,1044],{},[1046,5760,1049],{"stretchy":1048},[1051,5762,1053],{},[1046,5764,1056],{"stretchy":1048},[1058,5766,1061],{"encoding":1060},[1023,5768,5770],{"className":5769,"ariaHidden":1066},[1065],[1023,5771,5773,5776,5779,5782,5785],{"className":5772},[1070],[1023,5774],{"className":5775,"style":1075},[1074],[1023,5777,1044],{"className":5778,"style":1081},[1079,1080],[1023,5780,1049],{"className":5781},[1085],[1023,5783,1053],{"className":5784},[1079],[1023,5786,1056],{"className":5787},[1092],[1105,5789,5790,5799,5801],{},[1123,5791,5792,5795,5796],{},[992,5793,5794],{},"bool st_empty(const Stack *s)"," \u002F ",[992,5797,5798],{},"size_t st_size(...)",[1123,5800],{},[1123,5802,5803],{},[1023,5804,5806,5825],{"className":5805},[1026],[1023,5807,5809],{"className":5808},[1030],[1032,5810,5811],{"xmlns":1034},[1036,5812,5813,5823],{},[1039,5814,5815,5817,5819,5821],{},[1042,5816,1044],{},[1046,5818,1049],{"stretchy":1048},[1051,5820,1053],{},[1046,5822,1056],{"stretchy":1048},[1058,5824,1061],{"encoding":1060},[1023,5826,5828],{"className":5827,"ariaHidden":1066},[1065],[1023,5829,5831,5834,5837,5840,5843],{"className":5830},[1070],[1023,5832],{"className":5833,"style":1075},[1074],[1023,5835,1044],{"className":5836,"style":1081},[1079,1080],[1023,5838,1049],{"className":5839},[1085],[1023,5841,1053],{"className":5842},[1079],[1023,5844,1056],{"className":5845},[1092],[973,5847,5848,5851,5852,5855,5856,5859],{},[1487,5849,5850],{},"Ứng dụng:"," viết ",[992,5853,5854],{},"bool balanced(const char *s)"," kiểm tra ngoặc ",[992,5857,5858],{},"()[]{}"," cân bằng.",[1352,5861,5864],{"className":5862,"code":5863,"language":2241,"meta":1357},[2239],"\"([]{})\"      -> true\n\"([)]\"        -> false\n\"(((\"         -> false\n\"\"            -> true\n\"a(b[c]d)e\"   -> true   (bỏ qua ký tự khác ngoặc)\n",[992,5865,5863],{"__ignoreMap":1357},[981,5867,5869],{"id":5868},"bài-2-queue-bằng-mảng-vòng-ring-buffer","Bài 2: Queue bằng mảng vòng (ring buffer)",[1352,5871,5873],{"className":1354,"code":5872,"language":1356,"meta":1357,"style":1357},"typedef struct { int *buf; size_t head, count, capacity; } Queue;\n",[992,5874,5875],{"__ignoreMap":1357},[1023,5876,5877],{"class":1362,"line":63},[1023,5878,5872],{},[1099,5880,5881,5891],{},[1102,5882,5883],{},[1105,5884,5885,5887,5889],{},[1108,5886,1566],{},[1108,5888,1569],{},[1108,5890,1113],{},[1118,5892,5893,5956,6017],{},[1105,5894,5895,5900,5911],{},[1123,5896,5897],{},[992,5898,5899],{},"bool q_enqueue(Queue *q, int x)",[1123,5901,5902,5903,5906,5907,5910],{},"Ghi vào ",[992,5904,5905],{},"buf[(head + count) % capacity]",". Đầy thì nhân đôi và ",[1487,5908,5909],{},"sắp lại"," thứ tự",[1123,5912,5913,1230],{},[1023,5914,5916,5935],{"className":5915},[1026],[1023,5917,5919],{"className":5918},[1030],[1032,5920,5921],{"xmlns":1034},[1036,5922,5923,5933],{},[1039,5924,5925,5927,5929,5931],{},[1042,5926,1044],{},[1046,5928,1049],{"stretchy":1048},[1051,5930,1053],{},[1046,5932,1056],{"stretchy":1048},[1058,5934,1061],{"encoding":1060},[1023,5936,5938],{"className":5937,"ariaHidden":1066},[1065],[1023,5939,5941,5944,5947,5950,5953],{"className":5940},[1070],[1023,5942],{"className":5943,"style":1075},[1074],[1023,5945,1044],{"className":5946,"style":1081},[1079,1080],[1023,5948,1049],{"className":5949},[1085],[1023,5951,1053],{"className":5952},[1079],[1023,5954,1056],{"className":5955},[1092],[1105,5957,5958,5963,5972],{},[1123,5959,5960],{},[992,5961,5962],{},"bool q_dequeue(Queue *q, int *out)",[1123,5964,5965,5966,1656,5969],{},"Đọc ",[992,5967,5968],{},"buf[head]",[992,5970,5971],{},"head = (head + 1) % capacity",[1123,5973,5974],{},[1023,5975,5977,5996],{"className":5976},[1026],[1023,5978,5980],{"className":5979},[1030],[1032,5981,5982],{"xmlns":1034},[1036,5983,5984,5994],{},[1039,5985,5986,5988,5990,5992],{},[1042,5987,1044],{},[1046,5989,1049],{"stretchy":1048},[1051,5991,1053],{},[1046,5993,1056],{"stretchy":1048},[1058,5995,1061],{"encoding":1060},[1023,5997,5999],{"className":5998,"ariaHidden":1066},[1065],[1023,6000,6002,6005,6008,6011,6014],{"className":6001},[1070],[1023,6003],{"className":6004,"style":1075},[1074],[1023,6006,1044],{"className":6007,"style":1081},[1079,1080],[1023,6009,1049],{"className":6010},[1085],[1023,6012,1053],{"className":6013},[1079],[1023,6015,1056],{"className":6016},[1092],[1105,6018,6019,6024,6027],{},[1123,6020,6021],{},[992,6022,6023],{},"bool q_front(const Queue *q, int *out)",[1123,6025,6026],{},"Xem đầu",[1123,6028,6029],{},[1023,6030,6032,6051],{"className":6031},[1026],[1023,6033,6035],{"className":6034},[1030],[1032,6036,6037],{"xmlns":1034},[1036,6038,6039,6049],{},[1039,6040,6041,6043,6045,6047],{},[1042,6042,1044],{},[1046,6044,1049],{"stretchy":1048},[1051,6046,1053],{},[1046,6048,1056],{"stretchy":1048},[1058,6050,1061],{"encoding":1060},[1023,6052,6054],{"className":6053,"ariaHidden":1066},[1065],[1023,6055,6057,6060,6063,6066,6069],{"className":6056},[1070],[1023,6058],{"className":6059,"style":1075},[1074],[1023,6061,1044],{"className":6062,"style":1081},[1079,1080],[1023,6064,1049],{"className":6065},[1085],[1023,6067,1053],{"className":6068},[1079],[1023,6070,1056],{"className":6071},[1092],[973,6073,6074,6077,6078,6081,6082,6125],{},[1487,6075,6076],{},"Ràng buộc:"," không dịch mảng khi ",[992,6079,6080],{},"dequeue",". Mọi thao tác ",[1023,6083,6085,6104],{"className":6084},[1026],[1023,6086,6088],{"className":6087},[1030],[1032,6089,6090],{"xmlns":1034},[1036,6091,6092,6102],{},[1039,6093,6094,6096,6098,6100],{},[1042,6095,1044],{},[1046,6097,1049],{"stretchy":1048},[1051,6099,1053],{},[1046,6101,1056],{"stretchy":1048},[1058,6103,1061],{"encoding":1060},[1023,6105,6107],{"className":6106,"ariaHidden":1066},[1065],[1023,6108,6110,6113,6116,6119,6122],{"className":6109},[1070],[1023,6111],{"className":6112,"style":1075},[1074],[1023,6114,1044],{"className":6115,"style":1081},[1079,1080],[1023,6117,1049],{"className":6118},[1085],[1023,6120,1053],{"className":6121},[1079],[1023,6123,1056],{"className":6124},[1092]," (trừ lần nhân đôi).",[1352,6127,6130],{"className":6128,"code":6129,"language":2241,"meta":1357},[2239],"cap=4; enqueue 1,2,3; dequeue x2   -> ra 1, 2; head=2\nenqueue 4, 5, 6                     -> quấn vòng, nội dung [3, 4, 5, 6]\nenqueue 7                           -> đầy, nhân đôi thành cap=8, thứ tự vẫn 3,4,5,6,7\ndequeue 5 lần                       -> ra 3,4,5,6,7; lần 6 trả false\n",[992,6131,6129],{"__ignoreMap":1357},[981,6133,6135],{"id":6134},"bài-3-deque-và-bài-toán-cửa-sổ-trượt-nâng-cao","Bài 3: Deque và bài toán cửa sổ trượt (nâng cao)",[2273,6137,6138,6202],{},[989,6139,6140,6141,1656,6144,1656,6146,1656,6149,1656,6152,1656,6155,6158,6159,1517],{},"Viết deque trên ring buffer: ",[992,6142,6143],{},"push_front",[992,6145,4444],{},[992,6147,6148],{},"pop_front",[992,6150,6151],{},"pop_back",[992,6153,6154],{},"front",[992,6156,6157],{},"back",", đều ",[1023,6160,6162,6181],{"className":6161},[1026],[1023,6163,6165],{"className":6164},[1030],[1032,6166,6167],{"xmlns":1034},[1036,6168,6169,6179],{},[1039,6170,6171,6173,6175,6177],{},[1042,6172,1044],{},[1046,6174,1049],{"stretchy":1048},[1051,6176,1053],{},[1046,6178,1056],{"stretchy":1048},[1058,6180,1061],{"encoding":1060},[1023,6182,6184],{"className":6183,"ariaHidden":1066},[1065],[1023,6185,6187,6190,6193,6196,6199],{"className":6186},[1070],[1023,6188],{"className":6189,"style":1075},[1074],[1023,6191,1044],{"className":6192,"style":1081},[1079,1080],[1023,6194,1049],{"className":6195},[1085],[1023,6197,1053],{"className":6198},[1079],[1023,6200,1056],{"className":6201},[1092],[989,6203,6204,6205,1509,6208,6210,6211,6213,6214,1517],{},"Dùng deque giải: cho mảng ",[992,6206,6207],{},"a",[992,6209,4022],{},", in giá trị lớn nhất của mỗi cửa sổ độ dài ",[992,6212,4022],{},". Yêu cầu ",[1023,6215,6217,6236],{"className":6216},[1026],[1023,6218,6220],{"className":6219},[1030],[1032,6221,6222],{"xmlns":1034},[1036,6223,6224,6234],{},[1039,6225,6226,6228,6230,6232],{},[1042,6227,1044],{},[1046,6229,1049],{"stretchy":1048},[1042,6231,1262],{},[1046,6233,1056],{"stretchy":1048},[1058,6235,1267],{"encoding":1060},[1023,6237,6239],{"className":6238,"ariaHidden":1066},[1065],[1023,6240,6242,6245,6248,6251,6254],{"className":6241},[1070],[1023,6243],{"className":6244,"style":1075},[1074],[1023,6246,1044],{"className":6247,"style":1081},[1079,1080],[1023,6249,1049],{"className":6250},[1085],[1023,6252,1262],{"className":6253},[1079,1080],[1023,6255,1056],{"className":6256},[1092],[1352,6258,6261],{"className":6259,"code":6260,"language":2241,"meta":1357},[2239],"a = [1, 3, -1, -3, 5, 3, 6, 7], k = 3  -> [3, 3, 5, 5, 6, 7]\na = [9, 8, 7], k = 1                    -> [9, 8, 7]\na = [2, 2, 2, 2], k = 2                 -> [2, 2, 2]\n",[992,6262,6260],{"__ignoreMap":1357},[2245,6264,6265],{},[973,6266,6267,6268,6271],{},"Deque giữ ",[1487,6269,6270],{},"chỉ số",", giá trị giảm dần từ đầu tới cuối. Chỉ số ra khỏi cửa sổ thì bỏ ở đầu.",[981,6273,2711],{"id":2710},[986,6275,6277,6285,6294,6300],{"className":6276},[2715],[989,6278,6280,6282,6283,1517],{"className":6279},[2719],[2721,6281],{"disabled":2723,"type":2724}," Test mẫu cả 3 bài pass bằng ",[992,6284,2235],{},[989,6286,6288,6290,6291,1517],{"className":6287},[2719],[2721,6289],{"disabled":2723,"type":2724}," Ring buffer đúng khi quấn vòng và khi nhân đôi lúc ",[992,6292,6293],{},"head != 0",[989,6295,6297,6299],{"className":6296},[2719],[2721,6298],{"disabled":2723,"type":2724}," Sanitizer sạch.",[989,6301,6303,6305,6306,1517],{"className":6302},[2719],[2721,6304],{"disabled":2723,"type":2724}," Giải thích được vì sao queue bằng mảng \"xóa đầu rồi dịch\" là ",[1023,6307,6309,6328],{"className":6308},[1026],[1023,6310,6312],{"className":6311},[1030],[1032,6313,6314],{"xmlns":1034},[1036,6315,6316,6326],{},[1039,6317,6318,6320,6322,6324],{},[1042,6319,1044],{},[1046,6321,1049],{"stretchy":1048},[1042,6323,1262],{},[1046,6325,1056],{"stretchy":1048},[1058,6327,1267],{"encoding":1060},[1023,6329,6331],{"className":6330,"ariaHidden":1066},[1065],[1023,6332,6334,6337,6340,6343,6346],{"className":6333},[1070],[1023,6335],{"className":6336,"style":1075},[1074],[1023,6338,1044],{"className":6339,"style":1081},[1079,1080],[1023,6341,1049],{"className":6342},[1085],[1023,6344,1262],{"className":6345},[1079,1080],[1023,6347,1056],{"className":6348},[1092],[968,6350,2890],{"id":2889},[986,6352,6353,6356,6359,6405],{},[989,6354,6355],{},"LIFO khác FIFO ở điểm nào?",[989,6357,6358],{},"push, pop, enqueue, dequeue làm gì?",[989,6360,6361,6362,2997],{},"Vì sao mọi thao tác chuẩn đều ",[1023,6363,6365,6384],{"className":6364},[1026],[1023,6366,6368],{"className":6367},[1030],[1032,6369,6370],{"xmlns":1034},[1036,6371,6372,6382],{},[1039,6373,6374,6376,6378,6380],{},[1042,6375,1044],{},[1046,6377,1049],{"stretchy":1048},[1051,6379,1053],{},[1046,6381,1056],{"stretchy":1048},[1058,6383,1061],{"encoding":1060},[1023,6385,6387],{"className":6386,"ariaHidden":1066},[1065],[1023,6388,6390,6393,6396,6399,6402],{"className":6389},[1070],[1023,6391],{"className":6392,"style":1075},[1074],[1023,6394,1044],{"className":6395,"style":1081},[1079,1080],[1023,6397,1049],{"className":6398},[1085],[1023,6400,1053],{"className":6401},[1079],[1023,6403,1056],{"className":6404},[1092],[989,6406,6407],{},"undo dùng stack hay queue?",[3014,6409],{},[973,6411,6412],{},"🌕 Bạn đã hoàn thành ngày 4. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,6414,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":6416},[6417,6418,6423,6424,6430],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":6419},[6420,6421,6422],{"id":5216,"depth":73,"text":5217},{"id":5280,"depth":73,"text":5281},{"id":5387,"depth":73,"text":5388},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":6425},[6426,6427,6428,6429],{"id":5605,"depth":73,"text":5606},{"id":5868,"depth":73,"text":5869},{"id":6134,"depth":73,"text":6135},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nắm nguyên tắc LIFO của ngăn xếp và FIFO của hàng đợi, các thao tác chuẩn cùng độ phức tạp, qua hai ẩn dụ đời thực trong bài này.",{},[3050],{"title":75,"description":6431},[6436,6437],"stack","queue","VhSropps_zLpQuGOQOcksQMuQa_xKD6QsjhwLjpECgw",{"id":6440,"title":80,"body":6441,"category":3041,"day":83,"description":7031,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":7032,"navigation":2723,"outcomes":3047,"path":81,"prerequisites":7033,"seo":7034,"stem":82,"tags":7035,"__hash__":7037},"challenges\u002Fchallenges\u002F5.dictionary-va-set.md",{"type":965,"value":6442,"toc":7015},[6443,6445,6448,6450,6454,6514,6518,6535,6539,6553,6598,6600,6608,6628,6630,6645,6649,6652,6710,6716,6720,6736,6741,6747,6754,6758,6765,6831,6837,6843,6917,6919,6992,6994,7008,7010,7013],[968,6444,971],{"id":970},[973,6446,6447],{},"Bài này học từ điển khóa-giá trị và tập hợp. Bạn hiểu hàm băm giúp tra cứu rất nhanh.",[968,6449,979],{"id":978},[981,6451,6453],{"id":6452},"dictionary-cặp-khóa-giá-trị","Dictionary — cặp khóa giá trị",[986,6455,6456,6459,6462,6465,6468],{},[989,6457,6458],{},"Mỗi mục gồm khóa và giá trị.",[989,6460,6461],{},"Khóa duy nhất, ghi đè thì thay giá trị.",[989,6463,6464],{},"Khóa phải ổn định, không đổi giữa chừng.",[989,6466,6467],{},"Ví dụ đời thường: từ điển tiếng Việt tra nghĩa.",[989,6469,6470,6471,1517],{},"Tra cứu trung bình ",[1023,6472,6474,6493],{"className":6473},[1026],[1023,6475,6477],{"className":6476},[1030],[1032,6478,6479],{"xmlns":1034},[1036,6480,6481,6491],{},[1039,6482,6483,6485,6487,6489],{},[1042,6484,1044],{},[1046,6486,1049],{"stretchy":1048},[1051,6488,1053],{},[1046,6490,1056],{"stretchy":1048},[1058,6492,1061],{"encoding":1060},[1023,6494,6496],{"className":6495,"ariaHidden":1066},[1065],[1023,6497,6499,6502,6505,6508,6511],{"className":6498},[1070],[1023,6500],{"className":6501,"style":1075},[1074],[1023,6503,1044],{"className":6504,"style":1081},[1079,1080],[1023,6506,1049],{"className":6507},[1085],[1023,6509,1053],{"className":6510},[1079],[1023,6512,1056],{"className":6513},[1092],[981,6515,6517],{"id":6516},"set-tập-không-trùng","Set — tập không trùng",[986,6519,6520,6523,6526,6529,6532],{},[989,6521,6522],{},"Set chỉ giữ khóa, không giữ giá trị.",[989,6524,6525],{},"Mọi phần tử đều duy nhất.",[989,6527,6528],{},"Có phép hợp, giao, hiệu.",[989,6530,6531],{},"Ví dụ đời thường: danh sách email không trùng.",[989,6533,6534],{},"Cần ánh xạ thì dùng dict, chỉ cần tồn tại thì dùng set.",[981,6536,6538],{"id":6537},"hàm-băm-và-khi-nào-dùng-gì","Hàm băm và khi nào dùng gì",[986,6540,6541,6544,6547,6550],{},[989,6542,6543],{},"Hàm băm biến khóa thành chỉ số ô nhớ.",[989,6545,6546],{},"Nhờ đó nhảy thẳng tới ô, khỏi quét.",[989,6548,6549],{},"Hai khóa khác nhau có thể chung ô, gọi là xung đột.",[989,6551,6552],{},"Ví dụ đời thường: tủ đồ có số ngăn tính từ tên.",[1099,6554,6555,6565],{},[1102,6556,6557],{},[1105,6558,6559,6562],{},[1108,6560,6561],{},"Nhu cầu",[1108,6563,6564],{},"Dùng gì",[1118,6566,6567,6575,6583,6590],{},[1105,6568,6569,6572],{},[1123,6570,6571],{},"Tên -> điểm",[1123,6573,6574],{},"Dictionary",[1105,6576,6577,6580],{},[1123,6578,6579],{},"Lọc trùng",[1123,6581,6582],{},"Set",[1105,6584,6585,6588],{},[1123,6586,6587],{},"Tra cứu theo giá trị",[1123,6589,6574],{},[1105,6591,6592,6595],{},[1123,6593,6594],{},"Bạn chung 2 nhóm",[1123,6596,6597],{},"Giao 2 set",[968,6599,1433],{"id":1432},[986,6601,6602,6605],{},[989,6603,6604],{},"Input: dict {Vàng: thủ công}, hỏi màu đã duyệt. Output: Xanh lá.",[989,6606,6607],{},"Giải thích: đưa khóa vào là nhận giá trị ngay.",[1352,6609,6611],{"className":3538,"code":6610,"language":3540,"meta":1357,"style":1357},"diem = {\"An\": 9}  # từ điển tên -> điểm\ndiem[\"An\"] = 10  # ghi đè giá trị cũ\nprint(\"An\" in diem)  # kiểm tra khóa tồn tại\n",[992,6612,6613,6618,6623],{"__ignoreMap":1357},[1023,6614,6615],{"class":1362,"line":63},[1023,6616,6617],{},"diem = {\"An\": 9}  # từ điển tên -> điểm\n",[1023,6619,6620],{"class":1362,"line":68},[1023,6621,6622],{},"diem[\"An\"] = 10  # ghi đè giá trị cũ\n",[1023,6624,6625],{"class":1362,"line":73},[1023,6626,6627],{},"print(\"An\" in diem)  # kiểm tra khóa tồn tại\n",[968,6629,1482],{"id":1481},[973,6631,1485,6632,6634,6635,1656,6638,6641,6642,1517],{},[1487,6633,4800],{},". Bài 1 được dùng ",[992,6636,6637],{},"std::unordered_map",[992,6639,6640],{},"std::unordered_set",". Bài 3 tự cài. Nộp vào ",[992,6643,6644],{},"day-005\u002F",[981,6646,6648],{"id":6647},"bài-1-đếm-từ-và-lọc-trùng","Bài 1: Đếm từ và lọc trùng",[973,6650,6651],{},"Viết chương trình đọc một file văn bản tiếng Việt hoặc tiếng Anh.",[1099,6653,6654,6662],{},[1102,6655,6656],{},[1105,6657,6658,6660],{},[1108,6659,1566],{},[1108,6661,2547],{},[1118,6663,6664,6674,6684,6697],{},[1105,6665,6666,6671],{},[1123,6667,6668],{},[992,6669,6670],{},"std::vector\u003Cstd::string> tokenize(const std::string &text)",[1123,6672,6673],{},"Tách từ theo khoảng trắng và dấu câu, đưa về chữ thường",[1105,6675,6676,6681],{},[1123,6677,6678],{},[992,6679,6680],{},"std::unordered_map\u003Cstd::string, int> countWords(...)",[1123,6682,6683],{},"Đếm tần suất từng từ",[1105,6685,6686,6691],{},[1123,6687,6688],{},[992,6689,6690],{},"std::vector\u003Cstd::pair\u003Cstd::string,int>> topK(map, k)",[1123,6692,6693,6694,6696],{},"Trả ",[992,6695,4022],{}," từ xuất hiện nhiều nhất, hòa thì theo alphabet",[1105,6698,6699,6704],{},[1123,6700,6701],{},[992,6702,6703],{},"size_t distinctWords(...)",[1123,6705,6706,6707],{},"Số từ khác nhau, dùng ",[992,6708,6709],{},"unordered_set",[1352,6711,6714],{"className":6712,"code":6713,"language":2241,"meta":1357},[2239],"\"An an AN, bình. Bình!\"  -> {an: 3, bình: 2}; distinct = 2; top1 = (an, 3)\n\"\"                       -> {} ; distinct = 0\n",[992,6715,6713],{"__ignoreMap":1357},[981,6717,6719],{"id":6718},"bài-2-phép-toán-tập-hợp","Bài 2: Phép toán tập hợp",[973,6721,6722,6723,6726,6727,1656,6730,1656,6733,1517],{},"Viết 3 hàm nhận hai ",[992,6724,6725],{},"std::unordered_set\u003Cint>"," và trả tập mới: ",[992,6728,6729],{},"unionOf",[992,6731,6732],{},"intersectOf",[992,6734,6735],{},"differenceOf",[973,6737,6738,6740],{},[1487,6739,5850],{}," cho danh sách bạn bè của 2 người, in bạn chung và gợi ý kết bạn (bạn của B mà A chưa kết bạn, trừ chính A).",[1352,6742,6745],{"className":6743,"code":6744,"language":2241,"meta":1357},[2239],"A = {1,2,3,4}, B = {3,4,5}\nunion        -> {1,2,3,4,5}\nintersect    -> {3,4}\nA - B        -> {1,2}\n",[992,6746,6744],{"__ignoreMap":1357},[973,6748,6749,2308,6751,6753],{},[1487,6750,6076],{},[992,6752,6732],{}," duyệt tập nhỏ hơn, tra trong tập lớn hơn. Ghi độ phức tạp vào comment.",[981,6755,6757],{"id":6756},"bài-3-tự-cài-hash-set-số-nguyên-nâng-cao","Bài 3: Tự cài hash set số nguyên (nâng cao)",[973,6759,6760,6761,6764],{},"Cài ",[992,6762,6763],{},"IntHashSet"," bằng separate chaining. Không dùng container băm của thư viện.",[1099,6766,6767,6775],{},[1102,6768,6769],{},[1105,6770,6771,6773],{},[1108,6772,1566],{},[1108,6774,2547],{},[1118,6776,6777,6789,6798,6807,6819],{},[1105,6778,6779,6784],{},[1123,6780,6781],{},[992,6782,6783],{},"bool insert(int x)",[1123,6785,6693,6786,6788],{},[992,6787,1048],{}," nếu đã có",[1105,6790,6791,6796],{},[1123,6792,6793],{},[992,6794,6795],{},"bool contains(int x) const",[1123,6797],{},[1105,6799,6800,6805],{},[1123,6801,6802],{},[992,6803,6804],{},"bool erase(int x)",[1123,6806],{},[1105,6808,6809,6817],{},[1123,6810,6811,1656,6814],{},[992,6812,6813],{},"size_t size() const",[992,6815,6816],{},"double loadFactor() const",[1123,6818],{},[1105,6820,6821,6824],{},[1123,6822,6823],{},"Rehash",[1123,6825,6826,6827,6830],{},"Khi ",[992,6828,6829],{},"loadFactor > 0.75"," thì gấp đôi số bucket và chèn lại",[973,6832,6833,6834,1517],{},"Hàm băm: ",[992,6835,6836],{},"h(x) = (uint32_t)x * 2654435761u % buckets",[1352,6838,6841],{"className":6839,"code":6840,"language":2241,"meta":1357},[2239],"insert 1..1000             -> size=1000, loadFactor \u003C= 0.75\ncontains(500) \u002F (1001)     -> true \u002F false\nerase(500); contains(500)  -> false\ninsert -7; contains(-7)    -> true\n",[992,6842,6840],{"__ignoreMap":1357},[973,6844,6845,6846,2308,6848,6911,6912,6914,6915,1517],{},"Đo thời gian ",[992,6847,2251],{},[1023,6849,6851,6870],{"className":6850},[1026],[1023,6852,6854],{"className":6853},[1030],[1032,6855,6856],{"xmlns":1034},[1036,6857,6858,6867],{},[1039,6859,6860],{},[2327,6861,6862,6864],{},[1051,6863,2331],{},[1051,6865,6866],{},"6",[1058,6868,6869],{"encoding":1060},"10^6",[1023,6871,6873],{"className":6872,"ariaHidden":1066},[1065],[1023,6874,6876,6879,6882],{"className":6875},[1070],[1023,6877],{"className":6878,"style":2369},[1074],[1023,6880,1053],{"className":6881},[1079],[1023,6883,6885,6888],{"className":6884},[1079],[1023,6886,2379],{"className":6887},[1079],[1023,6889,6891],{"className":6890},[2383],[1023,6892,6894],{"className":6893},[2387],[1023,6895,6897],{"className":6896},[2391],[1023,6898,6900],{"className":6899,"style":2369},[2395],[1023,6901,6902,6905],{"style":2398},[1023,6903],{"className":6904,"style":2403},[2402],[1023,6906,6908],{"className":6907},[2407,2408,2409,2410],[1023,6909,6866],{"className":6910},[1079,2410]," số ngẫu nhiên, so với ",[992,6913,6640],{},". Ghi kết quả vào ",[992,6916,2513],{},[981,6918,2711],{"id":2710},[986,6920,6922,6928,6937,6942],{"className":6921},[2715],[989,6923,6925,6927],{"className":6924},[2719],[2721,6926],{"disabled":2723,"type":2724}," Test mẫu của cả 3 bài pass.",[989,6929,6931,6933,6934,1517],{"className":6930},[2719],[2721,6932],{"disabled":2723,"type":2724}," Bài 3 rehash đúng: sau rehash mọi phần tử cũ vẫn ",[992,6935,6936],{},"contains",[989,6938,6940,6299],{"className":6939},[2719],[2721,6941],{"disabled":2723,"type":2724},[989,6943,6945,6947,6948,6991],{"className":6944},[2719],[2721,6946],{"disabled":2723,"type":2724}," Giải thích được khi nào dùng dict, khi nào dùng set, và vì sao tra cứu là ",[1023,6949,6951,6970],{"className":6950},[1026],[1023,6952,6954],{"className":6953},[1030],[1032,6955,6956],{"xmlns":1034},[1036,6957,6958,6968],{},[1039,6959,6960,6962,6964,6966],{},[1042,6961,1044],{},[1046,6963,1049],{"stretchy":1048},[1051,6965,1053],{},[1046,6967,1056],{"stretchy":1048},[1058,6969,1061],{"encoding":1060},[1023,6971,6973],{"className":6972,"ariaHidden":1066},[1065],[1023,6974,6976,6979,6982,6985,6988],{"className":6975},[1070],[1023,6977],{"className":6978,"style":1075},[1074],[1023,6980,1044],{"className":6981,"style":1081},[1079,1080],[1023,6983,1049],{"className":6984},[1085],[1023,6986,1053],{"className":6987},[1079],[1023,6989,1056],{"className":6990},[1092]," trung bình chứ không phải tệ nhất.",[968,6993,2890],{"id":2889},[986,6995,6996,6999,7002,7005],{},[989,6997,6998],{},"Dictionary gồm gì, khóa có quy tắc gì?",[989,7000,7001],{},"Set khác dictionary ở điểm nào?",[989,7003,7004],{},"Hàm băm giúp tra cứu nhanh thế nào?",[989,7006,7007],{},"Khi nào dùng set thay dictionary?",[3014,7009],{},[973,7011,7012],{},"🌕 Bạn đã hoàn thành ngày 5. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,7014,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":7016},[7017,7018,7023,7024,7030],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":7019},[7020,7021,7022],{"id":6452,"depth":73,"text":6453},{"id":6516,"depth":73,"text":6517},{"id":6537,"depth":73,"text":6538},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":7025},[7026,7027,7028,7029],{"id":6647,"depth":73,"text":6648},{"id":6718,"depth":73,"text":6719},{"id":6756,"depth":73,"text":6757},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu cặp khóa giá trị của dictionary, tính duy nhất của set, vai trò hàm băm, và khi nào dùng cấu trúc nào.",{},[3050,4669],{"title":80,"description":7031},[7036],"hash-table","84Cv-b8qk5Vz6UBMherWQqe0sB3oWqgnkrgRxI0zRr0",{"id":7039,"title":85,"body":7040,"category":5189,"day":88,"description":7547,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":7548,"navigation":2723,"outcomes":3047,"path":86,"prerequisites":7549,"seo":7550,"stem":87,"tags":7551,"__hash__":7554},"challenges\u002Fchallenges\u002F6.strategy-pattern.md",{"type":965,"value":7041,"toc":7531},[7042,7044,7047,7049,7053,7067,7071,7085,7089,7103,7141,7143,7151,7153,7160,7164,7167,7235,7316,7322,7337,7341,7344,7378,7402,7408,7412,7436,7462,7468,7470,7508,7510,7524,7526,7529],[968,7043,971],{"id":970},[973,7045,7046],{},"Bài này học cách đóng gói họ thuật toán. Bạn đổi hành vi vịt ngay khi chạy.",[968,7048,979],{"id":978},[981,7050,7052],{"id":7051},"strategy-là-gì","Strategy là gì",[986,7054,7055,7058,7061,7064],{},[989,7056,7057],{},"Gom mỗi thuật toán thành một lớp riêng.",[989,7059,7060],{},"Các lớp cùng họ đổi chỗ được cho nhau.",[989,7062,7063],{},"Ví dụ đời thường: thay lưỡi dao cùng một cán.",[989,7065,7066],{},"Lớp dùng chỉ gọi, không cần biết chi tiết.",[981,7068,7070],{"id":7069},"câu-chuyện-simuduck","Câu chuyện SimUDuck",[986,7072,7073,7076,7079,7082],{},[989,7074,7075],{},"Đầu tiên vịt kế thừa, vịt đồ chơi cũng biết bay sai.",[989,7077,7078],{},"Tách giao diện thì logic bay bị sao chép khắp nơi.",[989,7080,7081],{},"Strategy: vịt giữ 1 cách bay và 1 cách kêu.",[989,7083,7084],{},"Ví dụ đời thường: gắn động cơ khác vào cùng thân xe.",[981,7086,7088],{"id":7087},"đổi-hành-vi-lúc-chạy","Đổi hành vi lúc chạy",[986,7090,7091,7094,7097,7100],{},[989,7092,7093],{},"Vịt gỗ gắn tên lửa là bay được ngay.",[989,7095,7096],{},"Thêm kiểu bay mới chỉ thêm lớp mới.",[989,7098,7099],{},"Lớp Vịt cũ không cần sửa chữ nào.",[989,7101,7102],{},"Ví dụ đời thường: đổi sim là đổi nhà mạng.",[1099,7104,7105,7115],{},[1102,7106,7107],{},[1105,7108,7109,7112],{},[1108,7110,7111],{},"Cách làm",[1108,7113,7114],{},"Thêm kiểu bay mới",[1118,7116,7117,7125,7133],{},[1105,7118,7119,7122],{},[1123,7120,7121],{},"Kế thừa",[1123,7123,7124],{},"Sửa nhiều lớp",[1105,7126,7127,7130],{},[1123,7128,7129],{},"Giao diện thuần",[1123,7131,7132],{},"Sửa mọi lớp liên quan",[1105,7134,7135,7138],{},[1123,7136,7137],{},"Strategy",[1123,7139,7140],{},"Thêm 1 lớp mới",[968,7142,1433],{"id":1432},[986,7144,7145,7148],{},[989,7146,7147],{},"Input: vịt mồi đang đứng yên, gắn tên lửa. Output: cùng nút bay nay bay được.",[989,7149,7150],{},"Giải thích: chỉ thay đối tượng hành vi bên trong.",[968,7152,1482],{"id":1481},[973,7154,1485,7155,4801,7157,1517],{},[1487,7156,4800],{},[992,7158,7159],{},"day-006\u002F",[981,7161,7163],{"id":7162},"bài-1-simuduck-với-strategy","Bài 1: SimUDuck với Strategy",[973,7165,7166],{},"Cài đặt đúng cấu trúc sau:",[1352,7168,7170],{"className":1393,"code":7169,"language":1395,"meta":1357,"style":1357},"struct FlyBehavior   { virtual std::string fly() const = 0;   virtual ~FlyBehavior() = default; };\nstruct QuackBehavior { virtual std::string quack() const = 0; virtual ~QuackBehavior() = default; };\n\nclass Duck {\n public:\n  Duck(std::unique_ptr\u003CFlyBehavior> f, std::unique_ptr\u003CQuackBehavior> q);\n  std::string performFly() const;\n  std::string performQuack() const;\n  void setFlyBehavior(std::unique_ptr\u003CFlyBehavior> f);   \u002F\u002F đổi lúc chạy\n  void setQuackBehavior(std::unique_ptr\u003CQuackBehavior> q);\n  virtual std::string display() const = 0;\n  virtual ~Duck() = default;\n};\n",[992,7171,7172,7177,7182,7187,7192,7196,7201,7206,7211,7216,7221,7226,7231],{"__ignoreMap":1357},[1023,7173,7174],{"class":1362,"line":63},[1023,7175,7176],{},"struct FlyBehavior   { virtual std::string fly() const = 0;   virtual ~FlyBehavior() = default; };\n",[1023,7178,7179],{"class":1362,"line":68},[1023,7180,7181],{},"struct QuackBehavior { virtual std::string quack() const = 0; virtual ~QuackBehavior() = default; };\n",[1023,7183,7184],{"class":1362,"line":73},[1023,7185,7186],{"emptyLinePlaceholder":2723},"\n",[1023,7188,7189],{"class":1362,"line":78},[1023,7190,7191],{},"class Duck {\n",[1023,7193,7194],{"class":1362,"line":83},[1023,7195,4836],{},[1023,7197,7198],{"class":1362,"line":88},[1023,7199,7200],{},"  Duck(std::unique_ptr\u003CFlyBehavior> f, std::unique_ptr\u003CQuackBehavior> q);\n",[1023,7202,7203],{"class":1362,"line":93},[1023,7204,7205],{},"  std::string performFly() const;\n",[1023,7207,7208],{"class":1362,"line":98},[1023,7209,7210],{},"  std::string performQuack() const;\n",[1023,7212,7213],{"class":1362,"line":103},[1023,7214,7215],{},"  void setFlyBehavior(std::unique_ptr\u003CFlyBehavior> f);   \u002F\u002F đổi lúc chạy\n",[1023,7217,7218],{"class":1362,"line":108},[1023,7219,7220],{},"  void setQuackBehavior(std::unique_ptr\u003CQuackBehavior> q);\n",[1023,7222,7223],{"class":1362,"line":113},[1023,7224,7225],{},"  virtual std::string display() const = 0;\n",[1023,7227,7228],{"class":1362,"line":118},[1023,7229,7230],{},"  virtual ~Duck() = default;\n",[1023,7232,7233],{"class":1362,"line":123},[1023,7234,4866],{},[1099,7236,7237,7247],{},[1102,7238,7239],{},[1105,7240,7241,7244],{},[1108,7242,7243],{},"Lớp cần viết",[1108,7245,7246],{},"Trả về",[1118,7248,7249,7273,7297],{},[1105,7250,7251,7262],{},[1123,7252,7253,1656,7256,1656,7259],{},[992,7254,7255],{},"FlyWithWings",[992,7257,7258],{},"FlyNoWay",[992,7260,7261],{},"FlyRocketPowered",[1123,7263,7264,1656,7267,1656,7270],{},[992,7265,7266],{},"\"bay bằng cánh\"",[992,7268,7269],{},"\"không bay được\"",[992,7271,7272],{},"\"bay bằng tên lửa\"",[1105,7274,7275,7286],{},[1123,7276,7277,1656,7280,1656,7283],{},[992,7278,7279],{},"Quack",[992,7281,7282],{},"Squeak",[992,7284,7285],{},"MuteQuack",[1123,7287,7288,1656,7291,1656,7294],{},[992,7289,7290],{},"\"quạc quạc\"",[992,7292,7293],{},"\"chít chít\"",[992,7295,7296],{},"\"...\"",[1105,7298,7299,7313],{},[1123,7300,7301,1656,7304,1656,7307,1656,7310],{},[992,7302,7303],{},"MallardDuck",[992,7305,7306],{},"RubberDuck",[992,7308,7309],{},"DecoyDuck",[992,7311,7312],{},"ModelDuck",[1123,7314,7315],{},"Mỗi lớp chọn hành vi mặc định trong constructor",[1352,7317,7320],{"className":7318,"code":7319,"language":2241,"meta":1357},[2239],"MallardDuck: performFly -> \"bay bằng cánh\", performQuack -> \"quạc quạc\"\nRubberDuck:  performFly -> \"không bay được\", performQuack -> \"chít chít\"\nModelDuck:   performFly -> \"không bay được\"\nModelDuck.setFlyBehavior(FlyRocketPowered) -> performFly -> \"bay bằng tên lửa\"\n",[992,7321,7319],{"__ignoreMap":1357},[973,7323,7324,7326,7327,7330,7331,2461,7333,7336],{},[1487,7325,6076],{}," lớp ",[992,7328,7329],{},"Duck"," không có ",[992,7332,4951],{},[992,7334,7335],{},"switch"," theo loại vịt.",[981,7338,7340],{"id":7339},"bài-2-refactor-tính-lương","Bài 2: Refactor tính lương",[973,7342,7343],{},"Code ban đầu:",[1352,7345,7347],{"className":1393,"code":7346,"language":1395,"meta":1357,"style":1357},"double salary(const std::string &type, double base, int hours, double sales) {\n  if (type == \"fulltime\") return base;\n  if (type == \"parttime\") return hours * 50000;\n  if (type == \"sales\") return base * 0.5 + sales * 0.1;\n  throw std::invalid_argument(\"unknown\");\n}\n",[992,7348,7349,7354,7359,7364,7369,7374],{"__ignoreMap":1357},[1023,7350,7351],{"class":1362,"line":63},[1023,7352,7353],{},"double salary(const std::string &type, double base, int hours, double sales) {\n",[1023,7355,7356],{"class":1362,"line":68},[1023,7357,7358],{},"  if (type == \"fulltime\") return base;\n",[1023,7360,7361],{"class":1362,"line":73},[1023,7362,7363],{},"  if (type == \"parttime\") return hours * 50000;\n",[1023,7365,7366],{"class":1362,"line":78},[1023,7367,7368],{},"  if (type == \"sales\") return base * 0.5 + sales * 0.1;\n",[1023,7370,7371],{"class":1362,"line":83},[1023,7372,7373],{},"  throw std::invalid_argument(\"unknown\");\n",[1023,7375,7376],{"class":1362,"line":88},[1023,7377,4986],{},[973,7379,7380,7382,7383,7386,7387,7390,7391,7394,7395,7397,7398,7401],{},[1487,7381,4871],{}," tạo interface ",[992,7384,7385],{},"PayPolicy"," với ",[992,7388,7389],{},"double pay(const Employee&) const",". Viết 3 policy tương ứng. ",[992,7392,7393],{},"Employee"," giữ một ",[992,7396,7385],{},". Sau đó thêm ",[992,7399,7400],{},"InternPolicy"," (lương cố định 3.000.000) mà không sửa code cũ.",[1352,7403,7406],{"className":7404,"code":7405,"language":2241,"meta":1357},[2239],"fulltime base=15e6            -> 15000000\nparttime hours=80             -> 4000000\nsales base=10e6 sales=50e6    -> 10000000\nintern                        -> 3000000\n",[992,7407,7405],{"__ignoreMap":1357},[981,7409,7411],{"id":7410},"bài-3-nhân-vật-game-đổi-vũ-khí-nâng-cao","Bài 3: Nhân vật game đổi vũ khí (nâng cao)",[973,7413,7414,5059,7417,7386,7420,7423,7424,7427,7428,7431,7432,7435],{},[992,7415,7416],{},"Character",[992,7418,7419],{},"WeaponBehavior",[992,7421,7422],{},"int attack(int enemyArmor)",". Viết ",[992,7425,7426],{},"Sword"," (sát thương 30 trừ giáp), ",[992,7429,7430],{},"Bow"," (20, bỏ qua giáp), ",[992,7433,7434],{},"Magic"," (45 trừ 2 lần giáp, tối thiểu 5).",[2273,7437,7438,7444,7450],{},[989,7439,7440,7441,1517],{},"Cho nhân vật đổi vũ khí giữa trận bằng ",[992,7442,7443],{},"setWeapon",[989,7445,1505,7446,7449],{},[992,7447,7448],{},"main"," mô phỏng 3 lượt đánh quái có giáp 10, mỗi lượt đổi vũ khí khác nhau. In sát thương từng lượt.",[989,7451,4938,7452,7454,7455,1656,7458,7461],{},[992,7453,2513],{},", lập bảng so sánh: thêm vũ khí thứ 4 bằng kế thừa (",[992,7456,7457],{},"SwordKnight",[992,7459,7460],{},"BowKnight","...) tốn bao nhiêu lớp so với Strategy.",[1352,7463,7466],{"className":7464,"code":7465,"language":2241,"meta":1357},[2239],"Sword vs armor 10 -> 20\nBow   vs armor 10 -> 20\nMagic vs armor 10 -> 25\nMagic vs armor 30 -> 5\n",[992,7467,7465],{"__ignoreMap":1357},[981,7469,2711],{"id":2710},[986,7471,7473,7479,7496,7502],{"className":7472},[2715],[989,7474,7476,7478],{"className":7475},[2719],[2721,7477],{"disabled":2723,"type":2724}," Toàn bộ test mẫu pass.",[989,7480,7482,7484,7485,2461,7487,7489,7490,1656,7492,1656,7494,1517],{"className":7481},[2719],[2721,7483],{"disabled":2723,"type":2724}," Không có chuỗi ",[992,7486,4951],{},[992,7488,7335],{}," chọn hành vi trong ",[992,7491,7329],{},[992,7493,7393],{},[992,7495,7416],{},[989,7497,7499,7501],{"className":7498},[2719],[2721,7500],{"disabled":2723,"type":2724}," Thêm hành vi mới chỉ tạo file mới, không sửa file cũ.",[989,7503,7505,7507],{"className":7504},[2719],[2721,7506],{"disabled":2723,"type":2724}," Vẽ sơ đồ lớp (tay hoặc Mermaid) có quan hệ \"has-a\" tới 2 họ hành vi.",[968,7509,2890],{"id":2889},[986,7511,7512,7515,7518,7521],{},[989,7513,7514],{},"Strategy là gì, nói 1 câu?",[989,7516,7517],{},"Vì sao kế thừa gây bay nhầm ở vịt cao su?",[989,7519,7520],{},"Đổi hành vi lúc chạy nghĩa là gì?",[989,7522,7523],{},"Khi nào nên dùng Strategy?",[3014,7525],{},[973,7527,7528],{},"🌕 Bạn đã hoàn thành ngày 6. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,7530,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":7532},[7533,7534,7539,7540,7546],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":7535},[7536,7537,7538],{"id":7051,"depth":73,"text":7052},{"id":7069,"depth":73,"text":7070},{"id":7087,"depth":73,"text":7088},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":7541},[7542,7543,7544,7545],{"id":7162,"depth":73,"text":7163},{"id":7339,"depth":73,"text":7340},{"id":7410,"depth":73,"text":7411},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Strategy, cấu trúc họ thuật toán hoán đổi được, và toàn bộ hành trình refactor SimUDuck từ kế thừa sụp đổ tới ủy thác linh hoạt.",{},[5194,5195],{"title":85,"description":7547},[7552,7553],"strategy","simuduck","i-PoqWXpX3LhOGrCeUGJuYAjaX_y3mcny24lG_dKW4o",{"id":7556,"title":90,"body":7557,"category":3041,"day":93,"description":8146,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":8147,"navigation":2723,"outcomes":3047,"path":91,"prerequisites":8148,"seo":8150,"stem":92,"tags":8151,"__hash__":8154},"challenges\u002Fchallenges\u002F7.cay-va-bst.md",{"type":965,"value":7558,"toc":8130},[7559,7561,7564,7566,7570,7587,7591,7608,7612,7733,7787,7789,7797,7799,7811,7815,7868,7992,7998,8002,8020,8026,8030,8058,8064,8072,8074,8107,8109,8123,8125,8128],[968,7560,971],{"id":970},[973,7562,7563],{},"Bài này học từ vựng cây và cây tìm kiếm. Bạn dùng nó cho heap và treap sau này.",[968,7565,979],{"id":978},[981,7567,7569],{"id":7568},"từ-vựng-cây","Từ vựng cây",[986,7571,7572,7575,7578,7581,7584],{},[989,7573,7574],{},"Gốc là nút duy nhất không có cha.",[989,7576,7577],{},"Lá là nút không có con nào.",[989,7579,7580],{},"Anh em là 2 nút cùng cha.",[989,7582,7583],{},"Ví dụ đời thường: cây gia phả có ông bà con cháu.",[989,7585,7586],{},"Bậc của nút là số con trực tiếp.",[981,7588,7590],{"id":7589},"cây-nhị-phân-và-bst","Cây nhị phân và BST",[986,7592,7593,7596,7599,7602,7605],{},[989,7594,7595],{},"Cây nhị phân mỗi nút tối đa 2 con.",[989,7597,7598],{},"BST thêm luật: trái nhỏ hơn, phải lớn hơn.",[989,7600,7601],{},"Luật này đúng với mọi nút trong cây.",[989,7603,7604],{},"Ví dụ đời thường: tủ hồ sơ xếp trái nhỏ phải lớn.",[989,7606,7607],{},"Tìm kiếm thì so sánh rồi rẽ trái hoặc phải.",[981,7609,7611],{"id":7610},"cây-lệch-và-cân-bằng","Cây lệch và cân bằng",[986,7613,7614,7617,7663,7730],{},[989,7615,7616],{},"Chèn tăng dần tạo cây nghiêng như list.",[989,7618,7619,7620,1517],{},"Cây lệch tìm kiếm tốn ",[1023,7621,7623,7642],{"className":7622},[1026],[1023,7624,7626],{"className":7625},[1030],[1032,7627,7628],{"xmlns":1034},[1036,7629,7630,7640],{},[1039,7631,7632,7634,7636,7638],{},[1042,7633,1044],{},[1046,7635,1049],{"stretchy":1048},[1042,7637,1262],{},[1046,7639,1056],{"stretchy":1048},[1058,7641,1267],{"encoding":1060},[1023,7643,7645],{"className":7644,"ariaHidden":1066},[1065],[1023,7646,7648,7651,7654,7657,7660],{"className":7647},[1070],[1023,7649],{"className":7650,"style":1075},[1074],[1023,7652,1044],{"className":7653,"style":1081},[1079,1080],[1023,7655,1049],{"className":7656},[1085],[1023,7658,1262],{"className":7659},[1079,1080],[1023,7661,1056],{"className":7662},[1092],[989,7664,7665,7666,1517],{},"Cây cân bằng tìm kiếm tốn ",[1023,7667,7669,7698],{"className":7668},[1026],[1023,7670,7672],{"className":7671},[1030],[1032,7673,7674],{"xmlns":1034},[1036,7675,7676,7695],{},[1039,7677,7678,7680,7682,7685,7688,7691,7693],{},[1042,7679,1044],{},[1046,7681,1049],{"stretchy":1048},[1042,7683,7684],{},"l",[1042,7686,7687],{},"o",[1042,7689,7690],{},"g",[1042,7692,1262],{},[1046,7694,1056],{"stretchy":1048},[1058,7696,7697],{"encoding":1060},"O(log n)",[1023,7699,7701],{"className":7700,"ariaHidden":1066},[1065],[1023,7702,7704,7707,7710,7713,7717,7720,7724,7727],{"className":7703},[1070],[1023,7705],{"className":7706,"style":1075},[1074],[1023,7708,1044],{"className":7709,"style":1081},[1079,1080],[1023,7711,1049],{"className":7712},[1085],[1023,7714,7684],{"className":7715,"style":7716},[1079,1080],"margin-right:0.0197em;",[1023,7718,7687],{"className":7719},[1079,1080],[1023,7721,7690],{"className":7722,"style":7723},[1079,1080],"margin-right:0.0359em;",[1023,7725,1262],{"className":7726},[1079,1080],[1023,7728,1056],{"className":7729},[1092],[989,7731,7732],{},"Ví dụ đời thường: thang thẳng đứng và thang rộng.",[1099,7734,7735,7745],{},[1102,7736,7737],{},[1105,7738,7739,7742],{},[1108,7740,7741],{},"Loại cây",[1108,7743,7744],{},"Đặc điểm",[1118,7746,7747,7755,7763,7771,7779],{},[1105,7748,7749,7752],{},[1123,7750,7751],{},"Nhị phân",[1123,7753,7754],{},"Tối đa 2 con",[1105,7756,7757,7760],{},[1123,7758,7759],{},"Đầy (full)",[1123,7761,7762],{},"Mọi nút có 0 hoặc 2 con",[1105,7764,7765,7768],{},[1123,7766,7767],{},"Hoàn chỉnh (complete)",[1123,7769,7770],{},"Mọi tầng đầy trừ tầng cuối, tầng cuối dồn trái (dùng cho heap)",[1105,7772,7773,7776],{},[1123,7774,7775],{},"Hoàn hảo",[1123,7777,7778],{},"Đầy và mọi lá cùng tầng",[1105,7780,7781,7784],{},[1123,7782,7783],{},"BST",[1123,7785,7786],{},"Trái nhỏ, phải lớn",[968,7788,1433],{"id":1432},[986,7790,7791,7794],{},[989,7792,7793],{},"Input: BST gốc 10, trái 5, phải 15, tìm 7. Output: thăm 10, 5 rồi báo không thấy.",[989,7795,7796],{},"Giải thích: nhỏ hơn thì rẽ trái, lớn hơn thì rẽ phải.",[968,7798,1482],{"id":1481},[973,7800,1485,7801,7803,7804,7807,7808,7810],{},[1487,7802,1493],{}," (hoặc C). Nộp vào ",[992,7805,7806],{},"day-007\u002F",". Khóa là ",[992,7809,1516],{},", không trùng.",[981,7812,7814],{"id":7813},"bài-1-bst-cơ-bản","Bài 1: BST cơ bản",[1352,7816,7818],{"className":1393,"code":7817,"language":1395,"meta":1357,"style":1357},"struct Node { int key; Node *left = nullptr, *right = nullptr; };\nclass BST {\n public:\n  bool insert(int key);         \u002F\u002F trả false nếu key đã có\n  bool contains(int key) const;\n  int  height() const;          \u002F\u002F cây rỗng = -1, 1 nút = 0\n  size_t size() const;\n  std::vector\u003Cint> inorder() const;\n  ~BST();                       \u002F\u002F giải phóng mọi nút\n};\n",[992,7819,7820,7825,7830,7834,7839,7844,7849,7854,7859,7864],{"__ignoreMap":1357},[1023,7821,7822],{"class":1362,"line":63},[1023,7823,7824],{},"struct Node { int key; Node *left = nullptr, *right = nullptr; };\n",[1023,7826,7827],{"class":1362,"line":68},[1023,7828,7829],{},"class BST {\n",[1023,7831,7832],{"class":1362,"line":73},[1023,7833,4836],{},[1023,7835,7836],{"class":1362,"line":78},[1023,7837,7838],{},"  bool insert(int key);         \u002F\u002F trả false nếu key đã có\n",[1023,7840,7841],{"class":1362,"line":83},[1023,7842,7843],{},"  bool contains(int key) const;\n",[1023,7845,7846],{"class":1362,"line":88},[1023,7847,7848],{},"  int  height() const;          \u002F\u002F cây rỗng = -1, 1 nút = 0\n",[1023,7850,7851],{"class":1362,"line":93},[1023,7852,7853],{},"  size_t size() const;\n",[1023,7855,7856],{"class":1362,"line":98},[1023,7857,7858],{},"  std::vector\u003Cint> inorder() const;\n",[1023,7860,7861],{"class":1362,"line":103},[1023,7862,7863],{},"  ~BST();                       \u002F\u002F giải phóng mọi nút\n",[1023,7865,7866],{"class":1362,"line":108},[1023,7867,4866],{},[1099,7869,7870,7878],{},[1102,7871,7872],{},[1105,7873,7874,7876],{},[1108,7875,1566],{},[1108,7877,1113],{},[1118,7879,7880,7935],{},[1105,7881,7882,7888],{},[1123,7883,7884,1656,7886],{},[992,7885,2251],{},[992,7887,6936],{},[1123,7889,7890],{},[1023,7891,7893,7914],{"className":7892},[1026],[1023,7894,7896],{"className":7895},[1030],[1032,7897,7898],{"xmlns":1034},[1036,7899,7900,7911],{},[1039,7901,7902,7904,7906,7909],{},[1042,7903,1044],{},[1046,7905,1049],{"stretchy":1048},[1042,7907,7908],{},"h",[1046,7910,1056],{"stretchy":1048},[1058,7912,7913],{"encoding":1060},"O(h)",[1023,7915,7917],{"className":7916,"ariaHidden":1066},[1065],[1023,7918,7920,7923,7926,7929,7932],{"className":7919},[1070],[1023,7921],{"className":7922,"style":1075},[1074],[1023,7924,1044],{"className":7925,"style":1081},[1079,1080],[1023,7927,1049],{"className":7928},[1085],[1023,7930,7908],{"className":7931},[1079,1080],[1023,7933,1056],{"className":7934},[1092],[1105,7936,7937,7947],{},[1123,7938,7939,1656,7942,1656,7944],{},[992,7940,7941],{},"height",[992,7943,994],{},[992,7945,7946],{},"inorder",[1123,7948,7949],{},[1023,7950,7952,7971],{"className":7951},[1026],[1023,7953,7955],{"className":7954},[1030],[1032,7956,7957],{"xmlns":1034},[1036,7958,7959,7969],{},[1039,7960,7961,7963,7965,7967],{},[1042,7962,1044],{},[1046,7964,1049],{"stretchy":1048},[1042,7966,1262],{},[1046,7968,1056],{"stretchy":1048},[1058,7970,1267],{"encoding":1060},[1023,7972,7974],{"className":7973,"ariaHidden":1066},[1065],[1023,7975,7977,7980,7983,7986,7989],{"className":7976},[1070],[1023,7978],{"className":7979,"style":1075},[1074],[1023,7981,1044],{"className":7982,"style":1081},[1079,1080],[1023,7984,1049],{"className":7985},[1085],[1023,7987,1262],{"className":7988},[1079,1080],[1023,7990,1056],{"className":7991},[1092],[1352,7993,7996],{"className":7994,"code":7995,"language":2241,"meta":1357},[2239],"insert 10, 5, 15, 3, 7, 12, 20  -> inorder = [3,5,7,10,12,15,20], height=2\ninsert 7 lần nữa                 -> false, size vẫn 7\ncontains(12) \u002F contains(8)       -> true \u002F false\n",[992,7997,7995],{"__ignoreMap":1357},[981,7999,8001],{"id":8000},"bài-2-kiểm-tra-bst-và-đường-tìm","Bài 2: Kiểm tra BST và đường tìm",[2273,8003,8004,8014],{},[989,8005,1505,8006,8009,8010,8013],{},[992,8007,8008],{},"bool isBST(const Node *root)",". Mỗi nút phải nằm trong khoảng ",[992,8011,8012],{},"(min, max)"," do tổ tiên quy định, không chỉ so với con trực tiếp.",[989,8015,1505,8016,8019],{},[992,8017,8018],{},"std::vector\u003Cint> searchPath(int key)"," trả dãy khóa đã thăm.",[1352,8021,8024],{"className":8022,"code":8023,"language":2241,"meta":1357},[2239],"Cây: 10 (trái 5 (phải 12), phải 15)   -> isBST = false (12 nằm bên trái 10)\nCây Bài 1, searchPath(8)               -> [10, 5, 7]\nCây Bài 1, searchPath(20)              -> [10, 15, 20]\n",[992,8025,8023],{"__ignoreMap":1357},[981,8027,8029],{"id":8028},"bài-3-cây-lệch-và-cây-cân-nâng-cao","Bài 3: Cây lệch và cây cân (nâng cao)",[2273,8031,8032,8038,8047,8052],{},[989,8033,8034,8035,1517],{},"Chèn 1..1000 theo thứ tự tăng. In ",[992,8036,8037],{},"height()",[989,8039,8040,8041,8044,8045,1517],{},"Chèn cùng tập khóa theo thứ tự \"giữa trước\": viết ",[992,8042,8043],{},"void insertBalanced(std::vector\u003Cint> &sorted, int l, int r)"," chèn phần tử giữa rồi đệ quy hai nửa. In ",[992,8046,8037],{},[989,8048,8049,8050,1517],{},"Chèn 1000 khóa theo thứ tự ngẫu nhiên (seed cố định). In ",[992,8051,8037],{},[989,8053,8054,8055,8057],{},"Đo thời gian 10^5 lần ",[992,8056,6936],{}," ngẫu nhiên trên cả 3 cây.",[1352,8059,8062],{"className":8060,"code":8061,"language":2241,"meta":1357},[2239],"Kỳ vọng: tăng dần -> height = 999; giữa trước -> height = 9; ngẫu nhiên -> khoảng 20\n",[992,8063,8061],{"__ignoreMap":1357},[2245,8065,8066],{},[973,8067,8068,8069,8071],{},"Cây 1000 nút chèn tăng dần mà dùng đệ quy có thể tràn stack ở máy yếu. Viết ",[992,8070,2251],{}," bằng vòng lặp.",[981,8073,2711],{"id":2710},[986,8075,8077,8086,8095,8101],{"className":8076},[2715],[989,8078,8080,8082,8083,8085],{"className":8079},[2719],[2721,8081],{"disabled":2723,"type":2724}," Test mẫu pass, ",[992,8084,7946],{}," luôn tăng dần.",[989,8087,8089,2308,8091,8094],{"className":8088},[2719],[2721,8090],{"disabled":2723,"type":2724},[992,8092,8093],{},"isBST"," bắt được ca vi phạm ở cháu, không chỉ ở con.",[989,8096,8098,8100],{"className":8097},[2719],[2721,8099],{"disabled":2723,"type":2724}," Bảng chiều cao và thời gian của Bài 3 có số thật.",[989,8102,8104,8106],{"className":8103},[2719],[2721,8105],{"disabled":2723,"type":2724}," Sanitizer sạch, destructor giải phóng hết nút.",[968,8108,2890],{"id":2889},[986,8110,8111,8114,8117,8120],{},[989,8112,8113],{},"Gốc, lá, anh em là gì?",[989,8115,8116],{},"BST khác cây nhị phân thường ở đâu?",[989,8118,8119],{},"Tìm kiếm trên BST đi thế nào?",[989,8121,8122],{},"Vì sao cây lệch lại chậm?",[3014,8124],{},[973,8126,8127],{},"🌕 Bạn đã hoàn thành ngày 7. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,8129,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":8131},[8132,8133,8138,8139,8145],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":8134},[8135,8136,8137],{"id":7568,"depth":73,"text":7569},{"id":7589,"depth":73,"text":7590},{"id":7610,"depth":73,"text":7611},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":8140},[8141,8142,8143,8144],{"id":7813,"depth":73,"text":7814},{"id":8000,"depth":73,"text":8001},{"id":8028,"depth":73,"text":8029},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Học từ vựng của cây, các loại cây nhị phân, và bất biến tìm kiếm làm nền cho treap, heap và cây quyết định.",{},[3050,8149],"de-quy",{"title":90,"description":8146},[8152,8153],"tree","bst","dI6ZdYDXlrl_1I3yOHS2eJuw0xjcuxKJcjmnu_aIY48",{"id":8156,"title":95,"body":8157,"category":8797,"day":98,"description":8798,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":8799,"navigation":2723,"outcomes":3047,"path":96,"prerequisites":8800,"seo":8801,"stem":97,"tags":8802,"__hash__":8804},"challenges\u002Fchallenges\u002F8.de-quy-thuc-hanh.md",{"type":965,"value":8158,"toc":8781},[8159,8161,8164,8166,8170,8187,8191,8205,8209,8223,8268,8270,8278,8280,8289,8293,8520,8524,8540,8546,8552,8556,8563,8696,8702,8708,8725,8727,8758,8760,8774,8776,8779],[968,8160,971],{"id":970},[973,8162,8163],{},"Bài này biến đệ quy thành công cụ quen tay. Bạn học điều kiện dừng và ghi nhớ.",[968,8165,979],{"id":978},[981,8167,8169],{"id":8168},"hai-mảnh-của-hàm-đệ-quy","Hai mảnh của hàm đệ quy",[986,8171,8172,8175,8178,8181,8184],{},[989,8173,8174],{},"Điều kiện dừng cho đáp án ngay, không gọi tiếp.",[989,8176,8177],{},"Bước đệ quy thu nhỏ bài toán rồi tự gọi.",[989,8179,8180],{},"Thiếu dừng thì gọi mãi không dứt.",[989,8182,8183],{},"Ví dụ đời thường: búp bê Nga, con trong nhỏ hơn con ngoài.",[989,8185,8186],{},"Thu nhỏ sai thì không bao giờ tới điểm dừng.",[981,8188,8190],{"id":8189},"truy-vết-ngăn-xếp-lời-gọi","Truy vết ngăn xếp lời gọi",[986,8192,8193,8196,8199,8202],{},[989,8194,8195],{},"Mỗi lần tự gọi là chồng thêm 1 khung.",[989,8197,8198],{},"Gặp dừng thì gỡ từng khung từ trên xuống.",[989,8200,8201],{},"Thứ tự gỡ ngược thứ tự gọi, đúng LIFO.",[989,8203,8204],{},"Ví dụ đời thường: chồng bát, đặt lên rồi lấy xuống.",[981,8206,8208],{"id":8207},"memo-ghi-nhớ-để-khỏi-tính-lại","Memo — ghi nhớ để khỏi tính lại",[986,8210,8211,8214,8217,8220],{},[989,8212,8213],{},"Tính xong thì cất kết quả vào bảng.",[989,8215,8216],{},"Gặp lại tham số cũ thì lấy ra dùng.",[989,8218,8219],{},"Chỉ hiệu quả khi bài toán con lặp lại.",[989,8221,8222],{},"Ví dụ đời thường: ghi đáp án ra giấy nháp.",[1352,8224,8226],{"className":3538,"code":8225,"language":3540,"meta":1357,"style":1357},"memo = {}  # bảng ghi nhớ\ndef f(n):\n    if n \u003C= 1:  # điều kiện dừng\n        return n\n    if n in memo:  # có rồi thì dùng lại\n        return memo[n]\n    memo[n] = f(n-1) + f(n-2)  # tính rồi cất\n    return memo[n]\n",[992,8227,8228,8233,8238,8243,8248,8253,8258,8263],{"__ignoreMap":1357},[1023,8229,8230],{"class":1362,"line":63},[1023,8231,8232],{},"memo = {}  # bảng ghi nhớ\n",[1023,8234,8235],{"class":1362,"line":68},[1023,8236,8237],{},"def f(n):\n",[1023,8239,8240],{"class":1362,"line":73},[1023,8241,8242],{},"    if n \u003C= 1:  # điều kiện dừng\n",[1023,8244,8245],{"class":1362,"line":78},[1023,8246,8247],{},"        return n\n",[1023,8249,8250],{"class":1362,"line":83},[1023,8251,8252],{},"    if n in memo:  # có rồi thì dùng lại\n",[1023,8254,8255],{"class":1362,"line":88},[1023,8256,8257],{},"        return memo[n]\n",[1023,8259,8260],{"class":1362,"line":93},[1023,8261,8262],{},"    memo[n] = f(n-1) + f(n-2)  # tính rồi cất\n",[1023,8264,8265],{"class":1362,"line":98},[1023,8266,8267],{},"    return memo[n]\n",[968,8269,1433],{"id":1432},[986,8271,8272,8275],{},[989,8273,8274],{},"Input: tính số hạng 5 của dãy truy hồi có memo. Output: mỗi chỉ số tính 1 lần.",[989,8276,8277],{},"Giải thích: bảng nhớ cắt hết tính toán trùng lặp.",[968,8279,1482],{"id":1481},[973,8281,1485,8282,8284,8285,8288],{},[1487,8283,1493],{}," (hoặc Python cho bài đo). Nộp vào ",[992,8286,8287],{},"day-008\u002F",". Mọi hàm phải đệ quy, ghi rõ base case bằng comment.",[981,8290,8292],{"id":8291},"bài-1-năm-hàm-đệ-quy-cơ-bản","Bài 1: Năm hàm đệ quy cơ bản",[1099,8294,8295,8307],{},[1102,8296,8297],{},[1105,8298,8299,8301,8304],{},[1108,8300,1566],{},[1108,8302,8303],{},"Mô tả",[1108,8305,8306],{},"Test",[1118,8308,8309,8449,8467,8491,8504],{},[1105,8310,8311,8316,8441],{},[1123,8312,8313],{},[992,8314,8315],{},"long long power(long long a, int n)",[1123,8317,8318,8378,8379],{},[1023,8319,8321,8339],{"className":8320},[1026],[1023,8322,8324],{"className":8323},[1030],[1032,8325,8326],{"xmlns":1034},[1036,8327,8328,8336],{},[1039,8329,8330],{},[2327,8331,8332,8334],{},[1042,8333,6207],{},[1042,8335,1262],{},[1058,8337,8338],{"encoding":1060},"a^n",[1023,8340,8342],{"className":8341,"ariaHidden":1066},[1065],[1023,8343,8345,8349],{"className":8344},[1070],[1023,8346],{"className":8347,"style":8348},[1074],"height:0.6644em;",[1023,8350,8352,8355],{"className":8351},[1079],[1023,8353,6207],{"className":8354},[1079,1080],[1023,8356,8358],{"className":8357},[2383],[1023,8359,8361],{"className":8360},[2387],[1023,8362,8364],{"className":8363},[2391],[1023,8365,8367],{"className":8366,"style":8348},[2395],[1023,8368,8369,8372],{"style":2398},[1023,8370],{"className":8371,"style":2403},[2402],[1023,8373,8375],{"className":8374},[2407,2408,2409,2410],[1023,8376,1262],{"className":8377},[1079,1080,2410]," bằng chia đôi số mũ, ",[1023,8380,8382,8408],{"className":8381},[1026],[1023,8383,8385],{"className":8384},[1030],[1032,8386,8387],{"xmlns":1034},[1036,8388,8389,8405],{},[1039,8390,8391,8393,8395,8398,8401,8403],{},[1042,8392,1044],{},[1046,8394,1049],{"stretchy":1048},[1042,8396,8397],{},"log",[1046,8399,8400],{},"⁡",[1042,8402,1262],{},[1046,8404,1056],{"stretchy":1048},[1058,8406,8407],{"encoding":1060},"O(\\log n)",[1023,8409,8411],{"className":8410,"ariaHidden":1066},[1065],[1023,8412,8414,8417,8420,8423,8431,8435,8438],{"className":8413},[1070],[1023,8415],{"className":8416,"style":1075},[1074],[1023,8418,1044],{"className":8419,"style":1081},[1079,1080],[1023,8421,1049],{"className":8422},[1085],[1023,8424,8427,8428],{"className":8425},[8426],"mop","lo",[1023,8429,7690],{"style":8430},"margin-right:0.0139em;",[1023,8432],{"className":8433,"style":8434},[2354],"margin-right:0.1667em;",[1023,8436,1262],{"className":8437},[1079,1080],[1023,8439,1056],{"className":8440},[1092],[1123,8442,8443,1656,8446],{},[992,8444,8445],{},"power(2,10)=1024",[992,8447,8448],{},"power(3,0)=1",[1105,8450,8451,8456,8462],{},[1123,8452,8453],{},[992,8454,8455],{},"int sumDigits(long long n)",[1123,8457,8458,8459],{},"Tổng chữ số, ",[992,8460,8461],{},"n >= 0",[1123,8463,8464],{},[992,8465,8466],{},"sumDigits(9045)=18",[1105,8468,8469,8474,8477],{},[1123,8470,8471],{},[992,8472,8473],{},"bool isPalindrome(const std::string &s, int l, int r)",[1123,8475,8476],{},"Chuỗi đối xứng",[1123,8478,8479,8482,8483,8486,8487,8490],{},[992,8480,8481],{},"\"racecar\""," true, ",[992,8484,8485],{},"\"ab\""," false, ",[992,8488,8489],{},"\"\""," true",[1105,8492,8493,8498,8501],{},[1123,8494,8495],{},[992,8496,8497],{},"int countLeaves(const Node *root)",[1123,8499,8500],{},"Đếm lá cây nhị phân",[1123,8502,8503],{},"Cây ngày 7 có 4 lá",[1105,8505,8506,8511,8514],{},[1123,8507,8508],{},[992,8509,8510],{},"void hanoi(int n, char from, char to, char via, std::vector\u003Cstd::string> &moves)",[1123,8512,8513],{},"Ghi từng bước chuyển đĩa",[1123,8515,8516,8519],{},[992,8517,8518],{},"n=3"," cho đúng 7 bước",[981,8521,8523],{"id":8522},"bài-2-vết-stack","Bài 2: Vết stack",[973,8525,8526,8527,8530,8531,1509,8534,8537,8538,4437],{},"Thêm tham số ",[992,8528,8529],{},"depth"," vào ",[992,8532,8533],{},"hanoi",[992,8535,8536],{},"countLeaves",". In mỗi lần vào hàm và ra hàm, thụt lề theo ",[992,8539,8529],{},[1352,8541,8544],{"className":8542,"code":8543,"language":2241,"meta":1357},[2239],"-> countLeaves(10)\n  -> countLeaves(5)\n    -> countLeaves(3)\n    \u003C- 1\n  ...\n\u003C- 4\n",[992,8545,8543],{"__ignoreMap":1357},[973,8547,8548,8549,8551],{},"Chụp output cho cây 7 nút vào ",[992,8550,2513],{},". Đánh dấu độ sâu stack lớn nhất.",[981,8553,8555],{"id":8554},"bài-3-fibonacci-ba-cách-nâng-cao","Bài 3: Fibonacci ba cách (nâng cao)",[973,8557,8558,8559,8562],{},"Viết 3 hàm và ",[1487,8560,8561],{},"đếm số lời gọi"," bằng biến toàn cục:",[1099,8564,8565,8574],{},[1102,8566,8567],{},[1105,8568,8569,8571],{},[1108,8570,1566],{},[1108,8572,8573],{},"Kỳ vọng",[1118,8575,8576,8586,8642],{},[1105,8577,8578,8583],{},[1123,8579,8580],{},[992,8581,8582],{},"fibNaive(n)",[1123,8584,8585],{},"Số lời gọi tăng theo hàm mũ",[1105,8587,8588,8593],{},[1123,8589,8590],{},[992,8591,8592],{},"fibMemo(n, memo)",[1123,8594,8595,8596,8598,8599],{},"Mỗi ",[992,8597,1262],{}," tính 1 lần, ",[1023,8600,8602,8621],{"className":8601},[1026],[1023,8603,8605],{"className":8604},[1030],[1032,8606,8607],{"xmlns":1034},[1036,8608,8609,8619],{},[1039,8610,8611,8613,8615,8617],{},[1042,8612,1044],{},[1046,8614,1049],{"stretchy":1048},[1042,8616,1262],{},[1046,8618,1056],{"stretchy":1048},[1058,8620,1267],{"encoding":1060},[1023,8622,8624],{"className":8623,"ariaHidden":1066},[1065],[1023,8625,8627,8630,8633,8636,8639],{"className":8626},[1070],[1023,8628],{"className":8629,"style":1075},[1074],[1023,8631,1044],{"className":8632,"style":1081},[1079,1080],[1023,8634,1049],{"className":8635},[1085],[1023,8637,1262],{"className":8638},[1079,1080],[1023,8640,1056],{"className":8641},[1092],[1105,8643,8644,8649],{},[1123,8645,8646],{},[992,8647,8648],{},"fibIter(n)",[1123,8650,8651,8652,8695],{},"Không đệ quy, ",[1023,8653,8655,8674],{"className":8654},[1026],[1023,8656,8658],{"className":8657},[1030],[1032,8659,8660],{"xmlns":1034},[1036,8661,8662,8672],{},[1039,8663,8664,8666,8668,8670],{},[1042,8665,1044],{},[1046,8667,1049],{"stretchy":1048},[1051,8669,1053],{},[1046,8671,1056],{"stretchy":1048},[1058,8673,1061],{"encoding":1060},[1023,8675,8677],{"className":8676,"ariaHidden":1066},[1065],[1023,8678,8680,8683,8686,8689,8692],{"className":8679},[1070],[1023,8681],{"className":8682,"style":1075},[1074],[1023,8684,1044],{"className":8685,"style":1081},[1079,1080],[1023,8687,1049],{"className":8688},[1085],[1023,8690,1053],{"className":8691},[1079],[1023,8693,1056],{"className":8694},[1092]," bộ nhớ",[973,8697,8698,8699,4437],{},"In bảng với ",[992,8700,8701],{},"n = 10, 20, 30, 40",[1352,8703,8706],{"className":8704,"code":8705,"language":2241,"meta":1357},[2239],"n    fib(n)       calls_naive    calls_memo\n10   55           177            19\n20   6765         21891          39\n30   832040       ...            ...\n",[992,8707,8705],{"__ignoreMap":1357},[973,8709,8710,8713,8714,8717,8718,8721,8722,8724],{},[1487,8711,8712],{},"Thêm:"," duyệt DFS đồ thị có chu trình ",[992,8715,8716],{},"0-1, 1-2, 2-0, 2-3"," bằng đệ quy. Viết bản có tập ",[992,8719,8720],{},"visited",". Giải thích (không cần chạy) vì sao bản thiếu ",[992,8723,8720],{}," không dừng.",[981,8726,2711],{"id":2710},[986,8728,8730,8736,8742,8748],{"className":8729},[2715],[989,8731,8733,8735],{"className":8732},[2719],[2721,8734],{"disabled":2723,"type":2724}," Mọi test mẫu pass.",[989,8737,8739,8741],{"className":8738},[2719],[2721,8740],{"disabled":2723,"type":2724}," Mỗi hàm có comment chỉ rõ base case và bước thu nhỏ.",[989,8743,8745,8747],{"className":8744},[2719],[2721,8746],{"disabled":2723,"type":2724}," Bảng số lời gọi Bài 3 khớp số thật đo được.",[989,8749,8751,8753,8754,8757],{"className":8750},[2719],[2721,8752],{"disabled":2723,"type":2724}," Vẽ được cây lời gọi ",[992,8755,8756],{},"fibNaive(5)"," và chỉ ra các nút bị tính lặp.",[968,8759,2890],{"id":2889},[986,8761,8762,8765,8768,8771],{},[989,8763,8764],{},"Điều kiện dừng là gì?",[989,8766,8767],{},"Truy vết ngăn xếp làm thế nào?",[989,8769,8770],{},"Memo giúp gì, khi nào dùng?",[989,8772,8773],{},"Quên tập đã thăm trên đồ thị vòng thì sao?",[3014,8775],{},[973,8777,8778],{},"🌕 Bạn đã hoàn thành ngày 8. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,8780,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":8782},[8783,8784,8789,8790,8796],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":8785},[8786,8787,8788],{"id":8168,"depth":73,"text":8169},{"id":8189,"depth":73,"text":8190},{"id":8207,"depth":73,"text":8208},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":8791},[8792,8793,8794,8795],{"id":8291,"depth":73,"text":8292},{"id":8522,"depth":73,"text":8523},{"id":8554,"depth":73,"text":8555},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"algorithm","Biến đệ quy từ nỗi sợ thành công cụ qua điều kiện dừng, truy vết ngăn xếp lời gọi và kỹ thuật ghi nhớ.",{},[8149,4669],{"title":95,"description":8798},[8803],"recursion","Ae_WCdg3O8NuJhm1qUCKSie8_IvGLbhTmnYX0-MVBcM",{"id":8806,"title":100,"body":8807,"category":5189,"day":103,"description":9246,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":9247,"navigation":2723,"outcomes":3047,"path":101,"prerequisites":9248,"seo":9249,"stem":102,"tags":9250,"__hash__":9253},"challenges\u002Fchallenges\u002F9.observer-co-ban.md",{"type":965,"value":8808,"toc":9230},[8809,8811,8814,8816,8820,8834,8838,8852,8856,8870,8907,8909,8917,8919,8926,8930,8969,9042,9046,9064,9070,9074,9076,9110,9127,9131,9141,9159,9165,9175,9177,9207,9209,9223,9225,9228],[968,8810,971],{"id":970},[973,8812,8813],{},"Bài này học cách một đổi lan tới nhiều bên. Bạn tách trạm đo khỏi bảng hiển thị.",[968,8815,979],{"id":978},[981,8817,8819],{"id":8818},"observer-một-nhiều","Observer một-nhiều",[986,8821,8822,8825,8828,8831],{},[989,8823,8824],{},"Một chủ đề đổi, nhiều người nghe cập nhật.",[989,8826,8827],{},"Chủ đề còn gọi là nhà xuất bản.",[989,8829,8830],{},"Người nghe còn gọi là người đăng ký.",[989,8832,8833],{},"Ví dụ đời thường: kênh video ra clip, fan nhận tin.",[981,8835,8837],{"id":8836},"trạm-thời-tiết-và-3-bảng","Trạm thời tiết và 3 bảng",[986,8839,8840,8843,8846,8849],{},[989,8841,8842],{},"Trạm giữ số đo, 3 bảng đăng ký nghe.",[989,8844,8845],{},"Số đổi thì trạm báo, mỗi bảng tự vẽ lại.",[989,8847,8848],{},"Trạm không biết bảng vẽ kiểu gì.",[989,8850,8851],{},"Ví dụ đời thường: loa phường phát, ai nghe thì nghe.",[981,8853,8855],{"id":8854},"lỏng-ràng-buộc-và-vòng-đời","Lỏng ràng buộc và vòng đời",[986,8857,8858,8861,8864,8867],{},[989,8859,8860],{},"Hai bên biết về nhau càng ít càng tốt.",[989,8862,8863],{},"Thêm bảng mới không sửa trạm cũ.",[989,8865,8866],{},"Vòng đời: đăng ký, báo đổi, hủy đăng ký.",[989,8868,8869],{},"Ví dụ đời thường: theo dõi rồi hủy theo dõi.",[1099,8871,8872,8881],{},[1102,8873,8874],{},[1105,8875,8876,8878],{},[1108,8877,7111],{},[1108,8879,8880],{},"Thêm bảng mới",[1118,8882,8883,8891,8899],{},[1105,8884,8885,8888],{},[1123,8886,8887],{},"Gọi trực tiếp",[1123,8889,8890],{},"Mở trạm ra sửa",[1105,8892,8893,8896],{},[1123,8894,8895],{},"Hỏi liên tục",[1123,8897,8898],{},"Tốn tài nguyên",[1105,8900,8901,8904],{},[1123,8902,8903],{},"Observer",[1123,8905,8906],{},"Chỉ cần đăng ký",[968,8908,1433],{"id":1432},[986,8910,8911,8914],{},[989,8912,8913],{},"Input: 3 bảng đã đăng ký, số mới về. Output: cả 3 cùng làm mới đúng số.",[989,8915,8916],{},"Giải thích: trạm duyệt danh sách và báo từng người.",[968,8918,1482],{"id":1481},[973,8920,1485,8921,4801,8923,1517],{},[1487,8922,4800],{},[992,8924,8925],{},"day-009\u002F",[981,8927,8929],{"id":8928},"bài-1-trạm-thời-tiết","Bài 1: Trạm thời tiết",[1352,8931,8933],{"className":1393,"code":8932,"language":1395,"meta":1357,"style":1357},"struct Observer { virtual void update(float temp, float humidity, float pressure) = 0; virtual ~Observer() = default; };\nstruct Subject {\n  virtual void registerObserver(Observer *o) = 0;\n  virtual void removeObserver(Observer *o) = 0;\n  virtual void notifyObservers() = 0;\n  virtual ~Subject() = default;\n};\n",[992,8934,8935,8940,8945,8950,8955,8960,8965],{"__ignoreMap":1357},[1023,8936,8937],{"class":1362,"line":63},[1023,8938,8939],{},"struct Observer { virtual void update(float temp, float humidity, float pressure) = 0; virtual ~Observer() = default; };\n",[1023,8941,8942],{"class":1362,"line":68},[1023,8943,8944],{},"struct Subject {\n",[1023,8946,8947],{"class":1362,"line":73},[1023,8948,8949],{},"  virtual void registerObserver(Observer *o) = 0;\n",[1023,8951,8952],{"class":1362,"line":78},[1023,8953,8954],{},"  virtual void removeObserver(Observer *o) = 0;\n",[1023,8956,8957],{"class":1362,"line":83},[1023,8958,8959],{},"  virtual void notifyObservers() = 0;\n",[1023,8961,8962],{"class":1362,"line":88},[1023,8963,8964],{},"  virtual ~Subject() = default;\n",[1023,8966,8967],{"class":1362,"line":93},[1023,8968,4866],{},[1099,8970,8971,8979],{},[1102,8972,8973],{},[1105,8974,8975,8977],{},[1108,8976,4881],{},[1108,8978,1569],{},[1118,8980,8981,8998,9011,9021],{},[1105,8982,8983,8988],{},[1123,8984,8985],{},[992,8986,8987],{},"WeatherData : Subject",[1123,8989,8990,8991,8994,8995],{},"Giữ số đo. ",[992,8992,8993],{},"setMeasurements(t, h, p)"," lưu rồi gọi ",[992,8996,8997],{},"notifyObservers()",[1105,8999,9000,9005],{},[1123,9001,9002],{},[992,9003,9004],{},"CurrentConditionsDisplay",[1123,9006,9007,9008],{},"In ",[992,9009,9010],{},"\"Hiện tại: 26.5C, 65% ẩm\"",[1105,9012,9013,9018],{},[1123,9014,9015],{},[992,9016,9017],{},"StatisticsDisplay",[1123,9019,9020],{},"Giữ min, max, trung bình nhiệt độ",[1105,9022,9023,9028],{},[1123,9024,9025],{},[992,9026,9027],{},"ForecastDisplay",[1123,9029,9030,9031,9034,9035,9038,9039],{},"Áp suất tăng: ",[992,9032,9033],{},"\"Trời đẹp\"",", giảm: ",[992,9036,9037],{},"\"Sắp mưa\"",", giữ nguyên: ",[992,9040,9041],{},"\"Như cũ\"",[973,9043,9044],{},[1487,9045,2194],{},[986,9047,9048,9054,9057],{},[989,9049,9050,9053],{},[992,9051,9052],{},"WeatherData"," không biết tên lớp display nào.",[989,9055,9056],{},"Đăng ký trùng một observer thì bỏ qua.",[989,9058,9059,9060,9063],{},"Hủy đăng ký trong lúc đang ",[992,9061,9062],{},"notify"," không được làm crash.",[1352,9065,9068],{"className":9066,"code":9067,"language":2241,"meta":1357},[2239],"setMeasurements(26, 65, 1012)  -> Current: 26C 65%; Stats: avg 26 min 26 max 26; Forecast: Trời đẹp\nsetMeasurements(28, 70, 1010)  -> Stats: avg 27 min 26 max 28; Forecast: Sắp mưa\nremoveObserver(forecast); setMeasurements(25, 90, 1010) -> chỉ 2 bảng in\n",[992,9069,9067],{"__ignoreMap":1357},[981,9071,9073],{"id":9072},"bài-2-đơn-hàng-gọi-thẳng-sang-observer","Bài 2: Đơn hàng gọi thẳng sang Observer",[973,9075,7343],{},[1352,9077,9079],{"className":1393,"code":9078,"language":1395,"meta":1357,"style":1357},"void Order::complete() {\n  status = \"done\";\n  inventory.decrease(items);\n  mailer.sendReceipt(customerEmail);\n  analytics.track(\"order_done\", id);\n}\n",[992,9080,9081,9086,9091,9096,9101,9106],{"__ignoreMap":1357},[1023,9082,9083],{"class":1362,"line":63},[1023,9084,9085],{},"void Order::complete() {\n",[1023,9087,9088],{"class":1362,"line":68},[1023,9089,9090],{},"  status = \"done\";\n",[1023,9092,9093],{"class":1362,"line":73},[1023,9094,9095],{},"  inventory.decrease(items);\n",[1023,9097,9098],{"class":1362,"line":78},[1023,9099,9100],{},"  mailer.sendReceipt(customerEmail);\n",[1023,9102,9103],{"class":1362,"line":83},[1023,9104,9105],{},"  analytics.track(\"order_done\", id);\n",[1023,9107,9108],{"class":1362,"line":88},[1023,9109,4986],{},[973,9111,9112,2308,9114,9116,9117,9120,9121,9124,9125,1517],{},[1487,9113,4871],{},[992,9115,4893],{}," chỉ phát sự kiện ",[992,9118,9119],{},"OrderCompleted{id, items, email}",". Ba module tự đăng ký. Thêm ",[992,9122,9123],{},"LoyaltyPoints"," (cộng 1 điểm mỗi 100.000đ) mà không sửa ",[992,9126,4893],{},[981,9128,9130],{"id":9129},"bài-3-phòng-đấu-giá-nâng-cao","Bài 3: Phòng đấu giá (nâng cao)",[973,9132,9133,9136,9137,9140],{},[992,9134,9135],{},"Auction"," là subject. ",[992,9138,9139],{},"Bidder"," là observer, mỗi người có ngân sách tối đa và bước giá riêng.",[2273,9142,9143,9149,9156],{},[989,9144,9145,9146,9148],{},"Khi có giá mới, ",[992,9147,9135],{}," báo mọi bidder trừ người vừa trả giá.",[989,9150,9151,9152,9155],{},"Bidder tự quyết: nếu ",[992,9153,9154],{},"giá hiện tại + bước \u003C= ngân sách"," thì trả giá, ngược lại rút lui (hủy đăng ký).",[989,9157,9158],{},"Phiên kết thúc khi không ai trả giá thêm. In người thắng và giá.",[1352,9160,9163],{"className":9161,"code":9162,"language":2241,"meta":1357},[2239],"Giá khởi điểm 100. An(ngân sách 300, bước 20), Bình(250, 50), Chi(180, 10)\n-> In từng lượt trả giá, ai rút lui lúc nào, người thắng cuối cùng.\n",[992,9164,9162],{"__ignoreMap":1357},[973,9166,9167,9168,9171,9172,9174],{},"Tránh đệ quy vô hạn: bidder trả giá trong ",[992,9169,9170],{},"update"," sẽ kích hoạt ",[992,9173,9062],{}," mới. Dùng hàng đợi sự kiện hoặc vòng lặp theo lượt.",[981,9176,2711],{"id":2710},[986,9178,9180,9186,9195,9201],{"className":9179},[2715],[989,9181,9183,9185],{"className":9182},[2719],[2721,9184],{"disabled":2723,"type":2724}," Test mẫu Bài 1 in đúng từng dòng.",[989,9187,9189,9191,9192,9194],{"className":9188},[2719],[2721,9190],{"disabled":2723,"type":2724}," Bài 2: thêm ",[992,9193,9123],{}," chỉ tạo file mới.",[989,9196,9198,9200],{"className":9197},[2719],[2721,9199],{"disabled":2723,"type":2724}," Bài 3 kết thúc đúng, không đệ quy vô hạn, không crash khi hủy đăng ký giữa chừng.",[989,9202,9204,9206],{"className":9203},[2719],[2721,9205],{"disabled":2723,"type":2724}," Giải thích được \"loose coupling\" bằng ví dụ trong code của mình.",[968,9208,2890],{"id":2889},[986,9210,9211,9214,9217,9220],{},[989,9212,9213],{},"Observer là gì, quan hệ mấy-nhiều?",[989,9215,9216],{},"Trạm thời tiết gồm những ai?",[989,9218,9219],{},"Lỏng ràng buộc nghĩa là gì?",[989,9221,9222],{},"Đăng ký rồi hủy hoạt động thế nào?",[3014,9224],{},[973,9226,9227],{},"🌕 Bạn đã hoàn thành ngày 9. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,9229,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":9231},[9232,9233,9238,9239,9245],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":9234},[9235,9236,9237],{"id":8818,"depth":73,"text":8819},{"id":8836,"depth":73,"text":8837},{"id":8854,"depth":73,"text":8855},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":9240},[9241,9242,9243,9244],{"id":8928,"depth":73,"text":8929},{"id":9072,"depth":73,"text":9073},{"id":9129,"depth":73,"text":9130},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Observer, quan hệ một-nhiều, nguyên lý loose coupling và câu chuyện trạm thời tiết với ba bảng hiển thị.",{},[5194,5195],{"title":100,"description":9246},[9251,9252],"observer","loose-coupling","ZEzC-4j5ALuaTKbwa2iiTa8QE5GxmJXhMfLgmNYjGlA",{"id":9255,"title":105,"body":9256,"category":8797,"day":108,"description":10185,"difficulty":3043,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":10186,"navigation":2723,"outcomes":3047,"path":106,"prerequisites":10187,"seo":10188,"stem":107,"tags":10189,"__hash__":10191},"challenges\u002Fchallenges\u002F10.sap-xep-co-ban.md",{"type":965,"value":9257,"toc":10169},[9258,9260,9263,9265,9269,9329,9333,9347,9351,9438,9872,9874,9886,9911,9913,9921,9925,9950,9958,9964,9968,10025,10031,10034,10038,10064,10070,10072,10146,10148,10162,10164,10167],[968,9259,971],{"id":970},[973,9261,9262],{},"Bài này học 3 cách sắp xếp đơn giản nhất. Bạn biết khi nào chúng vẫn đủ dùng.",[968,9264,979],{"id":978},[981,9266,9268],{"id":9267},"bubble-sort-bong-bóng-nổi-lên","Bubble sort — bong bóng nổi lên",[986,9270,9271,9274,9277,9280,9283],{},[989,9272,9273],{},"So sánh từng cặp kề, sai thì đổi chỗ.",[989,9275,9276],{},"Sau 1 lượt, số lớn nhất ra cuối.",[989,9278,9279],{},"Thêm cờ hiệu: không đổi chỗ nào thì dừng.",[989,9281,9282],{},"Ví dụ đời thường: bọt to nổi lên mặt nước.",[989,9284,9285,9286,1517],{},"Đã sắp xếp thì chỉ tốn ",[1023,9287,9289,9308],{"className":9288},[1026],[1023,9290,9292],{"className":9291},[1030],[1032,9293,9294],{"xmlns":1034},[1036,9295,9296,9306],{},[1039,9297,9298,9300,9302,9304],{},[1042,9299,1044],{},[1046,9301,1049],{"stretchy":1048},[1042,9303,1262],{},[1046,9305,1056],{"stretchy":1048},[1058,9307,1267],{"encoding":1060},[1023,9309,9311],{"className":9310,"ariaHidden":1066},[1065],[1023,9312,9314,9317,9320,9323,9326],{"className":9313},[1070],[1023,9315],{"className":9316,"style":1075},[1074],[1023,9318,1044],{"className":9319,"style":1081},[1079,1080],[1023,9321,1049],{"className":9322},[1085],[1023,9324,1262],{"className":9325},[1079,1080],[1023,9327,1056],{"className":9328},[1092],[981,9330,9332],{"id":9331},"selection-sort-mỗi-lượt-1-lần-đổi","Selection sort — mỗi lượt 1 lần đổi",[986,9334,9335,9338,9341,9344],{},[989,9336,9337],{},"Mỗi lượt tìm số lớn nhất rồi đổi 1 lần.",[989,9339,9340],{},"Tổng cả bài chỉ đổi tối đa n-1 lần.",[989,9342,9343],{},"Ví dụ đời thường: chọn quả to nhất bỏ vào rổ.",[989,9345,9346],{},"Hợp khi chi phí ghi đắt hơn đọc.",[981,9348,9350],{"id":9349},"insertion-sort-chèn-lá-bài","Insertion sort — chèn lá bài",[986,9352,9353,9356,9359,9435],{},[989,9354,9355],{},"Lấy từng lá chèn vào đoạn đã xếp.",[989,9357,9358],{},"Dữ liệu gần xếp rồi thì chạy rất nhanh.",[989,9360,9361,9362,1517],{},"Dữ liệu ngược thì chậm ",[1023,9363,9365,9388],{"className":9364},[1026],[1023,9366,9368],{"className":9367},[1030],[1032,9369,9370],{"xmlns":1034},[1036,9371,9372,9386],{},[1039,9373,9374,9376,9378,9384],{},[1042,9375,1044],{},[1046,9377,1049],{"stretchy":1048},[2327,9379,9380,9382],{},[1042,9381,1262],{},[1051,9383,2457],{},[1046,9385,1056],{"stretchy":1048},[1058,9387,2839],{"encoding":1060},[1023,9389,9391],{"className":9390,"ariaHidden":1066},[1065],[1023,9392,9394,9397,9400,9403,9432],{"className":9393},[1070],[1023,9395],{"className":9396,"style":2476},[1074],[1023,9398,1044],{"className":9399,"style":1081},[1079,1080],[1023,9401,1049],{"className":9402},[1085],[1023,9404,9406,9409],{"className":9405},[1079],[1023,9407,1262],{"className":9408},[1079,1080],[1023,9410,9412],{"className":9411},[2383],[1023,9413,9415],{"className":9414},[2387],[1023,9416,9418],{"className":9417},[2391],[1023,9419,9421],{"className":9420,"style":2369},[2395],[1023,9422,9423,9426],{"style":2398},[1023,9424],{"className":9425,"style":2403},[2402],[1023,9427,9429],{"className":9428},[2407,2408,2409,2410],[1023,9430,2457],{"className":9431},[1079,2410],[1023,9433,1056],{"className":9434},[1092],[989,9436,9437],{},"Ví dụ đời thường: xếp bài trên tay.",[1099,9439,9440,9456],{},[1102,9441,9442],{},[1105,9443,9444,9447,9450,9453],{},[1108,9445,9446],{},"Thuật toán",[1108,9448,9449],{},"Hay nhất",[1108,9451,9452],{},"Tệ nhất",[1108,9454,9455],{},"Thắng ở đâu",[1118,9457,9458,9586,9744],{},[1105,9459,9460,9463,9508,9583],{},[1123,9461,9462],{},"Bubble cờ hiệu",[1123,9464,9465],{},[1023,9466,9468,9487],{"className":9467},[1026],[1023,9469,9471],{"className":9470},[1030],[1032,9472,9473],{"xmlns":1034},[1036,9474,9475,9485],{},[1039,9476,9477,9479,9481,9483],{},[1042,9478,1044],{},[1046,9480,1049],{"stretchy":1048},[1042,9482,1262],{},[1046,9484,1056],{"stretchy":1048},[1058,9486,1267],{"encoding":1060},[1023,9488,9490],{"className":9489,"ariaHidden":1066},[1065],[1023,9491,9493,9496,9499,9502,9505],{"className":9492},[1070],[1023,9494],{"className":9495,"style":1075},[1074],[1023,9497,1044],{"className":9498,"style":1081},[1079,1080],[1023,9500,1049],{"className":9501},[1085],[1023,9503,1262],{"className":9504},[1079,1080],[1023,9506,1056],{"className":9507},[1092],[1123,9509,9510],{},[1023,9511,9513,9536],{"className":9512},[1026],[1023,9514,9516],{"className":9515},[1030],[1032,9517,9518],{"xmlns":1034},[1036,9519,9520,9534],{},[1039,9521,9522,9524,9526,9532],{},[1042,9523,1044],{},[1046,9525,1049],{"stretchy":1048},[2327,9527,9528,9530],{},[1042,9529,1262],{},[1051,9531,2457],{},[1046,9533,1056],{"stretchy":1048},[1058,9535,2839],{"encoding":1060},[1023,9537,9539],{"className":9538,"ariaHidden":1066},[1065],[1023,9540,9542,9545,9548,9551,9580],{"className":9541},[1070],[1023,9543],{"className":9544,"style":2476},[1074],[1023,9546,1044],{"className":9547,"style":1081},[1079,1080],[1023,9549,1049],{"className":9550},[1085],[1023,9552,9554,9557],{"className":9553},[1079],[1023,9555,1262],{"className":9556},[1079,1080],[1023,9558,9560],{"className":9559},[2383],[1023,9561,9563],{"className":9562},[2387],[1023,9564,9566],{"className":9565},[2391],[1023,9567,9569],{"className":9568,"style":2369},[2395],[1023,9570,9571,9574],{"style":2398},[1023,9572],{"className":9573,"style":2403},[2402],[1023,9575,9577],{"className":9576},[2407,2408,2409,2410],[1023,9578,2457],{"className":9579},[1079,2410],[1023,9581,1056],{"className":9582},[1092],[1123,9584,9585],{},"Nhỏ, đã xếp 1 phần",[1105,9587,9588,9591,9666,9741],{},[1123,9589,9590],{},"Selection",[1123,9592,9593],{},[1023,9594,9596,9619],{"className":9595},[1026],[1023,9597,9599],{"className":9598},[1030],[1032,9600,9601],{"xmlns":1034},[1036,9602,9603,9617],{},[1039,9604,9605,9607,9609,9615],{},[1042,9606,1044],{},[1046,9608,1049],{"stretchy":1048},[2327,9610,9611,9613],{},[1042,9612,1262],{},[1051,9614,2457],{},[1046,9616,1056],{"stretchy":1048},[1058,9618,2839],{"encoding":1060},[1023,9620,9622],{"className":9621,"ariaHidden":1066},[1065],[1023,9623,9625,9628,9631,9634,9663],{"className":9624},[1070],[1023,9626],{"className":9627,"style":2476},[1074],[1023,9629,1044],{"className":9630,"style":1081},[1079,1080],[1023,9632,1049],{"className":9633},[1085],[1023,9635,9637,9640],{"className":9636},[1079],[1023,9638,1262],{"className":9639},[1079,1080],[1023,9641,9643],{"className":9642},[2383],[1023,9644,9646],{"className":9645},[2387],[1023,9647,9649],{"className":9648},[2391],[1023,9650,9652],{"className":9651,"style":2369},[2395],[1023,9653,9654,9657],{"style":2398},[1023,9655],{"className":9656,"style":2403},[2402],[1023,9658,9660],{"className":9659},[2407,2408,2409,2410],[1023,9661,2457],{"className":9662},[1079,2410],[1023,9664,1056],{"className":9665},[1092],[1123,9667,9668],{},[1023,9669,9671,9694],{"className":9670},[1026],[1023,9672,9674],{"className":9673},[1030],[1032,9675,9676],{"xmlns":1034},[1036,9677,9678,9692],{},[1039,9679,9680,9682,9684,9690],{},[1042,9681,1044],{},[1046,9683,1049],{"stretchy":1048},[2327,9685,9686,9688],{},[1042,9687,1262],{},[1051,9689,2457],{},[1046,9691,1056],{"stretchy":1048},[1058,9693,2839],{"encoding":1060},[1023,9695,9697],{"className":9696,"ariaHidden":1066},[1065],[1023,9698,9700,9703,9706,9709,9738],{"className":9699},[1070],[1023,9701],{"className":9702,"style":2476},[1074],[1023,9704,1044],{"className":9705,"style":1081},[1079,1080],[1023,9707,1049],{"className":9708},[1085],[1023,9710,9712,9715],{"className":9711},[1079],[1023,9713,1262],{"className":9714},[1079,1080],[1023,9716,9718],{"className":9717},[2383],[1023,9719,9721],{"className":9720},[2387],[1023,9722,9724],{"className":9723},[2391],[1023,9725,9727],{"className":9726,"style":2369},[2395],[1023,9728,9729,9732],{"style":2398},[1023,9730],{"className":9731,"style":2403},[2402],[1023,9733,9735],{"className":9734},[2407,2408,2409,2410],[1023,9736,2457],{"className":9737},[1079,2410],[1023,9739,1056],{"className":9740},[1092],[1123,9742,9743],{},"Cần ít lần đổi",[1105,9745,9746,9749,9794,9869],{},[1123,9747,9748],{},"Insertion",[1123,9750,9751],{},[1023,9752,9754,9773],{"className":9753},[1026],[1023,9755,9757],{"className":9756},[1030],[1032,9758,9759],{"xmlns":1034},[1036,9760,9761,9771],{},[1039,9762,9763,9765,9767,9769],{},[1042,9764,1044],{},[1046,9766,1049],{"stretchy":1048},[1042,9768,1262],{},[1046,9770,1056],{"stretchy":1048},[1058,9772,1267],{"encoding":1060},[1023,9774,9776],{"className":9775,"ariaHidden":1066},[1065],[1023,9777,9779,9782,9785,9788,9791],{"className":9778},[1070],[1023,9780],{"className":9781,"style":1075},[1074],[1023,9783,1044],{"className":9784,"style":1081},[1079,1080],[1023,9786,1049],{"className":9787},[1085],[1023,9789,1262],{"className":9790},[1079,1080],[1023,9792,1056],{"className":9793},[1092],[1123,9795,9796],{},[1023,9797,9799,9822],{"className":9798},[1026],[1023,9800,9802],{"className":9801},[1030],[1032,9803,9804],{"xmlns":1034},[1036,9805,9806,9820],{},[1039,9807,9808,9810,9812,9818],{},[1042,9809,1044],{},[1046,9811,1049],{"stretchy":1048},[2327,9813,9814,9816],{},[1042,9815,1262],{},[1051,9817,2457],{},[1046,9819,1056],{"stretchy":1048},[1058,9821,2839],{"encoding":1060},[1023,9823,9825],{"className":9824,"ariaHidden":1066},[1065],[1023,9826,9828,9831,9834,9837,9866],{"className":9827},[1070],[1023,9829],{"className":9830,"style":2476},[1074],[1023,9832,1044],{"className":9833,"style":1081},[1079,1080],[1023,9835,1049],{"className":9836},[1085],[1023,9838,9840,9843],{"className":9839},[1079],[1023,9841,1262],{"className":9842},[1079,1080],[1023,9844,9846],{"className":9845},[2383],[1023,9847,9849],{"className":9848},[2387],[1023,9850,9852],{"className":9851},[2391],[1023,9853,9855],{"className":9854,"style":2369},[2395],[1023,9856,9857,9860],{"style":2398},[1023,9858],{"className":9859,"style":2403},[2402],[1023,9861,9863],{"className":9862},[2407,2408,2409,2410],[1023,9864,2457],{"className":9865},[1079,2410],[1023,9867,1056],{"className":9868},[1092],[1123,9870,9871],{},"Nhỏ, gần xếp rồi",[968,9873,1433],{"id":1432},[986,9875,9876,9883],{},[989,9877,9878,9879,9882],{},"Input: ",[1023,9880,9881],{},"5, 4, 3, 2, 1"," chạy selection. Output: 4 lượt, nhưng chỉ 2 lần đổi thật (2 lượt sau phần tử đã đúng chỗ), dãy tăng dần.",[989,9884,9885],{},"Giải thích: mỗi lượt chỉ đổi đúng 1 lần.",[1352,9887,9889],{"className":3538,"code":9888,"language":3540,"meta":1357,"style":1357},"# 1 lượt bubble đẩy số lớn ra cuối\nfor i in range(len(a) - 1):\n    if a[i] > a[i+1]:  # cặp kề sai thứ tự\n        a[i], a[i+1] = a[i+1], a[i]  # đổi chỗ\n",[992,9890,9891,9896,9901,9906],{"__ignoreMap":1357},[1023,9892,9893],{"class":1362,"line":63},[1023,9894,9895],{},"# 1 lượt bubble đẩy số lớn ra cuối\n",[1023,9897,9898],{"class":1362,"line":68},[1023,9899,9900],{},"for i in range(len(a) - 1):\n",[1023,9902,9903],{"class":1362,"line":73},[1023,9904,9905],{},"    if a[i] > a[i+1]:  # cặp kề sai thứ tự\n",[1023,9907,9908],{"class":1362,"line":78},[1023,9909,9910],{},"        a[i], a[i+1] = a[i+1], a[i]  # đổi chỗ\n",[968,9912,1482],{"id":1481},[973,9914,1485,9915,7803,9917,9920],{},[1487,9916,1493],{},[992,9918,9919],{},"day-010\u002F",". Mọi hàm sắp xếp tại chỗ, tăng dần.",[981,9922,9924],{"id":9923},"bài-1-ba-thuật-toán-có-bộ-đếm","Bài 1: Ba thuật toán có bộ đếm",[1352,9926,9928],{"className":1393,"code":9927,"language":1395,"meta":1357,"style":1357},"struct Stats { long long comparisons = 0; long long swaps = 0; long long passes = 0; };\nvoid bubbleSort(std::vector\u003Cint> &a, Stats &st);     \u002F\u002F có cờ dừng sớm\nvoid selectionSort(std::vector\u003Cint> &a, Stats &st);\nvoid insertionSort(std::vector\u003Cint> &a, Stats &st);  \u002F\u002F \"swaps\" = số lần dịch phần tử\n",[992,9929,9930,9935,9940,9945],{"__ignoreMap":1357},[1023,9931,9932],{"class":1362,"line":63},[1023,9933,9934],{},"struct Stats { long long comparisons = 0; long long swaps = 0; long long passes = 0; };\n",[1023,9936,9937],{"class":1362,"line":68},[1023,9938,9939],{},"void bubbleSort(std::vector\u003Cint> &a, Stats &st);     \u002F\u002F có cờ dừng sớm\n",[1023,9941,9942],{"class":1362,"line":73},[1023,9943,9944],{},"void selectionSort(std::vector\u003Cint> &a, Stats &st);\n",[1023,9946,9947],{"class":1362,"line":78},[1023,9948,9949],{},"void insertionSort(std::vector\u003Cint> &a, Stats &st);  \u002F\u002F \"swaps\" = số lần dịch phần tử\n",[973,9951,9952,5589,9954,9957],{},[1487,9953,6076],{},[992,9955,9956],{},"std::sort",". Mỗi hàm tăng đúng bộ đếm tại chỗ so sánh và đổi chỗ.",[1352,9959,9962],{"className":9960,"code":9961,"language":2241,"meta":1357},[2239],"bubble    [5,1,4,2,8]  -> [1,2,4,5,8]; swaps=4\nselection [5,4,3,2,1]  -> [1,2,3,4,5]; swaps=2  (bỏ qua đổi chỗ với chính nó)\ninsertion [1,2,3,4,5]  -> comparisons=4, swaps=0\nbubble    [1,2,3,4,5]  -> passes=1 (cờ dừng sớm)\nmảng rỗng, 1 phần tử   -> không lỗi, stats = 0\n",[992,9963,9961],{"__ignoreMap":1357},[981,9965,9967],{"id":9966},"bài-2-bảng-đếm-trên-4-loại-dữ-liệu","Bài 2: Bảng đếm trên 4 loại dữ liệu",[973,9969,9970,9971,10024],{},"Sinh 4 mảng cỡ ",[1023,9972,9974,9993],{"className":9973},[1026],[1023,9975,9977],{"className":9976},[1030],[1032,9978,9979],{"xmlns":1034},[1036,9980,9981,9990],{},[1039,9982,9983,9985,9987],{},[1042,9984,1262],{},[1046,9986,2325],{},[1051,9988,9989],{},"1000",[1058,9991,9992],{"encoding":1060},"n = 1000",[1023,9994,9996,10014],{"className":9995,"ariaHidden":1066},[1065],[1023,9997,9999,10002,10005,10008,10011],{"className":9998},[1070],[1023,10000],{"className":10001,"style":2347},[1074],[1023,10003,1262],{"className":10004},[1079,1080],[1023,10006],{"className":10007,"style":2355},[2354],[1023,10009,2325],{"className":10010},[2359],[1023,10012],{"className":10013,"style":2355},[2354],[1023,10015,10017,10021],{"className":10016},[1070],[1023,10018],{"className":10019,"style":10020},[1074],"height:0.6444em;",[1023,10022,9989],{"className":10023},[1079],": ngẫu nhiên, đã xếp, xếp ngược, gần xếp (xếp rồi đổi 10 cặp ngẫu nhiên). Chạy 3 thuật toán và in:",[1352,10026,10029],{"className":10027,"code":10028,"language":2241,"meta":1357},[2239],"data         algo        comparisons   swaps\nrandom       bubble      ...           ...\nrandom       selection   ...           ...\n...\n",[992,10030,10028],{"__ignoreMap":1357},[973,10032,10033],{},"Viết 4 câu kết luận: thuật toán nào thắng ở dữ liệu nào, vì sao.",[981,10035,10037],{"id":10036},"bài-3-tính-ổn-định-và-sắp-theo-khóa-nâng-cao","Bài 3: Tính ổn định và sắp theo khóa (nâng cao)",[2273,10039,10040,10046,10057],{},[989,10041,10042,10043,1517],{},"Đổi 3 hàm thành template nhận comparator: ",[992,10044,10045],{},"template\u003Cclass T, class Cmp> void insertionSort(std::vector\u003CT>&, Cmp)",[989,10047,10048,10049,10052,10053,10056],{},"Sắp danh sách sinh viên ",[992,10050,10051],{},"{name, score}"," theo ",[992,10054,10055],{},"score"," tăng dần.",[989,10058,10059,10060,10063],{},"Viết test phát hiện thuật toán ",[1487,10061,10062],{},"không ổn định",": hai sinh viên cùng điểm phải giữ thứ tự ban đầu.",[1352,10065,10068],{"className":10066,"code":10067,"language":2241,"meta":1357},[2239],"[(An,8), (Bình,7), (Chi,8), (Dũng,7)] sắp theo score\ninsertion \u002F bubble -> [(Bình,7), (Dũng,7), (An,8), (Chi,8)]   ổn định\nselection          -> có thể đảo An và Chi: tìm input cụ thể chứng minh\n",[992,10069,10067],{"__ignoreMap":1357},[981,10071,2711],{"id":2710},[986,10073,10075,10084,10090,10096],{"className":10074},[2715],[989,10076,10078,10080,10081,10083],{"className":10077},[2719],[2721,10079],{"disabled":2723,"type":2724}," Test mẫu pass, có test so với ",[992,10082,9956],{}," trên 1000 mảng ngẫu nhiên.",[989,10085,10087,10089],{"className":10086},[2719],[2721,10088],{"disabled":2723,"type":2724}," Bảng Bài 2 có số thật và 4 câu kết luận.",[989,10091,10093,10095],{"className":10092},[2719],[2721,10094],{"disabled":2723,"type":2724}," Bài 3 có input cụ thể chứng minh selection sort không ổn định.",[989,10097,10099,10101,10102,10145],{"className":10098},[2719],[2721,10100],{"disabled":2723,"type":2724}," Giải thích được vì sao insertion sort chạy ",[1023,10103,10105,10124],{"className":10104},[1026],[1023,10106,10108],{"className":10107},[1030],[1032,10109,10110],{"xmlns":1034},[1036,10111,10112,10122],{},[1039,10113,10114,10116,10118,10120],{},[1042,10115,1044],{},[1046,10117,1049],{"stretchy":1048},[1042,10119,1262],{},[1046,10121,1056],{"stretchy":1048},[1058,10123,1267],{"encoding":1060},[1023,10125,10127],{"className":10126,"ariaHidden":1066},[1065],[1023,10128,10130,10133,10136,10139,10142],{"className":10129},[1070],[1023,10131],{"className":10132,"style":1075},[1074],[1023,10134,1044],{"className":10135,"style":1081},[1079,1080],[1023,10137,1049],{"className":10138},[1085],[1023,10140,1262],{"className":10141},[1079,1080],[1023,10143,1056],{"className":10144},[1092]," trên dữ liệu gần xếp.",[968,10147,2890],{"id":2889},[986,10149,10150,10153,10156,10159],{},[989,10151,10152],{},"Bubble sort hoạt động thế nào?",[989,10154,10155],{},"Cờ hiệu giúp gì cho best case?",[989,10157,10158],{},"Selection đổi chỗ mấy lần mỗi lượt?",[989,10160,10161],{},"Khi nào insertion chạy nhanh nhất?",[3014,10163],{},[973,10165,10166],{},"🌕 Bạn đã hoàn thành ngày 10. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,10168,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":10170},[10171,10172,10177,10178,10184],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":10173},[10174,10175,10176],{"id":9267,"depth":73,"text":9268},{"id":9331,"depth":73,"text":9332},{"id":9349,"depth":73,"text":9350},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":10179},[10180,10181,10182,10183],{"id":9923,"depth":73,"text":9924},{"id":9966,"depth":73,"text":9967},{"id":10036,"depth":73,"text":10037},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cài đặt và phân tích ba thuật toán sắp xếp cơ bản, hiểu cờ hiệu dừng sớm, số lần đổi chỗ và khi nào chúng vẫn là lựa chọn đúng.",{},[3050,4669],{"title":105,"description":10185},[10190],"sorting","YpSWLcQa7PRvJG1OeHmgZh9wkkaHHvuIfA5dXDaIq_4",{"id":10193,"title":110,"body":10194,"category":8797,"day":113,"description":11568,"difficulty":3043,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":11569,"navigation":2723,"outcomes":3047,"path":111,"prerequisites":11570,"seo":11571,"stem":112,"tags":11572,"__hash__":11573},"challenges\u002Fchallenges\u002F11.sap-xep-hieu-qua.md",{"type":965,"value":10195,"toc":11552},[10196,10198,10201,10203,10207,10332,10336,10499,10503,10657,11138,11140,11158,11160,11172,11176,11231,11237,11241,11279,11374,11378,11472,11478,11487,11499,11501,11531,11533,11547,11549],[968,10197,971],{"id":970},[973,10199,10200],{},"Bài này học 3 cách sắp xếp nhanh cho dữ liệu lớn. Bạn biết chọn thuật toán theo tình huống.",[968,10202,979],{"id":978},[981,10204,10206],{"id":10205},"merge-sort-chia-rồi-trộn","Merge sort — chia rồi trộn",[986,10208,10209,10212,10215,10283,10286],{},[989,10210,10211],{},"Chia đôi tới khi mỗi mảnh 1 phần tử.",[989,10213,10214],{},"Trộn 2 nửa đã xếp thành nửa lớn hơn.",[989,10216,10217,10218,10282],{},"Luôn ",[1023,10219,10221,10249],{"className":10220},[1026],[1023,10222,10224],{"className":10223},[1030],[1032,10225,10226],{"xmlns":1034},[1036,10227,10228,10246],{},[1039,10229,10230,10232,10234,10236,10238,10240,10242,10244],{},[1042,10231,1044],{},[1046,10233,1049],{"stretchy":1048},[1042,10235,1262],{},[1042,10237,7684],{},[1042,10239,7687],{},[1042,10241,7690],{},[1042,10243,1262],{},[1046,10245,1056],{"stretchy":1048},[1058,10247,10248],{"encoding":1060},"O(n log n)",[1023,10250,10252],{"className":10251,"ariaHidden":1066},[1065],[1023,10253,10255,10258,10261,10264,10267,10270,10273,10276,10279],{"className":10254},[1070],[1023,10256],{"className":10257,"style":1075},[1074],[1023,10259,1044],{"className":10260,"style":1081},[1079,1080],[1023,10262,1049],{"className":10263},[1085],[1023,10265,1262],{"className":10266},[1079,1080],[1023,10268,7684],{"className":10269,"style":7716},[1079,1080],[1023,10271,7687],{"className":10272},[1079,1080],[1023,10274,7690],{"className":10275,"style":7723},[1079,1080],[1023,10277,1262],{"className":10278},[1079,1080],[1023,10280,1056],{"className":10281},[1092]," mọi đầu vào.",[989,10284,10285],{},"Ví dụ đời thường: chia xấp bài rồi gộp lại.",[989,10287,10288,10289,1517],{},"Giá phải trả là tốn bộ nhớ phụ ",[1023,10290,10292,10311],{"className":10291},[1026],[1023,10293,10295],{"className":10294},[1030],[1032,10296,10297],{"xmlns":1034},[1036,10298,10299,10309],{},[1039,10300,10301,10303,10305,10307],{},[1042,10302,1044],{},[1046,10304,1049],{"stretchy":1048},[1042,10306,1262],{},[1046,10308,1056],{"stretchy":1048},[1058,10310,1267],{"encoding":1060},[1023,10312,10314],{"className":10313,"ariaHidden":1066},[1065],[1023,10315,10317,10320,10323,10326,10329],{"className":10316},[1070],[1023,10318],{"className":10319,"style":1075},[1074],[1023,10321,1044],{"className":10322,"style":1081},[1079,1080],[1023,10324,1049],{"className":10325},[1085],[1023,10327,1262],{"className":10328},[1079,1080],[1023,10330,1056],{"className":10331},[1092],[981,10333,10335],{"id":10334},"shell-sort-chèn-nhảy-cóc","Shell sort — chèn nhảy cóc",[986,10337,10338,10341,10344,10347,10350,10353],{},[989,10339,10340],{},"So sánh các món cách nhau 1 khe hở.",[989,10342,10343],{},"Khe hở thu nhỏ dần, lượt cuối bằng 1.",[989,10345,10346],{},"Lượt đầu đưa món về gần đúng chỗ.",[989,10348,10349],{},"Ví dụ đời thường: nhảy cóc thay vì bò từng bước.",[989,10351,10352],{},"Tốt cho dữ liệu cỡ vài nghìn.",[989,10354,10355,10356,10434,10435,1517],{},"Độ phức tạp phụ thuộc dãy khe: khe Knuth cho khoảng ",[1023,10357,10359,10384],{"className":10358},[1026],[1023,10360,10362],{"className":10361},[1030],[1032,10363,10364],{"xmlns":1034},[1036,10365,10366,10381],{},[1039,10367,10368,10370,10372,10379],{},[1042,10369,1044],{},[1046,10371,1049],{"stretchy":1048},[2327,10373,10374,10376],{},[1042,10375,1262],{},[1051,10377,10378],{},"1.5",[1046,10380,1056],{"stretchy":1048},[1058,10382,10383],{"encoding":1060},"O(n^{1.5})",[1023,10385,10387],{"className":10386,"ariaHidden":1066},[1065],[1023,10388,10390,10393,10396,10399,10431],{"className":10389},[1070],[1023,10391],{"className":10392,"style":2476},[1074],[1023,10394,1044],{"className":10395,"style":1081},[1079,1080],[1023,10397,1049],{"className":10398},[1085],[1023,10400,10402,10405],{"className":10401},[1079],[1023,10403,1262],{"className":10404},[1079,1080],[1023,10406,10408],{"className":10407},[2383],[1023,10409,10411],{"className":10410},[2387],[1023,10412,10414],{"className":10413},[2391],[1023,10415,10417],{"className":10416,"style":2369},[2395],[1023,10418,10419,10422],{"style":2398},[1023,10420],{"className":10421,"style":2403},[2402],[1023,10423,10425],{"className":10424},[2407,2408,2409,2410],[1023,10426,10428],{"className":10427},[1079,2410],[1023,10429,10378],{"className":10430},[1079,2410],[1023,10432,1056],{"className":10433},[1092],", chưa có dãy khe nào đạt ",[1023,10436,10438,10464],{"className":10437},[1026],[1023,10439,10441],{"className":10440},[1030],[1032,10442,10443],{"xmlns":1034},[1036,10444,10445,10461],{},[1039,10446,10447,10449,10451,10453,10455,10457,10459],{},[1042,10448,1044],{},[1046,10450,1049],{"stretchy":1048},[1042,10452,1262],{},[1042,10454,8397],{},[1046,10456,8400],{},[1042,10458,1262],{},[1046,10460,1056],{"stretchy":1048},[1058,10462,10463],{"encoding":1060},"O(n \\log n)",[1023,10465,10467],{"className":10466,"ariaHidden":1066},[1065],[1023,10468,10470,10473,10476,10479,10482,10485,10490,10493,10496],{"className":10469},[1070],[1023,10471],{"className":10472,"style":1075},[1074],[1023,10474,1044],{"className":10475,"style":1081},[1079,1080],[1023,10477,1049],{"className":10478},[1085],[1023,10480,1262],{"className":10481},[1079,1080],[1023,10483],{"className":10484,"style":8434},[2354],[1023,10486,8427,10488],{"className":10487},[8426],[1023,10489,7690],{"style":8430},[1023,10491],{"className":10492,"style":8434},[2354],[1023,10494,1262],{"className":10495},[1079,1080],[1023,10497,1056],{"className":10498},[1092],[981,10500,10502],{"id":10501},"quick-sort-phân-hoạch-quanh-chốt","Quick sort — phân hoạch quanh chốt",[986,10504,10505,10508,10511,10651,10654],{},[989,10506,10507],{},"Chọn 1 chốt, chia thành nhỏ hơn và lớn hơn.",[989,10509,10510],{},"Chốt đứng đúng chỗ sau mỗi lần chia.",[989,10512,10513,10514,10577,10578,1517],{},"Trung bình ",[1023,10515,10517,10544],{"className":10516},[1026],[1023,10518,10520],{"className":10519},[1030],[1032,10521,10522],{"xmlns":1034},[1036,10523,10524,10542],{},[1039,10525,10526,10528,10530,10532,10534,10536,10538,10540],{},[1042,10527,1044],{},[1046,10529,1049],{"stretchy":1048},[1042,10531,1262],{},[1042,10533,7684],{},[1042,10535,7687],{},[1042,10537,7690],{},[1042,10539,1262],{},[1046,10541,1056],{"stretchy":1048},[1058,10543,10248],{"encoding":1060},[1023,10545,10547],{"className":10546,"ariaHidden":1066},[1065],[1023,10548,10550,10553,10556,10559,10562,10565,10568,10571,10574],{"className":10549},[1070],[1023,10551],{"className":10552,"style":1075},[1074],[1023,10554,1044],{"className":10555,"style":1081},[1079,1080],[1023,10557,1049],{"className":10558},[1085],[1023,10560,1262],{"className":10561},[1079,1080],[1023,10563,7684],{"className":10564,"style":7716},[1079,1080],[1023,10566,7687],{"className":10567},[1079,1080],[1023,10569,7690],{"className":10570,"style":7723},[1079,1080],[1023,10572,1262],{"className":10573},[1079,1080],[1023,10575,1056],{"className":10576},[1092],", xấu ",[1023,10579,10581,10604],{"className":10580},[1026],[1023,10582,10584],{"className":10583},[1030],[1032,10585,10586],{"xmlns":1034},[1036,10587,10588,10602],{},[1039,10589,10590,10592,10594,10600],{},[1042,10591,1044],{},[1046,10593,1049],{"stretchy":1048},[2327,10595,10596,10598],{},[1042,10597,1262],{},[1051,10599,2457],{},[1046,10601,1056],{"stretchy":1048},[1058,10603,2839],{"encoding":1060},[1023,10605,10607],{"className":10606,"ariaHidden":1066},[1065],[1023,10608,10610,10613,10616,10619,10648],{"className":10609},[1070],[1023,10611],{"className":10612,"style":2476},[1074],[1023,10614,1044],{"className":10615,"style":1081},[1079,1080],[1023,10617,1049],{"className":10618},[1085],[1023,10620,10622,10625],{"className":10621},[1079],[1023,10623,1262],{"className":10624},[1079,1080],[1023,10626,10628],{"className":10627},[2383],[1023,10629,10631],{"className":10630},[2387],[1023,10632,10634],{"className":10633},[2391],[1023,10635,10637],{"className":10636,"style":2369},[2395],[1023,10638,10639,10642],{"style":2398},[1023,10640],{"className":10641,"style":2403},[2402],[1023,10643,10645],{"className":10644},[2407,2408,2409,2410],[1023,10646,2457],{"className":10647},[1079,2410],[1023,10649,1056],{"className":10650},[1092],[989,10652,10653],{},"Ví dụ đời thường: xếp sách quanh 1 mốc chiều cao.",[989,10655,10656],{},"Tránh chốt xấu bằng chốt ngẫu nhiên.",[1099,10658,10659,10674],{},[1102,10660,10661],{},[1105,10662,10663,10665,10668,10671],{},[1108,10664,9446],{},[1108,10666,10667],{},"Trung bình",[1108,10669,10670],{},"Bộ nhớ phụ",[1108,10672,10673],{},"Khi nào dùng",[1118,10675,10676,10794,11005],{},[1105,10677,10678,10681,10746,10791],{},[1123,10679,10680],{},"Merge",[1123,10682,10683],{},[1023,10684,10686,10713],{"className":10685},[1026],[1023,10687,10689],{"className":10688},[1030],[1032,10690,10691],{"xmlns":1034},[1036,10692,10693,10711],{},[1039,10694,10695,10697,10699,10701,10703,10705,10707,10709],{},[1042,10696,1044],{},[1046,10698,1049],{"stretchy":1048},[1042,10700,1262],{},[1042,10702,7684],{},[1042,10704,7687],{},[1042,10706,7690],{},[1042,10708,1262],{},[1046,10710,1056],{"stretchy":1048},[1058,10712,10248],{"encoding":1060},[1023,10714,10716],{"className":10715,"ariaHidden":1066},[1065],[1023,10717,10719,10722,10725,10728,10731,10734,10737,10740,10743],{"className":10718},[1070],[1023,10720],{"className":10721,"style":1075},[1074],[1023,10723,1044],{"className":10724,"style":1081},[1079,1080],[1023,10726,1049],{"className":10727},[1085],[1023,10729,1262],{"className":10730},[1079,1080],[1023,10732,7684],{"className":10733,"style":7716},[1079,1080],[1023,10735,7687],{"className":10736},[1079,1080],[1023,10738,7690],{"className":10739,"style":7723},[1079,1080],[1023,10741,1262],{"className":10742},[1079,1080],[1023,10744,1056],{"className":10745},[1092],[1123,10747,10748],{},[1023,10749,10751,10770],{"className":10750},[1026],[1023,10752,10754],{"className":10753},[1030],[1032,10755,10756],{"xmlns":1034},[1036,10757,10758,10768],{},[1039,10759,10760,10762,10764,10766],{},[1042,10761,1044],{},[1046,10763,1049],{"stretchy":1048},[1042,10765,1262],{},[1046,10767,1056],{"stretchy":1048},[1058,10769,1267],{"encoding":1060},[1023,10771,10773],{"className":10772,"ariaHidden":1066},[1065],[1023,10774,10776,10779,10782,10785,10788],{"className":10775},[1070],[1023,10777],{"className":10778,"style":1075},[1074],[1023,10780,1044],{"className":10781,"style":1081},[1079,1080],[1023,10783,1049],{"className":10784},[1085],[1023,10786,1262],{"className":10787},[1079,1080],[1023,10789,1056],{"className":10790},[1092],[1123,10792,10793],{},"Lớn, cần ổn định",[1105,10795,10796,10799,10957,11002],{},[1123,10797,10798],{},"Shell",[1123,10800,10801,10802,10880,10881],{},"Khoảng ",[1023,10803,10805,10830],{"className":10804},[1026],[1023,10806,10808],{"className":10807},[1030],[1032,10809,10810],{"xmlns":1034},[1036,10811,10812,10827],{},[1039,10813,10814,10816,10818,10825],{},[1042,10815,1044],{},[1046,10817,1049],{"stretchy":1048},[2327,10819,10820,10822],{},[1042,10821,1262],{},[1051,10823,10824],{},"1.3",[1046,10826,1056],{"stretchy":1048},[1058,10828,10829],{"encoding":1060},"O(n^{1.3})",[1023,10831,10833],{"className":10832,"ariaHidden":1066},[1065],[1023,10834,10836,10839,10842,10845,10877],{"className":10835},[1070],[1023,10837],{"className":10838,"style":2476},[1074],[1023,10840,1044],{"className":10841,"style":1081},[1079,1080],[1023,10843,1049],{"className":10844},[1085],[1023,10846,10848,10851],{"className":10847},[1079],[1023,10849,1262],{"className":10850},[1079,1080],[1023,10852,10854],{"className":10853},[2383],[1023,10855,10857],{"className":10856},[2387],[1023,10858,10860],{"className":10859},[2391],[1023,10861,10863],{"className":10862,"style":2369},[2395],[1023,10864,10865,10868],{"style":2398},[1023,10866],{"className":10867,"style":2403},[2402],[1023,10869,10871],{"className":10870},[2407,2408,2409,2410],[1023,10872,10874],{"className":10873},[1079,2410],[1023,10875,10824],{"className":10876},[1079,2410],[1023,10878,1056],{"className":10879},[1092]," tới ",[1023,10882,10884,10907],{"className":10883},[1026],[1023,10885,10887],{"className":10886},[1030],[1032,10888,10889],{"xmlns":1034},[1036,10890,10891,10905],{},[1039,10892,10893,10895,10897,10903],{},[1042,10894,1044],{},[1046,10896,1049],{"stretchy":1048},[2327,10898,10899,10901],{},[1042,10900,1262],{},[1051,10902,10378],{},[1046,10904,1056],{"stretchy":1048},[1058,10906,10383],{"encoding":1060},[1023,10908,10910],{"className":10909,"ariaHidden":1066},[1065],[1023,10911,10913,10916,10919,10922,10954],{"className":10912},[1070],[1023,10914],{"className":10915,"style":2476},[1074],[1023,10917,1044],{"className":10918,"style":1081},[1079,1080],[1023,10920,1049],{"className":10921},[1085],[1023,10923,10925,10928],{"className":10924},[1079],[1023,10926,1262],{"className":10927},[1079,1080],[1023,10929,10931],{"className":10930},[2383],[1023,10932,10934],{"className":10933},[2387],[1023,10935,10937],{"className":10936},[2391],[1023,10938,10940],{"className":10939,"style":2369},[2395],[1023,10941,10942,10945],{"style":2398},[1023,10943],{"className":10944,"style":2403},[2402],[1023,10946,10948],{"className":10947},[2407,2408,2409,2410],[1023,10949,10951],{"className":10950},[1079,2410],[1023,10952,10378],{"className":10953},[1079,2410],[1023,10955,1056],{"className":10956},[1092],[1123,10958,10959],{},[1023,10960,10962,10981],{"className":10961},[1026],[1023,10963,10965],{"className":10964},[1030],[1032,10966,10967],{"xmlns":1034},[1036,10968,10969,10979],{},[1039,10970,10971,10973,10975,10977],{},[1042,10972,1044],{},[1046,10974,1049],{"stretchy":1048},[1051,10976,1053],{},[1046,10978,1056],{"stretchy":1048},[1058,10980,1061],{"encoding":1060},[1023,10982,10984],{"className":10983,"ariaHidden":1066},[1065],[1023,10985,10987,10990,10993,10996,10999],{"className":10986},[1070],[1023,10988],{"className":10989,"style":1075},[1074],[1023,10991,1044],{"className":10992,"style":1081},[1079,1080],[1023,10994,1049],{"className":10995},[1085],[1023,10997,1053],{"className":10998},[1079],[1023,11000,1056],{"className":11001},[1092],[1123,11003,11004],{},"Cỡ trung bình",[1105,11006,11007,11010,11075,11135],{},[1123,11008,11009],{},"Quick",[1123,11011,11012],{},[1023,11013,11015,11042],{"className":11014},[1026],[1023,11016,11018],{"className":11017},[1030],[1032,11019,11020],{"xmlns":1034},[1036,11021,11022,11040],{},[1039,11023,11024,11026,11028,11030,11032,11034,11036,11038],{},[1042,11025,1044],{},[1046,11027,1049],{"stretchy":1048},[1042,11029,1262],{},[1042,11031,7684],{},[1042,11033,7687],{},[1042,11035,7690],{},[1042,11037,1262],{},[1046,11039,1056],{"stretchy":1048},[1058,11041,10248],{"encoding":1060},[1023,11043,11045],{"className":11044,"ariaHidden":1066},[1065],[1023,11046,11048,11051,11054,11057,11060,11063,11066,11069,11072],{"className":11047},[1070],[1023,11049],{"className":11050,"style":1075},[1074],[1023,11052,1044],{"className":11053,"style":1081},[1079,1080],[1023,11055,1049],{"className":11056},[1085],[1023,11058,1262],{"className":11059},[1079,1080],[1023,11061,7684],{"className":11062,"style":7716},[1079,1080],[1023,11064,7687],{"className":11065},[1079,1080],[1023,11067,7690],{"className":11068,"style":7723},[1079,1080],[1023,11070,1262],{"className":11071},[1079,1080],[1023,11073,1056],{"className":11074},[1092],[1123,11076,11077],{},[1023,11078,11080,11105],{"className":11079},[1026],[1023,11081,11083],{"className":11082},[1030],[1032,11084,11085],{"xmlns":1034},[1036,11086,11087,11103],{},[1039,11088,11089,11091,11093,11095,11097,11099,11101],{},[1042,11090,1044],{},[1046,11092,1049],{"stretchy":1048},[1042,11094,7684],{},[1042,11096,7687],{},[1042,11098,7690],{},[1042,11100,1262],{},[1046,11102,1056],{"stretchy":1048},[1058,11104,7697],{"encoding":1060},[1023,11106,11108],{"className":11107,"ariaHidden":1066},[1065],[1023,11109,11111,11114,11117,11120,11123,11126,11129,11132],{"className":11110},[1070],[1023,11112],{"className":11113,"style":1075},[1074],[1023,11115,1044],{"className":11116,"style":1081},[1079,1080],[1023,11118,1049],{"className":11119},[1085],[1023,11121,7684],{"className":11122,"style":7716},[1079,1080],[1023,11124,7687],{"className":11125},[1079,1080],[1023,11127,7690],{"className":11128,"style":7723},[1079,1080],[1023,11130,1262],{"className":11131},[1079,1080],[1023,11133,1056],{"className":11134},[1092],[1123,11136,11137],{},"Lớn, cần nhanh",[968,11139,1433],{"id":1432},[986,11141,11142,11155],{},[989,11143,11144,11145,1509,11148,11151,11152,1517],{},"Input: trộn ",[1023,11146,11147],{},"1,4,7",[1023,11149,11150],{},"2,3,6",". Output: ",[1023,11153,11154],{},"1,2,3,4,6,7",[989,11156,11157],{},"Giải thích: mỗi bước lấy số nhỏ hơn trong 2 đầu.",[968,11159,1482],{"id":1481},[973,11161,1485,11162,5599,11164,2256,11167,1656,11169,1517],{},[1487,11163,1493],{},[992,11165,11166],{},"day-011\u002F",[992,11168,9956],{},[992,11170,11171],{},"std::stable_sort",[981,11173,11175],{"id":11174},"bài-1-merge-sort","Bài 1: Merge sort",[1099,11177,11178,11186],{},[1102,11179,11180],{},[1105,11181,11182,11184],{},[1108,11183,1566],{},[1108,11185,2547],{},[1118,11187,11188,11208,11221],{},[1105,11189,11190,11195],{},[1123,11191,11192],{},[992,11193,11194],{},"void merge(std::vector\u003Cint> &a, int l, int m, int r, std::vector\u003Cint> &tmp)",[1123,11196,11197,11198,1509,11201,11204,11205],{},"Trộn ",[992,11199,11200],{},"a[l..m]",[992,11202,11203],{},"a[m+1..r]",", dùng lại buffer ",[992,11206,11207],{},"tmp",[1105,11209,11210,11215],{},[1123,11211,11212],{},[992,11213,11214],{},"void mergeSort(std::vector\u003Cint> &a)",[1123,11216,11217,11218,11220],{},"Top-down, cấp ",[992,11219,11207],{}," đúng 1 lần",[1105,11222,11223,11228],{},[1123,11224,11225],{},[992,11226,11227],{},"void mergeSortBottomUp(std::vector\u003Cint> &a)",[1123,11229,11230],{},"Không đệ quy, độ rộng 1, 2, 4...",[1352,11232,11235],{"className":11233,"code":11234,"language":2241,"meta":1357},[2239],"merge [1,4,7 | 2,3,6]   -> [1,2,3,4,6,7]\nmergeSort [38,27,43,3,9,82,10] -> [3,9,10,27,38,43,82]\nmảng có phần tử trùng [2,1,2,1] -> [1,1,2,2]\n",[992,11236,11234],{"__ignoreMap":1357},[981,11238,11240],{"id":11239},"bài-2-quick-sort-và-shell-sort","Bài 2: Quick sort và Shell sort",[2273,11242,11243,11249,11255,11270],{},[989,11244,11245,11248],{},[992,11246,11247],{},"quickSort"," với phân hoạch Lomuto, chốt là phần tử cuối.",[989,11250,11251,11254],{},[992,11252,11253],{},"quickSortRandom"," chốt ngẫu nhiên.",[989,11256,11257,11260,11261,1656,11264,1656,11267,1517],{},[992,11258,11259],{},"quickSort3Way"," phân hoạch 3 phần ",[992,11262,11263],{},"\u003C chốt",[992,11265,11266],{},"= chốt",[992,11268,11269],{},"> chốt",[989,11271,11272,11275,11276,1517],{},[992,11273,11274],{},"shellSort"," với dãy khe Knuth ",[992,11277,11278],{},"1, 4, 13, 40, ...",[973,11280,11281,11284,11285,7386,11368,11370,11371,11373],{},[1487,11282,11283],{},"Test bắt buộc:"," mảng đã xếp ",[1023,11286,11288,11309],{"className":11287},[1026],[1023,11289,11291],{"className":11290},[1030],[1032,11292,11293],{"xmlns":1034},[1036,11294,11295,11307],{},[1039,11296,11297,11299,11301],{},[1042,11298,1262],{},[1046,11300,2325],{},[2327,11302,11303,11305],{},[1051,11304,2331],{},[1051,11306,2334],{},[1058,11308,2337],{"encoding":1060},[1023,11310,11312,11330],{"className":11311,"ariaHidden":1066},[1065],[1023,11313,11315,11318,11321,11324,11327],{"className":11314},[1070],[1023,11316],{"className":11317,"style":2347},[1074],[1023,11319,1262],{"className":11320},[1079,1080],[1023,11322],{"className":11323,"style":2355},[2354],[1023,11325,2325],{"className":11326},[2359],[1023,11328],{"className":11329,"style":2355},[2354],[1023,11331,11333,11336,11339],{"className":11332},[1070],[1023,11334],{"className":11335,"style":2369},[1074],[1023,11337,1053],{"className":11338},[1079],[1023,11340,11342,11345],{"className":11341},[1079],[1023,11343,2379],{"className":11344},[1079],[1023,11346,11348],{"className":11347},[2383],[1023,11349,11351],{"className":11350},[2387],[1023,11352,11354],{"className":11353},[2391],[1023,11355,11357],{"className":11356,"style":2369},[2395],[1023,11358,11359,11362],{"style":2398},[1023,11360],{"className":11361,"style":2403},[2402],[1023,11363,11365],{"className":11364},[2407,2408,2409,2410],[1023,11366,2334],{"className":11367},[1079,2410],[992,11369,11247],{}," chốt cuối phải chạy rất chậm hoặc tràn stack. Ghi lại hiện tượng. ",[992,11372,11253],{}," phải xong trong dưới 100 ms.",[981,11375,11377],{"id":11376},"bài-3-benchmark-và-hybrid-nâng-cao","Bài 3: Benchmark và hybrid (nâng cao)",[973,11379,11380,11381,11465,11466,11469,11470,1517],{},"Đo 5 hàm trên 4 loại dữ liệu cỡ ",[1023,11382,11384,11406],{"className":11383},[1026],[1023,11385,11387],{"className":11386},[1030],[1032,11388,11389],{"xmlns":1034},[1036,11390,11391,11403],{},[1039,11392,11393,11395,11397],{},[1042,11394,1262],{},[1046,11396,2325],{},[2327,11398,11399,11401],{},[1051,11400,2331],{},[1051,11402,6866],{},[1058,11404,11405],{"encoding":1060},"n = 10^6",[1023,11407,11409,11427],{"className":11408,"ariaHidden":1066},[1065],[1023,11410,11412,11415,11418,11421,11424],{"className":11411},[1070],[1023,11413],{"className":11414,"style":2347},[1074],[1023,11416,1262],{"className":11417},[1079,1080],[1023,11419],{"className":11420,"style":2355},[2354],[1023,11422,2325],{"className":11423},[2359],[1023,11425],{"className":11426,"style":2355},[2354],[1023,11428,11430,11433,11436],{"className":11429},[1070],[1023,11431],{"className":11432,"style":2369},[1074],[1023,11434,1053],{"className":11435},[1079],[1023,11437,11439,11442],{"className":11438},[1079],[1023,11440,2379],{"className":11441},[1079],[1023,11443,11445],{"className":11444},[2383],[1023,11446,11448],{"className":11447},[2387],[1023,11449,11451],{"className":11450},[2391],[1023,11452,11454],{"className":11453,"style":2369},[2395],[1023,11455,11456,11459],{"style":2398},[1023,11457],{"className":11458,"style":2403},[2402],[1023,11460,11462],{"className":11461},[2407,2408,2409,2410],[1023,11463,6866],{"className":11464},[1079,2410]," (ngẫu nhiên, đã xếp, xếp ngược, nhiều trùng lặp với giá trị trong ",[992,11467,11468],{},"[0, 10)","). So với ",[992,11471,9956],{},[1352,11473,11476],{"className":11474,"code":11475,"language":2241,"meta":1357},[2239],"algo              random   sorted   reversed   few_unique   (ms)\nmergeSort         ...\nquickSortRandom   ...\nquickSort3Way     ...\nshellSort         ...\nstd::sort         ...\n",[992,11477,11475],{"__ignoreMap":1357},[973,11479,11480,11481,11484,11485,1517],{},"Viết thêm ",[992,11482,11483],{},"introSortLite",": quick sort ngẫu nhiên, đoạn con dưới 16 phần tử thì chuyển sang insertion sort. So thời gian với ",[992,11486,11253],{},[2245,11488,11489],{},[973,11490,11491,11492,11495,11496,1517],{},"Build với ",[992,11493,11494],{},"-O2"," khi benchmark. Chạy mỗi ô 3 lần, lấy trung vị. Kiểm tra kết quả bằng ",[992,11497,11498],{},"std::is_sorted",[981,11500,2711],{"id":2710},[986,11502,11504,11513,11519,11525],{"className":11503},[2715],[989,11505,11507,11509,11510,11512],{"className":11506},[2719],[2721,11508],{"disabled":2723,"type":2724}," Mọi hàm pass test ngẫu nhiên so với ",[992,11511,9956],{}," (1000 mảng, cỡ 0 tới 200).",[989,11514,11516,11518],{"className":11515},[2719],[2721,11517],{"disabled":2723,"type":2724}," Ghi lại được worst case của quick sort chốt cuối.",[989,11520,11522,11524],{"className":11521},[2719],[2721,11523],{"disabled":2723,"type":2724}," Bảng benchmark có số thật và 4 câu nhận xét.",[989,11526,11528,11530],{"className":11527},[2719],[2721,11529],{"disabled":2723,"type":2724}," Giải thích được vì sao phân hoạch 3 phần thắng khi dữ liệu nhiều trùng lặp.",[968,11532,2890],{"id":2889},[986,11534,11535,11538,11541,11544],{},[989,11536,11537],{},"Merge sort gồm 2 pha nào?",[989,11539,11540],{},"Shell sort khác insertion ở đâu?",[989,11542,11543],{},"Quick sort chia theo gì?",[989,11545,11546],{},"Dữ liệu lớn cần ổn định thì chọn ai?",[3014,11548],{},[973,11550,11551],{},"🌕 Bạn đã hoàn thành ngày 11. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":11553},[11554,11555,11560,11561,11567],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":11556},[11557,11558,11559],{"id":10205,"depth":73,"text":10206},{"id":10334,"depth":73,"text":10335},{"id":10501,"depth":73,"text":10502},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":11562},[11563,11564,11565,11566],{"id":11174,"depth":73,"text":11175},{"id":11239,"depth":73,"text":11240},{"id":11376,"depth":73,"text":11377},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Học ba thuật toán sắp xếp hiệu quả với chia để trị, so sánh kề cách quãng và chốt pivot, cùng nghệ thuật chọn thuật toán.",{},[3050,8149],{"title":110,"description":11568},[10190],"QSprD5DEgQeAhr5ztoL7Jd2BMaNn3r0J3ySjhjkaKHw",{"id":11575,"title":115,"body":11576,"category":5189,"day":118,"description":12051,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":12052,"navigation":2723,"outcomes":3047,"path":116,"prerequisites":12053,"seo":12054,"stem":117,"tags":12055,"__hash__":12058},"challenges\u002Fchallenges\u002F12.decorator-co-ban.md",{"type":965,"value":11577,"toc":12035},[11578,11580,11583,11585,11589,11603,11607,11624,11628,11642,11678,11680,11688,11690,11701,11705,11766,11887,11893,11897,11922,11928,11932,11970,11976,11978,12012,12014,12028,12030,12033],[968,11579,971],{"id":970},[973,11581,11582],{},"Bài này học cách cộng topping không vỡ lớp cũ. Bạn bọc đối tượng như búp bê Nga.",[968,11584,979],{"id":978},[981,11586,11588],{"id":11587},"vấn-đề-của-kế-thừa","Vấn đề của kế thừa",[986,11590,11591,11594,11597,11600],{},[989,11592,11593],{},"Mỗi tổ hợp topping một lớp thì lớp bùng nổ.",[989,11595,11596],{},"Nhét hết vào lớp cha thì lớp cha phình to.",[989,11598,11599],{},"Thêm topping mới phải sửa code cũ.",[989,11601,11602],{},"Ví dụ đời thường: in menu riêng cho mọi combo.",[981,11604,11606],{"id":11605},"chuỗi-bọc-cộng-dồn","Chuỗi bọc cộng dồn",[986,11608,11609,11612,11615,11618,11621],{},[989,11610,11611],{},"Mỗi topping bọc đồ uống bên trong.",[989,11613,11614],{},"Hỏi giá thì hỏi vào trong rồi cộng thêm.",[989,11616,11617],{},"Hỏi mô tả thì nối thêm tên mình.",[989,11619,11620],{},"Ví dụ đời thường: hộp quà lồng nhau, mở dần.",[989,11622,11623],{},"Thêm topping mới chỉ thêm 1 lớp bọc.",[981,11625,11627],{"id":11626},"khi-nào-bọc-khi-nào-không","Khi nào bọc, khi nào không",[986,11629,11630,11633,11636,11639],{},[989,11631,11632],{},"Cần gắn thêm việc cho từng món riêng lẻ thì bọc.",[989,11634,11635],{},"Số combo quá lớn không liệt kê nổi thì bọc.",[989,11637,11638],{},"Chỉ 2-3 combo cố định thì liệt kê thẳng.",[989,11640,11641],{},"Ví dụ đời thường: dán sticker lên cốc riêng.",[1099,11643,11644,11653],{},[1102,11645,11646],{},[1105,11647,11648,11650],{},[1108,11649,7111],{},[1108,11651,11652],{},"Thêm topping mới",[1118,11654,11655,11663,11671],{},[1105,11656,11657,11660],{},[1123,11658,11659],{},"Mỗi combo 1 lớp",[1123,11661,11662],{},"Số lớp nhân đôi",[1105,11664,11665,11668],{},[1123,11666,11667],{},"Cờ ở lớp cha",[1123,11669,11670],{},"Mở lớp cha ra sửa",[1105,11672,11673,11676],{},[1123,11674,11675],{},"Chuỗi bọc",[1123,11677,7140],{},[968,11679,1433],{"id":1432},[986,11681,11682,11685],{},[989,11683,11684],{},"Input: cà phê đậm + 1 sữa. Output: giá nền + 1 sữa, mô tả đủ 2 món.",[989,11686,11687],{},"Giải thích: lớp sữa hỏi giá lõi rồi cộng phần mình.",[968,11689,1482],{"id":1481},[973,11691,1485,11692,4801,11694,11697,11698,1517],{},[1487,11693,4800],{},[992,11695,11696],{},"day-012\u002F",". Giá tính bằng đồng, kiểu ",[992,11699,11700],{},"long long",[981,11702,11704],{"id":11703},"bài-1-starbuzz-coffee","Bài 1: Starbuzz Coffee",[1352,11706,11708],{"className":1393,"code":11707,"language":1395,"meta":1357,"style":1357},"class Beverage {\n public:\n  virtual std::string description() const = 0;\n  virtual long long cost() const = 0;\n  virtual ~Beverage() = default;\n};\nclass CondimentDecorator : public Beverage {\n protected:\n  std::unique_ptr\u003CBeverage> inner;\n public:\n  explicit CondimentDecorator(std::unique_ptr\u003CBeverage> b);\n};\n",[992,11709,11710,11715,11719,11724,11729,11734,11738,11743,11748,11753,11757,11762],{"__ignoreMap":1357},[1023,11711,11712],{"class":1362,"line":63},[1023,11713,11714],{},"class Beverage {\n",[1023,11716,11717],{"class":1362,"line":68},[1023,11718,4836],{},[1023,11720,11721],{"class":1362,"line":73},[1023,11722,11723],{},"  virtual std::string description() const = 0;\n",[1023,11725,11726],{"class":1362,"line":78},[1023,11727,11728],{},"  virtual long long cost() const = 0;\n",[1023,11730,11731],{"class":1362,"line":83},[1023,11732,11733],{},"  virtual ~Beverage() = default;\n",[1023,11735,11736],{"class":1362,"line":88},[1023,11737,4866],{},[1023,11739,11740],{"class":1362,"line":93},[1023,11741,11742],{},"class CondimentDecorator : public Beverage {\n",[1023,11744,11745],{"class":1362,"line":98},[1023,11746,11747],{}," protected:\n",[1023,11749,11750],{"class":1362,"line":103},[1023,11751,11752],{},"  std::unique_ptr\u003CBeverage> inner;\n",[1023,11754,11755],{"class":1362,"line":108},[1023,11756,4836],{},[1023,11758,11759],{"class":1362,"line":113},[1023,11760,11761],{},"  explicit CondimentDecorator(std::unique_ptr\u003CBeverage> b);\n",[1023,11763,11764],{"class":1362,"line":118},[1023,11765,4866],{},[1099,11767,11768,11779],{},[1102,11769,11770],{},[1105,11771,11772,11774,11777],{},[1108,11773,4881],{},[1108,11775,11776],{},"Giá",[1108,11778,8303],{},[1118,11780,11781,11796,11811,11826,11842,11857,11872],{},[1105,11782,11783,11788,11791],{},[1123,11784,11785],{},[992,11786,11787],{},"Espresso",[1123,11789,11790],{},"30.000",[1123,11792,11793],{},[992,11794,11795],{},"\"Espresso\"",[1105,11797,11798,11803,11806],{},[1123,11799,11800],{},[992,11801,11802],{},"HouseBlend",[1123,11804,11805],{},"25.000",[1123,11807,11808],{},[992,11809,11810],{},"\"House Blend\"",[1105,11812,11813,11818,11821],{},[1123,11814,11815],{},[992,11816,11817],{},"DarkRoast",[1123,11819,11820],{},"28.000",[1123,11822,11823],{},[992,11824,11825],{},"\"Dark Roast\"",[1105,11827,11828,11833,11836],{},[1123,11829,11830],{},[992,11831,11832],{},"Milk",[1123,11834,11835],{},"+5.000",[1123,11837,11838,11839],{},"nối ",[992,11840,11841],{},"\", Sữa\"",[1105,11843,11844,11849,11852],{},[1123,11845,11846],{},[992,11847,11848],{},"Mocha",[1123,11850,11851],{},"+7.000",[1123,11853,11838,11854],{},[992,11855,11856],{},"\", Mocha\"",[1105,11858,11859,11864,11867],{},[1123,11860,11861],{},[992,11862,11863],{},"Soy",[1123,11865,11866],{},"+6.000",[1123,11868,11838,11869],{},[992,11870,11871],{},"\", Sữa đậu nành\"",[1105,11873,11874,11879,11882],{},[1123,11875,11876],{},[992,11877,11878],{},"Whip",[1123,11880,11881],{},"+4.000",[1123,11883,11838,11884],{},[992,11885,11886],{},"\", Kem\"",[1352,11888,11891],{"className":11889,"code":11890,"language":2241,"meta":1357},[2239],"DarkRoast + Mocha + Mocha + Whip  -> \"Dark Roast, Mocha, Mocha, Kem\" = 46000\nEspresso                          -> \"Espresso\" = 30000\nHouseBlend + Soy + Mocha + Whip   -> 42000\n",[992,11892,11890],{"__ignoreMap":1357},[981,11894,11896],{"id":11895},"bài-2-size-ly-và-thêm-topping-mới","Bài 2: Size ly và thêm topping mới",[2273,11898,11899,11911,11916],{},[989,11900,5030,11901,8530,11904,11907,11908,1517],{},[992,11902,11903],{},"enum class Size { Small, Medium, Large }",[992,11905,11906],{},"Beverage",". Topping lấy size từ ",[992,11909,11910],{},"inner",[989,11912,11913,11915],{},[992,11914,11863],{}," tính giá theo size: nhỏ 4.000, vừa 6.000, lớn 8.000.",[989,11917,5030,11918,11921],{},[992,11919,11920],{},"Caramel"," (+9.000) chỉ bằng một file mới.",[1352,11923,11926],{"className":11924,"code":11925,"language":2241,"meta":1357},[2239],"Espresso(Large) + Soy -> 38000\nEspresso(Small) + Soy + Caramel -> 43000\n",[992,11927,11925],{"__ignoreMap":1357},[981,11929,11931],{"id":11930},"bài-3-vé-xem-phim-và-decorator-vào-ra-nâng-cao","Bài 3: Vé xem phim và decorator vào-ra (nâng cao)",[2273,11933,11934,11952],{},[989,11935,11936,11939,11940,11943,11944,11947,11948,11951],{},[992,11937,11938],{},"Ticket"," gốc 90.000. Decorator: ",[992,11941,11942],{},"WeekendSurcharge"," (+20%), ",[992,11945,11946],{},"ThreeD"," (+30.000), ",[992,11949,11950],{},"StudentDiscount"," (-15%). Thứ tự bọc làm đổi giá: tính và giải thích 2 thứ tự khác nhau.",[989,11953,11954,11955,7423,11958,11961,11962,11965,11966,11969],{},"Viết interface ",[992,11956,11957],{},"TextSource { virtual std::optional\u003Cchar> read() = 0; }",[992,11959,11960],{},"StringSource"," và 2 decorator: ",[992,11963,11964],{},"UpperCase"," (đổi chữ thường thành hoa) và ",[992,11967,11968],{},"SkipSpaces"," (bỏ khoảng trắng).",[1352,11971,11974],{"className":11972,"code":11973,"language":2241,"meta":1357},[2239],"UpperCase(SkipSpaces(StringSource(\"a b c\"))) đọc hết -> \"ABC\"\nSkipSpaces(UpperCase(StringSource(\"x y\")))   đọc hết -> \"XY\"\n",[992,11975,11973],{"__ignoreMap":1357},[981,11977,2711],{"id":2710},[986,11979,11981,11987,11996,12002],{"className":11980},[2715],[989,11982,11984,11986],{"className":11983},[2719],[2721,11985],{"disabled":2723,"type":2724}," Test mẫu pass.",[989,11988,11990,11992,11993,11995],{"className":11989},[2719],[2721,11991],{"disabled":2723,"type":2724}," Thêm ",[992,11994,11920],{}," không sửa file cũ.",[989,11997,11999,12001],{"className":11998},[2719],[2721,12000],{"disabled":2723,"type":2724}," Bài 3 có bảng giá vé theo 2 thứ tự bọc kèm giải thích.",[989,12003,12005,12007,12008,12011],{"className":12004},[2719],[2721,12006],{"disabled":2723,"type":2724}," Không rò bộ nhớ: dùng ",[992,12009,12010],{},"unique_ptr",", sanitizer sạch.",[968,12013,2890],{"id":2889},[986,12015,12016,12019,12022,12025],{},[989,12017,12018],{},"Decorator là gì, nói 1 câu?",[989,12020,12021],{},"Vì sao kế thừa gây bùng nổ lớp?",[989,12023,12024],{},"Giá món bọc nhiều lớp tính thế nào?",[989,12026,12027],{},"Khi nào không nên bọc?",[3014,12029],{},[973,12031,12032],{},"🌕 Bạn đã hoàn thành ngày 12. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,12034,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":12036},[12037,12038,12043,12044,12050],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":12039},[12040,12041,12042],{"id":11587,"depth":73,"text":11588},{"id":11605,"depth":73,"text":11606},{"id":11626,"depth":73,"text":11627},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":12045},[12046,12047,12048,12049],{"id":11703,"depth":73,"text":11704},{"id":11895,"depth":73,"text":11896},{"id":11930,"depth":73,"text":11931},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Decorator, nguyên lý mở rộng không sửa đổi, và cách Starbuzz cộng dồn giá topping bằng chuỗi bọc.",{},[5194,5195],{"title":115,"description":12051},[12056,12057,5200],"decorator","starbuzz","RoVheV0UtWzU63W6uTUlLl8OHGEQtFSGd1mI_kjHywY",{"id":12060,"title":120,"body":12061,"category":8797,"day":123,"description":13219,"difficulty":3043,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":13220,"navigation":2723,"outcomes":3047,"path":121,"prerequisites":13221,"seo":13222,"stem":122,"tags":13223,"__hash__":13225},"challenges\u002Fchallenges\u002F13.tim-kiem-co-ban.md",{"type":965,"value":12062,"toc":13203},[12063,12065,12068,12070,12074,12135,12139,12215,12219,12345,12493,12495,12506,12536,12538,12553,12557,12835,12841,12853,12857,12866,12930,12944,12947,12953,12957,12960,13072,13074,13180,13182,13196,13198,13201],[968,12064,971],{"id":970},[973,12066,12067],{},"Bài này học 3 cách tìm kiếm nhanh dần. Bạn chọn đúng cách theo dữ liệu.",[968,12069,979],{"id":978},[981,12071,12073],{"id":12072},"linear-quét-cạn","Linear — quét cạn",[986,12075,12076,12079,12082,12129,12132],{},[989,12077,12078],{},"Duyệt từng món tới khi trúng hoặc hết.",[989,12080,12081],{},"Không cần sắp xếp trước.",[989,12083,12084,12085,12128],{},"Chậm ",[1023,12086,12088,12107],{"className":12087},[1026],[1023,12089,12091],{"className":12090},[1030],[1032,12092,12093],{"xmlns":1034},[1036,12094,12095,12105],{},[1039,12096,12097,12099,12101,12103],{},[1042,12098,1044],{},[1046,12100,1049],{"stretchy":1048},[1042,12102,1262],{},[1046,12104,1056],{"stretchy":1048},[1058,12106,1267],{"encoding":1060},[1023,12108,12110],{"className":12109,"ariaHidden":1066},[1065],[1023,12111,12113,12116,12119,12122,12125],{"className":12112},[1070],[1023,12114],{"className":12115,"style":1075},[1074],[1023,12117,1044],{"className":12118,"style":1081},[1079,1080],[1023,12120,1049],{"className":12121},[1085],[1023,12123,1262],{"className":12124},[1079,1080],[1023,12126,1056],{"className":12127},[1092]," khi kho to.",[989,12130,12131],{},"Ví dụ đời thường: tìm chìa khóa khắp nhà.",[989,12133,12134],{},"Hợp dữ liệu nhỏ hoặc tìm 1-2 lần.",[981,12136,12138],{"id":12137},"binary-chặt-đôi","Binary — chặt đôi",[986,12140,12141,12144,12147,12209,12212],{},[989,12142,12143],{},"Cần dữ liệu đã sắp xếp trước.",[989,12145,12146],{},"Mỗi lượt loại nửa vùng tìm kiếm.",[989,12148,12149,12150,12208],{},"Tốn ",[1023,12151,12153,12178],{"className":12152},[1026],[1023,12154,12156],{"className":12155},[1030],[1032,12157,12158],{"xmlns":1034},[1036,12159,12160,12176],{},[1039,12161,12162,12164,12166,12168,12170,12172,12174],{},[1042,12163,1044],{},[1046,12165,1049],{"stretchy":1048},[1042,12167,7684],{},[1042,12169,7687],{},[1042,12171,7690],{},[1042,12173,1262],{},[1046,12175,1056],{"stretchy":1048},[1058,12177,7697],{"encoding":1060},[1023,12179,12181],{"className":12180,"ariaHidden":1066},[1065],[1023,12182,12184,12187,12190,12193,12196,12199,12202,12205],{"className":12183},[1070],[1023,12185],{"className":12186,"style":1075},[1074],[1023,12188,1044],{"className":12189,"style":1081},[1079,1080],[1023,12191,1049],{"className":12192},[1085],[1023,12194,7684],{"className":12195,"style":7716},[1079,1080],[1023,12197,7687],{"className":12198},[1079,1080],[1023,12200,7690],{"className":12201,"style":7723},[1079,1080],[1023,12203,1262],{"className":12204},[1079,1080],[1023,12206,1056],{"className":12207},[1092]," bước.",[989,12210,12211],{},"Ví dụ đời thường: đoán số từ 1 tới 100.",[989,12213,12214],{},"Hợp kho đã xếp hoặc tìm lặp nhiều lần.",[981,12216,12218],{"id":12217},"interpolation-đoán-vị-trí","Interpolation — đoán vị trí",[986,12220,12221,12224,12227,12342],{},[989,12222,12223],{},"Cũng cần dữ liệu đã sắp xếp.",[989,12225,12226],{},"Dùng giá trị để đoán vị trí, không chém giữa mù.",[989,12228,12229,12230,12298,12299,1517],{},"Dữ liệu phân bố đều thì trung bình ",[1023,12231,12233,12261],{"className":12232},[1026],[1023,12234,12236],{"className":12235},[1030],[1032,12237,12238],{"xmlns":1034},[1036,12239,12240,12258],{},[1039,12241,12242,12244,12246,12248,12250,12252,12254,12256],{},[1042,12243,1044],{},[1046,12245,1049],{"stretchy":1048},[1042,12247,8397],{},[1046,12249,8400],{},[1042,12251,8397],{},[1046,12253,8400],{},[1042,12255,1262],{},[1046,12257,1056],{"stretchy":1048},[1058,12259,12260],{"encoding":1060},"O(\\log \\log n)",[1023,12262,12264],{"className":12263,"ariaHidden":1066},[1065],[1023,12265,12267,12270,12273,12276,12281,12284,12289,12292,12295],{"className":12266},[1070],[1023,12268],{"className":12269,"style":1075},[1074],[1023,12271,1044],{"className":12272,"style":1081},[1079,1080],[1023,12274,1049],{"className":12275},[1085],[1023,12277,8427,12279],{"className":12278},[8426],[1023,12280,7690],{"style":8430},[1023,12282],{"className":12283,"style":8434},[2354],[1023,12285,8427,12287],{"className":12286},[8426],[1023,12288,7690],{"style":8430},[1023,12290],{"className":12291,"style":8434},[2354],[1023,12293,1262],{"className":12294},[1079,1080],[1023,12296,1056],{"className":12297},[1092],", lệch nặng thì tệ nhất ",[1023,12300,12302,12321],{"className":12301},[1026],[1023,12303,12305],{"className":12304},[1030],[1032,12306,12307],{"xmlns":1034},[1036,12308,12309,12319],{},[1039,12310,12311,12313,12315,12317],{},[1042,12312,1044],{},[1046,12314,1049],{"stretchy":1048},[1042,12316,1262],{},[1046,12318,1056],{"stretchy":1048},[1058,12320,1267],{"encoding":1060},[1023,12322,12324],{"className":12323,"ariaHidden":1066},[1065],[1023,12325,12327,12330,12333,12336,12339],{"className":12326},[1070],[1023,12328],{"className":12329,"style":1075},[1074],[1023,12331,1044],{"className":12332,"style":1081},[1079,1080],[1023,12334,1049],{"className":12335},[1085],[1023,12337,1262],{"className":12338},[1079,1080],[1023,12340,1056],{"className":12341},[1092],[989,12343,12344],{},"Ví dụ đời thường: mở từ điển ngay quãng chữ R.",[1099,12346,12347,12360],{},[1102,12348,12349],{},[1105,12350,12351,12354,12357],{},[1108,12352,12353],{},"Cách tìm",[1108,12355,12356],{},"Cần xếp trước?",[1108,12358,12359],{},"Tốc độ",[1118,12361,12362,12415,12483],{},[1105,12363,12364,12367,12370],{},[1123,12365,12366],{},"Quét cạn",[1123,12368,12369],{},"Không",[1123,12371,12372],{},[1023,12373,12375,12394],{"className":12374},[1026],[1023,12376,12378],{"className":12377},[1030],[1032,12379,12380],{"xmlns":1034},[1036,12381,12382,12392],{},[1039,12383,12384,12386,12388,12390],{},[1042,12385,1044],{},[1046,12387,1049],{"stretchy":1048},[1042,12389,1262],{},[1046,12391,1056],{"stretchy":1048},[1058,12393,1267],{"encoding":1060},[1023,12395,12397],{"className":12396,"ariaHidden":1066},[1065],[1023,12398,12400,12403,12406,12409,12412],{"className":12399},[1070],[1023,12401],{"className":12402,"style":1075},[1074],[1023,12404,1044],{"className":12405,"style":1081},[1079,1080],[1023,12407,1049],{"className":12408},[1085],[1023,12410,1262],{"className":12411},[1079,1080],[1023,12413,1056],{"className":12414},[1092],[1105,12416,12417,12420,12423],{},[1123,12418,12419],{},"Chặt đôi",[1123,12421,12422],{},"Có",[1123,12424,12425],{},[1023,12426,12428,12453],{"className":12427},[1026],[1023,12429,12431],{"className":12430},[1030],[1032,12432,12433],{"xmlns":1034},[1036,12434,12435,12451],{},[1039,12436,12437,12439,12441,12443,12445,12447,12449],{},[1042,12438,1044],{},[1046,12440,1049],{"stretchy":1048},[1042,12442,7684],{},[1042,12444,7687],{},[1042,12446,7690],{},[1042,12448,1262],{},[1046,12450,1056],{"stretchy":1048},[1058,12452,7697],{"encoding":1060},[1023,12454,12456],{"className":12455,"ariaHidden":1066},[1065],[1023,12457,12459,12462,12465,12468,12471,12474,12477,12480],{"className":12458},[1070],[1023,12460],{"className":12461,"style":1075},[1074],[1023,12463,1044],{"className":12464,"style":1081},[1079,1080],[1023,12466,1049],{"className":12467},[1085],[1023,12469,7684],{"className":12470,"style":7716},[1079,1080],[1023,12472,7687],{"className":12473},[1079,1080],[1023,12475,7690],{"className":12476,"style":7723},[1079,1080],[1023,12478,1262],{"className":12479},[1079,1080],[1023,12481,1056],{"className":12482},[1092],[1105,12484,12485,12488,12490],{},[1123,12486,12487],{},"Nội suy đều",[1123,12489,12422],{},[1123,12491,12492],{},"Rất nhanh nếu đều",[968,12494,1433],{"id":1432},[986,12496,12497,12503],{},[989,12498,9878,12499,12502],{},[1023,12500,12501],{},"12,33,11,99,22",", tìm 12 kiểu quét. Output: trúng ngay lần đầu.",[989,12504,12505],{},"Giải thích: quét từ đầu nên món đầu tiên trúng luôn.",[1352,12507,12509],{"className":3538,"code":12508,"language":3540,"meta":1357,"style":1357},"# Quét tuyến tính\nfor i, x in enumerate(a):  # duyệt từng món\n    if x == target:  # trúng thì dừng\n        print(i)\n        break\n",[992,12510,12511,12516,12521,12526,12531],{"__ignoreMap":1357},[1023,12512,12513],{"class":1362,"line":63},[1023,12514,12515],{},"# Quét tuyến tính\n",[1023,12517,12518],{"class":1362,"line":68},[1023,12519,12520],{},"for i, x in enumerate(a):  # duyệt từng món\n",[1023,12522,12523],{"class":1362,"line":73},[1023,12524,12525],{},"    if x == target:  # trúng thì dừng\n",[1023,12527,12528],{"class":1362,"line":78},[1023,12529,12530],{},"        print(i)\n",[1023,12532,12533],{"class":1362,"line":83},[1023,12534,12535],{},"        break\n",[968,12537,1482],{"id":1481},[973,12539,1485,12540,5599,12542,12545,12546,12549,12550,1517],{},[1487,12541,1493],{},[992,12543,12544],{},"day-013\u002F",". Mọi hàm trả chỉ số tìm thấy, không thấy trả ",[992,12547,12548],{},"-1",", và đếm số lần so sánh qua tham số ",[992,12551,12552],{},"long long &cmp",[981,12554,12556],{"id":12555},"bài-1-linear-và-binary-search","Bài 1: Linear và binary search",[1099,12558,12559,12569],{},[1102,12560,12561],{},[1105,12562,12563,12565,12567],{},[1108,12564,1566],{},[1108,12566,2547],{},[1108,12568,1113],{},[1118,12570,12571,12626,12693,12766],{},[1105,12572,12573,12578,12581],{},[1123,12574,12575],{},[992,12576,12577],{},"int linearSearch(const std::vector\u003Cint>&, int x, long long &cmp)",[1123,12579,12580],{},"Quét từ đầu",[1123,12582,12583],{},[1023,12584,12586,12605],{"className":12585},[1026],[1023,12587,12589],{"className":12588},[1030],[1032,12590,12591],{"xmlns":1034},[1036,12592,12593,12603],{},[1039,12594,12595,12597,12599,12601],{},[1042,12596,1044],{},[1046,12598,1049],{"stretchy":1048},[1042,12600,1262],{},[1046,12602,1056],{"stretchy":1048},[1058,12604,1267],{"encoding":1060},[1023,12606,12608],{"className":12607,"ariaHidden":1066},[1065],[1023,12609,12611,12614,12617,12620,12623],{"className":12610},[1070],[1023,12612],{"className":12613,"style":1075},[1074],[1023,12615,1044],{"className":12616,"style":1081},[1079,1080],[1023,12618,1049],{"className":12619},[1085],[1023,12621,1262],{"className":12622},[1079,1080],[1023,12624,1056],{"className":12625},[1092],[1105,12627,12628,12633,12636],{},[1123,12629,12630],{},[992,12631,12632],{},"int binarySearch(const std::vector\u003Cint>&, int x, long long &cmp)",[1123,12634,12635],{},"Mảng tăng dần, vòng lặp, không đệ quy",[1123,12637,12638],{},[1023,12639,12641,12664],{"className":12640},[1026],[1023,12642,12644],{"className":12643},[1030],[1032,12645,12646],{"xmlns":1034},[1036,12647,12648,12662],{},[1039,12649,12650,12652,12654,12656,12658,12660],{},[1042,12651,1044],{},[1046,12653,1049],{"stretchy":1048},[1042,12655,8397],{},[1046,12657,8400],{},[1042,12659,1262],{},[1046,12661,1056],{"stretchy":1048},[1058,12663,8407],{"encoding":1060},[1023,12665,12667],{"className":12666,"ariaHidden":1066},[1065],[1023,12668,12670,12673,12676,12679,12684,12687,12690],{"className":12669},[1070],[1023,12671],{"className":12672,"style":1075},[1074],[1023,12674,1044],{"className":12675,"style":1081},[1079,1080],[1023,12677,1049],{"className":12678},[1085],[1023,12680,8427,12682],{"className":12681},[8426],[1023,12683,7690],{"style":8430},[1023,12685],{"className":12686,"style":8434},[2354],[1023,12688,1262],{"className":12689},[1079,1080],[1023,12691,1056],{"className":12692},[1092],[1105,12694,12695,12700,12709],{},[1123,12696,12697],{},[992,12698,12699],{},"int lowerBound(const std::vector\u003Cint>&, int x)",[1123,12701,12702,12703,12706,12707],{},"Chỉ số đầu tiên có ",[992,12704,12705],{},"a[i] >= x",", không có thì trả ",[992,12708,1262],{},[1123,12710,12711],{},[1023,12712,12714,12737],{"className":12713},[1026],[1023,12715,12717],{"className":12716},[1030],[1032,12718,12719],{"xmlns":1034},[1036,12720,12721,12735],{},[1039,12722,12723,12725,12727,12729,12731,12733],{},[1042,12724,1044],{},[1046,12726,1049],{"stretchy":1048},[1042,12728,8397],{},[1046,12730,8400],{},[1042,12732,1262],{},[1046,12734,1056],{"stretchy":1048},[1058,12736,8407],{"encoding":1060},[1023,12738,12740],{"className":12739,"ariaHidden":1066},[1065],[1023,12741,12743,12746,12749,12752,12757,12760,12763],{"className":12742},[1070],[1023,12744],{"className":12745,"style":1075},[1074],[1023,12747,1044],{"className":12748,"style":1081},[1079,1080],[1023,12750,1049],{"className":12751},[1085],[1023,12753,8427,12755],{"className":12754},[8426],[1023,12756,7690],{"style":8430},[1023,12758],{"className":12759,"style":8434},[2354],[1023,12761,1262],{"className":12762},[1079,1080],[1023,12764,1056],{"className":12765},[1092],[1105,12767,12768,12773,12778],{},[1123,12769,12770],{},[992,12771,12772],{},"int upperBound(const std::vector\u003Cint>&, int x)",[1123,12774,12702,12775],{},[992,12776,12777],{},"a[i] > x",[1123,12779,12780],{},[1023,12781,12783,12806],{"className":12782},[1026],[1023,12784,12786],{"className":12785},[1030],[1032,12787,12788],{"xmlns":1034},[1036,12789,12790,12804],{},[1039,12791,12792,12794,12796,12798,12800,12802],{},[1042,12793,1044],{},[1046,12795,1049],{"stretchy":1048},[1042,12797,8397],{},[1046,12799,8400],{},[1042,12801,1262],{},[1046,12803,1056],{"stretchy":1048},[1058,12805,8407],{"encoding":1060},[1023,12807,12809],{"className":12808,"ariaHidden":1066},[1065],[1023,12810,12812,12815,12818,12821,12826,12829,12832],{"className":12811},[1070],[1023,12813],{"className":12814,"style":1075},[1074],[1023,12816,1044],{"className":12817,"style":1081},[1079,1080],[1023,12819,1049],{"className":12820},[1085],[1023,12822,8427,12824],{"className":12823},[8426],[1023,12825,7690],{"style":8430},[1023,12827],{"className":12828,"style":8434},[2354],[1023,12830,1262],{"className":12831},[1079,1080],[1023,12833,1056],{"className":12834},[1092],[1352,12836,12839],{"className":12837,"code":12838,"language":2241,"meta":1357},[2239],"linear [12,33,11,99,22], 12      -> 0, cmp=1\nlinear [12,33,11,99,22], 7       -> -1, cmp=5\nbinary [1,3,5,7,9,11], 7         -> 3\nbinary [1,3,5,7,9,11], 4         -> -1\nlowerBound [1,2,2,2,5], 2        -> 1\nupperBound [1,2,2,2,5], 2        -> 4   (số lần xuất hiện của 2 = 4 - 1 = 3)\nmảng rỗng                        -> -1 \u002F 0\n",[992,12840,12838],{"__ignoreMap":1357},[2245,12842,12843],{},[973,12844,1505,12845,12848,12849,12852],{},[992,12846,12847],{},"mid = lo + (hi - lo) \u002F 2"," để tránh tràn số. Ghi bất biến vòng lặp bằng comment, ví dụ \"đáp án nằm trong ",[992,12850,12851],{},"[lo, hi)","\".",[981,12854,12856],{"id":12855},"bài-2-interpolation-search","Bài 2: Interpolation search",[973,12858,1505,12859,12862,12863,1517],{},[992,12860,12861],{},"int interpolationSearch(const std::vector\u003Cint>&, int x, long long &cmp)",". Chặn chia cho 0 khi ",[992,12864,12865],{},"a[lo] == a[hi]",[973,12867,12868,12869,4437],{},"Sinh 2 mảng cỡ ",[1023,12870,12872,12889],{"className":12871},[1026],[1023,12873,12875],{"className":12874},[1030],[1032,12876,12877],{"xmlns":1034},[1036,12878,12879,12887],{},[1039,12880,12881],{},[2327,12882,12883,12885],{},[1051,12884,2331],{},[1051,12886,6866],{},[1058,12888,6869],{"encoding":1060},[1023,12890,12892],{"className":12891,"ariaHidden":1066},[1065],[1023,12893,12895,12898,12901],{"className":12894},[1070],[1023,12896],{"className":12897,"style":2369},[1074],[1023,12899,1053],{"className":12900},[1079],[1023,12902,12904,12907],{"className":12903},[1079],[1023,12905,2379],{"className":12906},[1079],[1023,12908,12910],{"className":12909},[2383],[1023,12911,12913],{"className":12912},[2387],[1023,12914,12916],{"className":12915},[2391],[1023,12917,12919],{"className":12918,"style":2369},[2395],[1023,12920,12921,12924],{"style":2398},[1023,12922],{"className":12923,"style":2403},[2402],[1023,12925,12927],{"className":12926},[2407,2408,2409,2410],[1023,12928,6866],{"className":12929},[1079,2410],[986,12931,12932,12938],{},[989,12933,12934,12935,1517],{},"Đều: ",[992,12936,12937],{},"a[i] = 3 * i",[989,12939,12940,12941,1517],{},"Lệch: ",[992,12942,12943],{},"a[i] = i * i",[973,12945,12946],{},"Tìm 1000 giá trị ngẫu nhiên có trong mảng. In số so sánh trung bình:",[1352,12948,12951],{"className":12949,"code":12950,"language":2241,"meta":1357},[2239],"data      binary_avg_cmp   interp_avg_cmp\nuniform   ~20              ~2-3\nskewed    ~20              ...\n",[992,12952,12950],{"__ignoreMap":1357},[981,12954,12956],{"id":12955},"bài-3-tìm-kiếm-trên-đáp-án-nâng-cao","Bài 3: Tìm kiếm trên đáp án (nâng cao)",[973,12958,12959],{},"Dùng binary search trên khoảng giá trị, không phải trên mảng:",[2273,12961,12962,12987,13004],{},[989,12963,12964,12967,12968,5059,12971,12974,12975,1656,12978,1656,12981,1656,12984,1517],{},[992,12965,12966],{},"long long isqrt(long long n)",": số nguyên lớn nhất ",[992,12969,12970],{},"r",[992,12972,12973],{},"r*r \u003C= n",". Test ",[992,12976,12977],{},"isqrt(0)=0",[992,12979,12980],{},"isqrt(15)=3",[992,12982,12983],{},"isqrt(16)=4",[992,12985,12986],{},"isqrt(10^18)=10^9",[989,12988,12989,12990,12992,12993,12996,12997,13000,13001,1517],{},"Có ",[992,12991,1262],{}," gói hàng khối lượng ",[992,12994,12995],{},"w[i]",", chở trong đúng thứ tự bằng ",[992,12998,12999],{},"d"," ngày. Tìm tải trọng xe nhỏ nhất. ",[992,13002,13003],{},"w=[1..10], d=5 -> 15",[989,13005,13006,13007,13010,13011,2528,13013,13068,13069,13071],{},"Mảng tăng dần bị xoay (ví dụ ",[992,13008,13009],{},"[4,5,6,7,0,1,2]","). Tìm ",[992,13012,3904],{},[1023,13014,13016,13039],{"className":13015},[1026],[1023,13017,13019],{"className":13018},[1030],[1032,13020,13021],{"xmlns":1034},[1036,13022,13023,13037],{},[1039,13024,13025,13027,13029,13031,13033,13035],{},[1042,13026,1044],{},[1046,13028,1049],{"stretchy":1048},[1042,13030,8397],{},[1046,13032,8400],{},[1042,13034,1262],{},[1046,13036,1056],{"stretchy":1048},[1058,13038,8407],{"encoding":1060},[1023,13040,13042],{"className":13041,"ariaHidden":1066},[1065],[1023,13043,13045,13048,13051,13054,13059,13062,13065],{"className":13044},[1070],[1023,13046],{"className":13047,"style":1075},[1074],[1023,13049,1044],{"className":13050,"style":1081},[1079,1080],[1023,13052,1049],{"className":13053},[1085],[1023,13055,8427,13057],{"className":13056},[8426],[1023,13058,7690],{"style":8430},[1023,13060],{"className":13061,"style":8434},[2354],[1023,13063,1262],{"className":13064},[1079,1080],[1023,13066,1056],{"className":13067},[1092],". Tìm ",[992,13070,2379],{}," -> chỉ số 4.",[981,13073,2711],{"id":2710},[986,13075,13077,13089,13104,13110],{"className":13076},[2715],[989,13078,13080,13082,13083,7386,13086,1517],{"className":13079},[2719],[2721,13081],{"disabled":2723,"type":2724}," Test mẫu pass. Có test ngẫu nhiên so ",[992,13084,13085],{},"binarySearch",[992,13087,13088],{},"std::binary_search",[989,13090,13092,2308,13094,2461,13097,13100,13101,13103],{"className":13091},[2719],[2721,13093],{"disabled":2723,"type":2724},[992,13095,13096],{},"lowerBound",[992,13098,13099],{},"upperBound"," đúng khi mọi phần tử bằng nhau hoặc ",[992,13102,3904],{}," ngoài khoảng.",[989,13105,13107,13109],{"className":13106},[2719],[2721,13108],{"disabled":2723,"type":2724}," Bảng Bài 2 có số thật.",[989,13111,13113,13115,13116,13179],{"className":13112},[2719],[2721,13114],{"disabled":2723,"type":2724}," Giải thích được: xếp 1 lần tốn ",[1023,13117,13119,13144],{"className":13118},[1026],[1023,13120,13122],{"className":13121},[1030],[1032,13123,13124],{"xmlns":1034},[1036,13125,13126,13142],{},[1039,13127,13128,13130,13132,13134,13136,13138,13140],{},[1042,13129,1044],{},[1046,13131,1049],{"stretchy":1048},[1042,13133,1262],{},[1042,13135,8397],{},[1046,13137,8400],{},[1042,13139,1262],{},[1046,13141,1056],{"stretchy":1048},[1058,13143,10463],{"encoding":1060},[1023,13145,13147],{"className":13146,"ariaHidden":1066},[1065],[1023,13148,13150,13153,13156,13159,13162,13165,13170,13173,13176],{"className":13149},[1070],[1023,13151],{"className":13152,"style":1075},[1074],[1023,13154,1044],{"className":13155,"style":1081},[1079,1080],[1023,13157,1049],{"className":13158},[1085],[1023,13160,1262],{"className":13161},[1079,1080],[1023,13163],{"className":13164,"style":8434},[2354],[1023,13166,8427,13168],{"className":13167},[8426],[1023,13169,7690],{"style":8430},[1023,13171],{"className":13172,"style":8434},[2354],[1023,13174,1262],{"className":13175},[1079,1080],[1023,13177,1056],{"className":13178},[1092],", sau bao nhiêu lần tìm thì đáng hơn quét tuyến tính.",[968,13181,2890],{"id":2889},[986,13183,13184,13187,13190,13193],{},[989,13185,13186],{},"Quét cạn cần xếp trước không?",[989,13188,13189],{},"Chặt đôi cần điều kiện gì?",[989,13191,13192],{},"Nội suy thắng khi dữ liệu thế nào?",[989,13194,13195],{},"Tìm 1 lần trên kho chưa xếp thì dùng gì?",[3014,13197],{},[973,13199,13200],{},"🌕 Bạn đã hoàn thành ngày 13. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,13202,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":13204},[13205,13206,13211,13212,13218],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":13207},[13208,13209,13210],{"id":12072,"depth":73,"text":12073},{"id":12137,"depth":73,"text":12138},{"id":12217,"depth":73,"text":12218},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":13213},[13214,13215,13216,13217],{"id":12555,"depth":73,"text":12556},{"id":12855,"depth":73,"text":12856},{"id":12955,"depth":73,"text":12956},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"So sánh ba chiến lược tìm kiếm từ quét cạn tới chặt đôi và nội suy vị trí, cùng điều kiện dữ liệu mỗi thuật toán đòi hỏi.",{},[3050],{"title":120,"description":13219},[13224],"searching","rlA8xAhhF7D7-mYuAbgmZqPfw5PZYgLiahtYbpkjI14",{"id":13227,"title":125,"body":13228,"category":3041,"day":128,"description":14052,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":14053,"navigation":2723,"outcomes":3047,"path":126,"prerequisites":14054,"seo":14056,"stem":127,"tags":14057,"__hash__":14059},"challenges\u002Fchallenges\u002F14.ma-tran-va-du-lieu-bang.md",{"type":965,"value":13229,"toc":14035},[13230,13232,13235,13237,13241,13255,13259,13276,13280,13341,13515,13517,13525,13527,13540,13546,13552,13560,13572,13676,13682,13686,13727,13731,13959,13965,13967,14014,14016,14030,14032],[968,13231,971],{"id":970},[973,13233,13234],{},"Bài này học bảng hàng-cột và ma trận số. Bạn lọc đúng hàng cột cần dùng.",[968,13236,979],{"id":978},[981,13238,13240],{"id":13239},"bảng-dữ-liệu-hàng-và-cột","Bảng dữ liệu hàng và cột",[986,13242,13243,13246,13249,13252],{},[989,13244,13245],{},"Mỗi hàng là 1 điểm dữ liệu.",[989,13247,13248],{},"Mỗi cột là 1 thuộc tính.",[989,13250,13251],{},"Gọi tên cột là lấy được cột.",[989,13253,13254],{},"Ví dụ đời thường: bảng lương mỗi dòng 1 nhân viên.",[981,13256,13258],{"id":13257},"lọc-cột-và-lọc-hàng","Lọc cột và lọc hàng",[986,13260,13261,13264,13267,13270,13273],{},[989,13262,13263],{},"Lọc cột là chọn vài cột quan tâm.",[989,13265,13266],{},"Lọc hàng là chọn hàng thỏa điều kiện.",[989,13268,13269],{},"Kết hợp cả 2 được lát cắt chính xác.",[989,13271,13272],{},"Ví dụ đời thường: lọc học sinh giỏi toán.",[989,13274,13275],{},"Chọn đặc trưng là lọc cột, chọn mẫu là lọc hàng.",[981,13277,13279],{"id":13278},"ma-trận-và-chi-phí","Ma trận và chi phí",[986,13281,13282,13285,13288,13291,13294],{},[989,13283,13284],{},"Ma trận là bảng số chữ nhật.",[989,13286,13287],{},"Cộng 2 ma trận thì duyệt từng ô.",[989,13289,13290],{},"Nhân 2 ma trận rất đắt, bậc 3.",[989,13292,13293],{},"Ví dụ đời thường: bảng điểm nhân trọng số.",[989,13295,13296,13297,13340],{},"Lưu theo cột thì thêm cột chỉ tốn ",[1023,13298,13300,13319],{"className":13299},[1026],[1023,13301,13303],{"className":13302},[1030],[1032,13304,13305],{"xmlns":1034},[1036,13306,13307,13317],{},[1039,13308,13309,13311,13313,13315],{},[1042,13310,1044],{},[1046,13312,1049],{"stretchy":1048},[1042,13314,1262],{},[1046,13316,1056],{"stretchy":1048},[1058,13318,1267],{"encoding":1060},[1023,13320,13322],{"className":13321,"ariaHidden":1066},[1065],[1023,13323,13325,13328,13331,13334,13337],{"className":13324},[1070],[1023,13326],{"className":13327,"style":1075},[1074],[1023,13329,1044],{"className":13330,"style":1081},[1079,1080],[1023,13332,1049],{"className":13333},[1085],[1023,13335,1262],{"className":13336},[1079,1080],[1023,13338,1056],{"className":13339},[1092]," để tạo dữ liệu cột mới, không phải chép lại cả bảng.",[1099,13342,13343,13353],{},[1102,13344,13345],{},[1105,13346,13347,13350],{},[1108,13348,13349],{},"Thao tác bảng",[1108,13351,13352],{},"Chi phí thường",[1118,13354,13355,13405,13456,13507],{},[1105,13356,13357,13360],{},[1123,13358,13359],{},"Chọn cột theo tên",[1123,13361,13362],{},[1023,13363,13365,13384],{"className":13364},[1026],[1023,13366,13368],{"className":13367},[1030],[1032,13369,13370],{"xmlns":1034},[1036,13371,13372,13382],{},[1039,13373,13374,13376,13378,13380],{},[1042,13375,1044],{},[1046,13377,1049],{"stretchy":1048},[1051,13379,1053],{},[1046,13381,1056],{"stretchy":1048},[1058,13383,1061],{"encoding":1060},[1023,13385,13387],{"className":13386,"ariaHidden":1066},[1065],[1023,13388,13390,13393,13396,13399,13402],{"className":13389},[1070],[1023,13391],{"className":13392,"style":1075},[1074],[1023,13394,1044],{"className":13395,"style":1081},[1079,1080],[1023,13397,1049],{"className":13398},[1085],[1023,13400,1053],{"className":13401},[1079],[1023,13403,1056],{"className":13404},[1092],[1105,13406,13407,13410],{},[1123,13408,13409],{},"Thêm cột mới",[1123,13411,13412,13455],{},[1023,13413,13415,13434],{"className":13414},[1026],[1023,13416,13418],{"className":13417},[1030],[1032,13419,13420],{"xmlns":1034},[1036,13421,13422,13432],{},[1039,13423,13424,13426,13428,13430],{},[1042,13425,1044],{},[1046,13427,1049],{"stretchy":1048},[1042,13429,1262],{},[1046,13431,1056],{"stretchy":1048},[1058,13433,1267],{"encoding":1060},[1023,13435,13437],{"className":13436,"ariaHidden":1066},[1065],[1023,13438,13440,13443,13446,13449,13452],{"className":13439},[1070],[1023,13441],{"className":13442,"style":1075},[1074],[1023,13444,1044],{"className":13445,"style":1081},[1079,1080],[1023,13447,1049],{"className":13448},[1085],[1023,13450,1262],{"className":13451},[1079,1080],[1023,13453,1056],{"className":13454},[1092]," cho cột mới",[1105,13457,13458,13461],{},[1123,13459,13460],{},"Lọc hàng",[1123,13462,13463,13506],{},[1023,13464,13466,13485],{"className":13465},[1026],[1023,13467,13469],{"className":13468},[1030],[1032,13470,13471],{"xmlns":1034},[1036,13472,13473,13483],{},[1039,13474,13475,13477,13479,13481],{},[1042,13476,1044],{},[1046,13478,1049],{"stretchy":1048},[1042,13480,1262],{},[1046,13482,1056],{"stretchy":1048},[1058,13484,1267],{"encoding":1060},[1023,13486,13488],{"className":13487,"ariaHidden":1066},[1065],[1023,13489,13491,13494,13497,13500,13503],{"className":13490},[1070],[1023,13492],{"className":13493,"style":1075},[1074],[1023,13495,1044],{"className":13496,"style":1081},[1079,1080],[1023,13498,1049],{"className":13499},[1085],[1023,13501,1262],{"className":13502},[1079,1080],[1023,13504,1056],{"className":13505},[1092]," theo số hàng",[1105,13508,13509,13512],{},[1123,13510,13511],{},"Cộng ma trận",[1123,13513,13514],{},"Theo số ô",[968,13516,1433],{"id":1432},[986,13518,13519,13522],{},[989,13520,13521],{},"Input: bảng 3 nhân viên, trích cột lương. Output: đúng 3 con số đúng thứ tự.",[989,13523,13524],{},"Giải thích: gọi tên cột là lấy được vector cột.",[968,13526,1482],{"id":1481},[973,13528,1485,13529,13532,13533,13536,13537,1517],{},[1487,13530,13531],{},"Python 3",", chỉ dùng thư viện chuẩn (",[992,13534,13535],{},"csv",") cho Bài 1-2. Bài 3 dùng thêm NumPy. Nộp vào ",[992,13538,13539],{},"day-014\u002F",[973,13541,13542,13543,4437],{},"Tạo file ",[992,13544,13545],{},"employees.csv",[1352,13547,13550],{"className":13548,"code":13549,"language":2241,"meta":1357},[2239],"name,dept,salary,years\nAn,IT,25000000,3\nBình,HR,15000000,5\nChi,IT,32000000,7\nDũng,Sales,18000000,2\nHà,IT,21000000,1\nKhoa,Sales,27000000,6\n",[992,13551,13549],{"__ignoreMap":1357},[981,13553,13555,13556,13559],{"id":13554},"bài-1-lớp-table-tối-giản","Bài 1: Lớp ",[992,13557,13558],{},"Table"," tối giản",[973,13561,6760,13562,13564,13565,13568,13569,1517],{},[992,13563,13558],{}," lưu dữ liệu theo ",[1487,13566,13567],{},"cột",": ",[992,13570,13571],{},"dict[str, list]",[1099,13573,13574,13583],{},[1102,13575,13576],{},[1105,13577,13578,13581],{},[1108,13579,13580],{},"Phương thức",[1108,13582,2547],{},[1118,13584,13585,13597,13609,13623,13635,13651,13664],{},[1105,13586,13587,13592],{},[1123,13588,13589],{},[992,13590,13591],{},"Table.from_csv(path)",[1123,13593,13594,13595],{},"Đọc file, tự đổi cột số thành ",[992,13596,1516],{},[1105,13598,13599,13604],{},[1123,13600,13601],{},[992,13602,13603],{},"shape()",[1123,13605,6693,13606],{},[992,13607,13608],{},"(số hàng, số cột)",[1105,13610,13611,13616],{},[1123,13612,13613],{},[992,13614,13615],{},"column(name)",[1123,13617,13618,13619,13622],{},"Trả list giá trị của cột. Sai tên thì ",[992,13620,13621],{},"KeyError"," rõ ràng",[1105,13624,13625,13630],{},[1123,13626,13627],{},[992,13628,13629],{},"select(*names)",[1123,13631,6693,13632,13634],{},[992,13633,13558],{}," mới chỉ có các cột đó",[1105,13636,13637,13642],{},[1123,13638,13639],{},[992,13640,13641],{},"where(pred)",[1123,13643,13644,13647,13648,13650],{},[992,13645,13646],{},"pred"," nhận dict một hàng, trả ",[992,13649,13558],{}," mới gồm hàng thỏa",[1105,13652,13653,13658],{},[1123,13654,13655],{},[992,13656,13657],{},"add_column(name, values)",[1123,13659,13660,13661],{},"Thêm cột. Sai độ dài thì ",[992,13662,13663],{},"ValueError",[1105,13665,13666,13671],{},[1123,13667,13668],{},[992,13669,13670],{},"row(i)",[1123,13672,13673,13674],{},"Trả dict của hàng ",[992,13675,1837],{},[1352,13677,13680],{"className":13678,"code":13679,"language":2241,"meta":1357},[2239],"t.shape()                                      -> (6, 4)\nt.column(\"salary\")[:2]                         -> [25000000, 15000000]\nt.where(lambda r: r[\"salary\"] > 20e6).shape()  -> (4, 4)\nt.select(\"name\", \"dept\").shape()               -> (6, 2)\n",[992,13681,13679],{"__ignoreMap":1357},[981,13683,13685],{"id":13684},"bài-2-group-by-và-xếp-loại","Bài 2: Group-by và xếp loại",[2273,13687,13688,13701,13724],{},[989,13689,13690,13693,13694,13697,13698,1517],{},[992,13691,13692],{},"group_mean(table, key, value)"," trả dict trung bình theo nhóm. ",[992,13695,13696],{},"group_mean(t, \"dept\", \"salary\")[\"IT\"]"," = ",[992,13699,13700],{},"26000000",[989,13702,13703,13704,13568,13707,13710,13711,1656,13714,13710,13717,13720,13721,1517],{},"Thêm cột ",[992,13705,13706],{},"level",[992,13708,13709],{},"years >= 5"," là ",[992,13712,13713],{},"\"senior\"",[992,13715,13716],{},">= 2",[992,13718,13719],{},"\"mid\"",", còn lại ",[992,13722,13723],{},"\"junior\"",[989,13725,13726],{},"In bảng dạng text căn cột thẳng hàng.",[981,13728,13730],{"id":13729},"bài-3-ma-trận-nâng-cao","Bài 3: Ma trận (nâng cao)",[2273,13732,13733,13745,13868],{},[989,13734,13735,13736,1509,13739,13742,13743,1517],{},"Tự viết ",[992,13737,13738],{},"mat_add(A, B)",[992,13740,13741],{},"mat_mul(A, B)"," bằng list lồng nhau. Sai kích thước thì ",[992,13744,13663],{},[989,13746,13747,13748,13751,13752,13807,13808,1517],{},"Đếm số phép nhân trong ",[992,13749,13750],{},"mat_mul"," cho ma trận ",[1023,13753,13755,13774],{"className":13754},[1026],[1023,13756,13758],{"className":13757},[1030],[1032,13759,13760],{"xmlns":1034},[1036,13761,13762,13771],{},[1039,13763,13764,13766,13769],{},[1042,13765,1262],{},[1046,13767,13768],{},"×",[1042,13770,1262],{},[1058,13772,13773],{"encoding":1060},"n \\times n",[1023,13775,13777,13798],{"className":13776,"ariaHidden":1066},[1065],[1023,13778,13780,13784,13787,13791,13795],{"className":13779},[1070],[1023,13781],{"className":13782,"style":13783},[1074],"height:0.6667em;vertical-align:-0.0833em;",[1023,13785,1262],{"className":13786},[1079,1080],[1023,13788],{"className":13789,"style":13790},[2354],"margin-right:0.2222em;",[1023,13792,13768],{"className":13793},[13794],"mbin",[1023,13796],{"className":13797,"style":13790},[2354],[1023,13799,13801,13804],{"className":13800},[1070],[1023,13802],{"className":13803,"style":2347},[1074],[1023,13805,1262],{"className":13806},[1079,1080],". Kiểm tra bằng ",[1023,13809,13811,13830],{"className":13810},[1026],[1023,13812,13814],{"className":13813},[1030],[1032,13815,13816],{"xmlns":1034},[1036,13817,13818,13827],{},[1039,13819,13820],{},[2327,13821,13822,13824],{},[1042,13823,1262],{},[1051,13825,13826],{},"3",[1058,13828,13829],{"encoding":1060},"n^3",[1023,13831,13833],{"className":13832,"ariaHidden":1066},[1065],[1023,13834,13836,13839],{"className":13835},[1070],[1023,13837],{"className":13838,"style":2369},[1074],[1023,13840,13842,13845],{"className":13841},[1079],[1023,13843,1262],{"className":13844},[1079,1080],[1023,13846,13848],{"className":13847},[2383],[1023,13849,13851],{"className":13850},[2387],[1023,13852,13854],{"className":13853},[2391],[1023,13855,13857],{"className":13856,"style":2369},[2395],[1023,13858,13859,13862],{"style":2398},[1023,13860],{"className":13861,"style":2403},[2402],[1023,13863,13865],{"className":13864},[2407,2408,2409,2410],[1023,13866,13826],{"className":13867},[1079,2410],[989,13869,6845,13870,13872,13873,7386,13876,1517],{},[992,13871,13750],{}," tự viết và ",[992,13874,13875],{},"numpy.matmul",[1023,13877,13879,13909],{"className":13878},[1026],[1023,13880,13882],{"className":13881},[1030],[1032,13883,13884],{"xmlns":1034},[1036,13885,13886,13906],{},[1039,13887,13888,13890,13892,13895,13898,13901,13903],{},[1042,13889,1262],{},[1046,13891,2325],{},[1051,13893,13894],{},"50",[1046,13896,13897],{"separator":1066},",",[1051,13899,13900],{},"100",[1046,13902,13897],{"separator":1066},[1051,13904,13905],{},"200",[1058,13907,13908],{"encoding":1060},"n = 50, 100, 200",[1023,13910,13912,13930],{"className":13911,"ariaHidden":1066},[1065],[1023,13913,13915,13918,13921,13924,13927],{"className":13914},[1070],[1023,13916],{"className":13917,"style":2347},[1074],[1023,13919,1262],{"className":13920},[1079,1080],[1023,13922],{"className":13923,"style":2355},[2354],[1023,13925,2325],{"className":13926},[2359],[1023,13928],{"className":13929,"style":2355},[2354],[1023,13931,13933,13937,13940,13944,13947,13950,13953,13956],{"className":13932},[1070],[1023,13934],{"className":13935,"style":13936},[1074],"height:0.8389em;vertical-align:-0.1944em;",[1023,13938,13894],{"className":13939},[1079],[1023,13941,13897],{"className":13942},[13943],"mpunct",[1023,13945],{"className":13946,"style":8434},[2354],[1023,13948,13900],{"className":13949},[1079],[1023,13951,13897],{"className":13952},[13943],[1023,13954],{"className":13955,"style":8434},[2354],[1023,13957,13905],{"className":13958},[1079],[1352,13960,13963],{"className":13961,"code":13962,"language":2241,"meta":1357},[2239],"mat_add([[1,2],[3,4]], [[5,6],[7,8]]) -> [[6,8],[10,12]]\nmat_mul([[1,2],[3,4]], [[5,6],[7,8]]) -> [[19,22],[43,50]]\n",[992,13964,13962],{"__ignoreMap":1357},[981,13966,2711],{"id":2710},[986,13968,13970,13982,13994,14000],{"className":13969},[2715],[989,13971,13973,13975,13976,2528,13978,13981],{"className":13972},[2719],[2721,13974],{"disabled":2723,"type":2724}," Test mẫu viết bằng ",[992,13977,2235],{},[992,13979,13980],{},"test_table.py"," pass.",[989,13983,13985,2308,13987,1509,13990,13993],{"className":13984},[2719],[2721,13986],{"disabled":2723,"type":2724},[992,13988,13989],{},"where",[992,13991,13992],{},"select"," trả bảng mới, không sửa bảng gốc.",[989,13995,13997,13999],{"className":13996},[2719],[2721,13998],{"disabled":2723,"type":2724}," Bảng thời gian Bài 3 có số thật và 2 câu giải thích vì sao NumPy nhanh hơn.",[989,14001,14003,14005,14006,14009,14010,14013],{"className":14002},[2719],[2721,14004],{"disabled":2723,"type":2724}," Giải thích được vì sao lưu theo cột giúp ",[992,14007,14008],{},"column()"," rẻ, còn ",[992,14011,14012],{},"row()"," đắt hơn.",[968,14015,2890],{"id":2889},[986,14017,14018,14021,14024,14027],{},[989,14019,14020],{},"Hàng và cột trong bảng là gì?",[989,14022,14023],{},"Lọc cột khác lọc hàng thế nào?",[989,14025,14026],{},"Thêm cột tốn bao nhiêu?",[989,14028,14029],{},"Ma trận nhân nhau có đắt không?",[3014,14031],{},[973,14033,14034],{},"🌕 Bạn đã hoàn thành ngày 14. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":14036},[14037,14038,14043,14044,14051],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":14039},[14040,14041,14042],{"id":13239,"depth":73,"text":13240},{"id":13257,"depth":73,"text":13258},{"id":13278,"depth":73,"text":13279},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":14045},[14046,14048,14049,14050],{"id":13554,"depth":73,"text":14047},"Bài 1: Lớp Table tối giản",{"id":13684,"depth":73,"text":13685},{"id":13729,"depth":73,"text":13730},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Làm chủ ma trận và bảng dữ liệu dạng hàng cột cùng độ phức tạp thao tác: hàng là điểm dữ liệu, cột là thuộc tính, trục xác định hướng tính toán.",{},[3050,14055],"chieu-du-lieu-va-tinh-toan",{"title":125,"description":14052},[14058],"matrix","J_znhBbEjp0k04R2Vr3_LnVRb1Sqw_vkb36cJfufH-A",{"id":14061,"title":130,"body":14062,"category":5189,"day":133,"description":14443,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":14444,"navigation":2723,"outcomes":3047,"path":131,"prerequisites":14445,"seo":14446,"stem":132,"tags":14447,"__hash__":14449},"challenges\u002Fchallenges\u002F15.observer-nang-cao.md",{"type":965,"value":14063,"toc":14427},[14064,14066,14069,14071,14075,14089,14093,14107,14111,14125,14174,14176,14184,14186,14194,14198,14231,14286,14292,14296,14310,14326,14330,14347,14366,14372,14374,14404,14406,14420,14422,14425],[968,14065,971],{"id":970},[973,14067,14068],{},"Bài này học 2 cách truyền tin đẩy và kéo. Bạn chọn đúng cách cho từng bảng.",[968,14070,979],{"id":978},[981,14072,14074],{"id":14073},"đẩy-gửi-cả-gói","Đẩy — gửi cả gói",[986,14076,14077,14080,14083,14086],{},[989,14078,14079],{},"Trạm gửi kèm toàn bộ số đo trong tin báo.",[989,14081,14082],{},"Bảng nhận 1 bước là đủ, khỏi hỏi lại.",[989,14084,14085],{},"Nhược điểm là bảng nào cũng nhận thừa.",[989,14087,14088],{},"Ví dụ đời thường: phát cả tờ báo dù chỉ đọc 1 tin.",[981,14090,14092],{"id":14091},"kéo-báo-rồi-tự-lấy","Kéo — báo rồi tự lấy",[986,14094,14095,14098,14101,14104],{},[989,14096,14097],{},"Trạm chỉ báo tin ngắn đã đổi.",[989,14099,14100],{},"Bảng cần gì thì tới lấy đúng phần đó.",[989,14102,14103],{},"Thêm chỉ số mới không làm bảng cũ hỏng.",[989,14105,14106],{},"Ví dụ đời thường: tin nhắn có hàng, tới lấy món mình.",[981,14108,14110],{"id":14109},"cờ-đã-đổi-và-hàng-dựng-sẵn","Cờ đã đổi và hàng dựng sẵn",[986,14112,14113,14116,14119,14122],{},[989,14114,14115],{},"Số mới giống số cũ thì khỏi báo.",[989,14117,14118],{},"Cờ đã đổi giúp tránh vẽ lại vô ích.",[989,14120,14121],{},"Hàng dựng sẵn nhanh nhưng khóa cứng và khó đổi.",[989,14123,14124],{},"Ví dụ đời thường: giá không đổi thì khỏi hét.",[1099,14126,14127,14139],{},[1102,14128,14129],{},[1105,14130,14131,14133,14136],{},[1108,14132,5414],{},[1108,14134,14135],{},"Đẩy",[1108,14137,14138],{},"Kéo",[1118,14140,14141,14152,14163],{},[1105,14142,14143,14146,14149],{},[1123,14144,14145],{},"Số bước",[1123,14147,14148],{},"1 bước nhận đủ",[1123,14150,14151],{},"2 bước báo rồi lấy",[1105,14153,14154,14157,14160],{},[1123,14155,14156],{},"Nhận thừa",[1123,14158,14159],{},"Hay thừa",[1123,14161,14162],{},"Chỉ lấy phần cần",[1105,14164,14165,14168,14171],{},[1123,14166,14167],{},"Thêm chỉ số mới",[1123,14169,14170],{},"Nhiều bảng phải sửa",[1123,14172,14173],{},"Bảng cũ nguyên vẹn",[968,14175,1433],{"id":1432},[986,14177,14178,14181],{},[989,14179,14180],{},"Input: số mới khác số cũ, 3 bảng đang nghe. Output: cả 3 kéo đúng phần mình và vẽ lại.",[989,14182,14183],{},"Giải thích: trạm dựng cờ rồi báo tin ngắn.",[968,14185,1482],{"id":1481},[973,14187,1485,14188,4801,14190,14193],{},[1487,14189,4800],{},[992,14191,14192],{},"day-015\u002F",". Dùng lại trạm thời tiết ngày 9.",[981,14195,14197],{"id":14196},"bài-1-chuyển-trạm-từ-đẩy-sang-kéo","Bài 1: Chuyển trạm từ đẩy sang kéo",[1352,14199,14201],{"className":1393,"code":14200,"language":1395,"meta":1357,"style":1357},"struct Observer { virtual void update(Subject &changed) = 0; virtual ~Observer() = default; };\nclass WeatherData : public Subject {\n public:\n  float temperature() const; float humidity() const; float pressure() const;\n  void setMeasurements(float t, float h, float p);\n};\n",[992,14202,14203,14208,14213,14217,14222,14227],{"__ignoreMap":1357},[1023,14204,14205],{"class":1362,"line":63},[1023,14206,14207],{},"struct Observer { virtual void update(Subject &changed) = 0; virtual ~Observer() = default; };\n",[1023,14209,14210],{"class":1362,"line":68},[1023,14211,14212],{},"class WeatherData : public Subject {\n",[1023,14214,14215],{"class":1362,"line":73},[1023,14216,4836],{},[1023,14218,14219],{"class":1362,"line":78},[1023,14220,14221],{},"  float temperature() const; float humidity() const; float pressure() const;\n",[1023,14223,14224],{"class":1362,"line":83},[1023,14225,14226],{},"  void setMeasurements(float t, float h, float p);\n",[1023,14228,14229],{"class":1362,"line":88},[1023,14230,4866],{},[1099,14232,14233,14242],{},[1102,14234,14235],{},[1105,14236,14237,14239],{},[1108,14238,2547],{},[1108,14240,14241],{},"Chi tiết",[1118,14243,14244,14255,14272],{},[1105,14245,14246,14249],{},[1123,14247,14248],{},"Chỉ báo tin ngắn",[1123,14250,14251,14254],{},[992,14252,14253],{},"update(*this)",", observer tự gọi getter cần thiết",[1105,14256,14257,14263],{},[1123,14258,14259,14260],{},"Cờ ",[992,14261,14262],{},"changed",[1123,14264,14265,14268,14269,14271],{},[992,14266,14267],{},"setChanged()"," bật cờ; ",[992,14270,8997],{}," chỉ báo khi cờ bật rồi tắt cờ",[1105,14273,14274,14277],{},[1123,14275,14276],{},"Bỏ qua thay đổi nhỏ",[1123,14278,14279,14282,14283,14285],{},[992,14280,14281],{},"setMeasurements"," chỉ ",[992,14284,14267],{}," khi nhiệt độ lệch ít nhất 0.5 độ so với lần báo trước",[1352,14287,14290],{"className":14288,"code":14289,"language":2241,"meta":1357},[2239],"set(26.0, 65, 1012)  -> báo\nset(26.3, 66, 1012)  -> KHÔNG báo (lệch 0.3)\nset(26.6, 66, 1011)  -> báo\n",[992,14291,14289],{"__ignoreMap":1357},[981,14293,14295],{"id":14294},"bài-2-thêm-chỉ-số-không-khí","Bài 2: Thêm chỉ số không khí",[973,14297,5030,14298,8530,14301,1509,14303,14306,14307,1517],{},[992,14299,14300],{},"int aqi() const",[992,14302,9052],{},[992,14304,14305],{},"AirQualityDisplay"," in cảnh báo khi ",[992,14308,14309],{},"aqi > 150",[973,14311,14312,14314,14315,14317,14318,14321,14322,14325],{},[1487,14313,4871],{}," 3 display cũ không sửa dòng nào. Trong ",[992,14316,2513],{}," chứng minh bằng ",[992,14319,14320],{},"git diff --stat",". Viết thêm 3 câu: nếu vẫn dùng kiểu đẩy ",[992,14323,14324],{},"update(t, h, p)"," thì phải sửa những gì.",[981,14327,14329],{"id":14328},"bài-3-một-bảng-nghe-hai-trạm-nâng-cao","Bài 3: Một bảng nghe hai trạm (nâng cao)",[973,14331,14332,14335,14336,1509,14339,14342,14343,14346],{},[992,14333,14334],{},"IndoorOutdoorDisplay"," đăng ký cả ",[992,14337,14338],{},"indoor",[992,14340,14341],{},"outdoor",". Khi ",[992,14344,14345],{},"update(Subject &s)"," được gọi, bảng phân biệt nguồn bằng so sánh địa chỉ và in chênh lệch nhiệt độ trong-ngoài.",[973,14348,14349,14350,7386,14353,13710,14356,1656,14359,1656,14362,14365],{},"Thêm cơ chế đăng ký theo chủ đề: ",[992,14351,14352],{},"subscribe(topic, observer)",[992,14354,14355],{},"topic",[992,14357,14358],{},"\"temperature\"",[992,14360,14361],{},"\"humidity\"",[992,14363,14364],{},"\"aqi\"",". Trạm chỉ báo observer của chủ đề vừa đổi.",[1352,14367,14370],{"className":14368,"code":14369,"language":2241,"meta":1357},[2239],"indoor.set(24,...), outdoor.set(31,...) -> \"Ngoài nóng hơn trong 7.0C\"\nđổi mỗi humidity                         -> observer chỉ đăng ký \"temperature\" không nhận tin\n",[992,14371,14369],{"__ignoreMap":1357},[981,14373,2711],{"id":2710},[986,14375,14377,14386,14392,14398],{"className":14376},[2715],[989,14378,14380,14382,14383,14385],{"className":14379},[2719],[2721,14381],{"disabled":2723,"type":2724}," Test mẫu Bài 1 pass: đếm đúng số lần ",[992,14384,9170],{}," được gọi.",[989,14387,14389,14391],{"className":14388},[2719],[2721,14390],{"disabled":2723,"type":2724}," Bài 2: 3 display cũ không đổi.",[989,14393,14395,14397],{"className":14394},[2719],[2721,14396],{"disabled":2723,"type":2724}," Bài 3 phân biệt đúng 2 nguồn và lọc đúng theo chủ đề.",[989,14399,14401,14403],{"className":14400},[2719],[2721,14402],{"disabled":2723,"type":2724}," Lập bảng đẩy và kéo với số liệu thật từ code của mình (số lần gọi getter, số byte thừa).",[968,14405,2890],{"id":2889},[986,14407,14408,14411,14414,14417],{},[989,14409,14410],{},"Đẩy khác kéo ở điểm nào?",[989,14412,14413],{},"Khi nào nên dùng kéo?",[989,14415,14416],{},"Cờ đã đổi để làm gì?",[989,14418,14419],{},"Hàng dựng sẵn có nhược điểm gì?",[3014,14421],{},[973,14423,14424],{},"🌕 Bạn đã hoàn thành ngày 15. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,14426,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":14428},[14429,14430,14435,14436,14442],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":14431},[14432,14433,14434],{"id":14073,"depth":73,"text":14074},{"id":14091,"depth":73,"text":14092},{"id":14109,"depth":73,"text":14110},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":14437},[14438,14439,14440,14441],{"id":14196,"depth":73,"text":14197},{"id":14294,"depth":73,"text":14295},{"id":14328,"depth":73,"text":14329},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"So sánh mô hình đẩy và kéo dữ liệu, bài toán bảng chỉ cần một phần số đo, và Observer có sẵn trong thư viện.",{},[5194],{"title":130,"description":14443},[9251,14448],"pull-push","1D59Z4iYPUsHdpV9T3cLauaVGbc2OTUPiZ1jEy2nyTo",{"id":14451,"title":135,"body":14452,"category":8797,"day":138,"description":15140,"difficulty":3043,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":15141,"navigation":2723,"outcomes":3047,"path":136,"prerequisites":15142,"seo":15145,"stem":137,"tags":15146,"__hash__":15149},"challenges\u002Fchallenges\u002F16.brute-force-va-greedy.md",{"type":965,"value":14453,"toc":15124},[14454,14456,14459,14461,14465,14479,14483,14500,14504,14518,14556,14558,14566,14568,14580,14584,14619,14625,14774,14778,14784,14928,14932,14946,14952,14954,15103,15105,15119,15121],[968,14455,971],{"id":970},[973,14457,14458],{},"Bài này học vét cạn và tham lam qua giao hàng. Bạn hiểu nhanh và chuẩn khó cùng lúc.",[968,14460,979],{"id":978},[981,14462,14464],{"id":14463},"tsp-thăm-mỗi-nơi-1-lần","TSP — thăm mỗi nơi 1 lần",[986,14466,14467,14470,14473,14476],{},[989,14468,14469],{},"Vào là n thành phố và khoảng cách.",[989,14471,14472],{},"Ra là tour ngắn nhất quay về chỗ cũ.",[989,14474,14475],{},"Ví dụ đời thường: shipper đi 1 vòng giao hết đơn.",[989,14477,14478],{},"Phát biểu dễ nhưng giải tối ưu rất khó.",[981,14480,14482],{"id":14481},"vét-cạn-thử-hết","Vét cạn — thử hết",[986,14484,14485,14488,14491,14494,14497],{},[989,14486,14487],{},"Liệt kê mọi tour rồi chọn ngắn nhất.",[989,14489,14490],{},"n thành phố có (n-1)! tour.",[989,14492,14493],{},"5 nơi còn làm tay, 10 nơi máy cũng đuối.",[989,14495,14496],{},"Ví dụ đời thường: thử mọi đường đi rồi so.",[989,14498,14499],{},"Chuẩn tuyệt đối nhưng chỉ dùng khi n nhỏ.",[981,14501,14503],{"id":14502},"tham-lam-gần-thì-đi-trước","Tham lam — gần thì đi trước",[986,14505,14506,14509,14512,14515],{},[989,14507,14508],{},"Mỗi bước đi tới nơi gần nhất chưa thăm.",[989,14510,14511],{},"Nhanh nhưng hay sập bẫy đường cuối dài.",[989,14513,14514],{},"Ví dụ đời thường: thấy quán gần là ghé luôn.",[989,14516,14517],{},"Hợp khi cần nhanh, chấp nhận gần đúng.",[1099,14519,14520,14532],{},[1102,14521,14522],{},[1105,14523,14524,14527,14530],{},[1108,14525,14526],{},"Cách",[1108,14528,14529],{},"Chất lượng",[1108,14531,12359],{},[1118,14533,14534,14545],{},[1105,14535,14536,14539,14542],{},[1123,14537,14538],{},"Vét cạn",[1123,14540,14541],{},"Chuẩn",[1123,14543,14544],{},"Giai thừa, rất chậm",[1105,14546,14547,14550,14553],{},[1123,14548,14549],{},"Tham lam",[1123,14551,14552],{},"Gần đúng",[1123,14554,14555],{},"Nhanh đa thức",[968,14557,1433],{"id":1432},[986,14559,14560,14563],{},[989,14561,14562],{},"Input: 3 nơi cách đều 10. Output: mọi tour dài 30.",[989,14564,14565],{},"Giải thích: đường nào cũng bằng nhau nên 2 cách đồng thuận.",[968,14567,1482],{"id":1481},[973,14569,1485,14570,5599,14572,14575,14576,14579],{},[1487,14571,1493],{},[992,14573,14574],{},"day-016\u002F",". Khoảng cách là ma trận đối xứng ",[992,14577,14578],{},"std::vector\u003Cstd::vector\u003Cdouble>>",", tour bắt đầu và kết thúc ở thành phố 0.",[981,14581,14583],{"id":14582},"bài-1-vét-cạn-tsp","Bài 1: Vét cạn TSP",[1099,14585,14586,14594],{},[1102,14587,14588],{},[1105,14589,14590,14592],{},[1108,14591,1566],{},[1108,14593,2547],{},[1118,14595,14596,14606],{},[1105,14597,14598,14603],{},[1123,14599,14600],{},[992,14601,14602],{},"double tourLength(const Matrix &d, const std::vector\u003Cint> &tour)",[1123,14604,14605],{},"Tổng các chặng, cộng chặng quay về",[1105,14607,14608,14613],{},[1123,14609,14610],{},[992,14611,14612],{},"std::pair\u003Cdouble, std::vector\u003Cint>> bruteForce(const Matrix &d)",[1123,14614,14615,14616],{},"Cố định thành phố 0, thử mọi hoán vị còn lại bằng ",[992,14617,14618],{},"std::next_permutation",[1352,14620,14623],{"className":14621,"code":14622,"language":2241,"meta":1357},[2239],"4 thành phố:\n     A  B  C  D\nA    0 10 15 20\nB   10  0 35 25\nC   15 35  0 30\nD   20 25 30  0\nbruteForce -> 80, tour A B D C A\n",[992,14624,14622],{"__ignoreMap":1357},[973,14626,14627,14628,14720,14721,14773],{},"Đo thời gian với ",[1023,14629,14631,14663],{"className":14630},[1026],[1023,14632,14634],{"className":14633},[1030],[1032,14635,14636],{"xmlns":1034},[1036,14637,14638,14660],{},[1039,14639,14640,14642,14644,14646,14648,14651,14653,14655,14657],{},[1042,14641,1262],{},[1046,14643,2325],{},[1051,14645,6866],{},[1046,14647,13897],{"separator":1066},[1051,14649,14650],{},"8",[1046,14652,13897],{"separator":1066},[1051,14654,2331],{},[1046,14656,13897],{"separator":1066},[1051,14658,14659],{},"11",[1058,14661,14662],{"encoding":1060},"n = 6, 8, 10, 11",[1023,14664,14666,14684],{"className":14665,"ariaHidden":1066},[1065],[1023,14667,14669,14672,14675,14678,14681],{"className":14668},[1070],[1023,14670],{"className":14671,"style":2347},[1074],[1023,14673,1262],{"className":14674},[1079,1080],[1023,14676],{"className":14677,"style":2355},[2354],[1023,14679,2325],{"className":14680},[2359],[1023,14682],{"className":14683,"style":2355},[2354],[1023,14685,14687,14690,14693,14696,14699,14702,14705,14708,14711,14714,14717],{"className":14686},[1070],[1023,14688],{"className":14689,"style":13936},[1074],[1023,14691,6866],{"className":14692},[1079],[1023,14694,13897],{"className":14695},[13943],[1023,14697],{"className":14698,"style":8434},[2354],[1023,14700,14650],{"className":14701},[1079],[1023,14703,13897],{"className":14704},[13943],[1023,14706],{"className":14707,"style":8434},[2354],[1023,14709,2331],{"className":14710},[1079],[1023,14712,13897],{"className":14713},[13943],[1023,14715],{"className":14716,"style":8434},[2354],[1023,14718,14659],{"className":14719},[1079],". In bảng và ước lượng ",[1023,14722,14724,14743],{"className":14723},[1026],[1023,14725,14727],{"className":14726},[1030],[1032,14728,14729],{"xmlns":1034},[1036,14730,14731,14740],{},[1039,14732,14733,14735,14737],{},[1042,14734,1262],{},[1046,14736,2325],{},[1051,14738,14739],{},"15",[1058,14741,14742],{"encoding":1060},"n = 15",[1023,14744,14746,14764],{"className":14745,"ariaHidden":1066},[1065],[1023,14747,14749,14752,14755,14758,14761],{"className":14748},[1070],[1023,14750],{"className":14751,"style":2347},[1074],[1023,14753,1262],{"className":14754},[1079,1080],[1023,14756],{"className":14757,"style":2355},[2354],[1023,14759,2325],{"className":14760},[2359],[1023,14762],{"className":14763,"style":2355},[2354],[1023,14765,14767,14770],{"className":14766},[1070],[1023,14768],{"className":14769,"style":10020},[1074],[1023,14771,14739],{"className":14772},[1079]," mất bao lâu.",[981,14775,14777],{"id":14776},"bài-2-tham-lam-láng-giềng-gần-nhất","Bài 2: Tham lam láng giềng gần nhất",[973,14779,1505,14780,14783],{},[992,14781,14782],{},"nearestNeighbor(const Matrix &d, int start)",". Mỗi bước tới thành phố gần nhất chưa thăm. Hòa thì chọn chỉ số nhỏ hơn.",[2273,14785,14786,14789],{},[989,14787,14788],{},"Chạy với mọi điểm xuất phát, lấy tour tốt nhất.",[989,14790,14791,14792,14876,14877,1517],{},"Sinh 200 điểm ngẫu nhiên trên mặt phẳng ",[1023,14793,14795,14823],{"className":14794},[1026],[1023,14796,14798],{"className":14797},[1030],[1032,14799,14800],{"xmlns":1034},[1036,14801,14802,14820],{},[1039,14803,14804,14807,14809,14811,14813],{},[1046,14805,14806],{"stretchy":1048},"[",[1051,14808,2379],{},[1046,14810,13897],{"separator":1066},[1051,14812,9989],{},[2327,14814,14815,14818],{},[1046,14816,14817],{"stretchy":1048},"]",[1051,14819,2457],{},[1058,14821,14822],{"encoding":1060},"[0, 1000]^2",[1023,14824,14826],{"className":14825,"ariaHidden":1066},[1065],[1023,14827,14829,14832,14835,14838,14841,14844,14847],{"className":14828},[1070],[1023,14830],{"className":14831,"style":2476},[1074],[1023,14833,14806],{"className":14834},[1085],[1023,14836,2379],{"className":14837},[1079],[1023,14839,13897],{"className":14840},[13943],[1023,14842],{"className":14843,"style":8434},[2354],[1023,14845,9989],{"className":14846},[1079],[1023,14848,14850,14853],{"className":14849},[1092],[1023,14851,14817],{"className":14852},[1092],[1023,14854,14856],{"className":14855},[2383],[1023,14857,14859],{"className":14858},[2387],[1023,14860,14862],{"className":14861},[2391],[1023,14863,14865],{"className":14864,"style":2369},[2395],[1023,14866,14867,14870],{"style":2398},[1023,14868],{"className":14869,"style":2403},[2402],[1023,14871,14873],{"className":14872},[2407,2408,2409,2410],[1023,14874,2457],{"className":14875},[1079,2410]," (seed cố định). So độ dài và thời gian với bruteForce ở ",[1023,14878,14880,14898],{"className":14879},[1026],[1023,14881,14883],{"className":14882},[1030],[1032,14884,14885],{"xmlns":1034},[1036,14886,14887,14895],{},[1039,14888,14889,14891,14893],{},[1042,14890,1262],{},[1046,14892,2325],{},[1051,14894,2331],{},[1058,14896,14897],{"encoding":1060},"n = 10",[1023,14899,14901,14919],{"className":14900,"ariaHidden":1066},[1065],[1023,14902,14904,14907,14910,14913,14916],{"className":14903},[1070],[1023,14905],{"className":14906,"style":2347},[1074],[1023,14908,1262],{"className":14909},[1079,1080],[1023,14911],{"className":14912,"style":2355},[2354],[1023,14914,2325],{"className":14915},[2359],[1023,14917],{"className":14918,"style":2355},[2354],[1023,14920,14922,14925],{"className":14921},[1070],[1023,14923],{"className":14924,"style":10020},[1074],[1023,14926,2331],{"className":14927},[1079],[981,14929,14931],{"id":14930},"bài-3-bẫy-tham-lam-nâng-cao","Bài 3: Bẫy tham lam (nâng cao)",[2273,14933,14934,14939],{},[989,14935,14936,14937,1517],{},"Tự thiết kế ma trận 5 thành phố mà tour tham lam từ 0 dài hơn tối ưu ít nhất 25%. Ghi ma trận và 2 tour vào ",[992,14938,2513],{},[989,14940,14941,14942,14945],{},"Chạy 1000 bộ 9 điểm ngẫu nhiên. In tỉ lệ ",[992,14943,14944],{},"greedy \u002F optimal"," trung bình và lớn nhất.",[1352,14947,14950],{"className":14948,"code":14949,"language":2241,"meta":1357},[2239],"Kết quả mẫu: avg ratio ~1.1-1.25, max ratio > 1.4\n",[992,14951,14949],{"__ignoreMap":1357},[981,14953,2711],{"id":2710},[986,14955,14957,14963,14969,14975],{"className":14956},[2715],[989,14958,14960,14962],{"className":14959},[2719],[2721,14961],{"disabled":2723,"type":2724}," Ví dụ 4 thành phố ra đúng 80.",[989,14964,14966,14968],{"className":14965},[2719],[2721,14967],{"disabled":2723,"type":2724}," Bảng thời gian vét cạn cho thấy tăng theo giai thừa.",[989,14970,14972,14974],{"className":14971},[2719],[2721,14973],{"disabled":2723,"type":2724}," Có ma trận bẫy tự thiết kế kèm giải thích.",[989,14976,14978,14980,14981,15029,15030,1517],{"className":14977},[2719],[2721,14979],{"disabled":2723,"type":2724}," Nêu được độ phức tạp: vét cạn ",[1023,14982,14984,15007],{"className":14983},[1026],[1023,14985,14987],{"className":14986},[1030],[1032,14988,14989],{"xmlns":1034},[1036,14990,14991,15004],{},[1039,14992,14993,14995,14997,14999,15002],{},[1042,14994,1044],{},[1046,14996,1049],{"stretchy":1048},[1042,14998,1262],{},[1046,15000,15001],{"stretchy":1048},"!",[1046,15003,1056],{"stretchy":1048},[1058,15005,15006],{"encoding":1060},"O(n!)",[1023,15008,15010],{"className":15009,"ariaHidden":1066},[1065],[1023,15011,15013,15016,15019,15022,15025],{"className":15012},[1070],[1023,15014],{"className":15015,"style":1075},[1074],[1023,15017,1044],{"className":15018,"style":1081},[1079,1080],[1023,15020,1049],{"className":15021},[1085],[1023,15023,1262],{"className":15024},[1079,1080],[1023,15026,15028],{"className":15027},[1092],"!)",", tham lam ",[1023,15031,15033,15056],{"className":15032},[1026],[1023,15034,15036],{"className":15035},[1030],[1032,15037,15038],{"xmlns":1034},[1036,15039,15040,15054],{},[1039,15041,15042,15044,15046,15052],{},[1042,15043,1044],{},[1046,15045,1049],{"stretchy":1048},[2327,15047,15048,15050],{},[1042,15049,1262],{},[1051,15051,2457],{},[1046,15053,1056],{"stretchy":1048},[1058,15055,2839],{"encoding":1060},[1023,15057,15059],{"className":15058,"ariaHidden":1066},[1065],[1023,15060,15062,15065,15068,15071,15100],{"className":15061},[1070],[1023,15063],{"className":15064,"style":2476},[1074],[1023,15066,1044],{"className":15067,"style":1081},[1079,1080],[1023,15069,1049],{"className":15070},[1085],[1023,15072,15074,15077],{"className":15073},[1079],[1023,15075,1262],{"className":15076},[1079,1080],[1023,15078,15080],{"className":15079},[2383],[1023,15081,15083],{"className":15082},[2387],[1023,15084,15086],{"className":15085},[2391],[1023,15087,15089],{"className":15088,"style":2369},[2395],[1023,15090,15091,15094],{"style":2398},[1023,15092],{"className":15093,"style":2403},[2402],[1023,15095,15097],{"className":15096},[2407,2408,2409,2410],[1023,15098,2457],{"className":15099},[1079,2410],[1023,15101,1056],{"className":15102},[1092],[968,15104,2890],{"id":2889},[986,15106,15107,15110,15113,15116],{},[989,15108,15109],{},"TSP vào ra là gì?",[989,15111,15112],{},"Vì sao vét cạn chỉ dùng khi n nhỏ?",[989,15114,15115],{},"Tham lam đi thế nào?",[989,15117,15118],{},"Khi nào chấp nhận nghiệm gần đúng?",[3014,15120],{},[973,15122,15123],{},"🌕 Bạn đã hoàn thành ngày 16. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":15125},[15126,15127,15132,15133,15139],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":15128},[15129,15130,15131],{"id":14463,"depth":73,"text":14464},{"id":14481,"depth":73,"text":14482},{"id":14502,"depth":73,"text":14503},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":15134},[15135,15136,15137,15138],{"id":14582,"depth":73,"text":14583},{"id":14776,"depth":73,"text":14777},{"id":14930,"depth":73,"text":14931},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Dùng bài toán người bán hàng rong để hiểu vét cạn tối ưu nhưng mũ giai thừa và tham lam nhanh nhưng chỉ gần đúng.",{},[15143,15144],"p-np-va-do-kho","thiet-ke-va-kiem-chung-thuat-toan",{"title":135,"description":15140},[15147,15148],"brute-force","greedy","CM3SzdpblTePAjRe7aaNslK7vYNuuZGxU7XT-db0atM",{"id":15151,"title":140,"body":15152,"category":8797,"day":143,"description":15586,"difficulty":3043,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":15587,"navigation":2723,"outcomes":3047,"path":141,"prerequisites":15588,"seo":15589,"stem":142,"tags":15590,"__hash__":15592},"challenges\u002Fchallenges\u002F17.quy-hoach-dong-nhap-mon.md",{"type":965,"value":15153,"toc":15570},[15154,15156,15159,15161,15165,15179,15183,15197,15201,15215,15261,15263,15271,15273,15281,15285,15291,15346,15352,15356,15366,15388,15394,15398,15408,15510,15516,15518,15549,15551,15565,15567],[968,15155,971],{"id":970},[973,15157,15158],{},"Bài này học cách giải từ bài nhỏ đi lên. Bạn dùng bảng nhớ để khỏi tính lại.",[968,15160,979],{"id":978},[981,15162,15164],{"id":15163},"từ-dưới-lên-khác-từ-trên-xuống","Từ dưới lên khác từ trên xuống",[986,15166,15167,15170,15173,15176],{},[989,15168,15169],{},"Chia để trị bổ bài lớn thành mảnh độc lập.",[989,15171,15172],{},"Quy hoạch động giải bài nhỏ rồi dựng bài lớn.",[989,15174,15175],{},"Hợp khi bài con gối nhau, lặp lại nhiều lần.",[989,15177,15178],{},"Ví dụ đời thường: xây tường từ viên gạch nhỏ.",[981,15180,15182],{"id":15181},"đệ-quy-ghi-nhớ","Đệ quy + ghi nhớ",[986,15184,15185,15188,15191,15194],{},[989,15186,15187],{},"Đệ quy gọi lại chính mình trên bản nhỏ hơn.",[989,15189,15190],{},"Ghi nhớ cất đáp án, gặp lại thì lấy ra.",[989,15192,15193],{},"Không nhớ thì cây gọi phình theo mũ.",[989,15195,15196],{},"Ví dụ đời thường: làm 1 lần rồi photo dùng lại.",[981,15198,15200],{"id":15199},"hai-điều-kiện-dùng","Hai điều kiện dùng",[986,15202,15203,15206,15209,15212],{},[989,15204,15205],{},"Bài lớn dựng được từ đáp án bài con tối ưu.",[989,15207,15208],{},"Cùng 1 bài con xuất hiện lặp đi lặp lại.",[989,15210,15211],{},"Ví dụ dùng: giao hàng, đường bay, chia tài xế.",[989,15213,15214],{},"Thiếu 2 điều này thì đừng dùng bảng nhớ.",[1099,15216,15217,15229],{},[1102,15218,15219],{},[1105,15220,15221,15223,15226],{},[1108,15222,14526],{},[1108,15224,15225],{},"Hướng đi",[1108,15227,15228],{},"Có cần bảng?",[1118,15230,15231,15241,15252],{},[1105,15232,15233,15236,15239],{},[1123,15234,15235],{},"Chia để trị",[1123,15237,15238],{},"Trên xuống",[1123,15240,12369],{},[1105,15242,15243,15246,15249],{},[1123,15244,15245],{},"Quy hoạch động",[1123,15247,15248],{},"Dưới lên (bảng) hoặc trên xuống (memo)",[1123,15250,15251],{},"Có, bắt buộc",[1105,15253,15254,15256,15259],{},[1123,15255,14549],{},[1123,15257,15258],{},"Từng bước tốt nhất",[1123,15260,12369],{},[968,15262,1433],{"id":1432},[986,15264,15265,15268],{},[989,15266,15267],{},"Input: tính số hạng 5 không memo và có memo. Output: không memo gọi mũ, có memo gọi tuyến tính.",[989,15269,15270],{},"Giải thích: mỗi bài con chỉ tính đúng 1 lần.",[968,15272,1482],{"id":1481},[973,15274,1485,15275,5599,15277,15280],{},[1487,15276,1493],{},[992,15278,15279],{},"day-017\u002F",". Mỗi bài viết 2 bản: đệ quy có memo (top-down) và bảng (bottom-up).",[981,15282,15284],{"id":15283},"bài-1-leo-cầu-thang","Bài 1: Leo cầu thang",[973,15286,15287,15288,15290],{},"Leo ",[992,15289,1262],{}," bậc, mỗi bước 1 hoặc 2 bậc. Đếm số cách.",[1099,15292,15293,15301],{},[1102,15294,15295],{},[1105,15296,15297,15299],{},[1108,15298,1566],{},[1108,15300,2547],{},[1118,15302,15303,15313,15323,15336],{},[1105,15304,15305,15310],{},[1123,15306,15307],{},[992,15308,15309],{},"long long waysNaive(int n, long long &calls)",[1123,15311,15312],{},"Đệ quy thuần, đếm lời gọi",[1105,15314,15315,15320],{},[1123,15316,15317],{},[992,15318,15319],{},"long long waysMemo(int n, std::vector\u003Clong long> &memo)",[1123,15321,15322],{},"Có memo",[1105,15324,15325,15330],{},[1123,15326,15327],{},[992,15328,15329],{},"long long waysTable(int n)",[1123,15331,15332,15333],{},"Mảng ",[992,15334,15335],{},"dp[0..n]",[1105,15337,15338,15343],{},[1123,15339,15340],{},[992,15341,15342],{},"long long waysO1(int n)",[1123,15344,15345],{},"Chỉ giữ 2 biến",[1352,15347,15350],{"className":15348,"code":15349,"language":2241,"meta":1357},[2239],"n=1 -> 1; n=2 -> 2; n=5 -> 8; n=45 -> 1836311903\nn=30: calls_naive > 1 triệu, memo mỗi n tính 1 lần\n",[992,15351,15349],{"__ignoreMap":1357},[981,15353,15355],{"id":15354},"bài-2-đổi-tiền","Bài 2: Đổi tiền",[973,15357,15358,15359,15362,15363,1517],{},"Cho mệnh giá ",[992,15360,15361],{},"coins"," và số tiền ",[992,15364,15365],{},"amount",[2273,15367,15368,15376,15382],{},[989,15369,15370,15373,15374,1517],{},[992,15371,15372],{},"int minCoins(coins, amount)",": số đồng ít nhất, không đổi được trả ",[992,15375,12548],{},[989,15377,15378,15381],{},[992,15379,15380],{},"long long countWays(coins, amount)",": số cách đổi (không tính thứ tự).",[989,15383,15384,15387],{},[992,15385,15386],{},"std::vector\u003Cint> reconstruct(coins, amount)",": trả danh sách đồng cụ thể của nghiệm ít nhất.",[1352,15389,15392],{"className":15390,"code":15391,"language":2241,"meta":1357},[2239],"coins=[1,5,10,25], amount=63 -> minCoins=6 (25,25,10,1,1,1)\ncoins=[2], amount=3          -> -1\ncoins=[1,2,5], amount=5      -> countWays=4\ncoins=[1,3,4], amount=6      -> minCoins=2 (3,3); tham lam chọn 4,1,1 = 3 đồng\n",[992,15393,15391],{"__ignoreMap":1357},[981,15395,15397],{"id":15396},"bài-3-lưới-có-chướng-ngại-nâng-cao","Bài 3: Lưới có chướng ngại (nâng cao)",[973,15399,15400,15401,15404,15405,15407],{},"Lưới ",[992,15402,15403],{},"m x n",", ô ",[992,15406,1053],{}," là đá. Robot đi từ góc trên trái tới góc dưới phải, chỉ sang phải hoặc xuống.",[2273,15409,15410,15413,15416],{},[989,15411,15412],{},"Đếm số đường đi.",[989,15414,15415],{},"Mỗi ô có chi phí. Tìm đường chi phí nhỏ nhất và in đường đi.",[989,15417,15418,15419,15466,15467,1517],{},"Giảm bộ nhớ bảng từ ",[1023,15420,15422,15445],{"className":15421},[1026],[1023,15423,15425],{"className":15424},[1030],[1032,15426,15427],{"xmlns":1034},[1036,15428,15429,15442],{},[1039,15430,15431,15433,15435,15438,15440],{},[1042,15432,1044],{},[1046,15434,1049],{"stretchy":1048},[1042,15436,15437],{},"m",[1042,15439,1262],{},[1046,15441,1056],{"stretchy":1048},[1058,15443,15444],{"encoding":1060},"O(mn)",[1023,15446,15448],{"className":15447,"ariaHidden":1066},[1065],[1023,15449,15451,15454,15457,15460,15463],{"className":15450},[1070],[1023,15452],{"className":15453,"style":1075},[1074],[1023,15455,1044],{"className":15456,"style":1081},[1079,1080],[1023,15458,1049],{"className":15459},[1085],[1023,15461,1051],{"className":15462},[1079,1080],[1023,15464,1056],{"className":15465},[1092]," xuống ",[1023,15468,15470,15489],{"className":15469},[1026],[1023,15471,15473],{"className":15472},[1030],[1032,15474,15475],{"xmlns":1034},[1036,15476,15477,15487],{},[1039,15478,15479,15481,15483,15485],{},[1042,15480,1044],{},[1046,15482,1049],{"stretchy":1048},[1042,15484,1262],{},[1046,15486,1056],{"stretchy":1048},[1058,15488,1267],{"encoding":1060},[1023,15490,15492],{"className":15491,"ariaHidden":1066},[1065],[1023,15493,15495,15498,15501,15504,15507],{"className":15494},[1070],[1023,15496],{"className":15497,"style":1075},[1074],[1023,15499,1044],{"className":15500,"style":1081},[1079,1080],[1023,15502,1049],{"className":15503},[1085],[1023,15505,1262],{"className":15506},[1079,1080],[1023,15508,1056],{"className":15509},[1092],[1352,15511,15514],{"className":15512,"code":15513,"language":2241,"meta":1357},[2239],"[[0,0,0],\n [0,1,0],\n [0,0,0]]   -> 2 đường\n\nchi phí [[1,3,1],[1,5,1],[4,2,1]] -> 7, đường (0,0)(0,1)(0,2)(1,2)(2,2)\n",[992,15515,15513],{"__ignoreMap":1357},[981,15517,2711],{"id":2710},[986,15519,15521,15527,15537,15543],{"className":15520},[2715],[989,15522,15524,15526],{"className":15523},[2719],[2721,15525],{"disabled":2723,"type":2724}," Test mẫu pass cho cả bản memo và bản bảng.",[989,15528,15530,15532,15533,15536],{"className":15529},[2719],[2721,15531],{"disabled":2723,"type":2724}," Mỗi bài ghi rõ: trạng thái ",[992,15534,15535],{},"dp[i]"," nghĩa là gì, công thức chuyển, base case.",[989,15538,15540,15542],{"className":15539},[2719],[2721,15541],{"disabled":2723,"type":2724}," Bài 2 chỉ ra được input mà tham lam sai.",[989,15544,15546,15548],{"className":15545},[2719],[2721,15547],{"disabled":2723,"type":2724}," Nói được 2 điều kiện dùng quy hoạch động bằng ví dụ trong bài.",[968,15550,2890],{"id":2889},[986,15552,15553,15556,15559,15562],{},[989,15554,15555],{},"Quy hoạch động đi từ đâu lên đâu?",[989,15557,15558],{},"Memo là gì, đặt ở đâu trong hàm?",[989,15560,15561],{},"Hai điều kiện dùng là gì?",[989,15563,15564],{},"Đúng trước hay tối ưu trước?",[3014,15566],{},[973,15568,15569],{},"🌕 Bạn đã hoàn thành ngày 17. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":15571},[15572,15573,15578,15579,15585],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":15574},[15575,15576,15577],{"id":15163,"depth":73,"text":15164},{"id":15181,"depth":73,"text":15182},{"id":15199,"depth":73,"text":15200},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":15580},[15581,15582,15583,15584],{"id":15283,"depth":73,"text":15284},{"id":15354,"depth":73,"text":15355},{"id":15396,"depth":73,"text":15397},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu chiến lược từ dưới lên của Bellman với đệ quy và ghi nhớ, hai điều kiện áp dụng và các bài toán tối ưu kinh điển.",{},[8149,15144],{"title":140,"description":15586},[15591],"dp","_Nssiytn3osfsdO72amU2luwxMcLJCnY0pFGgkOV3BM",{"id":15594,"title":145,"body":15595,"category":5189,"day":148,"description":16066,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":16067,"navigation":2723,"outcomes":3047,"path":146,"prerequisites":16068,"seo":16069,"stem":147,"tags":16070,"__hash__":16073},"challenges\u002Fchallenges\u002F18.simple-factory.md",{"type":965,"value":15596,"toc":16050},[15597,15599,15602,15604,15608,15622,15626,15640,15644,15658,15707,15709,15717,15719,15726,15730,15796,15860,15864,15892,15898,15902,15931,15935,15964,15984,15994,15996,16027,16029,16043,16045,16048],[968,15598,971],{"id":970},[973,15600,15601],{},"Bài này học cách gom chỗ tạo đối tượng. Bạn không rải lệnh tạo khắp nơi nữa.",[968,15603,979],{"id":978},[981,15605,15607],{"id":15606},"rải-lệnh-tạo-gây-cứng","Rải lệnh tạo gây cứng",[986,15609,15610,15613,15616,15619],{},[989,15611,15612],{},"Mỗi nhánh gọi thẳng 1 lớp pizza cụ thể.",[989,15614,15615],{},"Thêm loại mới phải mở cửa hàng ra sửa.",[989,15617,15618],{},"Đổi tên lớp cũng phải sửa cửa hàng.",[989,15620,15621],{},"Ví dụ đời thường: mỗi chi nhánh tự nặn công thức.",[981,15623,15625],{"id":15624},"xưởng-đơn-giản-gom-lại","Xưởng đơn giản gom lại",[986,15627,15628,15631,15634,15637],{},[989,15629,15630],{},"Mọi cách tạo dồn vào 1 xưởng chung.",[989,15632,15633],{},"Cửa hàng hỏi xưởng, nhận pizza chung.",[989,15635,15636],{},"Cửa hàng chạy 4 bước chuẩn không cần biết loại.",[989,15638,15639],{},"Ví dụ đời thường: kho tổng phát hàng cho chi nhánh.",[981,15641,15643],{"id":15642},"giới-hạn-của-xưởng-đơn","Giới hạn của xưởng đơn",[986,15645,15646,15649,15652,15655],{},[989,15647,15648],{},"Thêm chiều vùng miền thì xưởng phình to.",[989,15650,15651],{},"Pizza cùng tên mà New York khác Chicago.",[989,15653,15654],{},"Lúc đó cần Factory Method bài sau.",[989,15656,15657],{},"Ví dụ đời thường: 1 kho không cân 2 miền vị khác.",[1099,15659,15660,15672],{},[1102,15661,15662],{},[1105,15663,15664,15666,15669],{},[1108,15665,5414],{},[1108,15667,15668],{},"Rải khắp nơi",[1108,15670,15671],{},"Qua xưởng",[1118,15673,15674,15685,15696],{},[1105,15675,15676,15679,15682],{},[1123,15677,15678],{},"Biết lớp cụ thể",[1123,15680,15681],{},"Rải trong cửa hàng",[1123,15683,15684],{},"Gom trong xưởng",[1105,15686,15687,15690,15693],{},[1123,15688,15689],{},"Thêm loại mới",[1123,15691,15692],{},"Mở cửa hàng sửa",[1123,15694,15695],{},"Sửa đúng xưởng",[1105,15697,15698,15701,15704],{},[1123,15699,15700],{},"Dùng lại",[1123,15702,15703],{},"Sao chép khối lệnh",[1123,15705,15706],{},"Dùng chung xưởng",[968,15708,1433],{"id":1432},[986,15710,15711,15714],{},[989,15712,15713],{},"Input: khách gọi pizza phô mai. Output: xưởng trả đúng loại, cửa hàng chạy đủ 4 bước.",[989,15715,15716],{},"Giải thích: kiến thức lớp cụ thể nằm 1 chỗ duy nhất.",[968,15718,1482],{"id":1481},[973,15720,1485,15721,4801,15723,1517],{},[1487,15722,4800],{},[992,15724,15725],{},"day-018\u002F",[981,15727,15729],{"id":15728},"bài-1-pizza-store-với-simple-factory","Bài 1: Pizza Store với Simple Factory",[1352,15731,15733],{"className":1393,"code":15732,"language":1395,"meta":1357,"style":1357},"class Pizza {\n public:\n  virtual std::string name() const = 0;\n  virtual void prepare(); virtual void bake(); virtual void cut(); virtual void box();\n  const std::vector\u003Cstd::string> &log() const;   \u002F\u002F ghi lại các bước để test\n  virtual ~Pizza() = default;\n};\nclass SimplePizzaFactory { public: std::unique_ptr\u003CPizza> create(const std::string &type) const; };\nclass PizzaStore {\n public:\n  explicit PizzaStore(const SimplePizzaFactory &f);\n  std::unique_ptr\u003CPizza> order(const std::string &type);  \u002F\u002F create + 4 bước\n};\n",[992,15734,15735,15740,15744,15749,15754,15759,15764,15768,15773,15778,15782,15787,15792],{"__ignoreMap":1357},[1023,15736,15737],{"class":1362,"line":63},[1023,15738,15739],{},"class Pizza {\n",[1023,15741,15742],{"class":1362,"line":68},[1023,15743,4836],{},[1023,15745,15746],{"class":1362,"line":73},[1023,15747,15748],{},"  virtual std::string name() const = 0;\n",[1023,15750,15751],{"class":1362,"line":78},[1023,15752,15753],{},"  virtual void prepare(); virtual void bake(); virtual void cut(); virtual void box();\n",[1023,15755,15756],{"class":1362,"line":83},[1023,15757,15758],{},"  const std::vector\u003Cstd::string> &log() const;   \u002F\u002F ghi lại các bước để test\n",[1023,15760,15761],{"class":1362,"line":88},[1023,15762,15763],{},"  virtual ~Pizza() = default;\n",[1023,15765,15766],{"class":1362,"line":93},[1023,15767,4866],{},[1023,15769,15770],{"class":1362,"line":98},[1023,15771,15772],{},"class SimplePizzaFactory { public: std::unique_ptr\u003CPizza> create(const std::string &type) const; };\n",[1023,15774,15775],{"class":1362,"line":103},[1023,15776,15777],{},"class PizzaStore {\n",[1023,15779,15780],{"class":1362,"line":108},[1023,15781,4836],{},[1023,15783,15784],{"class":1362,"line":113},[1023,15785,15786],{},"  explicit PizzaStore(const SimplePizzaFactory &f);\n",[1023,15788,15789],{"class":1362,"line":118},[1023,15790,15791],{},"  std::unique_ptr\u003CPizza> order(const std::string &type);  \u002F\u002F create + 4 bước\n",[1023,15793,15794],{"class":1362,"line":123},[1023,15795,4866],{},[1099,15797,15798,15810],{},[1102,15799,15800],{},[1105,15801,15802,15805],{},[1108,15803,15804],{},"Loại",[1108,15806,15807],{},[992,15808,15809],{},"name()",[1118,15811,15812,15824,15836,15848],{},[1105,15813,15814,15819],{},[1123,15815,15816],{},[992,15817,15818],{},"\"cheese\"",[1123,15820,15821],{},[992,15822,15823],{},"\"Pizza phô mai\"",[1105,15825,15826,15831],{},[1123,15827,15828],{},[992,15829,15830],{},"\"pepperoni\"",[1123,15832,15833],{},[992,15834,15835],{},"\"Pizza xúc xích\"",[1105,15837,15838,15843],{},[1123,15839,15840],{},[992,15841,15842],{},"\"veggie\"",[1123,15844,15845],{},[992,15846,15847],{},"\"Pizza rau\"",[1105,15849,15850,15855],{},[1123,15851,15852],{},[992,15853,15854],{},"\"clam\"",[1123,15856,15857],{},[992,15858,15859],{},"\"Pizza nghêu\"",[973,15861,15862],{},[1487,15863,2194],{},[986,15865,15866,15875],{},[989,15867,15868,15871,15872,15874],{},[992,15869,15870],{},"PizzaStore"," không ",[992,15873,5026],{}," lớp pizza cụ thể nào.",[989,15876,15877,15878,15881,15882,1656,15885,15888,15889,1517],{},"Loại không tồn tại: ",[992,15879,15880],{},"create"," trả ",[992,15883,15884],{},"nullptr",[992,15886,15887],{},"order"," ném ",[992,15890,15891],{},"std::invalid_argument",[1352,15893,15896],{"className":15894,"code":15895,"language":2241,"meta":1357},[2239],"order(\"cheese\")  -> name \"Pizza phô mai\", log = [prepare, bake, cut, box]\norder(\"sushi\")   -> ném invalid_argument\n",[992,15897,15895],{"__ignoreMap":1357},[981,15899,15901],{"id":15900},"bài-2-thêm-loại-mới","Bài 2: Thêm loại mới",[2273,15903,15904,15914],{},[989,15905,5030,15906,15909,15910,15913],{},[992,15907,15908],{},"\"seafood\""," và chứng minh chỉ ",[992,15911,15912],{},"SimplePizzaFactory"," và file lớp mới thay đổi.",[989,15915,15916,15917,15919,15920,13568,15923,15926,15927,15930],{},"Đổi ",[992,15918,15880],{}," sang ",[1487,15921,15922],{},"bảng đăng ký",[992,15924,15925],{},"std::unordered_map\u003Cstd::string, std::function\u003Cstd::unique_ptr\u003CPizza>()>>",". Thêm hàm ",[992,15928,15929],{},"registerType(name, creator)",". Thêm loại mới lúc chạy mà không sửa factory.",[981,15932,15934],{"id":15933},"bài-3-xưởng-tài-liệu-nâng-cao","Bài 3: Xưởng tài liệu (nâng cao)",[973,15936,15937,15940,15941,15944,15945,1656,15948,15944,15951,1656,15954,15944,15957,15960,15961,1517],{},[992,15938,15939],{},"DocumentFactory::create(path)"," chọn lớp theo đuôi file: ",[992,15942,15943],{},".txt"," ra ",[992,15946,15947],{},"TextDocument",[992,15949,15950],{},".csv",[992,15952,15953],{},"SpreadsheetDocument",[992,15955,15956],{},".md",[992,15958,15959],{},"MarkdownDocument",". Mỗi lớp có ",[992,15962,15963],{},"std::string summary()",[986,15965,15966,15971,15976],{},[989,15967,15968,15970],{},[992,15969,15947],{},": số dòng, số từ.",[989,15972,15973,15975],{},[992,15974,15953],{},": số hàng, số cột.",[989,15977,15978,15980,15981,1517],{},[992,15979,15959],{},": số heading ",[992,15982,15983],{},"#",[973,15985,15986,15987,15989,15990,15993],{},"Đuôi không hỗ trợ thì trả lỗi rõ ràng. Viết ",[992,15988,7448],{}," nhận danh sách file từ dòng lệnh và in ",[992,15991,15992],{},"summary()"," từng file.",[981,15995,2711],{"id":2710},[986,15997,15999,16004,16015,16021],{"className":15998},[2715],[989,16000,16002,11986],{"className":16001},[2719],[2721,16003],{"disabled":2723,"type":2724},[989,16005,16007,2308,16009,16011,16012,16014],{"className":16006},[2719],[2721,16008],{"disabled":2723,"type":2724},[992,16010,15870],{}," không phụ thuộc lớp cụ thể (kiểm tra bằng ",[992,16013,5026],{},").",[989,16016,16018,16020],{"className":16017},[2719],[2721,16019],{"disabled":2723,"type":2724}," Bảng đăng ký cho phép thêm loại lúc chạy.",[989,16022,16024,16026],{"className":16023},[2719],[2721,16025],{"disabled":2723,"type":2724}," Giải thích được giới hạn của Simple Factory khi có thêm chiều vùng miền.",[968,16028,2890],{"id":2889},[986,16030,16031,16034,16037,16040],{},[989,16032,16033],{},"Vì sao rải lệnh tạo khắp nơi lại xấu?",[989,16035,16036],{},"Xưởng đơn giản làm gì?",[989,16038,16039],{},"Quy trình pizza gồm 4 bước nào?",[989,16041,16042],{},"Khi nào xưởng đơn không đủ?",[3014,16044],{},[973,16046,16047],{},"🌕 Bạn đã hoàn thành ngày 18. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,16049,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":16051},[16052,16053,16058,16059,16065],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":16054},[16055,16056,16057],{"id":15606,"depth":73,"text":15607},{"id":15624,"depth":73,"text":15625},{"id":15642,"depth":73,"text":15643},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":16060},[16061,16062,16063,16064],{"id":15728,"depth":73,"text":15729},{"id":15900,"depth":73,"text":15901},{"id":15933,"depth":73,"text":15934},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Vì sao từ khóa tạo mới gây cứng nhắc, cách gom khởi tạo vào một xưởng đơn giản qua câu chuyện Pizza Store.",{},[5194,5195],{"title":145,"description":16066},[16071,16072],"factory","simple-factory","1hxYTQD1zrsdadLgrkOGv7k1fncCEQgC8R76o_Ief7M",{"id":16075,"title":150,"body":16076,"category":5189,"day":153,"description":16563,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":16564,"navigation":2723,"outcomes":3047,"path":151,"prerequisites":16565,"seo":16566,"stem":152,"tags":16567,"__hash__":16570},"challenges\u002Fchallenges\u002F19.singleton-pattern.md",{"type":965,"value":16077,"toc":16546},[16078,16080,16083,16085,16089,16103,16107,16121,16125,16139,16188,16192,16218,16220,16228,16230,16244,16248,16311,16361,16367,16371,16381,16409,16426,16440,16446,16450,16460,16489,16491,16523,16525,16539,16541,16544],[968,16079,971],{"id":970},[973,16081,16082],{},"Bài này học cách giữ đúng 1 thực thể duy nhất. Bạn tránh tạo 2 nồi sô cô la.",[968,16084,979],{"id":978},[981,16086,16088],{"id":16087},"singleton-là-gì","Singleton là gì",[986,16090,16091,16094,16097,16100],{},[989,16092,16093],{},"Đảm bảo lớp chỉ có 1 thực thể.",[989,16095,16096],{},"Chặn đường tạo mới từ bên ngoài.",[989,16098,16099],{},"Mở 1 cổng chung để mọi người lấy.",[989,16101,16102],{},"Ví dụ đời thường: cả nhà dùng chung 1 nồi.",[981,16104,16106],{"id":16105},"nồi-sô-cô-la-và-đa-luồng","Nồi sô cô la và đa luồng",[986,16108,16109,16112,16115,16118],{},[989,16110,16111],{},"Nồi có 3 trạng thái rỗng, đang đun, xong.",[989,16113,16114],{},"2 nồi cùng chạy thì mẻ hỏng.",[989,16116,16117],{},"2 luồng cùng tạo lúc chưa có thì ra 2 nồi.",[989,16119,16120],{},"Ví dụ đời thường: 2 người cùng bật bếp khác nhau.",[981,16122,16124],{"id":16123},"ba-cách-chống-2-nồi","Ba cách chống 2 nồi",[986,16126,16127,16130,16133,16136],{},[989,16128,16129],{},"Đúc sẵn khi nạp lớp, đơn giản nhất.",[989,16131,16132],{},"Khóa cả cổng, chắc nhưng chậm.",[989,16134,16135],{},"Kiểm tra kép, nhanh nhưng khó viết đúng.",[989,16137,16138],{},"Ví dụ đời thường: khóa cửa kho chung.",[1099,16140,16141,16153],{},[1102,16142,16143],{},[1105,16144,16145,16147,16150],{},[1108,16146,14526],{},[1108,16148,16149],{},"Ưu điểm",[1108,16151,16152],{},"Nhược điểm",[1118,16154,16155,16166,16177],{},[1105,16156,16157,16160,16163],{},[1123,16158,16159],{},"Đúc sẵn",[1123,16161,16162],{},"Đơn giản, an toàn",[1123,16164,16165],{},"Tốn nếu không dùng",[1105,16167,16168,16171,16174],{},[1123,16169,16170],{},"Khóa cả cổng",[1123,16172,16173],{},"Chắc chắn",[1123,16175,16176],{},"Chậm",[1105,16178,16179,16182,16185],{},[1123,16180,16181],{},"Kiểm tra kép",[1123,16183,16184],{},"Nhanh về sau",[1123,16186,16187],{},"Khó viết đúng",[981,16189,16191],{"id":16190},"cách-cài-an-toàn-luồng-trong-từng-ngôn-ngữ","Cách cài an toàn luồng trong từng ngôn ngữ",[986,16193,16194,16201,16208,16215],{},[989,16195,16196,16197,16200],{},"Java: khóa kiểm tra kép phải có ",[992,16198,16199],{},"volatile"," cho biến thực thể, thiếu thì luồng khác có thể thấy đối tượng dựng dở.",[989,16202,16203,16204,16207],{},"Java: ",[992,16205,16206],{},"enum"," một phần tử là cách gọn nhất, JVM tự đảm bảo duy nhất và an toàn luồng.",[989,16209,16210,16211,16214],{},"C++11 trở lên: biến ",[992,16212,16213],{},"static"," cục bộ trong hàm (Meyers singleton) được khởi tạo an toàn luồng, không cần tự khóa.",[989,16216,16217],{},"Singleton về bản chất là biến toàn cục có kiểm soát. Nó làm khó kiểm thử, nên cân nhắc truyền phụ thuộc qua constructor.",[968,16219,1433],{"id":1432},[986,16221,16222,16225],{},[989,16223,16224],{},"Input: gọi cổng 2 lần liên tiếp. Output: cùng 1 nồi, đổ đầy lần 1 thì lần 2 thấy.",[989,16226,16227],{},"Giải thích: cổng trả đúng thực thể duy nhất.",[968,16229,1482],{"id":1481},[973,16231,1485,16232,16234,16235,1656,16238,3568,16241,1517],{},[1487,16233,4800],{}," (có ",[992,16236,16237],{},"std::thread",[992,16239,16240],{},"std::mutex",[992,16242,16243],{},"day-019\u002F",[981,16245,16247],{"id":16246},"bài-1-nồi-sô-cô-la","Bài 1: Nồi sô cô la",[1352,16249,16251],{"className":1393,"code":16250,"language":1395,"meta":1357,"style":1357},"class ChocolateBoiler {\n public:\n  static ChocolateBoiler &instance();\n  ChocolateBoiler(const ChocolateBoiler &) = delete;\n  ChocolateBoiler &operator=(const ChocolateBoiler &) = delete;\n  void fill();    \u002F\u002F chỉ khi rỗng\n  void boil();    \u002F\u002F chỉ khi đầy và chưa đun\n  void drain();   \u002F\u002F chỉ khi đầy và đã đun\n  bool isEmpty() const; bool isBoiled() const;\n private:\n  ChocolateBoiler();\n};\n",[992,16252,16253,16258,16262,16267,16272,16277,16282,16287,16292,16297,16302,16307],{"__ignoreMap":1357},[1023,16254,16255],{"class":1362,"line":63},[1023,16256,16257],{},"class ChocolateBoiler {\n",[1023,16259,16260],{"class":1362,"line":68},[1023,16261,4836],{},[1023,16263,16264],{"class":1362,"line":73},[1023,16265,16266],{},"  static ChocolateBoiler &instance();\n",[1023,16268,16269],{"class":1362,"line":78},[1023,16270,16271],{},"  ChocolateBoiler(const ChocolateBoiler &) = delete;\n",[1023,16273,16274],{"class":1362,"line":83},[1023,16275,16276],{},"  ChocolateBoiler &operator=(const ChocolateBoiler &) = delete;\n",[1023,16278,16279],{"class":1362,"line":88},[1023,16280,16281],{},"  void fill();    \u002F\u002F chỉ khi rỗng\n",[1023,16283,16284],{"class":1362,"line":93},[1023,16285,16286],{},"  void boil();    \u002F\u002F chỉ khi đầy và chưa đun\n",[1023,16288,16289],{"class":1362,"line":98},[1023,16290,16291],{},"  void drain();   \u002F\u002F chỉ khi đầy và đã đun\n",[1023,16293,16294],{"class":1362,"line":103},[1023,16295,16296],{},"  bool isEmpty() const; bool isBoiled() const;\n",[1023,16298,16299],{"class":1362,"line":108},[1023,16300,16301],{}," private:\n",[1023,16303,16304],{"class":1362,"line":113},[1023,16305,16306],{},"  ChocolateBoiler();\n",[1023,16308,16309],{"class":1362,"line":118},[1023,16310,4866],{},[1099,16312,16313,16322],{},[1102,16314,16315],{},[1105,16316,16317,16320],{},[1108,16318,16319],{},"Thao tác sai trạng thái",[1108,16321,4292],{},[1118,16323,16324,16337,16349],{},[1105,16325,16326,16332],{},[1123,16327,16328,16331],{},[992,16329,16330],{},"fill()"," khi đang đầy",[1123,16333,2628,16334],{},[992,16335,16336],{},"std::logic_error",[1105,16338,16339,16345],{},[1123,16340,16341,16344],{},[992,16342,16343],{},"boil()"," khi rỗng",[1123,16346,2628,16347],{},[992,16348,16336],{},[1105,16350,16351,16357],{},[1123,16352,16353,16356],{},[992,16354,16355],{},"drain()"," khi chưa đun",[1123,16358,2628,16359],{},[992,16360,16336],{},[1352,16362,16365],{"className":16363,"code":16364,"language":2241,"meta":1357},[2239],"&instance() == &instance()          -> true\nfill; boil; drain                   -> hợp lệ, cuối cùng isEmpty = true\nfill; fill                          -> lần 2 ném logic_error\nChocolateBoiler b;                  -> KHÔNG biên dịch được\n",[992,16366,16364],{"__ignoreMap":1357},[981,16368,16370],{"id":16369},"bài-2-ba-biến-thể-và-kiểm-tra-đa-luồng","Bài 2: Ba biến thể và kiểm tra đa luồng",[973,16372,16373,16374,16377,16378,4437],{},"Viết 3 biến thể ",[992,16375,16376],{},"getInstance()"," cho lớp ",[992,16379,16380],{},"Registry",[2273,16382,16383,16392,16400],{},[989,16384,16385,16388,16389,16391],{},[1487,16386,16387],{},"Eager",": biến ",[992,16390,16213],{}," khởi tạo sẵn.",[989,16393,16394,13568,16397,16399],{},[1487,16395,16396],{},"Lock toàn bộ",[992,16398,16240],{}," khóa mỗi lần gọi.",[989,16401,16402,13568,16405,16408],{},[1487,16403,16404],{},"Meyers singleton",[992,16406,16407],{},"static Registry r;"," trong hàm (C++11 đảm bảo an toàn luồng).",[973,16410,16411,16412,1509,16415,16418,16419,16421,16422,16425],{},"Constructor tăng một biến đếm ",[992,16413,16414],{},"std::atomic\u003Cint> created",[992,16416,16417],{},"sleep"," 50 ms. Tạo 16 luồng cùng gọi ",[992,16420,16376],{},". Kiểm tra ",[992,16423,16424],{},"created == 1"," cho cả 3 biến thể.",[973,16427,16428,16429,16432,16433,16436,16437,1517],{},"Viết thêm biến thể ",[1487,16430,16431],{},"sai cố ý",": kiểm tra ",[992,16434,16435],{},"if (ptr == nullptr) ptr = new Registry();"," không khóa. Chạy 100 lần, ghi lại số lần ",[992,16438,16439],{},"created > 1",[973,16441,16442,16443,16445],{},"Đo thời gian 10^7 lần gọi ",[992,16444,16376],{}," cho biến thể 2 và 3.",[981,16447,16449],{"id":16448},"bài-3-bỏ-singleton-để-dễ-test-nâng-cao","Bài 3: Bỏ Singleton để dễ test (nâng cao)",[973,16451,16452,16453,16456,16457,1517],{},"Cho lớp ",[992,16454,16455],{},"Logger"," dùng Singleton, được gọi trực tiếp trong ",[992,16458,16459],{},"OrderService::place()",[2273,16461,16462,16469,16482],{},[989,16463,16464,16465,16468],{},"Viết test cho ",[992,16466,16467],{},"OrderService"," và ghi lại lý do test khó: không thay được logger, trạng thái rò giữa các test.",[989,16470,16471,16472,5016,16474,16477,16478,16481],{},"Refactor: ",[992,16473,16467],{},[992,16475,16476],{},"Logger&"," qua constructor. Viết ",[992,16479,16480],{},"FakeLogger"," ghi log vào vector.",[989,16483,16484,16485,16488],{},"Viết test kiểm tra ",[992,16486,16487],{},"place()"," ghi đúng 1 dòng log.",[981,16490,2711],{"id":2710},[986,16492,16494,16500,16506,16515],{"className":16493},[2715],[989,16495,16497,16499],{"className":16496},[2719],[2721,16498],{"disabled":2723,"type":2724}," Test mẫu Bài 1 pass, dòng tạo trực tiếp không biên dịch được.",[989,16501,16503,16505],{"className":16502},[2719],[2721,16504],{"disabled":2723,"type":2724}," Bài 2 có kết quả chạy 16 luồng và số lần biến thể sai tạo 2 thực thể.",[989,16507,16509,2734,16511,16514],{"className":16508},[2719],[2721,16510],{"disabled":2723,"type":2724},[992,16512,16513],{},"-fsanitize=thread"," không báo data race ở 3 biến thể đúng.",[989,16516,16518,16520,16521,13981],{"className":16517},[2719],[2721,16519],{"disabled":2723,"type":2724}," Bài 3 có test dùng ",[992,16522,16480],{},[968,16524,2890],{"id":2889},[986,16526,16527,16530,16533,16536],{},[989,16528,16529],{},"Singleton đảm bảo điều gì?",[989,16531,16532],{},"Vì sao đa luồng tạo ra 2 nồi?",[989,16534,16535],{},"Ba biến thể khác nhau thế nào?",[989,16537,16538],{},"Khi nào không nên dùng Singleton?",[3014,16540],{},[973,16542,16543],{},"🌕 Bạn đã hoàn thành ngày 19. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,16545,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":16547},[16548,16549,16555,16556,16562],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":16550},[16551,16552,16553,16554],{"id":16087,"depth":73,"text":16088},{"id":16105,"depth":73,"text":16106},{"id":16123,"depth":73,"text":16124},{"id":16190,"depth":73,"text":16191},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":16557},[16558,16559,16560,16561],{"id":16246,"depth":73,"text":16247},{"id":16369,"depth":73,"text":16370},{"id":16448,"depth":73,"text":16449},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Singleton, câu chuyện nồi sô cô la, ba biến thể đa luồng và tranh cãi khi nào không nên dùng.",{},[5194,5195],{"title":150,"description":16563},[16568,16569],"singleton","multithreading","WDRQkdzNPK2ontRkZv0oLtXNvFyWDtBrtUvZuRPRh2A",{"id":16572,"title":155,"body":16573,"category":5189,"day":158,"description":17012,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":17013,"navigation":2723,"outcomes":3047,"path":156,"prerequisites":17014,"seo":17015,"stem":157,"tags":17016,"__hash__":17019},"challenges\u002Fchallenges\u002F20.adapter-pattern.md",{"type":965,"value":16574,"toc":16996},[16575,16577,16580,16582,16586,16600,16604,16621,16625,16639,16686,16688,16696,16698,16705,16709,16724,16823,16840,16846,16850,16880,16884,16887,16896,16903,16918,16930,16936,16938,16973,16975,16989,16991,16994],[968,16576,971],{"id":970},[973,16578,16579],{},"Bài này học cục chuyển đổi giao diện. Bạn cho gà tây đóng giả vịt.",[968,16581,979],{"id":978},[981,16583,16585],{"id":16584},"adapter-là-gì","Adapter là gì",[986,16587,16588,16591,16594,16597],{},[989,16589,16590],{},"Đổi giao diện cũ thành giao diện khách chờ.",[989,16592,16593],{},"Không sửa bên cũ, không sửa bên mới.",[989,16595,16596],{},"Ví dụ đời thường: cục chuyển phích cắm du lịch.",[989,16598,16599],{},"Giúp 2 bên không khớp vẫn làm việc chung.",[981,16601,16603],{"id":16602},"gà-tây-giả-vịt","Gà tây giả vịt",[986,16605,16606,16609,16612,16615,16618],{},[989,16607,16608],{},"Vịt kêu quạc bay xa, gà kêu cục tác bay ngắn.",[989,16610,16611],{},"Bộ đổi đứng giữa, ngoài là vịt trong là gà.",[989,16613,16614],{},"Kêu thì dịch thành cục tác.",[989,16616,16617],{},"Bay xa thì cho bay ngắn nhiều lần.",[989,16619,16620],{},"Ví dụ đời thường: phiên dịch viên giữa 2 người.",[981,16622,16624],{"id":16623},"hai-biến-thể-và-phân-biệt","Hai biến thể và phân biệt",[986,16626,16627,16630,16633,16636],{},[989,16628,16629],{},"Bọc đối tượng: giữ gà bên trong, linh hoạt.",[989,16631,16632],{},"Kế thừa lớp: vừa là vịt vừa là gà, gọn nhưng cứng.",[989,16634,16635],{},"Nên ưu tiên bọc đối tượng.",[989,16637,16638],{},"Ví dụ đời thường: thuê dịch vụ và tự học tiếng.",[1099,16640,16641,16653],{},[1102,16642,16643],{},[1105,16644,16645,16647,16650],{},[1108,16646,5414],{},[1108,16648,16649],{},"Bọc đối tượng",[1108,16651,16652],{},"Kế thừa lớp",[1118,16654,16655,16665,16675],{},[1105,16656,16657,16660,16663],{},[1123,16658,16659],{},"Cơ chế",[1123,16661,16662],{},"Giữ tham chiếu",[1123,16664,7121],{},[1105,16666,16667,16670,16673],{},[1123,16668,16669],{},"Dùng cho con của gà",[1123,16671,16672],{},"Được",[1123,16674,12369],{},[1105,16676,16677,16680,16683],{},[1123,16678,16679],{},"Cần ngôn ngữ gì",[1123,16681,16682],{},"Mọi nơi",[1123,16684,16685],{},"Cần đa kế thừa",[968,16687,1433],{"id":1432},[986,16689,16690,16693],{},[989,16691,16692],{},"Input: bầy vịt gọi kêu. Output: nghe cục tác nhưng vẫn chấp nhận.",[989,16694,16695],{},"Giải thích: bộ đổi dịch đúng chuẩn vịt ra ngoài.",[968,16697,1482],{"id":1481},[973,16699,1485,16700,4801,16702,1517],{},[1487,16701,4800],{},[992,16703,16704],{},"day-020\u002F",[981,16706,16708],{"id":16707},"bài-1-gà-tây-giả-vịt-object-adapter","Bài 1: Gà tây giả vịt (object adapter)",[1352,16710,16712],{"className":1393,"code":16711,"language":1395,"meta":1357,"style":1357},"struct Duck   { virtual std::string quack() = 0;  virtual std::string fly() = 0; virtual ~Duck() = default; };\nstruct Turkey { virtual std::string gobble() = 0; virtual std::string fly() = 0; virtual ~Turkey() = default; };\n",[992,16713,16714,16719],{"__ignoreMap":1357},[1023,16715,16716],{"class":1362,"line":63},[1023,16717,16718],{},"struct Duck   { virtual std::string quack() = 0;  virtual std::string fly() = 0; virtual ~Duck() = default; };\n",[1023,16720,16721],{"class":1362,"line":68},[1023,16722,16723],{},"struct Turkey { virtual std::string gobble() = 0; virtual std::string fly() = 0; virtual ~Turkey() = default; };\n",[1099,16725,16726,16734],{},[1102,16727,16728],{},[1105,16729,16730,16732],{},[1108,16731,4881],{},[1108,16733,4292],{},[1118,16735,16736,16757,16777,16804],{},[1105,16737,16738,16743],{},[1123,16739,16740],{},[992,16741,16742],{},"MallardDuck : Duck",[1123,16744,16745,15881,16748,1656,16751,15881,16754],{},[992,16746,16747],{},"quack()",[992,16749,16750],{},"\"Quạc\"",[992,16752,16753],{},"fly()",[992,16755,16756],{},"\"Bay xa\"",[1105,16758,16759,16764],{},[1123,16760,16761],{},[992,16762,16763],{},"WildTurkey : Turkey",[1123,16765,16766,15881,16769,1656,16772,15881,16774],{},[992,16767,16768],{},"gobble()",[992,16770,16771],{},"\"Cục tác\"",[992,16773,16753],{},[992,16775,16776],{},"\"Bay ngắn\"",[1105,16778,16779,16784],{},[1123,16780,16781],{},[992,16782,16783],{},"TurkeyAdapter : Duck",[1123,16785,16786,16787,1838,16790,16792,16793,1838,16795,16792,16797,16800,16801],{},"Giữ ",[992,16788,16789],{},"Turkey&",[992,16791,16747],{}," gọi ",[992,16794,16768],{},[992,16796,16753],{},[992,16798,16799],{},"turkey.fly()"," 5 lần, nối kết quả bằng ",[992,16802,16803],{},"\" \"",[1105,16805,16806,16811],{},[1123,16807,16808],{},[992,16809,16810],{},"DuckAdapter : Turkey",[1123,16812,16813,16814,16816,16817,16819,16820],{},"Chiều ngược lại. ",[992,16815,16753],{}," của vịt chỉ được gọi 1 lần mỗi 5 lần ",[992,16818,16753],{}," của gà tây; 4 lần còn lại trả ",[992,16821,16822],{},"\"Nghỉ\"",[973,16824,1505,16825,16828,16829,1509,16831,16833,16834,1509,16836,16839],{},[992,16826,16827],{},"void testDuck(Duck &d)"," in ",[992,16830,16747],{},[992,16832,16753],{},". Truyền cả ",[992,16835,7303],{},[992,16837,16838],{},"TurkeyAdapter"," vào.",[1352,16841,16844],{"className":16842,"code":16843,"language":2241,"meta":1357},[2239],"testDuck(TurkeyAdapter(turkey)) -> \"Cục tác\", \"Bay ngắn Bay ngắn Bay ngắn Bay ngắn Bay ngắn\"\nDuckAdapter gọi fly 6 lần       -> \"Bay xa\", \"Nghỉ\", \"Nghỉ\", \"Nghỉ\", \"Nghỉ\", \"Bay xa\"\n",[992,16845,16843],{"__ignoreMap":1357},[981,16847,16849],{"id":16848},"bài-2-class-adapter-và-so-sánh","Bài 2: Class adapter và so sánh",[2273,16851,16852,16858,16875],{},[989,16853,1505,16854,16857],{},[992,16855,16856],{},"TurkeyClassAdapter : public Duck, private WildTurkey"," bằng đa kế thừa.",[989,16859,16860,16861,16864,16865,15881,16867,16870,16871,16874],{},"Tạo ",[992,16862,16863],{},"OldTurkey : WildTurkey"," ghi đè ",[992,16866,16753],{},[992,16868,16869],{},"\"Không bay nổi\"",". Object adapter dùng được ",[992,16872,16873],{},"OldTurkey",", class adapter thì không. Viết test chứng minh.",[989,16876,16877,16878,1517],{},"Viết bảng so sánh 2 biến thể vào ",[992,16879,2513],{},[981,16881,16883],{"id":16882},"bài-3-adapter-cho-thư-viện-thật-nâng-cao","Bài 3: Adapter cho thư viện thật (nâng cao)",[973,16885,16886],{},"Ứng dụng của bạn có interface:",[1352,16888,16890],{"className":1393,"code":16889,"language":1395,"meta":1357,"style":1357},"struct Logger { virtual void log(Level lv, const std::string &msg) = 0; };  \u002F\u002F Level: Info, Warn, Error\n",[992,16891,16892],{"__ignoreMap":1357},[1023,16893,16894],{"class":1362,"line":63},[1023,16895,16889],{},[973,16897,16898,16899,16902],{},"Có 2 \"thư viện ngoài\" với API khác nhau (tự viết giả lập, ",[1487,16900,16901],{},"không được sửa","):",[1352,16904,16906],{"className":1393,"code":16905,"language":1395,"meta":1357,"style":1357},"class LegacyFileLog { public: void write(const char *line); };                       \u002F\u002F ghi \"[I] msg\"\nclass CloudLog { public: void send(std::map\u003Cstd::string, std::string> fields); };    \u002F\u002F {\"severity\", \"text\"}\n",[992,16907,16908,16913],{"__ignoreMap":1357},[1023,16909,16910],{"class":1362,"line":63},[1023,16911,16912],{},"class LegacyFileLog { public: void write(const char *line); };                       \u002F\u002F ghi \"[I] msg\"\n",[1023,16914,16915],{"class":1362,"line":68},[1023,16916,16917],{},"class CloudLog { public: void send(std::map\u003Cstd::string, std::string> fields); };    \u002F\u002F {\"severity\", \"text\"}\n",[973,16919,1505,16920,1509,16923,16926,16927,16929],{},[992,16921,16922],{},"LegacyFileLogAdapter",[992,16924,16925],{},"CloudLogAdapter",". Ứng dụng chỉ biết ",[992,16928,16455],{},". Viết test cho mỗi adapter kiểm tra định dạng đầu ra đúng.",[1352,16931,16934],{"className":16932,"code":16933,"language":2241,"meta":1357},[2239],"log(Warn, \"đĩa đầy\") qua LegacyFileLogAdapter -> write(\"[W] đĩa đầy\")\nlog(Error, \"mất kết nối\") qua CloudLogAdapter  -> send({severity: \"ERROR\", text: \"mất kết nối\"})\n",[992,16935,16933],{"__ignoreMap":1357},[981,16937,2711],{"id":2710},[986,16939,16941,16946,16961,16967],{"className":16940},[2715],[989,16942,16944,11986],{"className":16943},[2719],[2721,16945],{"disabled":2723,"type":2724},[989,16947,16949,16951,16952,1656,16955,1656,16958,1517],{"className":16948},[2719],[2721,16950],{"disabled":2723,"type":2724}," Không sửa ",[992,16953,16954],{},"Turkey",[992,16956,16957],{},"LegacyFileLog",[992,16959,16960],{},"CloudLog",[989,16962,16964,16966],{"className":16963},[2719],[2721,16965],{"disabled":2723,"type":2724}," Có test chứng minh class adapter không dùng được với lớp con của adaptee.",[989,16968,16970,16972],{"className":16969},[2719],[2721,16971],{"disabled":2723,"type":2724}," Phân biệt được Adapter với Decorator: Adapter đổi interface, Decorator giữ interface.",[968,16974,2890],{"id":2889},[986,16976,16977,16980,16983,16986],{},[989,16978,16979],{},"Adapter giải bài toán gì?",[989,16981,16982],{},"Gà tây giả vịt bằng cách nào?",[989,16984,16985],{},"Bọc đối tượng khác kế thừa lớp ở đâu?",[989,16987,16988],{},"Adapter khác Decorator ở đâu?",[3014,16990],{},[973,16992,16993],{},"🌕 Bạn đã hoàn thành ngày 20. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,16995,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":16997},[16998,16999,17004,17005,17011],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":17000},[17001,17002,17003],{"id":16584,"depth":73,"text":16585},{"id":16602,"depth":73,"text":16603},{"id":16623,"depth":73,"text":16624},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":17006},[17007,17008,17009,17010],{"id":16707,"depth":73,"text":16708},{"id":16848,"depth":73,"text":16849},{"id":16882,"depth":73,"text":16883},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Adapter, câu chuyện vịt kêu quạc gặp gà tây kêu cục tác, và so sánh bộ điều hợp đối tượng với bộ điều hợp lớp.",{},[5194,5195],{"title":155,"description":17012},[17017,17018],"adapter","turkey","80w1W1dBPd9QnF1jWKanxegG9h6ZcjGMvN0YevDlfu4",{"id":17021,"title":160,"body":17022,"category":8797,"day":163,"description":17496,"difficulty":5191,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":17497,"navigation":2723,"outcomes":3047,"path":161,"prerequisites":17498,"seo":17500,"stem":162,"tags":17501,"__hash__":17503},"challenges\u002Fchallenges\u002F21.mini-project-sort.md",{"type":965,"value":17023,"toc":17479},[17024,17026,17029,17031,17035,17049,17053,17067,17071,17085,17127,17129,17137,17139,17148,17152,17158,17244,17249,17253,17279,17295,17299,17386,17392,17396,17420,17422,17458,17460,17474,17476],[968,17025,971],{"id":970},[973,17027,17028],{},"Bài này gom kiến thức tuần đầu thành 1 thí nghiệm. Bạn đo rồi kết luận bằng số.",[968,17030,979],{"id":978},[981,17032,17034],{"id":17033},"mục-tiêu-dự-án","Mục tiêu dự án",[986,17036,17037,17040,17043,17046],{},[989,17038,17039],{},"Đo 5 thuật toán sắp xếp trên cùng dữ liệu.",[989,17041,17042],{},"Đo 6 cấu trúc list, tuple, stack, queue, dict, set.",[989,17044,17045],{},"Ra báo cáo có bảng số và biểu đồ.",[989,17047,17048],{},"Ví dụ đời thường: đua xe cùng đường để so.",[981,17050,17052],{"id":17051},"thí-nghiệm-công-bằng","Thí nghiệm công bằng",[986,17054,17055,17058,17061,17064],{},[989,17056,17057],{},"Cùng 1 máy, cùng 1 bộ dữ liệu mỗi lượt.",[989,17059,17060],{},"Đo nhiều lần lấy trung vị cho đỡ nhiễu.",[989,17062,17063],{},"Tách thời gian tạo dữ liệu khỏi thời gian chạy.",[989,17065,17066],{},"Ví dụ đời thường: chấm thi cùng đề cùng giờ.",[981,17068,17070],{"id":17069},"đo-gì-và-báo-cáo-gì","Đo gì và báo cáo gì",[986,17072,17073,17076,17079,17082],{},[989,17074,17075],{},"Đo thời gian, số lần so sánh, đổi chỗ.",[989,17077,17078],{},"Vẽ đường cong thời gian theo n.",[989,17080,17081],{},"Báo cáo 5 phần: mục tiêu, cách làm, số liệu, giải thích, khuyến nghị.",[989,17083,17084],{},"Ví dụ đời thường: bảng điểm kèm nhận xét.",[1099,17086,17087,17097],{},[1102,17088,17089],{},[1105,17090,17091,17094],{},[1108,17092,17093],{},"Dạng dữ liệu",[1108,17095,17096],{},"Thuật toán thắng",[1118,17098,17099,17106,17113,17120],{},[1105,17100,17101,17103],{},[1123,17102,9585],{},[1123,17104,17105],{},"Bubble, insertion",[1105,17107,17108,17111],{},[1123,17109,17110],{},"Gần xếp lệch ít",[1123,17112,9748],{},[1105,17114,17115,17118],{},[1123,17116,17117],{},"Lớn cần ổn định",[1123,17119,10680],{},[1105,17121,17122,17125],{},[1123,17123,17124],{},"Lớn cần nhanh tại chỗ",[1123,17126,11009],{},[968,17128,1433],{"id":1432},[986,17130,17131,17134],{},[989,17132,17133],{},"Input: mọi thuật toán trên cùng dãy 100 số ngẫu nhiên. Output: kết quả trùng nhau, thời gian chênh ít.",[989,17135,17136],{},"Giải thích: n nhỏ nên chưa thấy khác biệt lớn.",[968,17138,1482],{"id":1481},[973,17140,1485,17141,17143,17144,17147],{},[1487,17142,1493],{}," (dùng lại code ngày 1, 2, 4, 5, 10, 11). Nộp vào ",[992,17145,17146],{},"day-021-mini-project\u002F",". Đây là mini project, dành 90 phút.",[981,17149,17151],{"id":17150},"bài-1-khung-benchmark","Bài 1: Khung benchmark",[973,17153,1505,17154,17157],{},[992,17155,17156],{},"bench.hpp"," với:",[1099,17159,17160,17168],{},[1102,17161,17162],{},[1105,17163,17164,17166],{},[1108,17165,2544],{},[1108,17167,2547],{},[1118,17169,17170,17201,17219,17230],{},[1105,17171,17172,17177],{},[1123,17173,17174],{},[992,17175,17176],{},"std::vector\u003Cint> makeData(Kind k, size_t n, uint32_t seed)",[1123,17178,17179,13568,17182,1656,17185,1656,17188,1656,17191,17194,17195,17198,17199,1056],{},[992,17180,17181],{},"Kind",[992,17183,17184],{},"Random",[992,17186,17187],{},"Sorted",[992,17189,17190],{},"Reversed",[992,17192,17193],{},"NearlySorted"," (đổi 1% cặp), ",[992,17196,17197],{},"FewUnique"," (giá trị trong ",[992,17200,11468],{},[1105,17202,17203,17208],{},[1123,17204,17205],{},[992,17206,17207],{},"double timeMs(std::function\u003Cvoid()> f, int repeat)",[1123,17209,17210,17211,17214,17215,17218],{},"Chạy ",[992,17212,17213],{},"repeat"," lần, trả ",[1487,17216,17217],{},"trung vị"," (ms)",[1105,17220,17221,17224],{},[1123,17222,17223],{},"Kiểm tra đúng",[1123,17225,17226,17227],{},"Sau mỗi lần sắp, ",[992,17228,17229],{},"assert(std::is_sorted(...))",[1105,17231,17232,17235],{},[1123,17233,17234],{},"Xuất CSV",[1123,17236,17237,17240,17241],{},[992,17238,17239],{},"results.csv"," với cột ",[992,17242,17243],{},"algo,kind,n,ms,comparisons,swaps",[973,17245,17246,17248],{},[1487,17247,6076],{}," mỗi lần chạy dùng bản copy mới của dữ liệu. Thời gian tạo và copy dữ liệu không tính vào kết quả.",[981,17250,17252],{"id":17251},"bài-2-chạy-thí-nghiệm-sắp-xếp","Bài 2: Chạy thí nghiệm sắp xếp",[973,17254,17255,17256,1656,17259,1656,17262,1656,17265,1656,17268,17271,17272,17275,17276,1517],{},"Chạy 5 thuật toán (",[992,17257,17258],{},"bubble",[992,17260,17261],{},"insertion",[992,17263,17264],{},"merge",[992,17266,17267],{},"quickRandom",[992,17269,17270],{},"shell",") với ",[992,17273,17274],{},"n = 1000, 5000, 20000"," trên 5 loại dữ liệu. Bubble và insertion bỏ qua ",[992,17277,17278],{},"n > 20000",[973,17280,17281,17282,10052,17285,17287,17288,17290,17291,17294],{},"Vẽ biểu đồ ",[992,17283,17284],{},"ms",[992,17286,1262],{}," cho dữ liệu ",[992,17289,17184],{}," bằng Python ",[992,17292,17293],{},"matplotlib"," hoặc gnuplot. Trục log nếu cần.",[981,17296,17298],{"id":17297},"bài-3-thí-nghiệm-cấu-trúc-dữ-liệu","Bài 3: Thí nghiệm cấu trúc dữ liệu",[973,17300,17301,17302,17385],{},"Đo với ",[1023,17303,17305,17326],{"className":17304},[1026],[1023,17306,17308],{"className":17307},[1030],[1032,17309,17310],{"xmlns":1034},[1036,17311,17312,17324],{},[1039,17313,17314,17316,17318],{},[1042,17315,1262],{},[1046,17317,2325],{},[2327,17319,17320,17322],{},[1051,17321,2331],{},[1051,17323,2334],{},[1058,17325,2337],{"encoding":1060},[1023,17327,17329,17347],{"className":17328,"ariaHidden":1066},[1065],[1023,17330,17332,17335,17338,17341,17344],{"className":17331},[1070],[1023,17333],{"className":17334,"style":2347},[1074],[1023,17336,1262],{"className":17337},[1079,1080],[1023,17339],{"className":17340,"style":2355},[2354],[1023,17342,2325],{"className":17343},[2359],[1023,17345],{"className":17346,"style":2355},[2354],[1023,17348,17350,17353,17356],{"className":17349},[1070],[1023,17351],{"className":17352,"style":2369},[1074],[1023,17354,1053],{"className":17355},[1079],[1023,17357,17359,17362],{"className":17358},[1079],[1023,17360,2379],{"className":17361},[1079],[1023,17363,17365],{"className":17364},[2383],[1023,17366,17368],{"className":17367},[2387],[1023,17369,17371],{"className":17370},[2391],[1023,17372,17374],{"className":17373,"style":2369},[2395],[1023,17375,17376,17379],{"style":2398},[1023,17377],{"className":17378,"style":2403},[2402],[1023,17380,17382],{"className":17381},[2407,2408,2409,2410],[1023,17383,2334],{"className":17384},[1079,2410],", mỗi dòng 1 thao tác:",[1352,17387,17390],{"className":17388,"code":17389,"language":2241,"meta":1357},[2239],"thao_tac                     DynamicArray   SList   RingQueue   IntHashSet   std::set\npush_back n phần tử          ...            ...     ...         -            -\npush_front n phần tử         ...            ...     -           -            -\ntra cứu n lần (có mặt)       ...(linear)    ...     -           ...          ...\nxóa đầu n lần                ...            ...     ...         -            -\n",[992,17391,17389],{"__ignoreMap":1357},[981,17393,17395],{"id":17394},"báo-cáo","Báo cáo",[973,17397,1505,17398,17401,17402,1656,17405,17407,17408,17411,17412,17415,17416,17419],{},[992,17399,17400],{},"REPORT.md"," gồm 5 phần: ",[1487,17403,17404],{},"Mục tiêu",[1487,17406,7111],{}," (máy, cờ biên dịch, số lần lặp), ",[1487,17409,17410],{},"Số liệu"," (bảng + biểu đồ), ",[1487,17413,17414],{},"Giải thích"," (nối số liệu với Big-O và cache), ",[1487,17417,17418],{},"Khuyến nghị"," (bảng \"dữ liệu kiểu này thì dùng gì\").",[981,17421,2711],{"id":2710},[986,17423,17425,17436,17444,17452],{"className":17424},[2715],[989,17426,17428,2308,17430,17432,17433,1517],{"className":17427},[2719],[2721,17429],{"disabled":2723,"type":2724},[992,17431,17239],{}," có đủ dòng, mọi lần sắp đều pass ",[992,17434,17435],{},"is_sorted",[989,17437,17439,17441,17442,1517],{"className":17438},[2719],[2721,17440],{"disabled":2723,"type":2724}," Có ít nhất 1 biểu đồ đường thời gian theo ",[992,17443,1262],{},[989,17445,17447,2308,17449,17451],{"className":17446},[2719],[2721,17448],{"disabled":2723,"type":2724},[992,17450,17400],{}," đủ 5 phần, mỗi kết luận có số liệu đi kèm.",[989,17453,17455,17457],{"className":17454},[2719],[2721,17456],{"disabled":2723,"type":2724}," Chỉ ra ít nhất 1 chỗ số đo không khớp dự đoán Big-O và giải thích vì sao.",[968,17459,2890],{"id":2889},[986,17461,17462,17465,17468,17471],{},[989,17463,17464],{},"Muốn công bằng khi đo thì làm gì?",[989,17466,17467],{},"Tạo 4 dạng dữ liệu thế nào?",[989,17469,17470],{},"Đo 3 chỉ số nào mỗi lần chạy?",[989,17472,17473],{},"Báo cáo gồm mấy phần?",[3014,17475],{},[973,17477,17478],{},"🌕 Bạn đã hoàn thành ngày 21. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":17480},[17481,17482,17487,17488,17495],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":17483},[17484,17485,17486],{"id":17033,"depth":73,"text":17034},{"id":17051,"depth":73,"text":17052},{"id":17069,"depth":73,"text":17070},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":17489},[17490,17491,17492,17493,17494],{"id":17150,"depth":73,"text":17151},{"id":17251,"depth":73,"text":17252},{"id":17297,"depth":73,"text":17298},{"id":17394,"depth":73,"text":17395},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tổng hợp tuần đầu bằng dự án đo hiệu năng sắp xếp và cấu trúc cơ bản, từ thiết kế thí nghiệm tới báo cáo.",{},[3050,17499],"ram-model-va-chi-phi",{"title":160,"description":17496},[17502],"capstone","ok8fZdFNkhI8dRlZuqsBa6Zv0kf2KwUIyRV51xm0pNQ",{"id":17505,"title":165,"body":17506,"category":8797,"day":168,"description":18466,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":18467,"navigation":2723,"outcomes":3047,"path":166,"prerequisites":18468,"seo":18470,"stem":167,"tags":18471,"__hash__":18475},"challenges\u002Fchallenges\u002F22.unsupervised-tong-quan.md",{"type":965,"value":17507,"toc":18450},[17508,17510,17513,17515,17519,17533,17537,17554,17558,17572,17610,17612,17620,17622,17638,17642,18271,18274,18280,18284,18358,18361,18367,18378,18382,18393,18395,18429,18431,18445,18447],[968,17509,971],{"id":970},[973,17511,17512],{},"Bài này học cách máy tự tìm nhóm khách. Bạn đo khoảng cách rồi phân khúc thị trường.",[968,17514,979],{"id":978},[981,17516,17518],{"id":17517},"học-không-giám-sát-là-gì","Học không giám sát là gì",[986,17520,17521,17524,17527,17530],{},[989,17522,17523],{},"Tự tìm cấu trúc ẩn trong dữ liệu không nhãn.",[989,17525,17526],{},"Việc chính: gom cụm, giảm chiều, tìm luật chung.",[989,17528,17529],{},"Không có thầy chấm đúng sai từng ví dụ.",[989,17531,17532],{},"Ví dụ đời thường: tự xếp sách theo màu không ai bảo.",[981,17534,17536],{"id":17535},"vòng-đời-6-giai-đoạn","Vòng đời 6 giai đoạn",[986,17538,17539,17542,17545,17548,17551],{},[989,17540,17541],{},"Hiểu bài toán kinh doanh cần gì.",[989,17543,17544],{},"Hiểu dữ liệu đang có gì.",[989,17546,17547],{},"Làm sạch và chuẩn hóa dữ liệu.",[989,17549,17550],{},"Chọn mô hình gom cụm.",[989,17552,17553],{},"Ví dụ đời thường: nấu ăn từ đi chợ tới dọn mâm.",[981,17555,17557],{"id":17556},"ba-khoảng-cách","Ba khoảng cách",[986,17559,17560,17563,17566,17569],{},[989,17561,17562],{},"Euclid là đường chim bay, hợp số liên tục.",[989,17564,17565],{},"Manhattan là đi theo lưới phố, đỡ sợ ngoại lệ.",[989,17567,17568],{},"Cosine đo hướng, hợp văn bản dài ngắn khác nhau.",[989,17570,17571],{},"Ví dụ đời thường: bay thẳng, đi taxi, so chủ đề.",[1099,17573,17574,17584],{},[1102,17575,17576],{},[1105,17577,17578,17581],{},[1108,17579,17580],{},"Khoảng cách",[1108,17582,17583],{},"Hợp dữ liệu nào",[1118,17585,17586,17594,17602],{},[1105,17587,17588,17591],{},[1123,17589,17590],{},"Euclid",[1123,17592,17593],{},"Số liên tục đã chuẩn hóa",[1105,17595,17596,17599],{},[1123,17597,17598],{},"Manhattan",[1123,17600,17601],{},"Rời rạc, nhiều ngoại lệ",[1105,17603,17604,17607],{},[1123,17605,17606],{},"Cosine",[1123,17608,17609],{},"Văn bản, chỉ cần hướng",[968,17611,1433],{"id":1432},[986,17613,17614,17617],{},[989,17615,17616],{},"Input: 2 vector giống hệt nhau. Output: cả 3 khoảng cách bằng 0.",[989,17618,17619],{},"Giải thích: giống nhau thì khoảng cách bằng không.",[968,17621,1482],{"id":1481},[973,17623,1485,17624,17626,17627,17630,17631,17634,17635,1517],{},[1487,17625,13531],{}," với NumPy. Không dùng ",[992,17628,17629],{},"scipy.spatial.distance"," hay ",[992,17632,17633],{},"sklearn"," cho Bài 1-2. Nộp vào ",[992,17636,17637],{},"day-022\u002F",[981,17639,17641],{"id":17640},"bài-1-ba-hàm-khoảng-cách","Bài 1: Ba hàm khoảng cách",[1099,17643,17644,17656],{},[1102,17645,17646],{},[1105,17647,17648,17650,17653],{},[1108,17649,1566],{},[1108,17651,17652],{},"Công thức",[1108,17654,17655],{},"Ghi chú",[1118,17657,17658,17924,18084],{},[1105,17659,17660,17665,17922],{},[1123,17661,17662],{},[992,17663,17664],{},"euclidean(a, b)",[1123,17666,17667],{},[1023,17668,17670,17715],{"className":17669},[1026],[1023,17671,17673],{"className":17672},[1030],[1032,17674,17675],{"xmlns":1034},[1036,17676,17677,17712],{},[1039,17678,17679],{},[17680,17681,17682],"msqrt",{},[1039,17683,17684,17687,17689,17696,17699,17706],{},[1046,17685,17686],{},"∑",[1046,17688,1049],{"stretchy":1048},[17690,17691,17692,17694],"msub",{},[1042,17693,6207],{},[1042,17695,1837],{},[1046,17697,17698],{},"−",[17690,17700,17701,17704],{},[1042,17702,17703],{},"b",[1042,17705,1837],{},[2327,17707,17708,17710],{},[1046,17709,1056],{"stretchy":1048},[1051,17711,2457],{},[1058,17713,17714],{"encoding":1060},"\\sqrt{\\sum (a_i - b_i)^2}",[1023,17716,17718],{"className":17717,"ariaHidden":1066},[1065],[1023,17719,17721,17725],{"className":17720},[1070],[1023,17722],{"className":17723,"style":17724},[1074],"height:1.24em;vertical-align:-0.305em;",[1023,17726,17729],{"className":17727},[1079,17728],"sqrt",[1023,17730,17733,17913],{"className":17731},[2387,17732],"vlist-t2",[1023,17734,17736,17910],{"className":17735},[2391],[1023,17737,17740,17887],{"className":17738,"style":17739},[2395],"height:0.935em;",[1023,17741,17745,17749],{"className":17742,"style":17744},[17743],"svg-align","top:-3.2em;",[1023,17746],{"className":17747,"style":17748},[2402],"height:3.2em;",[1023,17750,17753,17759,17762,17807,17810,17813,17816,17856],{"className":17751,"style":17752},[1079],"padding-left:1em;",[1023,17754,17686],{"className":17755,"style":17758},[8426,17756,17757],"op-symbol","small-op","position:relative;top:0em;",[1023,17760,1049],{"className":17761},[1085],[1023,17763,17765,17768],{"className":17764},[1079],[1023,17766,6207],{"className":17767},[1079,1080],[1023,17769,17771],{"className":17770},[2383],[1023,17772,17774,17798],{"className":17773},[2387,17732],[1023,17775,17777,17793],{"className":17776},[2391],[1023,17778,17781],{"className":17779,"style":17780},[2395],"height:0.3117em;",[1023,17782,17784,17787],{"style":17783},"top:-2.55em;margin-left:0em;margin-right:0.05em;",[1023,17785],{"className":17786,"style":2403},[2402],[1023,17788,17790],{"className":17789},[2407,2408,2409,2410],[1023,17791,1837],{"className":17792},[1079,1080,2410],[1023,17794,17797],{"className":17795},[17796],"vlist-s","​",[1023,17799,17801],{"className":17800},[2391],[1023,17802,17805],{"className":17803,"style":17804},[2395],"height:0.15em;",[1023,17806],{},[1023,17808],{"className":17809,"style":13790},[2354],[1023,17811,17698],{"className":17812},[13794],[1023,17814],{"className":17815,"style":13790},[2354],[1023,17817,17819,17822],{"className":17818},[1079],[1023,17820,17703],{"className":17821},[1079,1080],[1023,17823,17825],{"className":17824},[2383],[1023,17826,17828,17848],{"className":17827},[2387,17732],[1023,17829,17831,17845],{"className":17830},[2391],[1023,17832,17834],{"className":17833,"style":17780},[2395],[1023,17835,17836,17839],{"style":17783},[1023,17837],{"className":17838,"style":2403},[2402],[1023,17840,17842],{"className":17841},[2407,2408,2409,2410],[1023,17843,1837],{"className":17844},[1079,1080,2410],[1023,17846,17797],{"className":17847},[17796],[1023,17849,17851],{"className":17850},[2391],[1023,17852,17854],{"className":17853,"style":17804},[2395],[1023,17855],{},[1023,17857,17859,17862],{"className":17858},[1092],[1023,17860,1056],{"className":17861},[1092],[1023,17863,17865],{"className":17864},[2383],[1023,17866,17868],{"className":17867},[2387],[1023,17869,17871],{"className":17870},[2391],[1023,17872,17875],{"className":17873,"style":17874},[2395],"height:0.7401em;",[1023,17876,17878,17881],{"style":17877},"top:-2.989em;margin-right:0.05em;",[1023,17879],{"className":17880,"style":2403},[2402],[1023,17882,17884],{"className":17883},[2407,2408,2409,2410],[1023,17885,2457],{"className":17886},[1079,2410],[1023,17888,17890,17893],{"style":17889},"top:-2.895em;",[1023,17891],{"className":17892,"style":17748},[2402],[1023,17894,17898],{"className":17895,"style":17897},[17896],"hide-tail","min-width:1.02em;height:1.28em;",[17899,17900,17906],"svg",{"xmlns":17901,"width":17902,"height":17903,"viewBox":17904,"preserveAspectRatio":17905},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","400em","1.28em","0 0 400000 1296","xMinYMin slice",[17907,17908],"path",{"d":17909},"M263,681c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl0 -0\nc4.7,-7.3,11,-11,19,-11\nH40000v40H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM1001 80h400000v40h-400000z",[1023,17911,17797],{"className":17912},[17796],[1023,17914,17916],{"className":17915},[2391],[1023,17917,17920],{"className":17918,"style":17919},[2395],"height:0.305em;",[1023,17921],{},[1123,17923],{},[1105,17925,17926,17931,18082],{},[1123,17927,17928],{},[992,17929,17930],{},"manhattan(a, b)",[1123,17932,17933],{},[1023,17934,17936,17969],{"className":17935},[1026],[1023,17937,17939],{"className":17938},[1030],[1032,17940,17941],{"xmlns":1034},[1036,17942,17943,17966],{},[1039,17944,17945,17947,17950,17956,17958,17964],{},[1046,17946,17686],{},[1046,17948,17949],{"stretchy":1048},"∣",[17690,17951,17952,17954],{},[1042,17953,6207],{},[1042,17955,1837],{},[1046,17957,17698],{},[17690,17959,17960,17962],{},[1042,17961,17703],{},[1042,17963,1837],{},[1046,17965,17949],{"stretchy":1048},[1058,17967,17968],{"encoding":1060},"\\sum \\lvert a_i - b_i \\rvert",[1023,17970,17972,18033],{"className":17971,"ariaHidden":1066},[1065],[1023,17973,17975,17978,17981,17984,18024,18027,18030],{"className":17974},[1070],[1023,17976],{"className":17977,"style":1075},[1074],[1023,17979,17686],{"className":17980,"style":17758},[8426,17756,17757],[1023,17982,17949],{"className":17983},[1085],[1023,17985,17987,17990],{"className":17986},[1079],[1023,17988,6207],{"className":17989},[1079,1080],[1023,17991,17993],{"className":17992},[2383],[1023,17994,17996,18016],{"className":17995},[2387,17732],[1023,17997,17999,18013],{"className":17998},[2391],[1023,18000,18002],{"className":18001,"style":17780},[2395],[1023,18003,18004,18007],{"style":17783},[1023,18005],{"className":18006,"style":2403},[2402],[1023,18008,18010],{"className":18009},[2407,2408,2409,2410],[1023,18011,1837],{"className":18012},[1079,1080,2410],[1023,18014,17797],{"className":18015},[17796],[1023,18017,18019],{"className":18018},[2391],[1023,18020,18022],{"className":18021,"style":17804},[2395],[1023,18023],{},[1023,18025],{"className":18026,"style":13790},[2354],[1023,18028,17698],{"className":18029},[13794],[1023,18031],{"className":18032,"style":13790},[2354],[1023,18034,18036,18039,18079],{"className":18035},[1070],[1023,18037],{"className":18038,"style":1075},[1074],[1023,18040,18042,18045],{"className":18041},[1079],[1023,18043,17703],{"className":18044},[1079,1080],[1023,18046,18048],{"className":18047},[2383],[1023,18049,18051,18071],{"className":18050},[2387,17732],[1023,18052,18054,18068],{"className":18053},[2391],[1023,18055,18057],{"className":18056,"style":17780},[2395],[1023,18058,18059,18062],{"style":17783},[1023,18060],{"className":18061,"style":2403},[2402],[1023,18063,18065],{"className":18064},[2407,2408,2409,2410],[1023,18066,1837],{"className":18067},[1079,1080,2410],[1023,18069,17797],{"className":18070},[17796],[1023,18072,18074],{"className":18073},[2391],[1023,18075,18077],{"className":18076,"style":17804},[2395],[1023,18078],{},[1023,18080,17949],{"className":18081},[1092],[1123,18083],{},[1105,18085,18086,18091,18266],{},[1123,18087,18088],{},[992,18089,18090],{},"cosine_distance(a, b)",[1123,18092,18093],{},[1023,18094,18096,18139],{"className":18095},[1026],[1023,18097,18099],{"className":18098},[1030],[1032,18100,18101],{"xmlns":1034},[1036,18102,18103,18136],{},[1039,18104,18105,18107,18109],{},[1051,18106,1053],{},[1046,18108,17698],{},[18110,18111,18112,18121],"mfrac",{},[1039,18113,18114,18116,18119],{},[1042,18115,6207],{},[1046,18117,18118],{},"⋅",[1042,18120,17703],{},[1039,18122,18123,18126,18128,18130,18132,18134],{},[1046,18124,18125],{"stretchy":1048},"∥",[1042,18127,6207],{},[1046,18129,18125],{"stretchy":1048},[1046,18131,18125],{"stretchy":1048},[1042,18133,17703],{},[1046,18135,18125],{"stretchy":1048},[1058,18137,18138],{"encoding":1060},"1 - \\frac{a \\cdot b}{\\lVert a \\rVert \\lVert b \\rVert}",[1023,18140,18142,18161],{"className":18141,"ariaHidden":1066},[1065],[1023,18143,18145,18149,18152,18155,18158],{"className":18144},[1070],[1023,18146],{"className":18147,"style":18148},[1074],"height:0.7278em;vertical-align:-0.0833em;",[1023,18150,1053],{"className":18151},[1079],[1023,18153],{"className":18154,"style":13790},[2354],[1023,18156,17698],{"className":18157},[13794],[1023,18159],{"className":18160,"style":13790},[2354],[1023,18162,18164,18168],{"className":18163},[1070],[1023,18165],{"className":18166,"style":18167},[1074],"height:1.4001em;vertical-align:-0.52em;",[1023,18169,18171,18175,18263],{"className":18170},[1079],[1023,18172],{"className":18173},[1085,18174],"nulldelimiter",[1023,18176,18178],{"className":18177},[18110],[1023,18179,18181,18254],{"className":18180},[2387,17732],[1023,18182,18184,18251],{"className":18183},[2391],[1023,18185,18188,18219,18230],{"className":18186,"style":18187},[2395],"height:0.8801em;",[1023,18189,18191,18195],{"style":18190},"top:-2.655em;",[1023,18192],{"className":18193,"style":18194},[2402],"height:3em;",[1023,18196,18198],{"className":18197},[2407,2408,2409,2410],[1023,18199,18201,18204,18207,18210,18213,18216],{"className":18200},[1079,2410],[1023,18202,18125],{"className":18203},[1085,2410],[1023,18205,6207],{"className":18206},[1079,1080,2410],[1023,18208,18125],{"className":18209},[1092,2410],[1023,18211,18125],{"className":18212},[1085,2410],[1023,18214,17703],{"className":18215},[1079,1080,2410],[1023,18217,18125],{"className":18218},[1092,2410],[1023,18220,18222,18225],{"style":18221},"top:-3.23em;",[1023,18223],{"className":18224,"style":18194},[2402],[1023,18226],{"className":18227,"style":18229},[18228],"frac-line","border-bottom-width:0.04em;",[1023,18231,18233,18236],{"style":18232},"top:-3.394em;",[1023,18234],{"className":18235,"style":18194},[2402],[1023,18237,18239],{"className":18238},[2407,2408,2409,2410],[1023,18240,18242,18245,18248],{"className":18241},[1079,2410],[1023,18243,6207],{"className":18244},[1079,1080,2410],[1023,18246,18118],{"className":18247},[13794,2410],[1023,18249,17703],{"className":18250},[1079,1080,2410],[1023,18252,17797],{"className":18253},[17796],[1023,18255,18257],{"className":18256},[2391],[1023,18258,18261],{"className":18259,"style":18260},[2395],"height:0.52em;",[1023,18262],{},[1023,18264],{"className":18265},[1092,18174],[1123,18267,18268,18269],{},"Vector 0 thì ném ",[992,18270,13663],{},[973,18272,18273],{},"Mọi hàm kiểm tra 2 vector cùng độ dài.",[1352,18275,18278],{"className":18276,"code":18277,"language":2241,"meta":1357},[2239],"a=[1,2,3], b=[1,2,3]      -> 0, 0, 0\na=[0,0],   b=[3,4]        -> euclid 5, manhattan 7, cosine ValueError\na=[1,0],   b=[0,1]        -> euclid 1.414, manhattan 2, cosine 1\na=[1,1],   b=[10,10]      -> euclid 12.73, cosine 0 (cùng hướng)\n",[992,18279,18277],{"__ignoreMap":1357},[981,18281,18283],{"id":18282},"bài-2-chuẩn-hóa-và-ma-trận-khoảng-cách","Bài 2: Chuẩn hóa và ma trận khoảng cách",[2273,18285,18286,18296,18302],{},[989,18287,18288,18291,18292,18295],{},[992,18289,18290],{},"minmax_scale(X)",": mỗi cột về ",[992,18293,18294],{},"[0, 1]",". Cột hằng số thì giữ 0.",[989,18297,18298,18301],{},[992,18299,18300],{},"zscore(X)",": mỗi cột trung bình 0, độ lệch chuẩn 1.",[989,18303,18304,18307,18308,1517],{},[992,18305,18306],{},"pairwise(X, metric)",": trả ma trận ",[1023,18309,18311,18328],{"className":18310},[1026],[1023,18312,18314],{"className":18313},[1030],[1032,18315,18316],{"xmlns":1034},[1036,18317,18318,18326],{},[1039,18319,18320,18322,18324],{},[1042,18321,1262],{},[1046,18323,13768],{},[1042,18325,1262],{},[1058,18327,13773],{"encoding":1060},[1023,18329,18331,18349],{"className":18330,"ariaHidden":1066},[1065],[1023,18332,18334,18337,18340,18343,18346],{"className":18333},[1070],[1023,18335],{"className":18336,"style":13783},[1074],[1023,18338,1262],{"className":18339},[1079,1080],[1023,18341],{"className":18342,"style":13790},[2354],[1023,18344,13768],{"className":18345},[13794],[1023,18347],{"className":18348,"style":13790},[2354],[1023,18350,18352,18355],{"className":18351},[1070],[1023,18353],{"className":18354,"style":2347},[1074],[1023,18356,1262],{"className":18357},[1079,1080],[973,18359,18360],{},"Dữ liệu khách hàng (tuổi, thu nhập triệu\u002Ftháng, số lần mua\u002Ftháng):",[1352,18362,18365],{"className":18363,"code":18364,"language":2241,"meta":1357},[2239],"An   [25,  12, 8]\nBình [26, 120, 1]\nChi  [55,  14, 7]\nDũng [24,  13, 9]\n",[992,18366,18364],{"__ignoreMap":1357},[973,18368,18369,18370,18373,18374,18377],{},"In khách gần An nhất khi ",[1487,18371,18372],{},"chưa"," chuẩn hóa và ",[1487,18375,18376],{},"sau"," z-score. Giải thích vì sao đáp án đổi.",[981,18379,18381],{"id":18380},"bài-3-văn-bản-và-cosine-nâng-cao","Bài 3: Văn bản và cosine (nâng cao)",[2273,18383,18384,18387,18390],{},[989,18385,18386],{},"Biến 5 câu thành vector đếm từ (bag of words tự cài, tách theo khoảng trắng, chữ thường).",[989,18388,18389],{},"Câu thứ 5 là câu thứ 1 lặp lại 3 lần. Chứng minh cosine distance giữa 1 và 5 bằng 0, còn Euclid thì lớn.",[989,18391,18392],{},"Tìm cặp câu gần nhau nhất theo cosine.",[981,18394,2711],{"id":2710},[986,18396,18398,18411,18417,18423],{"className":18397},[2715],[989,18399,18401,18403,18404,18407,18408,16014],{"className":18400},[2719],[2721,18402],{"disabled":2723,"type":2724}," Test mẫu pass với sai số ",[992,18405,18406],{},"1e-3"," (",[992,18409,18410],{},"math.isclose",[989,18412,18414,18416],{"className":18413},[2719],[2721,18415],{"disabled":2723,"type":2724}," Bài 2 có giải thích bằng số tại sao thu nhập lấn át khi chưa chuẩn hóa.",[989,18418,18420,18422],{"className":18419},[2719],[2721,18421],{"disabled":2723,"type":2724}," Bài 3 chứng minh được cosine bỏ qua độ dài văn bản.",[989,18424,18426,18428],{"className":18425},[2719],[2721,18427],{"disabled":2723,"type":2724}," Viết được 6 giai đoạn vòng đời bằng lời của mình, gắn với bài toán phân khúc khách hàng.",[968,18430,2890],{"id":2889},[986,18432,18433,18436,18439,18442],{},[989,18434,18435],{},"Học không giám sát khác có giám sát ở đâu?",[989,18437,18438],{},"Vòng đời gồm những giai đoạn nào?",[989,18440,18441],{},"Ba khoảng cách dùng khi nào?",[989,18443,18444],{},"Phân khúc khách để làm gì?",[3014,18446],{},[973,18448,18449],{},"🌕 Bạn đã hoàn thành ngày 22. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":18451},[18452,18453,18458,18459,18465],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":18454},[18455,18456,18457],{"id":17517,"depth":73,"text":17518},{"id":17535,"depth":73,"text":17536},{"id":17556,"depth":73,"text":17557},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":18460},[18461,18462,18463,18464],{"id":17640,"depth":73,"text":17641},{"id":18282,"depth":73,"text":18283},{"id":18380,"depth":73,"text":18381},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tổng quan học không giám sát: vòng đời khai phá sáu giai đoạn, ba khoảng cách Euclid Manhattan cosine và phân khúc marketing.",{},[15144,18469],"giai-thuat-ngau-nhien-va-do-chinh-xac",{"title":165,"description":18466},[18472,18473,18474],"ml","unsupervised","lifecycle","1ODMZTMYxoQeuGDxc6afupXQbI0lzlEYxlK3g9wNs4U",{"id":18477,"title":170,"body":18478,"category":3041,"day":173,"description":19401,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":19402,"navigation":2723,"outcomes":3047,"path":171,"prerequisites":19403,"seo":19404,"stem":172,"tags":19405,"__hash__":19408},"challenges\u002Fchallenges\u002F23.priority-queue-va-heap.md",{"type":965,"value":18479,"toc":19385},[18480,18482,18543,18545,18549,18563,18567,18581,18585,18602,18948,18950,18958,18960,18973,18977,19044,19176,19182,19186,19191,19197,19203,19214,19218,19221,19314,19320,19322,19362,19364,19378,19380,19383],[968,18481,971],{"id":970},[973,18483,18484,18485,1517],{},"Bài này học hàng đợi ưu tiên qua lỗi phần mềm. Bạn lấy việc khẩn nhất trong ",[1023,18486,18488,18513],{"className":18487},[1026],[1023,18489,18491],{"className":18490},[1030],[1032,18492,18493],{"xmlns":1034},[1036,18494,18495,18511],{},[1039,18496,18497,18499,18501,18503,18505,18507,18509],{},[1042,18498,1044],{},[1046,18500,1049],{"stretchy":1048},[1042,18502,7684],{},[1042,18504,7687],{},[1042,18506,7690],{},[1042,18508,1262],{},[1046,18510,1056],{"stretchy":1048},[1058,18512,7697],{"encoding":1060},[1023,18514,18516],{"className":18515,"ariaHidden":1066},[1065],[1023,18517,18519,18522,18525,18528,18531,18534,18537,18540],{"className":18518},[1070],[1023,18520],{"className":18521,"style":1075},[1074],[1023,18523,1044],{"className":18524,"style":1081},[1079,1080],[1023,18526,1049],{"className":18527},[1085],[1023,18529,7684],{"className":18530,"style":7716},[1079,1080],[1023,18532,7687],{"className":18533},[1079,1080],[1023,18535,7690],{"className":18536,"style":7723},[1079,1080],[1023,18538,1262],{"className":18539},[1079,1080],[1023,18541,1056],{"className":18542},[1092],[968,18544,979],{"id":978},[981,18546,18548],{"id":18547},"bài-toán-ưu-tiên","Bài toán ưu tiên",[986,18550,18551,18554,18557,18560],{},[989,18552,18553],{},"Nhiều việc, mỗi việc 1 độ khẩn khác nhau.",[989,18555,18556],{},"Mỗi lần cần việc khẩn nhất, không cần xếp hết.",[989,18558,18559],{},"Giữ list xếp sẵn thì chèn sửa rất đắt.",[989,18561,18562],{},"Ví dụ đời thường: phòng cấp cứu khám ca nặng trước.",[981,18564,18566],{"id":18565},"hàng-đợi-ưu-tiên-và-api","Hàng đợi ưu tiên và API",[986,18568,18569,18572,18575,18578],{},[989,18570,18571],{},"Chỉ đảm bảo món lấy ra là khẩn nhất.",[989,18573,18574],{},"Có chèn, lấy khẩn nhất, nhìn, đổi ưu tiên.",[989,18576,18577],{},"Dùng như hộp đen, khỏi biết bên trong là gì.",[989,18579,18580],{},"Ví dụ đời thường: bấm số thứ tự ưu tiên.",[981,18582,18584],{"id":18583},"min-heap-max-heap-mảng","Min-heap, max-heap, mảng",[986,18586,18587,18590,18593,18596,18599],{},[989,18588,18589],{},"Max-heap đặt lớn nhất ở gốc.",[989,18591,18592],{},"Min-heap đặt nhỏ nhất ở gốc.",[989,18594,18595],{},"Cây hoàn chỉnh nhét vừa khít vào mảng.",[989,18597,18598],{},"Ví dụ đời thường: sếp to nhất ngồi đỉnh tháp.",[989,18600,18601],{},"Cha của i ở (i-1)\u002F\u002F2, con ở 2i+1 và 2i+2.",[1099,18603,18604,18616],{},[1102,18605,18606],{},[1105,18607,18608,18610,18613],{},[1108,18609,1110],{},[1108,18611,18612],{},"List xếp sẵn",[1108,18614,18615],{},"Heap",[1118,18617,18618,18728,18838],{},[1105,18619,18620,18623,18668],{},[1123,18621,18622],{},"Chèn",[1123,18624,18625],{},[1023,18626,18628,18647],{"className":18627},[1026],[1023,18629,18631],{"className":18630},[1030],[1032,18632,18633],{"xmlns":1034},[1036,18634,18635,18645],{},[1039,18636,18637,18639,18641,18643],{},[1042,18638,1044],{},[1046,18640,1049],{"stretchy":1048},[1042,18642,1262],{},[1046,18644,1056],{"stretchy":1048},[1058,18646,1267],{"encoding":1060},[1023,18648,18650],{"className":18649,"ariaHidden":1066},[1065],[1023,18651,18653,18656,18659,18662,18665],{"className":18652},[1070],[1023,18654],{"className":18655,"style":1075},[1074],[1023,18657,1044],{"className":18658,"style":1081},[1079,1080],[1023,18660,1049],{"className":18661},[1085],[1023,18663,1262],{"className":18664},[1079,1080],[1023,18666,1056],{"className":18667},[1092],[1123,18669,18670],{},[1023,18671,18673,18698],{"className":18672},[1026],[1023,18674,18676],{"className":18675},[1030],[1032,18677,18678],{"xmlns":1034},[1036,18679,18680,18696],{},[1039,18681,18682,18684,18686,18688,18690,18692,18694],{},[1042,18683,1044],{},[1046,18685,1049],{"stretchy":1048},[1042,18687,7684],{},[1042,18689,7687],{},[1042,18691,7690],{},[1042,18693,1262],{},[1046,18695,1056],{"stretchy":1048},[1058,18697,7697],{"encoding":1060},[1023,18699,18701],{"className":18700,"ariaHidden":1066},[1065],[1023,18702,18704,18707,18710,18713,18716,18719,18722,18725],{"className":18703},[1070],[1023,18705],{"className":18706,"style":1075},[1074],[1023,18708,1044],{"className":18709,"style":1081},[1079,1080],[1023,18711,1049],{"className":18712},[1085],[1023,18714,7684],{"className":18715,"style":7716},[1079,1080],[1023,18717,7687],{"className":18718},[1079,1080],[1023,18720,7690],{"className":18721,"style":7723},[1079,1080],[1023,18723,1262],{"className":18724},[1079,1080],[1023,18726,1056],{"className":18727},[1092],[1105,18729,18730,18733,18778],{},[1123,18731,18732],{},"Lấy khẩn nhất",[1123,18734,18735],{},[1023,18736,18738,18757],{"className":18737},[1026],[1023,18739,18741],{"className":18740},[1030],[1032,18742,18743],{"xmlns":1034},[1036,18744,18745,18755],{},[1039,18746,18747,18749,18751,18753],{},[1042,18748,1044],{},[1046,18750,1049],{"stretchy":1048},[1051,18752,1053],{},[1046,18754,1056],{"stretchy":1048},[1058,18756,1061],{"encoding":1060},[1023,18758,18760],{"className":18759,"ariaHidden":1066},[1065],[1023,18761,18763,18766,18769,18772,18775],{"className":18762},[1070],[1023,18764],{"className":18765,"style":1075},[1074],[1023,18767,1044],{"className":18768,"style":1081},[1079,1080],[1023,18770,1049],{"className":18771},[1085],[1023,18773,1053],{"className":18774},[1079],[1023,18776,1056],{"className":18777},[1092],[1123,18779,18780],{},[1023,18781,18783,18808],{"className":18782},[1026],[1023,18784,18786],{"className":18785},[1030],[1032,18787,18788],{"xmlns":1034},[1036,18789,18790,18806],{},[1039,18791,18792,18794,18796,18798,18800,18802,18804],{},[1042,18793,1044],{},[1046,18795,1049],{"stretchy":1048},[1042,18797,7684],{},[1042,18799,7687],{},[1042,18801,7690],{},[1042,18803,1262],{},[1046,18805,1056],{"stretchy":1048},[1058,18807,7697],{"encoding":1060},[1023,18809,18811],{"className":18810,"ariaHidden":1066},[1065],[1023,18812,18814,18817,18820,18823,18826,18829,18832,18835],{"className":18813},[1070],[1023,18815],{"className":18816,"style":1075},[1074],[1023,18818,1044],{"className":18819,"style":1081},[1079,1080],[1023,18821,1049],{"className":18822},[1085],[1023,18824,7684],{"className":18825,"style":7716},[1079,1080],[1023,18827,7687],{"className":18828},[1079,1080],[1023,18830,7690],{"className":18831,"style":7723},[1079,1080],[1023,18833,1262],{"className":18834},[1079,1080],[1023,18836,1056],{"className":18837},[1092],[1105,18839,18840,18843,18888],{},[1123,18841,18842],{},"Đổi ưu tiên",[1123,18844,18845],{},[1023,18846,18848,18867],{"className":18847},[1026],[1023,18849,18851],{"className":18850},[1030],[1032,18852,18853],{"xmlns":1034},[1036,18854,18855,18865],{},[1039,18856,18857,18859,18861,18863],{},[1042,18858,1044],{},[1046,18860,1049],{"stretchy":1048},[1042,18862,1262],{},[1046,18864,1056],{"stretchy":1048},[1058,18866,1267],{"encoding":1060},[1023,18868,18870],{"className":18869,"ariaHidden":1066},[1065],[1023,18871,18873,18876,18879,18882,18885],{"className":18872},[1070],[1023,18874],{"className":18875,"style":1075},[1074],[1023,18877,1044],{"className":18878,"style":1081},[1079,1080],[1023,18880,1049],{"className":18881},[1085],[1023,18883,1262],{"className":18884},[1079,1080],[1023,18886,1056],{"className":18887},[1092],[1123,18889,18890],{},[1023,18891,18893,18918],{"className":18892},[1026],[1023,18894,18896],{"className":18895},[1030],[1032,18897,18898],{"xmlns":1034},[1036,18899,18900,18916],{},[1039,18901,18902,18904,18906,18908,18910,18912,18914],{},[1042,18903,1044],{},[1046,18905,1049],{"stretchy":1048},[1042,18907,7684],{},[1042,18909,7687],{},[1042,18911,7690],{},[1042,18913,1262],{},[1046,18915,1056],{"stretchy":1048},[1058,18917,7697],{"encoding":1060},[1023,18919,18921],{"className":18920,"ariaHidden":1066},[1065],[1023,18922,18924,18927,18930,18933,18936,18939,18942,18945],{"className":18923},[1070],[1023,18925],{"className":18926,"style":1075},[1074],[1023,18928,1044],{"className":18929,"style":1081},[1079,1080],[1023,18931,1049],{"className":18932},[1085],[1023,18934,7684],{"className":18935,"style":7716},[1079,1080],[1023,18937,7687],{"className":18938},[1079,1080],[1023,18940,7690],{"className":18941,"style":7723},[1079,1080],[1023,18943,1262],{"className":18944},[1079,1080],[1023,18946,1056],{"className":18947},[1092],[968,18949,1433],{"id":1432},[986,18951,18952,18955],{},[989,18953,18954],{},"Input: chèn lỗi ưu tiên 5, 9, 7 vào max-heap. Output: gốc là 9.",[989,18956,18957],{},"Giải thích: cha luôn khẩn hơn con trên cùng đường.",[968,18959,1482],{"id":1481},[973,18961,1485,18962,2256,18964,1656,18967,5599,18970,1517],{},[1487,18963,1493],{},[992,18965,18966],{},"std::priority_queue",[992,18968,18969],{},"std::make_heap",[992,18971,18972],{},"day-023\u002F",[981,18974,18976],{"id":18975},"bài-1-max-heap-trên-mảng","Bài 1: Max-heap trên mảng",[1352,18978,18980],{"className":1393,"code":18979,"language":1395,"meta":1357,"style":1357},"class MaxHeap {\n public:\n  void push(int x);\n  int  top() const;          \u002F\u002F ném std::out_of_range nếu rỗng\n  int  pop();                \u002F\u002F lấy và trả gốc\n  size_t size() const; bool empty() const;\n  bool isValid() const;      \u002F\u002F kiểm tra bất biến heap, dùng khi test\n private:\n  std::vector\u003Cint> a;\n  static size_t parent(size_t i) { return (i - 1) \u002F 2; }\n  static size_t left(size_t i)   { return 2 * i + 1; }\n  static size_t right(size_t i)  { return 2 * i + 2; }\n};\n",[992,18981,18982,18987,18991,18996,19001,19006,19011,19016,19020,19025,19030,19035,19040],{"__ignoreMap":1357},[1023,18983,18984],{"class":1362,"line":63},[1023,18985,18986],{},"class MaxHeap {\n",[1023,18988,18989],{"class":1362,"line":68},[1023,18990,4836],{},[1023,18992,18993],{"class":1362,"line":73},[1023,18994,18995],{},"  void push(int x);\n",[1023,18997,18998],{"class":1362,"line":78},[1023,18999,19000],{},"  int  top() const;          \u002F\u002F ném std::out_of_range nếu rỗng\n",[1023,19002,19003],{"class":1362,"line":83},[1023,19004,19005],{},"  int  pop();                \u002F\u002F lấy và trả gốc\n",[1023,19007,19008],{"class":1362,"line":88},[1023,19009,19010],{},"  size_t size() const; bool empty() const;\n",[1023,19012,19013],{"class":1362,"line":93},[1023,19014,19015],{},"  bool isValid() const;      \u002F\u002F kiểm tra bất biến heap, dùng khi test\n",[1023,19017,19018],{"class":1362,"line":98},[1023,19019,16301],{},[1023,19021,19022],{"class":1362,"line":103},[1023,19023,19024],{},"  std::vector\u003Cint> a;\n",[1023,19026,19027],{"class":1362,"line":108},[1023,19028,19029],{},"  static size_t parent(size_t i) { return (i - 1) \u002F 2; }\n",[1023,19031,19032],{"class":1362,"line":113},[1023,19033,19034],{},"  static size_t left(size_t i)   { return 2 * i + 1; }\n",[1023,19036,19037],{"class":1362,"line":118},[1023,19038,19039],{},"  static size_t right(size_t i)  { return 2 * i + 2; }\n",[1023,19041,19042],{"class":1362,"line":123},[1023,19043,4866],{},[1099,19045,19046,19054],{},[1102,19047,19048],{},[1105,19049,19050,19052],{},[1108,19051,1110],{},[1108,19053,1113],{},[1118,19055,19056,19122],{},[1105,19057,19058,19065],{},[1123,19059,19060,1656,19062],{},[992,19061,1010],{},[992,19063,19064],{},"pop",[1123,19066,19067],{},[1023,19068,19070,19093],{"className":19069},[1026],[1023,19071,19073],{"className":19072},[1030],[1032,19074,19075],{"xmlns":1034},[1036,19076,19077,19091],{},[1039,19078,19079,19081,19083,19085,19087,19089],{},[1042,19080,1044],{},[1046,19082,1049],{"stretchy":1048},[1042,19084,8397],{},[1046,19086,8400],{},[1042,19088,1262],{},[1046,19090,1056],{"stretchy":1048},[1058,19092,8407],{"encoding":1060},[1023,19094,19096],{"className":19095,"ariaHidden":1066},[1065],[1023,19097,19099,19102,19105,19108,19113,19116,19119],{"className":19098},[1070],[1023,19100],{"className":19101,"style":1075},[1074],[1023,19103,1044],{"className":19104,"style":1081},[1079,1080],[1023,19106,1049],{"className":19107},[1085],[1023,19109,8427,19111],{"className":19110},[8426],[1023,19112,7690],{"style":8430},[1023,19114],{"className":19115,"style":8434},[2354],[1023,19117,1262],{"className":19118},[1079,1080],[1023,19120,1056],{"className":19121},[1092],[1105,19123,19124,19131],{},[1123,19125,19126,1656,19129],{},[992,19127,19128],{},"top",[992,19130,994],{},[1123,19132,19133],{},[1023,19134,19136,19155],{"className":19135},[1026],[1023,19137,19139],{"className":19138},[1030],[1032,19140,19141],{"xmlns":1034},[1036,19142,19143,19153],{},[1039,19144,19145,19147,19149,19151],{},[1042,19146,1044],{},[1046,19148,1049],{"stretchy":1048},[1051,19150,1053],{},[1046,19152,1056],{"stretchy":1048},[1058,19154,1061],{"encoding":1060},[1023,19156,19158],{"className":19157,"ariaHidden":1066},[1065],[1023,19159,19161,19164,19167,19170,19173],{"className":19160},[1070],[1023,19162],{"className":19163,"style":1075},[1074],[1023,19165,1044],{"className":19166,"style":1081},[1079,1080],[1023,19168,1049],{"className":19169},[1085],[1023,19171,1053],{"className":19172},[1079],[1023,19174,1056],{"className":19175},[1092],[1352,19177,19180],{"className":19178,"code":19179,"language":2241,"meta":1357},[2239],"push 5, 9, 7          -> top = 9, mảng [9, 5, 7]\npush 1, 12            -> top = 12\npop x5                -> 12, 9, 7, 5, 1\npop khi rỗng          -> ném out_of_range\n",[992,19181,19179],{"__ignoreMap":1357},[981,19183,19185],{"id":19184},"bài-2-hàng-đợi-ưu-tiên-cho-ticket-hỗ-trợ","Bài 2: Hàng đợi ưu tiên cho ticket hỗ trợ",[973,19187,19188],{},[992,19189,19190],{},"struct Ticket { int priority; long long createdAt; std::string title; };",[973,19192,1505,19193,19196],{},[992,19194,19195],{},"TicketQueue"," dựa trên heap với comparator: ưu tiên cao hơn ra trước; cùng ưu tiên thì ticket tạo sớm hơn ra trước.",[1352,19198,19201],{"className":19199,"code":19200,"language":2241,"meta":1357},[2239],"push (3, t=1, \"A\"), (5, t=2, \"B\"), (3, t=0, \"C\"), (5, t=3, \"D\")\npop hết -> B, D, C, A\n",[992,19202,19200],{"__ignoreMap":1357},[973,19204,19205,19206,19209,19210,19213],{},"Chuyển ",[992,19207,19208],{},"MaxHeap"," thành template ",[992,19211,19212],{},"Heap\u003CT, Compare>"," để dùng chung.",[981,19215,19217],{"id":19216},"bài-3-so-sánh-3-cách-cài-nâng-cao","Bài 3: So sánh 3 cách cài (nâng cao)",[973,19219,19220],{},"Cài hàng đợi ưu tiên bằng: (a) mảng chưa xếp, (b) mảng luôn xếp, (c) heap.",[973,19222,19223,19224,19307,19308,19310,19311,19313],{},"Chạy kịch bản ",[1023,19225,19227,19248],{"className":19226},[1026],[1023,19228,19230],{"className":19229},[1030],[1032,19231,19232],{"xmlns":1034},[1036,19233,19234,19246],{},[1039,19235,19236,19238,19240],{},[1042,19237,1262],{},[1046,19239,2325],{},[2327,19241,19242,19244],{},[1051,19243,2331],{},[1051,19245,2334],{},[1058,19247,2337],{"encoding":1060},[1023,19249,19251,19269],{"className":19250,"ariaHidden":1066},[1065],[1023,19252,19254,19257,19260,19263,19266],{"className":19253},[1070],[1023,19255],{"className":19256,"style":2347},[1074],[1023,19258,1262],{"className":19259},[1079,1080],[1023,19261],{"className":19262,"style":2355},[2354],[1023,19264,2325],{"className":19265},[2359],[1023,19267],{"className":19268,"style":2355},[2354],[1023,19270,19272,19275,19278],{"className":19271},[1070],[1023,19273],{"className":19274,"style":2369},[1074],[1023,19276,1053],{"className":19277},[1079],[1023,19279,19281,19284],{"className":19280},[1079],[1023,19282,2379],{"className":19283},[1079],[1023,19285,19287],{"className":19286},[2383],[1023,19288,19290],{"className":19289},[2387],[1023,19291,19293],{"className":19292},[2391],[1023,19294,19296],{"className":19295,"style":2369},[2395],[1023,19297,19298,19301],{"style":2398},[1023,19299],{"className":19300,"style":2403},[2402],[1023,19302,19304],{"className":19303},[2407,2408,2409,2410],[1023,19305,2334],{"className":19306},[1079,2410],": xen kẽ 2 lần ",[992,19309,1010],{}," giá trị ngẫu nhiên và 1 lần ",[992,19312,19064],{},". In bảng thời gian và độ phức tạp lý thuyết của từng thao tác.",[1352,19315,19318],{"className":19316,"code":19317,"language":2241,"meta":1357},[2239],"impl         push     pop      tổng (ms)\nunsorted     O(1)     O(n)     ...\nsorted       O(n)     O(1)     ...\nheap         O(logn)  O(logn)  ...\n",[992,19319,19317],{"__ignoreMap":1357},[981,19321,2711],{"id":2710},[986,19323,19325,19341,19350,19356],{"className":19324},[2715],[989,19326,19328,19330,19331,2461,19333,19335,19336,13710,19339,1517],{"className":19327},[2719],[2721,19329],{"disabled":2723,"type":2724}," Test mẫu pass. Sau mỗi ",[992,19332,1010],{},[992,19334,19064],{}," trong test ngẫu nhiên, ",[992,19337,19338],{},"isValid()",[992,19340,1066],{},[989,19342,19344,19346,19347,19349],{"className":19343},[2719],[2721,19345],{"disabled":2723,"type":2724}," Kết quả ",[992,19348,19064],{}," hết khớp với sắp xếp giảm dần (test 1000 lần ngẫu nhiên).",[989,19351,19353,19355],{"className":19352},[2719],[2721,19354],{"disabled":2723,"type":2724}," Bảng Bài 3 có số thật.",[989,19357,19359,19361],{"className":19358},[2719],[2721,19360],{"disabled":2723,"type":2724}," Vẽ tay được cây và mảng tương ứng sau mỗi thao tác của test mẫu.",[968,19363,2890],{"id":2889},[986,19365,19366,19369,19372,19375],{},[989,19367,19368],{},"Vì sao list xếp sẵn không đủ cho việc động?",[989,19370,19371],{},"API hàng đợi ưu tiên có gì?",[989,19373,19374],{},"Min-heap khác max-heap ở đâu?",[989,19376,19377],{},"Công thức cha con trong mảng là gì?",[3014,19379],{},[973,19381,19382],{},"🌕 Bạn đã hoàn thành ngày 23. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,19384,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":19386},[19387,19388,19393,19394,19400],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":19389},[19390,19391,19392],{"id":18547,"depth":73,"text":18548},{"id":18565,"depth":73,"text":18566},{"id":18583,"depth":73,"text":18584},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":19395},[19396,19397,19398,19399],{"id":18975,"depth":73,"text":18976},{"id":19184,"depth":73,"text":19185},{"id":19216,"depth":73,"text":19217},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu hàng đợi ưu tiên qua bài toán theo dõi lỗi, hợp đồng API, min-heap max-heap và cách mảng biểu diễn cây hoàn chỉnh.",{},[3050,3049],{"title":170,"description":19401},[19406,19407],"priority-queue","heap","ak4Bb1B3VeTyg533xMYglqdTk9_qAhmijRmK1k5e854",{"id":19410,"title":175,"body":19411,"category":3041,"day":178,"description":20610,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":20611,"navigation":2723,"outcomes":3047,"path":176,"prerequisites":20612,"seo":20613,"stem":177,"tags":20614,"__hash__":20615},"challenges\u002Fchallenges\u002F24.heap-operations.md",{"type":965,"value":19412,"toc":20594},[19413,19415,19418,19420,19424,19496,19500,19558,19562,19576,19831,19833,19841,19843,19854,19858,20146,20152,20246,20250,20261,20324,20386,20392,20396,20473,20479,20482,20484,20573,20575,20589,20591],[968,19414,971],{"id":970},[973,19416,19417],{},"Bài này mổ từng thao tác của heap. Bạn đẩy lên đẩy xuống đúng hướng.",[968,19419,979],{"id":978},[981,19421,19423],{"id":19422},"đẩy-lên-và-đẩy-xuống","Đẩy lên và đẩy xuống",[986,19425,19426,19429,19432,19493],{},[989,19427,19428],{},"Con vượt cha thì đổi chỗ rồi đi lên.",[989,19430,19431],{},"Cha thua con thì đổi với con mạnh nhất rồi đi xuống.",[989,19433,19434,19435,1517],{},"Mỗi vòng đi đúng 1 tầng nên tốn ",[1023,19436,19438,19463],{"className":19437},[1026],[1023,19439,19441],{"className":19440},[1030],[1032,19442,19443],{"xmlns":1034},[1036,19444,19445,19461],{},[1039,19446,19447,19449,19451,19453,19455,19457,19459],{},[1042,19448,1044],{},[1046,19450,1049],{"stretchy":1048},[1042,19452,7684],{},[1042,19454,7687],{},[1042,19456,7690],{},[1042,19458,1262],{},[1046,19460,1056],{"stretchy":1048},[1058,19462,7697],{"encoding":1060},[1023,19464,19466],{"className":19465,"ariaHidden":1066},[1065],[1023,19467,19469,19472,19475,19478,19481,19484,19487,19490],{"className":19468},[1070],[1023,19470],{"className":19471,"style":1075},[1074],[1023,19473,1044],{"className":19474,"style":1081},[1079,1080],[1023,19476,1049],{"className":19477},[1085],[1023,19479,7684],{"className":19480,"style":7716},[1079,1080],[1023,19482,7687],{"className":19483},[1079,1080],[1023,19485,7690],{"className":19486,"style":7723},[1079,1080],[1023,19488,1262],{"className":19489},[1079,1080],[1023,19491,1056],{"className":19492},[1092],[989,19494,19495],{},"Ví dụ đời thường: nhân viên giỏi thăng chức lên trên.",[981,19497,19499],{"id":19498},"chèn-lấy-gốc-nhìn-gốc","Chèn, lấy gốc, nhìn gốc",[986,19501,19502,19505,19508,19555],{},[989,19503,19504],{},"Chèn: đặt vào đuôi mảng rồi đẩy lên.",[989,19506,19507],{},"Lấy gốc: đưa đuôi lên gốc rồi đẩy xuống.",[989,19509,19510,19511,19554],{},"Nhìn gốc chỉ tốn ",[1023,19512,19514,19533],{"className":19513},[1026],[1023,19515,19517],{"className":19516},[1030],[1032,19518,19519],{"xmlns":1034},[1036,19520,19521,19531],{},[1039,19522,19523,19525,19527,19529],{},[1042,19524,1044],{},[1046,19526,1049],{"stretchy":1048},[1051,19528,1053],{},[1046,19530,1056],{"stretchy":1048},[1058,19532,1061],{"encoding":1060},[1023,19534,19536],{"className":19535,"ariaHidden":1066},[1065],[1023,19537,19539,19542,19545,19548,19551],{"className":19538},[1070],[1023,19540],{"className":19541,"style":1075},[1074],[1023,19543,1044],{"className":19544,"style":1081},[1079,1080],[1023,19546,1049],{"className":19547},[1085],[1023,19549,1053],{"className":19550},[1079],[1023,19552,1056],{"className":19553},[1092],", không sửa gì.",[989,19556,19557],{},"Ví dụ đời thường: lấy sếp ra rồi đôn người dưới lên.",[981,19559,19561],{"id":19560},"đổi-ưu-tiên-và-dựng-nhanh","Đổi ưu tiên và dựng nhanh",[986,19563,19564,19567,19570,19573],{},[989,19565,19566],{},"Tăng ưu tiên thì đẩy lên, giảm thì đẩy xuống.",[989,19568,19569],{},"Nhiều bài như Dijkstra chỉ cần giảm.",[989,19571,19572],{},"Dựng từ n món sẵn thì duyệt ngược và đẩy xuống.",[989,19574,19575],{},"Ví dụ đời thường: xếp lại tháp khi đổi điểm.",[1099,19577,19578,19588],{},[1102,19579,19580],{},[1105,19581,19582,19584,19586],{},[1108,19583,1110],{},[1108,19585,7111],{},[1108,19587,5448],{},[1118,19589,19590,19657,19725,19778],{},[1105,19591,19592,19594,19597],{},[1123,19593,18622],{},[1123,19595,19596],{},"Đuôi rồi đẩy lên",[1123,19598,19599],{},[1023,19600,19602,19627],{"className":19601},[1026],[1023,19603,19605],{"className":19604},[1030],[1032,19606,19607],{"xmlns":1034},[1036,19608,19609,19625],{},[1039,19610,19611,19613,19615,19617,19619,19621,19623],{},[1042,19612,1044],{},[1046,19614,1049],{"stretchy":1048},[1042,19616,7684],{},[1042,19618,7687],{},[1042,19620,7690],{},[1042,19622,1262],{},[1046,19624,1056],{"stretchy":1048},[1058,19626,7697],{"encoding":1060},[1023,19628,19630],{"className":19629,"ariaHidden":1066},[1065],[1023,19631,19633,19636,19639,19642,19645,19648,19651,19654],{"className":19632},[1070],[1023,19634],{"className":19635,"style":1075},[1074],[1023,19637,1044],{"className":19638,"style":1081},[1079,1080],[1023,19640,1049],{"className":19641},[1085],[1023,19643,7684],{"className":19644,"style":7716},[1079,1080],[1023,19646,7687],{"className":19647},[1079,1080],[1023,19649,7690],{"className":19650,"style":7723},[1079,1080],[1023,19652,1262],{"className":19653},[1079,1080],[1023,19655,1056],{"className":19656},[1092],[1105,19658,19659,19662,19665],{},[1123,19660,19661],{},"Lấy gốc",[1123,19663,19664],{},"Đuôi thế gốc rồi đẩy xuống",[1123,19666,19667],{},[1023,19668,19670,19695],{"className":19669},[1026],[1023,19671,19673],{"className":19672},[1030],[1032,19674,19675],{"xmlns":1034},[1036,19676,19677,19693],{},[1039,19678,19679,19681,19683,19685,19687,19689,19691],{},[1042,19680,1044],{},[1046,19682,1049],{"stretchy":1048},[1042,19684,7684],{},[1042,19686,7687],{},[1042,19688,7690],{},[1042,19690,1262],{},[1046,19692,1056],{"stretchy":1048},[1058,19694,7697],{"encoding":1060},[1023,19696,19698],{"className":19697,"ariaHidden":1066},[1065],[1023,19699,19701,19704,19707,19710,19713,19716,19719,19722],{"className":19700},[1070],[1023,19702],{"className":19703,"style":1075},[1074],[1023,19705,1044],{"className":19706,"style":1081},[1079,1080],[1023,19708,1049],{"className":19709},[1085],[1023,19711,7684],{"className":19712,"style":7716},[1079,1080],[1023,19714,7687],{"className":19715},[1079,1080],[1023,19717,7690],{"className":19718,"style":7723},[1079,1080],[1023,19720,1262],{"className":19721},[1079,1080],[1023,19723,1056],{"className":19724},[1092],[1105,19726,19727,19730,19733],{},[1123,19728,19729],{},"Nhìn gốc",[1123,19731,19732],{},"Nhìn thôi",[1123,19734,19735],{},[1023,19736,19738,19757],{"className":19737},[1026],[1023,19739,19741],{"className":19740},[1030],[1032,19742,19743],{"xmlns":1034},[1036,19744,19745,19755],{},[1039,19746,19747,19749,19751,19753],{},[1042,19748,1044],{},[1046,19750,1049],{"stretchy":1048},[1051,19752,1053],{},[1046,19754,1056],{"stretchy":1048},[1058,19756,1061],{"encoding":1060},[1023,19758,19760],{"className":19759,"ariaHidden":1066},[1065],[1023,19761,19763,19766,19769,19772,19775],{"className":19762},[1070],[1023,19764],{"className":19765,"style":1075},[1074],[1023,19767,1044],{"className":19768,"style":1081},[1079,1080],[1023,19770,1049],{"className":19771},[1085],[1023,19773,1053],{"className":19774},[1079],[1023,19776,1056],{"className":19777},[1092],[1105,19779,19780,19783,19786],{},[1123,19781,19782],{},"Dựng sẵn",[1123,19784,19785],{},"Đẩy xuống từ cuối về đầu",[1123,19787,19788],{},[1023,19789,19791,19810],{"className":19790},[1026],[1023,19792,19794],{"className":19793},[1030],[1032,19795,19796],{"xmlns":1034},[1036,19797,19798,19808],{},[1039,19799,19800,19802,19804,19806],{},[1042,19801,1044],{},[1046,19803,1049],{"stretchy":1048},[1042,19805,1262],{},[1046,19807,1056],{"stretchy":1048},[1058,19809,1267],{"encoding":1060},[1023,19811,19813],{"className":19812,"ariaHidden":1066},[1065],[1023,19814,19816,19819,19822,19825,19828],{"className":19815},[1070],[1023,19817],{"className":19818,"style":1075},[1074],[1023,19820,1044],{"className":19821,"style":1081},[1079,1080],[1023,19823,1049],{"className":19824},[1085],[1023,19826,1262],{"className":19827},[1079,1080],[1023,19829,1056],{"className":19830},[1092],[968,19832,1433],{"id":1432},[986,19834,19835,19838],{},[989,19836,19837],{},"Input: chèn 9 vào heap mà cha là 8. Output: đổi 1 lần rồi dừng.",[989,19839,19840],{},"Giải thích: tổ tiên trên đã mạnh hơn nên khỏi đi tiếp.",[968,19842,1482],{"id":1481},[973,19844,1485,19845,19847,19848,19850,19851,1517],{},[1487,19846,1493],{},". Dùng tiếp ",[992,19849,19212],{}," ngày 23. Nộp vào ",[992,19852,19853],{},"day-024\u002F",[981,19855,19857],{"id":19856},"bài-1-heapify-và-heap-sort","Bài 1: Heapify và heap sort",[1099,19859,19860,19870],{},[1102,19861,19862],{},[1105,19863,19864,19866,19868],{},[1108,19865,1566],{},[1108,19867,2547],{},[1108,19869,1113],{},[1118,19871,19872,19939,20009,20071],{},[1105,19873,19874,19879,19882],{},[1123,19875,19876],{},[992,19877,19878],{},"void siftUp(std::vector\u003Cint>&, size_t i)",[1123,19880,19881],{},"Đẩy lên",[1123,19883,19884],{},[1023,19885,19887,19910],{"className":19886},[1026],[1023,19888,19890],{"className":19889},[1030],[1032,19891,19892],{"xmlns":1034},[1036,19893,19894,19908],{},[1039,19895,19896,19898,19900,19902,19904,19906],{},[1042,19897,1044],{},[1046,19899,1049],{"stretchy":1048},[1042,19901,8397],{},[1046,19903,8400],{},[1042,19905,1262],{},[1046,19907,1056],{"stretchy":1048},[1058,19909,8407],{"encoding":1060},[1023,19911,19913],{"className":19912,"ariaHidden":1066},[1065],[1023,19914,19916,19919,19922,19925,19930,19933,19936],{"className":19915},[1070],[1023,19917],{"className":19918,"style":1075},[1074],[1023,19920,1044],{"className":19921,"style":1081},[1079,1080],[1023,19923,1049],{"className":19924},[1085],[1023,19926,8427,19928],{"className":19927},[8426],[1023,19929,7690],{"style":8430},[1023,19931],{"className":19932,"style":8434},[2354],[1023,19934,1262],{"className":19935},[1079,1080],[1023,19937,1056],{"className":19938},[1092],[1105,19940,19941,19946,19952],{},[1123,19942,19943],{},[992,19944,19945],{},"void siftDown(std::vector\u003Cint>&, size_t i, size_t n)",[1123,19947,19948,19949,19951],{},"Đẩy xuống trong ",[992,19950,1262],{}," phần tử đầu",[1123,19953,19954],{},[1023,19955,19957,19980],{"className":19956},[1026],[1023,19958,19960],{"className":19959},[1030],[1032,19961,19962],{"xmlns":1034},[1036,19963,19964,19978],{},[1039,19965,19966,19968,19970,19972,19974,19976],{},[1042,19967,1044],{},[1046,19969,1049],{"stretchy":1048},[1042,19971,8397],{},[1046,19973,8400],{},[1042,19975,1262],{},[1046,19977,1056],{"stretchy":1048},[1058,19979,8407],{"encoding":1060},[1023,19981,19983],{"className":19982,"ariaHidden":1066},[1065],[1023,19984,19986,19989,19992,19995,20000,20003,20006],{"className":19985},[1070],[1023,19987],{"className":19988,"style":1075},[1074],[1023,19990,1044],{"className":19991,"style":1081},[1079,1080],[1023,19993,1049],{"className":19994},[1085],[1023,19996,8427,19998],{"className":19997},[8426],[1023,19999,7690],{"style":8430},[1023,20001],{"className":20002,"style":8434},[2354],[1023,20004,1262],{"className":20005},[1079,1080],[1023,20007,1056],{"className":20008},[1092],[1105,20010,20011,20016,20026],{},[1123,20012,20013],{},[992,20014,20015],{},"void heapify(std::vector\u003Cint>&)",[1123,20017,20018,20019,20022,20023],{},"Duyệt từ ",[992,20020,20021],{},"n\u002F2 - 1"," về 0, gọi ",[992,20024,20025],{},"siftDown",[1123,20027,20028],{},[1023,20029,20031,20050],{"className":20030},[1026],[1023,20032,20034],{"className":20033},[1030],[1032,20035,20036],{"xmlns":1034},[1036,20037,20038,20048],{},[1039,20039,20040,20042,20044,20046],{},[1042,20041,1044],{},[1046,20043,1049],{"stretchy":1048},[1042,20045,1262],{},[1046,20047,1056],{"stretchy":1048},[1058,20049,1267],{"encoding":1060},[1023,20051,20053],{"className":20052,"ariaHidden":1066},[1065],[1023,20054,20056,20059,20062,20065,20068],{"className":20055},[1070],[1023,20057],{"className":20058,"style":1075},[1074],[1023,20060,1044],{"className":20061,"style":1081},[1079,1080],[1023,20063,1049],{"className":20064},[1085],[1023,20066,1262],{"className":20067},[1079,1080],[1023,20069,1056],{"className":20070},[1092],[1105,20072,20073,20078,20081],{},[1123,20074,20075],{},[992,20076,20077],{},"void heapSort(std::vector\u003Cint>&)",[1123,20079,20080],{},"Heapify rồi lần lượt đưa gốc về cuối",[1123,20082,20083],{},[1023,20084,20086,20111],{"className":20085},[1026],[1023,20087,20089],{"className":20088},[1030],[1032,20090,20091],{"xmlns":1034},[1036,20092,20093,20109],{},[1039,20094,20095,20097,20099,20101,20103,20105,20107],{},[1042,20096,1044],{},[1046,20098,1049],{"stretchy":1048},[1042,20100,1262],{},[1042,20102,8397],{},[1046,20104,8400],{},[1042,20106,1262],{},[1046,20108,1056],{"stretchy":1048},[1058,20110,10463],{"encoding":1060},[1023,20112,20114],{"className":20113,"ariaHidden":1066},[1065],[1023,20115,20117,20120,20123,20126,20129,20132,20137,20140,20143],{"className":20116},[1070],[1023,20118],{"className":20119,"style":1075},[1074],[1023,20121,1044],{"className":20122,"style":1081},[1079,1080],[1023,20124,1049],{"className":20125},[1085],[1023,20127,1262],{"className":20128},[1079,1080],[1023,20130],{"className":20131,"style":8434},[2354],[1023,20133,8427,20135],{"className":20134},[8426],[1023,20136,7690],{"style":8430},[1023,20138],{"className":20139,"style":8434},[2354],[1023,20141,1262],{"className":20142},[1079,1080],[1023,20144,1056],{"className":20145},[1092],[1352,20147,20150],{"className":20148,"code":20149,"language":2241,"meta":1357},[2239],"heapify [3, 1, 6, 5, 2, 4]  -> [6, 5, 4, 1, 2, 3]\nheapSort [3, 1, 6, 5, 2, 4] -> [1, 2, 3, 4, 5, 6]\n",[992,20151,20149],{"__ignoreMap":1357},[973,20153,20154,20155,20158,20159,20161,20162,20245],{},"Đếm số lần đổi chỗ khi dựng heap bằng ",[992,20156,20157],{},"heapify"," so với ",[992,20160,1010],{}," từng phần tử, với ",[1023,20163,20165,20186],{"className":20164},[1026],[1023,20166,20168],{"className":20167},[1030],[1032,20169,20170],{"xmlns":1034},[1036,20171,20172,20184],{},[1039,20173,20174,20176,20178],{},[1042,20175,1262],{},[1046,20177,2325],{},[2327,20179,20180,20182],{},[1051,20181,2331],{},[1051,20183,2334],{},[1058,20185,2337],{"encoding":1060},[1023,20187,20189,20207],{"className":20188,"ariaHidden":1066},[1065],[1023,20190,20192,20195,20198,20201,20204],{"className":20191},[1070],[1023,20193],{"className":20194,"style":2347},[1074],[1023,20196,1262],{"className":20197},[1079,1080],[1023,20199],{"className":20200,"style":2355},[2354],[1023,20202,2325],{"className":20203},[2359],[1023,20205],{"className":20206,"style":2355},[2354],[1023,20208,20210,20213,20216],{"className":20209},[1070],[1023,20211],{"className":20212,"style":2369},[1074],[1023,20214,1053],{"className":20215},[1079],[1023,20217,20219,20222],{"className":20218},[1079],[1023,20220,2379],{"className":20221},[1079],[1023,20223,20225],{"className":20224},[2383],[1023,20226,20228],{"className":20227},[2387],[1023,20229,20231],{"className":20230},[2391],[1023,20232,20234],{"className":20233,"style":2369},[2395],[1023,20235,20236,20239],{"style":2398},[1023,20237],{"className":20238,"style":2403},[2402],[1023,20240,20242],{"className":20241},[2407,2408,2409,2410],[1023,20243,2334],{"className":20244},[1079,2410]," mảng tăng dần. Ghi kết quả.",[981,20247,20249],{"id":20248},"bài-2-indexed-heap-có-đổi-ưu-tiên","Bài 2: Indexed heap có đổi ưu tiên",[973,20251,1505,20252,2434,20255,20257,20258,4437],{},[992,20253,20254],{},"IndexedMinHeap",[992,20256,1262],{}," phần tử có id ",[992,20259,20260],{},"0..n-1",[1099,20262,20263,20271],{},[1102,20264,20265],{},[1105,20266,20267,20269],{},[1108,20268,1566],{},[1108,20270,2547],{},[1118,20272,20273,20282,20292,20305,20315],{},[1105,20274,20275,20280],{},[1123,20276,20277],{},[992,20278,20279],{},"void push(int id, int key)",[1123,20281],{},[1105,20283,20284,20289],{},[1123,20285,20286],{},[992,20287,20288],{},"int popMin()",[1123,20290,20291],{},"Trả id có key nhỏ nhất",[1105,20293,20294,20299],{},[1123,20295,20296],{},[992,20297,20298],{},"void decreaseKey(int id, int newKey)",[1123,20300,20301,20304],{},[992,20302,20303],{},"newKey"," lớn hơn key cũ thì ném lỗi",[1105,20306,20307,20312],{},[1123,20308,20309],{},[992,20310,20311],{},"void update(int id, int newKey)",[1123,20313,20314],{},"Tăng hoặc giảm, tự chọn siftUp hay siftDown",[1105,20316,20317,20322],{},[1123,20318,20319],{},[992,20320,20321],{},"bool contains(int id)",[1123,20323],{},[973,20325,20326,20327,20330,20331,1517],{},"Giữ mảng ",[992,20328,20329],{},"pos[id]"," để biết id đang ở đâu trong heap. Mọi thao tác ",[1023,20332,20334,20357],{"className":20333},[1026],[1023,20335,20337],{"className":20336},[1030],[1032,20338,20339],{"xmlns":1034},[1036,20340,20341,20355],{},[1039,20342,20343,20345,20347,20349,20351,20353],{},[1042,20344,1044],{},[1046,20346,1049],{"stretchy":1048},[1042,20348,8397],{},[1046,20350,8400],{},[1042,20352,1262],{},[1046,20354,1056],{"stretchy":1048},[1058,20356,8407],{"encoding":1060},[1023,20358,20360],{"className":20359,"ariaHidden":1066},[1065],[1023,20361,20363,20366,20369,20372,20377,20380,20383],{"className":20362},[1070],[1023,20364],{"className":20365,"style":1075},[1074],[1023,20367,1044],{"className":20368,"style":1081},[1079,1080],[1023,20370,1049],{"className":20371},[1085],[1023,20373,8427,20375],{"className":20374},[8426],[1023,20376,7690],{"style":8430},[1023,20378],{"className":20379,"style":8434},[2354],[1023,20381,1262],{"className":20382},[1079,1080],[1023,20384,1056],{"className":20385},[1092],[1352,20387,20390],{"className":20388,"code":20389,"language":2241,"meta":1357},[2239],"push (0,50) (1,20) (2,30)\ndecreaseKey(0, 10) -> popMin = 0\nupdate(1, 40)      -> popMin = 2, rồi 1\n",[992,20391,20389],{"__ignoreMap":1357},[981,20393,20395],{"id":20394},"bài-3-gộp-k-danh-sách-đã-xếp-nâng-cao","Bài 3: Gộp K danh sách đã xếp (nâng cao)",[973,20397,20398,20399,20402,20403,1962,20470,20472],{},"Cho ",[992,20400,20401],{},"K"," vector đã xếp tăng dần. Gộp thành 1 vector xếp tăng dần trong ",[1023,20404,20406,20433],{"className":20405},[1026],[1023,20407,20409],{"className":20408},[1030],[1032,20410,20411],{"xmlns":1034},[1036,20412,20413,20430],{},[1039,20414,20415,20417,20419,20422,20424,20426,20428],{},[1042,20416,1044],{},[1046,20418,1049],{"stretchy":1048},[1042,20420,20421],{},"N",[1042,20423,8397],{},[1046,20425,8400],{},[1042,20427,20401],{},[1046,20429,1056],{"stretchy":1048},[1058,20431,20432],{"encoding":1060},"O(N \\log K)",[1023,20434,20436],{"className":20435,"ariaHidden":1066},[1065],[1023,20437,20439,20442,20445,20448,20452,20455,20460,20463,20467],{"className":20438},[1070],[1023,20440],{"className":20441,"style":1075},[1074],[1023,20443,1044],{"className":20444,"style":1081},[1079,1080],[1023,20446,1049],{"className":20447},[1085],[1023,20449,20421],{"className":20450,"style":20451},[1079,1080],"margin-right:0.109em;",[1023,20453],{"className":20454,"style":8434},[2354],[1023,20456,8427,20458],{"className":20457},[8426],[1023,20459,7690],{"style":8430},[1023,20461],{"className":20462,"style":8434},[2354],[1023,20464,20401],{"className":20465,"style":20466},[1079,1080],"margin-right:0.0715em;",[1023,20468,1056],{"className":20469},[1092],[992,20471,20421],{}," là tổng số phần tử.",[1352,20474,20477],{"className":20475,"code":20476,"language":2241,"meta":1357},[2239],"[[1,4,7], [2,5,8], [0,9]] -> [0,1,2,4,5,7,8,9]\n[[], [1], []]             -> [1]\n",[992,20478,20476],{"__ignoreMap":1357},[973,20480,20481],{},"Ứng dụng: sinh 8 file, mỗi file 10^5 số đã xếp. Gộp thành 1 file mà không đọc toàn bộ vào RAM cùng lúc (đọc từng số một).",[981,20483,2711],{"id":2710},[986,20485,20487,20499,20511,20523],{"className":20486},[2715],[989,20488,20490,20492,20493,20496,20497,1517],{"className":20489},[2719],[2721,20491],{"disabled":2723,"type":2724}," Test mẫu pass. ",[992,20494,20495],{},"heapSort"," pass test ngẫu nhiên so với ",[992,20498,9956],{},[989,20500,20502,2308,20504,20506,20507,20510],{"className":20501},[2719],[2721,20503],{"disabled":2723,"type":2724},[992,20505,20254],{}," giữ ",[992,20508,20509],{},"pos"," đúng sau mọi thao tác (viết hàm kiểm tra).",[989,20512,20514,20516,20517,20519,20520,20522],{"className":20513},[2719],[2721,20515],{"disabled":2723,"type":2724}," Có số liệu chứng minh ",[992,20518,20157],{}," rẻ hơn ",[992,20521,1010],{}," từng phần tử.",[989,20524,20526,20528,20529,1517],{"className":20525},[2719],[2721,20527],{"disabled":2723,"type":2724}," Bài 3 gộp file đúng, bộ nhớ chỉ ",[1023,20530,20532,20552],{"className":20531},[1026],[1023,20533,20535],{"className":20534},[1030],[1032,20536,20537],{"xmlns":1034},[1036,20538,20539,20549],{},[1039,20540,20541,20543,20545,20547],{},[1042,20542,1044],{},[1046,20544,1049],{"stretchy":1048},[1042,20546,20401],{},[1046,20548,1056],{"stretchy":1048},[1058,20550,20551],{"encoding":1060},"O(K)",[1023,20553,20555],{"className":20554,"ariaHidden":1066},[1065],[1023,20556,20558,20561,20564,20567,20570],{"className":20557},[1070],[1023,20559],{"className":20560,"style":1075},[1074],[1023,20562,1044],{"className":20563,"style":1081},[1079,1080],[1023,20565,1049],{"className":20566},[1085],[1023,20568,20401],{"className":20569,"style":20466},[1079,1080],[1023,20571,1056],{"className":20572},[1092],[968,20574,2890],{"id":2889},[986,20576,20577,20580,20583,20586],{},[989,20578,20579],{},"Đẩy lên dùng khi nào?",[989,20581,20582],{},"Đẩy xuống dùng khi nào?",[989,20584,20585],{},"Lấy gốc vì sao đưa đuôi lên?",[989,20587,20588],{},"Dựng sẵn nhanh hơn chèn lẻ ở đâu?",[3014,20590],{},[973,20592,20593],{},"🌕 Bạn đã hoàn thành ngày 24. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":20595},[20596,20597,20602,20603,20609],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":20598},[20599,20600,20601],{"id":19422,"depth":73,"text":19423},{"id":19498,"depth":73,"text":19499},{"id":19560,"depth":73,"text":19561},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":20604},[20605,20606,20607,20608],{"id":19856,"depth":73,"text":19857},{"id":20248,"depth":73,"text":20249},{"id":20394,"depth":73,"text":20395},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mổ xẻ từng thao tác heap từ đẩy lên, đẩy xuống tới dựng heap tuyến tính, kèm phân tích số bước logarit.",{},[3050,4669],{"title":175,"description":20610},[19407],"z7tF1nAMvDdQiv-1ko9Fk6agbXfhMDzsOm_C9HRtlHs",{"id":20617,"title":180,"body":20618,"category":5189,"day":183,"description":21053,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":21054,"navigation":2723,"outcomes":3047,"path":181,"prerequisites":21055,"seo":21056,"stem":182,"tags":21057,"__hash__":21059},"challenges\u002Fchallenges\u002F25.factory-method.md",{"type":965,"value":20619,"toc":21037},[20620,20622,20625,20627,20631,20645,20649,20663,20667,20681,20730,20732,20740,20742,20749,20753,20789,20855,20882,20888,20892,20901,20911,20915,20918,20950,20975,20981,20983,21014,21016,21030,21032,21035],[968,20621,971],{"id":970},[973,20623,20624],{},"Bài này học cách nhượng quyền pizza 2 miền. Bạn để chi nhánh tự quyết khâu tạo.",[968,20626,979],{"id":978},[981,20628,20630],{"id":20629},"vấn-đề-nhượng-quyền","Vấn đề nhượng quyền",[986,20632,20633,20636,20639,20642],{},[989,20634,20635],{},"Quy trình chung nhưng vị mỗi vùng khác nhau.",[989,20637,20638],{},"Phô mai New York vỏ mỏng, Chicago vỏ dày.",[989,20640,20641],{},"1 xưởng trung tâm không cân 2 chiều loại và vùng.",[989,20643,20644],{},"Ví dụ đời thường: cùng phở mà Bắc Nam khác vị.",[981,20646,20648],{"id":20647},"hai-hệ-song-song","Hai hệ song song",[986,20650,20651,20654,20657,20660],{},[989,20652,20653],{},"Một bên là khung cửa hàng giữ quy trình chung.",[989,20655,20656],{},"Một bên là họ pizza từng vùng.",[989,20658,20659],{},"Khâu tạo để trống, chi nhánh tự điền.",[989,20661,20662],{},"Ví dụ đời thường: công thức chung, bếp vùng tự nấu.",[981,20664,20666],{"id":20665},"thêm-vùng-mới-không-sửa-cũ","Thêm vùng mới không sửa cũ",[986,20668,20669,20672,20675,20678],{},[989,20670,20671],{},"Thêm California chỉ thêm chi nhánh và pizza mới.",[989,20673,20674],{},"Khung cũ và 2 vùng cũ nguyên vẹn.",[989,20676,20677],{},"Mỗi chi nhánh gắn với cụm pizza của mình.",[989,20679,20680],{},"Ví dụ đời thường: mở chi nhánh mới không sửa trụ sở.",[1099,20682,20683,20695],{},[1102,20684,20685],{},[1105,20686,20687,20689,20692],{},[1108,20688,5414],{},[1108,20690,20691],{},"Xưởng đơn",[1108,20693,20694],{},"Factory Method",[1118,20696,20697,20708,20719],{},[1105,20698,20699,20702,20705],{},[1123,20700,20701],{},"Ai quyết tạo",[1123,20703,20704],{},"1 xưởng giữa",[1123,20706,20707],{},"Mỗi chi nhánh tự quyết",[1105,20709,20710,20713,20716],{},[1123,20711,20712],{},"Thêm vùng mới",[1123,20714,20715],{},"Mở xưởng sửa",[1123,20717,20718],{},"Thêm nhánh mới",[1105,20720,20721,20724,20727],{},[1123,20722,20723],{},"Quy trình chung",[1123,20725,20726],{},"Không có",[1123,20728,20729],{},"Có ở khung",[968,20731,1433],{"id":1432},[986,20733,20734,20737],{},[989,20735,20736],{},"Input: gọi phô mai ở New York và Chicago. Output: 2 chiếc khác vị đúng vùng.",[989,20738,20739],{},"Giải thích: cùng khung chạy nhưng khâu tạo khác nhau.",[968,20741,1482],{"id":1481},[973,20743,1485,20744,4801,20746,1517],{},[1487,20745,4800],{},[992,20747,20748],{},"day-025\u002F",[981,20750,20752],{"id":20751},"bài-1-factory-method-cho-chuỗi-pizza","Bài 1: Factory Method cho chuỗi pizza",[1352,20754,20756],{"className":1393,"code":20755,"language":1395,"meta":1357,"style":1357},"class PizzaStore {\n public:\n  std::unique_ptr\u003CPizza> orderPizza(const std::string &type);   \u002F\u002F không virtual: quy trình chung\n  virtual ~PizzaStore() = default;\n protected:\n  virtual std::unique_ptr\u003CPizza> createPizza(const std::string &type) = 0;  \u002F\u002F factory method\n};\n",[992,20757,20758,20762,20766,20771,20776,20780,20785],{"__ignoreMap":1357},[1023,20759,20760],{"class":1362,"line":63},[1023,20761,15777],{},[1023,20763,20764],{"class":1362,"line":68},[1023,20765,4836],{},[1023,20767,20768],{"class":1362,"line":73},[1023,20769,20770],{},"  std::unique_ptr\u003CPizza> orderPizza(const std::string &type);   \u002F\u002F không virtual: quy trình chung\n",[1023,20772,20773],{"class":1362,"line":78},[1023,20774,20775],{},"  virtual ~PizzaStore() = default;\n",[1023,20777,20778],{"class":1362,"line":83},[1023,20779,11747],{},[1023,20781,20782],{"class":1362,"line":88},[1023,20783,20784],{},"  virtual std::unique_ptr\u003CPizza> createPizza(const std::string &type) = 0;  \u002F\u002F factory method\n",[1023,20786,20787],{"class":1362,"line":93},[1023,20788,4866],{},[1099,20790,20791,20813],{},[1102,20792,20793],{},[1105,20794,20795,20798,20804,20808],{},[1108,20796,20797],{},"Chi nhánh",[1108,20799,20800,20803],{},[992,20801,20802],{},"createPizza(\"cheese\")"," trả",[1108,20805,20806],{},[992,20807,15809],{},[1108,20809,20810],{},[992,20811,20812],{},"cut()",[1118,20814,20815,20835],{},[1105,20816,20817,20822,20827,20832],{},[1123,20818,20819],{},[992,20820,20821],{},"NYPizzaStore",[1123,20823,20824],{},[992,20825,20826],{},"NYStyleCheesePizza",[1123,20828,20829],{},[992,20830,20831],{},"\"NY phô mai vỏ mỏng\"",[1123,20833,20834],{},"cắt chéo",[1105,20836,20837,20842,20847,20852],{},[1123,20838,20839],{},[992,20840,20841],{},"ChicagoPizzaStore",[1123,20843,20844],{},[992,20845,20846],{},"ChicagoStyleCheesePizza",[1123,20848,20849],{},[992,20850,20851],{},"\"Chicago phô mai vỏ dày\"",[1123,20853,20854],{},"cắt ô vuông",[973,20856,20857,20858,1509,20860,1838,20862,16792,20865,20868,20869,1656,20872,1656,20875,1656,20878,20881],{},"Mỗi chi nhánh có 2 loại: ",[992,20859,15818],{},[992,20861,15842],{},[992,20863,20864],{},"orderPizza",[992,20866,20867],{},"createPizza"," rồi ",[992,20870,20871],{},"prepare",[992,20873,20874],{},"bake",[992,20876,20877],{},"cut",[992,20879,20880],{},"box",". Ghi các bước vào log để test.",[1352,20883,20886],{"className":20884,"code":20885,"language":2241,"meta":1357},[2239],"NYPizzaStore.orderPizza(\"cheese\")      -> \"NY phô mai vỏ mỏng\", log có \"cắt chéo\"\nChicagoPizzaStore.orderPizza(\"cheese\") -> \"Chicago phô mai vỏ dày\", log có \"cắt ô vuông\"\norderPizza(\"unknown\")                  -> ném invalid_argument\n",[992,20887,20885],{"__ignoreMap":1357},[981,20889,20891],{"id":20890},"bài-2-thêm-vùng-california","Bài 2: Thêm vùng California",[973,20893,5030,20894,20897,20898,20900],{},[992,20895,20896],{},"CaliforniaPizzaStore"," với 2 loại pizza mới. Chứng minh bằng ",[992,20899,14320],{},": không file cũ nào đổi.",[973,20902,20903,20904,20906,20907,20910],{},"Viết thêm 3 câu: vì sao ",[992,20905,20864],{}," không nên ",[992,20908,20909],{},"virtual",", và điều gì xảy ra nếu chi nhánh ghi đè nó.",[981,20912,20914],{"id":20913},"bài-3-factory-method-ngoài-pizza-nâng-cao","Bài 3: Factory Method ngoài pizza (nâng cao)",[973,20916,20917],{},"Viết khung xuất báo cáo:",[1352,20919,20921],{"className":1393,"code":20920,"language":1395,"meta":1357,"style":1357},"class ReportExporter {\n public:\n  std::string exportReport(const std::vector\u003CRow> &rows);  \u002F\u002F header + từng dòng + footer\n protected:\n  virtual std::unique_ptr\u003CFormatter> createFormatter() = 0;\n};\n",[992,20922,20923,20928,20932,20937,20941,20946],{"__ignoreMap":1357},[1023,20924,20925],{"class":1362,"line":63},[1023,20926,20927],{},"class ReportExporter {\n",[1023,20929,20930],{"class":1362,"line":68},[1023,20931,4836],{},[1023,20933,20934],{"class":1362,"line":73},[1023,20935,20936],{},"  std::string exportReport(const std::vector\u003CRow> &rows);  \u002F\u002F header + từng dòng + footer\n",[1023,20938,20939],{"class":1362,"line":78},[1023,20940,11747],{},[1023,20942,20943],{"class":1362,"line":83},[1023,20944,20945],{},"  virtual std::unique_ptr\u003CFormatter> createFormatter() = 0;\n",[1023,20947,20948],{"class":1362,"line":88},[1023,20949,4866],{},[973,20951,1505,20952,1656,20955,1656,20958,20961,20962,20965,20966,1656,20969,1656,20972,1517],{},[992,20953,20954],{},"CsvExporter",[992,20956,20957],{},"JsonExporter",[992,20959,20960],{},"MarkdownExporter",". Mỗi exporter tạo ",[992,20963,20964],{},"Formatter"," riêng với ",[992,20967,20968],{},"header()",[992,20970,20971],{},"row(const Row&)",[992,20973,20974],{},"footer()",[1352,20976,20979],{"className":20977,"code":20978,"language":2241,"meta":1357},[2239],"rows = [{name: \"An\", score: 9}, {name: \"Bình\", score: 7}]\nCsvExporter      -> \"name,score\\nAn,9\\nBình,7\\n\"\nMarkdownExporter -> \"| name | score |\\n| --- | --- |\\n| An | 9 |\\n| Bình | 7 |\\n\"\nJsonExporter     -> \"[{\\\"name\\\":\\\"An\\\",\\\"score\\\":9},{\\\"name\\\":\\\"Bình\\\",\\\"score\\\":7}]\"\n",[992,20980,20978],{"__ignoreMap":1357},[981,20982,2711],{"id":2710},[986,20984,20986,20991,21002,21008],{"className":20985},[2715],[989,20987,20989,11986],{"className":20988},[2719],[2721,20990],{"disabled":2723,"type":2724},[989,20992,20994,2308,20996,1509,20998,21001],{"className":20993},[2719],[2721,20995],{"disabled":2723,"type":2724},[992,20997,15870],{},[992,20999,21000],{},"ReportExporter"," không biết lớp sản phẩm cụ thể nào.",[989,21003,21005,21007],{"className":21004},[2719],[2721,21006],{"disabled":2723,"type":2724}," Thêm California chỉ thêm file mới.",[989,21009,21011,21013],{"className":21010},[2719],[2721,21012],{"disabled":2723,"type":2724}," Vẽ sơ đồ 2 hệ song song Creator và Product.",[968,21015,2890],{"id":2889},[986,21017,21018,21021,21024,21027],{},[989,21019,21020],{},"Factory Method là gì, nói 1 câu?",[989,21022,21023],{},"Khung giữ gì, chi nhánh giữ gì?",[989,21025,21026],{},"Vì sao thêm vùng không sửa khung?",[989,21028,21029],{},"Khác xưởng đơn ở đâu?",[3014,21031],{},[973,21033,21034],{},"🌕 Bạn đã hoàn thành ngày 25. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,21036,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":21038},[21039,21040,21045,21046,21052],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":21041},[21042,21043,21044],{"id":20629,"depth":73,"text":20630},{"id":20647,"depth":73,"text":20648},{"id":20665,"depth":73,"text":20666},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":21047},[21048,21049,21050,21051],{"id":20751,"depth":73,"text":20752},{"id":20890,"depth":73,"text":20891},{"id":20913,"depth":73,"text":20914},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Factory Method, khung cửa hàng nhượng quyền, và cấu trúc creator song song product qua New York và Chicago.",{},[5194],{"title":180,"description":21053},[16071,21058],"factory-method","b6qH9lkGg4O3FCMpd-Vu6t_ZvnpaWt3fJ1nzY9v4Y28",{"id":21061,"title":185,"body":21062,"category":3041,"day":188,"description":22225,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":22226,"navigation":2723,"outcomes":3047,"path":186,"prerequisites":22227,"seo":22228,"stem":187,"tags":22229,"__hash__":22231},"challenges\u002Fchallenges\u002F26.d-ary-heap-va-topk.md",{"type":965,"value":21063,"toc":22209},[21064,21066,21069,21071,21075,21089,21093,21187,21191,21252,21289,21291,21299,21334,21336,21343,21347,21380,21397,21403,21407,21496,21605,21703,21707,21948,21954,22101,22103,22186,22188,22202,22204,22207],[968,21065,971],{"id":970},[973,21067,21068],{},"Bài này mở heap 2 con thành nhiều con. Bạn tìm top K nhanh gọn.",[968,21070,979],{"id":978},[981,21072,21074],{"id":21073},"heap-nhiều-nhánh-là-gì","Heap nhiều nhánh là gì",[986,21076,21077,21080,21083,21086],{},[989,21078,21079],{},"Nhánh là số con tối đa mỗi nút.",[989,21081,21082],{},"Nhánh 3 thì con của i ở 3i+1 tới 3i+3.",[989,21084,21085],{},"Nhánh to thì cây thấp hơn.",[989,21087,21088],{},"Ví dụ đời thường: sếp quản 2 người và quản 4 người.",[981,21090,21092],{"id":21091},"nhánh-to-không-phải-luôn-tốt","Nhánh to không phải luôn tốt",[986,21094,21095,21098,21101,21104,21184],{},[989,21096,21097],{},"Đẩy lên hưởng lợi vì cây thấp đi.",[989,21099,21100],{},"Đẩy xuống mỗi tầng phải soi D con nên đắt.",[989,21102,21103],{},"D quá to thì tiền soi nuốt tiền cây thấp.",[989,21105,21106,21107,21183],{},"Lý thuyết cho thấy cân bằng tốt nhất giữa chèn và lấy gốc nằm ở ",[1023,21108,21110,21133],{"className":21109},[1026],[1023,21111,21113],{"className":21112},[1030],[1032,21114,21115],{"xmlns":1034},[1036,21116,21117,21130],{},[1039,21118,21119,21121,21124,21126,21128],{},[1051,21120,2457],{},[1046,21122,21123],{},"≤",[1042,21125,4780],{},[1046,21127,21123],{},[1051,21129,2334],{},[1058,21131,21132],{"encoding":1060},"2 \\le D \\le 5",[1023,21134,21136,21155,21174],{"className":21135,"ariaHidden":1066},[1065],[1023,21137,21139,21143,21146,21149,21152],{"className":21138},[1070],[1023,21140],{"className":21141,"style":21142},[1074],"height:0.7804em;vertical-align:-0.136em;",[1023,21144,2457],{"className":21145},[1079],[1023,21147],{"className":21148,"style":2355},[2354],[1023,21150,21123],{"className":21151},[2359],[1023,21153],{"className":21154,"style":2355},[2354],[1023,21156,21158,21162,21165,21168,21171],{"className":21157},[1070],[1023,21159],{"className":21160,"style":21161},[1074],"height:0.8193em;vertical-align:-0.136em;",[1023,21163,4780],{"className":21164,"style":1081},[1079,1080],[1023,21166],{"className":21167,"style":2355},[2354],[1023,21169,21123],{"className":21170},[2359],[1023,21172],{"className":21173,"style":2355},[2354],[1023,21175,21177,21180],{"className":21176},[1070],[1023,21178],{"className":21179,"style":10020},[1074],[1023,21181,2334],{"className":21182},[1079],". Thực tế heap nhị phân hiếm khi nhanh nhất, D bằng 3 hoặc 4 thường thắng. Nên bắt đầu với D = 4 rồi đo trên dữ liệu thật.",[989,21185,21186],{},"Ví dụ đời thường: họp 10 người lâu hơn họp 3.",[981,21188,21190],{"id":21189},"top-k-bằng-min-heap","Top-K bằng min-heap",[986,21192,21193,21196,21199,21202,21205],{},[989,21194,21195],{},"Giữ min-heap đúng K món.",[989,21197,21198],{},"Món mới lớn hơn gốc thì thay gốc.",[989,21200,21201],{},"Cuối cùng heap giữ K món lớn nhất.",[989,21203,21204],{},"Ví dụ đời thường: giữ bảng top 3 điểm cao.",[989,21206,21207,21208,21251],{},"Tốn bộ nhớ ",[1023,21209,21211,21230],{"className":21210},[1026],[1023,21212,21214],{"className":21213},[1030],[1032,21215,21216],{"xmlns":1034},[1036,21217,21218,21228],{},[1039,21219,21220,21222,21224,21226],{},[1042,21221,1044],{},[1046,21223,1049],{"stretchy":1048},[1042,21225,20401],{},[1046,21227,1056],{"stretchy":1048},[1058,21229,20551],{"encoding":1060},[1023,21231,21233],{"className":21232,"ariaHidden":1066},[1065],[1023,21234,21236,21239,21242,21245,21248],{"className":21235},[1070],[1023,21237],{"className":21238,"style":1075},[1074],[1023,21240,1044],{"className":21241,"style":1081},[1079,1080],[1023,21243,1049],{"className":21244},[1085],[1023,21246,20401],{"className":21247,"style":20466},[1079,1080],[1023,21249,1056],{"className":21250},[1092],", khỏi xếp cả kho.",[1099,21253,21254,21263],{},[1102,21255,21256],{},[1105,21257,21258,21260],{},[1108,21259,6564],{},[1108,21261,21262],{},"Cho bài nào",[1118,21264,21265,21273,21281],{},[1105,21266,21267,21270],{},[1123,21268,21269],{},"Min-heap cỡ K",[1123,21271,21272],{},"Top K lớn nhất",[1105,21274,21275,21278],{},[1123,21276,21277],{},"Min-heap",[1123,21279,21280],{},"Huffman, Dijkstra",[1105,21282,21283,21286],{},[1123,21284,21285],{},"Heap nhánh 4+",[1123,21287,21288],{},"Chèn lấy liên tục",[968,21290,1433],{"id":1432},[986,21292,21293,21296],{},[989,21294,21295],{},"Input: dòng 5,1,4,2,3 với K=2. Output: heap giữ 4 và 5, gốc là 4.",[989,21297,21298],{},"Giải thích: món nhỏ hơn gốc thì bỏ qua.",[1352,21300,21302],{"className":3538,"code":21301,"language":3540,"meta":1357,"style":1357},"import heapq  # min-heap sẵn\nh = []  # giữ đúng K món\nfor x in data:  # duyệt dòng dữ liệu\n    heapq.heappush(h, x)  # thêm vào heap\n    if len(h) > K:  # quá K thì bỏ nhỏ nhất\n        heapq.heappop(h)\n",[992,21303,21304,21309,21314,21319,21324,21329],{"__ignoreMap":1357},[1023,21305,21306],{"class":1362,"line":63},[1023,21307,21308],{},"import heapq  # min-heap sẵn\n",[1023,21310,21311],{"class":1362,"line":68},[1023,21312,21313],{},"h = []  # giữ đúng K món\n",[1023,21315,21316],{"class":1362,"line":73},[1023,21317,21318],{},"for x in data:  # duyệt dòng dữ liệu\n",[1023,21320,21321],{"class":1362,"line":78},[1023,21322,21323],{},"    heapq.heappush(h, x)  # thêm vào heap\n",[1023,21325,21326],{"class":1362,"line":83},[1023,21327,21328],{},"    if len(h) > K:  # quá K thì bỏ nhỏ nhất\n",[1023,21330,21331],{"class":1362,"line":88},[1023,21332,21333],{},"        heapq.heappop(h)\n",[968,21335,1482],{"id":1481},[973,21337,1485,21338,5599,21340,1517],{},[1487,21339,1493],{},[992,21341,21342],{},"day-026\u002F",[981,21344,21346],{"id":21345},"bài-1-d-ary-min-heap","Bài 1: d-ary min-heap",[1352,21348,21350],{"className":1393,"code":21349,"language":1395,"meta":1357,"style":1357},"template \u003Cclass T, class Cmp = std::less\u003CT>>\nclass DaryHeap {\n public:\n  explicit DaryHeap(int d);   \u002F\u002F d >= 2, sai thì ném invalid_argument\n  void push(const T &x); T pop(); const T &top() const; size_t size() const;\n};\n",[992,21351,21352,21357,21362,21366,21371,21376],{"__ignoreMap":1357},[1023,21353,21354],{"class":1362,"line":63},[1023,21355,21356],{},"template \u003Cclass T, class Cmp = std::less\u003CT>>\n",[1023,21358,21359],{"class":1362,"line":68},[1023,21360,21361],{},"class DaryHeap {\n",[1023,21363,21364],{"class":1362,"line":73},[1023,21365,4836],{},[1023,21367,21368],{"class":1362,"line":78},[1023,21369,21370],{},"  explicit DaryHeap(int d);   \u002F\u002F d >= 2, sai thì ném invalid_argument\n",[1023,21372,21373],{"class":1362,"line":83},[1023,21374,21375],{},"  void push(const T &x); T pop(); const T &top() const; size_t size() const;\n",[1023,21377,21378],{"class":1362,"line":88},[1023,21379,4866],{},[973,21381,21382,21383,13710,21385,21388,21389,13710,21391,10880,21394,1517],{},"Cha của ",[992,21384,1837],{},[992,21386,21387],{},"(i - 1) \u002F d",". Con của ",[992,21390,1837],{},[992,21392,21393],{},"d*i + 1",[992,21395,21396],{},"d*i + d",[1352,21398,21401],{"className":21399,"code":21400,"language":2241,"meta":1357},[2239],"d=3, push 5,1,4,2,3,9,0 -> pop hết ra 0,1,2,3,4,5,9\nd=2 cho cùng kết quả với heap ngày 23\nd=1                     -> ném invalid_argument\n",[992,21402,21400],{"__ignoreMap":1357},[981,21404,21406],{"id":21405},"bài-2-tìm-d-tốt-nhất","Bài 2: Tìm d tốt nhất",[973,21408,21409,21410,2434,21493,4437],{},"Chạy 2 kịch bản với ",[1023,21411,21413,21434],{"className":21412},[1026],[1023,21414,21416],{"className":21415},[1030],[1032,21417,21418],{"xmlns":1034},[1036,21419,21420,21432],{},[1039,21421,21422,21424,21426],{},[1042,21423,1262],{},[1046,21425,2325],{},[2327,21427,21428,21430],{},[1051,21429,2331],{},[1051,21431,6866],{},[1058,21433,11405],{"encoding":1060},[1023,21435,21437,21455],{"className":21436,"ariaHidden":1066},[1065],[1023,21438,21440,21443,21446,21449,21452],{"className":21439},[1070],[1023,21441],{"className":21442,"style":2347},[1074],[1023,21444,1262],{"className":21445},[1079,1080],[1023,21447],{"className":21448,"style":2355},[2354],[1023,21450,2325],{"className":21451},[2359],[1023,21453],{"className":21454,"style":2355},[2354],[1023,21456,21458,21461,21464],{"className":21457},[1070],[1023,21459],{"className":21460,"style":2369},[1074],[1023,21462,1053],{"className":21463},[1079],[1023,21465,21467,21470],{"className":21466},[1079],[1023,21468,2379],{"className":21469},[1079],[1023,21471,21473],{"className":21472},[2383],[1023,21474,21476],{"className":21475},[2387],[1023,21477,21479],{"className":21478},[2391],[1023,21480,21482],{"className":21481,"style":2369},[2395],[1023,21483,21484,21487],{"style":2398},[1023,21485],{"className":21486,"style":2403},[2402],[1023,21488,21490],{"className":21489},[2407,2408,2409,2410],[1023,21491,6866],{"className":21492},[1079,2410],[992,21494,21495],{},"d = 2, 3, 4, 8, 16",[2273,21497,21498,21571],{},[989,21499,21500,21503,21504,21532,21533,21570],{},[1487,21501,21502],{},"Nhiều push:"," push ",[1023,21505,21507,21520],{"className":21506},[1026],[1023,21508,21510],{"className":21509},[1030],[1032,21511,21512],{"xmlns":1034},[1036,21513,21514,21518],{},[1039,21515,21516],{},[1042,21517,1262],{},[1058,21519,1262],{"encoding":1060},[1023,21521,21523],{"className":21522,"ariaHidden":1066},[1065],[1023,21524,21526,21529],{"className":21525},[1070],[1023,21527],{"className":21528,"style":2347},[1074],[1023,21530,1262],{"className":21531},[1079,1080]," số ngẫu nhiên, pop ",[1023,21534,21536,21554],{"className":21535},[1026],[1023,21537,21539],{"className":21538},[1030],[1032,21540,21541],{"xmlns":1034},[1036,21542,21543,21551],{},[1039,21544,21545,21547,21549],{},[1042,21546,1262],{},[1042,21548,2461],{"mathvariant":2460},[1051,21550,2331],{},[1058,21552,21553],{"encoding":1060},"n\u002F10",[1023,21555,21557],{"className":21556,"ariaHidden":1066},[1065],[1023,21558,21560,21563,21566],{"className":21559},[1070],[1023,21561],{"className":21562,"style":1075},[1074],[1023,21564,1262],{"className":21565},[1079,1080],[1023,21567,21569],{"className":21568},[1079],"\u002F10"," lần.",[989,21572,21573,21503,21576,21604],{},[1487,21574,21575],{},"Nhiều pop:",[1023,21577,21579,21592],{"className":21578},[1026],[1023,21580,21582],{"className":21581},[1030],[1032,21583,21584],{"xmlns":1034},[1036,21585,21586,21590],{},[1039,21587,21588],{},[1042,21589,1262],{},[1058,21591,1262],{"encoding":1060},[1023,21593,21595],{"className":21594,"ariaHidden":1066},[1065],[1023,21596,21598,21601],{"className":21597},[1070],[1023,21599],{"className":21600,"style":2347},[1074],[1023,21602,1262],{"className":21603},[1079,1080]," số, pop hết.",[973,21606,21607,21608,21610,21611,21699,21700,21702],{},"In bảng thời gian và số lần so sánh. Chỉ ra ",[992,21609,12999],{}," tốt nhất cho mỗi kịch bản và giải thích bằng chiều cao cây ",[1023,21612,21614,21638],{"className":21613},[1026],[1023,21615,21617],{"className":21616},[1030],[1032,21618,21619],{"xmlns":1034},[1036,21620,21621,21635],{},[1039,21622,21623,21633],{},[17690,21624,21625,21631],{},[1039,21626,21627,21629],{},[1042,21628,8397],{},[1046,21630,8400],{},[1042,21632,12999],{},[1042,21634,1262],{},[1058,21636,21637],{"encoding":1060},"\\log_d n",[1023,21639,21641],{"className":21640,"ariaHidden":1066},[1065],[1023,21642,21644,21648,21693,21696],{"className":21643},[1070],[1023,21645],{"className":21646,"style":21647},[1074],"height:0.9386em;vertical-align:-0.2441em;",[1023,21649,21651,21656],{"className":21650},[8426],[1023,21652,8427,21654],{"className":21653},[8426],[1023,21655,7690],{"style":8430},[1023,21657,21659],{"className":21658},[2383],[1023,21660,21662,21684],{"className":21661},[2387,17732],[1023,21663,21665,21681],{"className":21664},[2391],[1023,21666,21669],{"className":21667,"style":21668},[2395],"height:0.242em;",[1023,21670,21672,21675],{"style":21671},"top:-2.4559em;margin-right:0.05em;",[1023,21673],{"className":21674,"style":2403},[2402],[1023,21676,21678],{"className":21677},[2407,2408,2409,2410],[1023,21679,12999],{"className":21680},[1079,1080,2410],[1023,21682,17797],{"className":21683},[17796],[1023,21685,21687],{"className":21686},[2391],[1023,21688,21691],{"className":21689,"style":21690},[2395],"height:0.2441em;",[1023,21692],{},[1023,21694],{"className":21695,"style":8434},[2354],[1023,21697,1262],{"className":21698},[1079,1080]," và chi phí soi ",[992,21701,12999],{}," con.",[981,21704,21706],{"id":21705},"bài-3-top-k-trên-luồng-dữ-liệu-nâng-cao","Bài 3: Top-K trên luồng dữ liệu (nâng cao)",[1099,21708,21709,21719],{},[1102,21710,21711],{},[1105,21712,21713,21715,21717],{},[1108,21714,1566],{},[1108,21716,2547],{},[1108,21718,1113],{},[1118,21720,21721,21847],{},[1105,21722,21723,21728,21737],{},[1123,21724,21725],{},[992,21726,21727],{},"std::vector\u003Cint> topK(std::istream &in, int k)",[1123,21729,21730,21731,21733,21734,21736],{},"Đọc từng số, giữ min-heap cỡ ",[992,21732,4022],{},", trả ",[992,21735,4022],{}," số lớn nhất giảm dần",[1123,21738,21739,21803,21804,8695],{},[1023,21740,21742,21768],{"className":21741},[1026],[1023,21743,21745],{"className":21744},[1030],[1032,21746,21747],{"xmlns":1034},[1036,21748,21749,21765],{},[1039,21750,21751,21753,21755,21757,21759,21761,21763],{},[1042,21752,1044],{},[1046,21754,1049],{"stretchy":1048},[1042,21756,1262],{},[1042,21758,8397],{},[1046,21760,8400],{},[1042,21762,4022],{},[1046,21764,1056],{"stretchy":1048},[1058,21766,21767],{"encoding":1060},"O(n \\log k)",[1023,21769,21771],{"className":21770,"ariaHidden":1066},[1065],[1023,21772,21774,21777,21780,21783,21786,21789,21794,21797,21800],{"className":21773},[1070],[1023,21775],{"className":21776,"style":1075},[1074],[1023,21778,1044],{"className":21779,"style":1081},[1079,1080],[1023,21781,1049],{"className":21782},[1085],[1023,21784,1262],{"className":21785},[1079,1080],[1023,21787],{"className":21788,"style":8434},[2354],[1023,21790,8427,21792],{"className":21791},[8426],[1023,21793,7690],{"style":8430},[1023,21795],{"className":21796,"style":8434},[2354],[1023,21798,4022],{"className":21799,"style":4066},[1079,1080],[1023,21801,1056],{"className":21802},[1092]," thời gian, ",[1023,21805,21807,21826],{"className":21806},[1026],[1023,21808,21810],{"className":21809},[1030],[1032,21811,21812],{"xmlns":1034},[1036,21813,21814,21824],{},[1039,21815,21816,21818,21820,21822],{},[1042,21817,1044],{},[1046,21819,1049],{"stretchy":1048},[1042,21821,4022],{},[1046,21823,1056],{"stretchy":1048},[1058,21825,4047],{"encoding":1060},[1023,21827,21829],{"className":21828,"ariaHidden":1066},[1065],[1023,21830,21832,21835,21838,21841,21844],{"className":21831},[1070],[1023,21833],{"className":21834,"style":1075},[1074],[1023,21836,1044],{"className":21837,"style":1081},[1079,1080],[1023,21839,1049],{"className":21840},[1085],[1023,21842,4022],{"className":21843,"style":4066},[1079,1080],[1023,21845,1056],{"className":21846},[1092],[1105,21848,21849,21854,21859],{},[1123,21850,21851],{},[992,21852,21853],{},"std::vector\u003Cstd::string> topKWords(std::istream &in, int k)",[1123,21855,21856,21858],{},[992,21857,4022],{}," từ xuất hiện nhiều nhất. Hòa thì theo alphabet",[1123,21860,21861],{},[1023,21862,21864,21895],{"className":21863},[1026],[1023,21865,21867],{"className":21866},[1030],[1032,21868,21869],{"xmlns":1034},[1036,21870,21871,21892],{},[1039,21872,21873,21875,21877,21879,21882,21884,21886,21888,21890],{},[1042,21874,1044],{},[1046,21876,1049],{"stretchy":1048},[1042,21878,1262],{},[1046,21880,21881],{},"+",[1042,21883,15437],{},[1042,21885,8397],{},[1046,21887,8400],{},[1042,21889,4022],{},[1046,21891,1056],{"stretchy":1048},[1058,21893,21894],{"encoding":1060},"O(n + m \\log k)",[1023,21896,21898,21922],{"className":21897,"ariaHidden":1066},[1065],[1023,21899,21901,21904,21907,21910,21913,21916,21919],{"className":21900},[1070],[1023,21902],{"className":21903,"style":1075},[1074],[1023,21905,1044],{"className":21906,"style":1081},[1079,1080],[1023,21908,1049],{"className":21909},[1085],[1023,21911,1262],{"className":21912},[1079,1080],[1023,21914],{"className":21915,"style":13790},[2354],[1023,21917,21881],{"className":21918},[13794],[1023,21920],{"className":21921,"style":13790},[2354],[1023,21923,21925,21928,21931,21934,21939,21942,21945],{"className":21924},[1070],[1023,21926],{"className":21927,"style":1075},[1074],[1023,21929,15437],{"className":21930},[1079,1080],[1023,21932],{"className":21933,"style":8434},[2354],[1023,21935,8427,21937],{"className":21936},[8426],[1023,21938,7690],{"style":8430},[1023,21940],{"className":21941,"style":8434},[2354],[1023,21943,4022],{"className":21944,"style":4066},[1079,1080],[1023,21946,1056],{"className":21947},[1092],[1352,21949,21952],{"className":21950,"code":21951,"language":2241,"meta":1357},[2239],"stream 5,1,4,2,3, k=2           -> [5, 4]\nstream có 3 số, k=5             -> trả đủ 3 số\n\"a b a c b a\", k=2               -> [\"a\", \"b\"]\n",[992,21953,21951],{"__ignoreMap":1357},[973,21955,21956,21957,21960,21961,21963,21964,1656,22049,1517],{},"So thời gian ",[992,21958,21959],{},"topK"," với cách \"đọc hết rồi ",[992,21962,9956],{},"\" cho ",[1023,21965,21967,21990],{"className":21966},[1026],[1023,21968,21970],{"className":21969},[1030],[1032,21971,21972],{"xmlns":1034},[1036,21973,21974,21987],{},[1039,21975,21976,21978,21980],{},[1042,21977,1262],{},[1046,21979,2325],{},[2327,21981,21982,21984],{},[1051,21983,2331],{},[1051,21985,21986],{},"7",[1058,21988,21989],{"encoding":1060},"n = 10^7",[1023,21991,21993,22011],{"className":21992,"ariaHidden":1066},[1065],[1023,21994,21996,21999,22002,22005,22008],{"className":21995},[1070],[1023,21997],{"className":21998,"style":2347},[1074],[1023,22000,1262],{"className":22001},[1079,1080],[1023,22003],{"className":22004,"style":2355},[2354],[1023,22006,2325],{"className":22007},[2359],[1023,22009],{"className":22010,"style":2355},[2354],[1023,22012,22014,22017,22020],{"className":22013},[1070],[1023,22015],{"className":22016,"style":2369},[1074],[1023,22018,1053],{"className":22019},[1079],[1023,22021,22023,22026],{"className":22022},[1079],[1023,22024,2379],{"className":22025},[1079],[1023,22027,22029],{"className":22028},[2383],[1023,22030,22032],{"className":22031},[2387],[1023,22033,22035],{"className":22034},[2391],[1023,22036,22038],{"className":22037,"style":2369},[2395],[1023,22039,22040,22043],{"style":2398},[1023,22041],{"className":22042,"style":2403},[2402],[1023,22044,22046],{"className":22045},[2407,2408,2409,2410],[1023,22047,21986],{"className":22048},[1079,2410],[1023,22050,22052,22070],{"className":22051},[1026],[1023,22053,22055],{"className":22054},[1030],[1032,22056,22057],{"xmlns":1034},[1036,22058,22059,22067],{},[1039,22060,22061,22063,22065],{},[1042,22062,4022],{},[1046,22064,2325],{},[1051,22066,13900],{},[1058,22068,22069],{"encoding":1060},"k = 100",[1023,22071,22073,22092],{"className":22072,"ariaHidden":1066},[1065],[1023,22074,22076,22080,22083,22086,22089],{"className":22075},[1070],[1023,22077],{"className":22078,"style":22079},[1074],"height:0.6944em;",[1023,22081,4022],{"className":22082,"style":4066},[1079,1080],[1023,22084],{"className":22085,"style":2355},[2354],[1023,22087,2325],{"className":22088},[2359],[1023,22090],{"className":22091,"style":2355},[2354],[1023,22093,22095,22098],{"className":22094},[1070],[1023,22096],{"className":22097,"style":10020},[1074],[1023,22099,13900],{"className":22100},[1079],[981,22102,2711],{"id":2710},[986,22104,22106,22115,22124,22176],{"className":22105},[2715],[989,22107,22109,22111,22112,22114],{"className":22108},[2719],[2721,22110],{"disabled":2723,"type":2724}," Test mẫu pass với mọi ",[992,22113,12999],{}," từ 2 tới 16.",[989,22116,22118,22120,22121,22123],{"className":22117},[2719],[2721,22119],{"disabled":2723,"type":2724}," Bảng Bài 2 có số thật và kết luận ",[992,22122,12999],{}," tốt nhất.",[989,22125,22127,2308,22129,22131,22132,22175],{"className":22126},[2719],[2721,22128],{"disabled":2723,"type":2724},[992,22130,21959],{}," chỉ dùng bộ nhớ ",[1023,22133,22135,22154],{"className":22134},[1026],[1023,22136,22138],{"className":22137},[1030],[1032,22139,22140],{"xmlns":1034},[1036,22141,22142,22152],{},[1039,22143,22144,22146,22148,22150],{},[1042,22145,1044],{},[1046,22147,1049],{"stretchy":1048},[1042,22149,4022],{},[1046,22151,1056],{"stretchy":1048},[1058,22153,4047],{"encoding":1060},[1023,22155,22157],{"className":22156,"ariaHidden":1066},[1065],[1023,22158,22160,22163,22166,22169,22172],{"className":22159},[1070],[1023,22161],{"className":22162,"style":1075},[1074],[1023,22164,1044],{"className":22165,"style":1081},[1079,1080],[1023,22167,1049],{"className":22168},[1085],[1023,22170,4022],{"className":22171,"style":4066},[1079,1080],[1023,22173,1056],{"className":22174},[1092],", không lưu toàn bộ luồng.",[989,22177,22179,22181,22182,22185],{"className":22178},[2719],[2721,22180],{"disabled":2723,"type":2724}," Giải thích được vì sao tìm top-K lớn nhất lại dùng ",[1487,22183,22184],{},"min","-heap.",[968,22187,2890],{"id":2889},[986,22189,22190,22193,22196,22199],{},[989,22191,22192],{},"Nhánh của heap là gì?",[989,22194,22195],{},"Vì sao nhánh to không luôn nhanh?",[989,22197,22198],{},"Top-K dùng heap nào, cỡ bao nhiêu?",[989,22200,22201],{},"Kể 3 ứng dụng lớn của heap?",[3014,22203],{},[973,22205,22206],{},"🌕 Bạn đã hoàn thành ngày 26. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,22208,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":22210},[22211,22212,22217,22218,22224],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":22213},[22214,22215,22216],{"id":21073,"depth":73,"text":21074},{"id":21091,"depth":73,"text":21092},{"id":21189,"depth":73,"text":21190},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":22219},[22220,22221,22222,22223],{"id":21345,"depth":73,"text":21346},{"id":21405,"depth":73,"text":21406},{"id":21705,"depth":73,"text":21706},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mở rộng heap nhị phân thành heap đa nhánh, phân tích nhánh tối ưu và áp dụng vào top-K, Dijkstra, Prim, Huffman.",{},[3050,17499],{"title":185,"description":22225},[19407,22230],"top-k","ghih4ZUJHR9f5FfhTbdnHMlErOoicyikk6Qg9E8Ggak",{"id":22233,"title":190,"body":22234,"category":8797,"day":193,"description":22651,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":22652,"navigation":2723,"outcomes":3047,"path":191,"prerequisites":22653,"seo":22654,"stem":192,"tags":22655,"__hash__":22657},"challenges\u002Fchallenges\u002F27.ma-huffman.md",{"type":965,"value":22235,"toc":22635},[22236,22238,22241,22243,22247,22261,22265,22282,22286,22361,22410,22412,22420,22422,22432,22436,22466,22470,22484,22490,22494,22542,22548,22552,22561,22568,22574,22580,22582,22612,22614,22628,22630,22633],[968,22237,971],{"id":970},[973,22239,22240],{},"Bài này học cách nén chữ theo tần suất. Bạn cho chữ hay gặp mã ngắn.",[968,22242,979],{"id":978},[981,22244,22246],{"id":22245},"ý-tưởng-gán-mã-theo-tần-suất","Ý tưởng gán mã theo tần suất",[986,22248,22249,22252,22255,22258],{},[989,22250,22251],{},"Chữ gặp nhiều thì mã ngắn, hiếm thì mã dài.",[989,22253,22254],{},"Văn bản toàn A thì A chỉ tốn 1 bit.",[989,22256,22257],{},"Đầu ra là bảng chữ sang dãy bit.",[989,22259,22260],{},"Ví dụ đời thường: phím tắt cho việc hay làm.",[981,22262,22264],{"id":22263},"vòng-gộp-2-nút-nhỏ-nhất","Vòng gộp 2 nút nhỏ nhất",[986,22266,22267,22270,22273,22276,22279],{},[989,22268,22269],{},"Bắt đầu từ mỗi chữ và số lần gặp.",[989,22271,22272],{},"Mỗi lượt gộp 2 nút nhỏ nhất thành cha.",[989,22274,22275],{},"Tần suất cha bằng tổng 2 con.",[989,22277,22278],{},"Ví dụ đời thường: gộp 2 đống nhỏ nhất trước.",[989,22280,22281],{},"Lặp tới khi còn 1 gốc là xong cây.",[981,22283,22285],{"id":22284},"min-heap-và-mã-tiền-tố","Min-heap và mã tiền tố",[986,22287,22288,22349,22352,22355,22358],{},[989,22289,22290,22291,1517],{},"Min-heap lấy 2 nút nhỏ nhanh ",[1023,22292,22294,22319],{"className":22293},[1026],[1023,22295,22297],{"className":22296},[1030],[1032,22298,22299],{"xmlns":1034},[1036,22300,22301,22317],{},[1039,22302,22303,22305,22307,22309,22311,22313,22315],{},[1042,22304,1044],{},[1046,22306,1049],{"stretchy":1048},[1042,22308,7684],{},[1042,22310,7687],{},[1042,22312,7690],{},[1042,22314,1262],{},[1046,22316,1056],{"stretchy":1048},[1058,22318,7697],{"encoding":1060},[1023,22320,22322],{"className":22321,"ariaHidden":1066},[1065],[1023,22323,22325,22328,22331,22334,22337,22340,22343,22346],{"className":22324},[1070],[1023,22326],{"className":22327,"style":1075},[1074],[1023,22329,1044],{"className":22330,"style":1081},[1079,1080],[1023,22332,1049],{"className":22333},[1085],[1023,22335,7684],{"className":22336,"style":7716},[1079,1080],[1023,22338,7687],{"className":22339},[1079,1080],[1023,22341,7690],{"className":22342,"style":7723},[1079,1080],[1023,22344,1262],{"className":22345},[1079,1080],[1023,22347,1056],{"className":22348},[1092],[989,22350,22351],{},"Trái là 0, phải là 1, đường đi là mã.",[989,22353,22354],{},"Không mã nào là đầu của mã khác.",[989,22356,22357],{},"Ví dụ đời thường: mã vùng không lẫn nhau.",[989,22359,22360],{},"Nhờ đó giải mã khỏi cần dấu cách.",[1099,22362,22363,22376],{},[1102,22364,22365],{},[1105,22366,22367,22370,22373],{},[1108,22368,22369],{},"Chữ mẫu",[1108,22371,22372],{},"Tần suất",[1108,22374,22375],{},"Mã",[1118,22377,22378,22389,22399],{},[1105,22379,22380,22383,22386],{},[1123,22381,22382],{},"A",[1123,22384,22385],{},"0.6",[1123,22387,22388],{},"Ngắn nhất",[1105,22390,22391,22394,22397],{},[1123,22392,22393],{},"B",[1123,22395,22396],{},"0.2",[1123,22398,10667],{},[1105,22400,22401,22404,22407],{},[1123,22402,22403],{},"F, E",[1123,22405,22406],{},"0.02, 0.05",[1123,22408,22409],{},"Dài nhất",[968,22411,1433],{"id":1432},[986,22413,22414,22417],{},[989,22415,22416],{},"Input: A 5 lần, B 2 lần, C 1 lần. Output: A mã ngắn nhất, C dài nhất.",[989,22418,22419],{},"Giải thích: gộp C với B trước vì nhỏ nhất.",[968,22421,1482],{"id":1481},[973,22423,1485,22424,22426,22427,5599,22429,1517],{},[1487,22425,1493],{},". Được dùng ",[992,22428,18966],{},[992,22430,22431],{},"day-027\u002F",[981,22433,22435],{"id":22434},"bài-1-dựng-cây-và-bảng-mã","Bài 1: Dựng cây và bảng mã",[1352,22437,22439],{"className":1393,"code":22438,"language":1395,"meta":1357,"style":1357},"struct HNode { long long freq; unsigned char ch; HNode *left = nullptr, *right = nullptr; };\nstd::array\u003Clong long, 256> countFreq(const std::string &text);\nHNode *buildTree(const std::array\u003Clong long, 256> &freq);\nstd::unordered_map\u003Cunsigned char, std::string> buildCodes(const HNode *root);  \u002F\u002F trái '0', phải '1'\nvoid freeTree(HNode *root);\n",[992,22440,22441,22446,22451,22456,22461],{"__ignoreMap":1357},[1023,22442,22443],{"class":1362,"line":63},[1023,22444,22445],{},"struct HNode { long long freq; unsigned char ch; HNode *left = nullptr, *right = nullptr; };\n",[1023,22447,22448],{"class":1362,"line":68},[1023,22449,22450],{},"std::array\u003Clong long, 256> countFreq(const std::string &text);\n",[1023,22452,22453],{"class":1362,"line":73},[1023,22454,22455],{},"HNode *buildTree(const std::array\u003Clong long, 256> &freq);\n",[1023,22457,22458],{"class":1362,"line":78},[1023,22459,22460],{},"std::unordered_map\u003Cunsigned char, std::string> buildCodes(const HNode *root);  \u002F\u002F trái '0', phải '1'\n",[1023,22462,22463],{"class":1362,"line":83},[1023,22464,22465],{},"void freeTree(HNode *root);\n",[973,22467,22468],{},[1487,22469,2194],{},[986,22471,22472,22475,22481],{},[989,22473,22474],{},"Hòa tần suất thì nút có ký tự nhỏ hơn ra trước. Nhờ vậy kết quả tất định, dễ test.",[989,22476,22477,22478,1517],{},"Văn bản chỉ có 1 loại ký tự: mã của ký tự đó là ",[992,22479,22480],{},"\"0\"",[989,22482,22483],{},"Văn bản rỗng: trả bảng mã rỗng.",[1352,22485,22488],{"className":22486,"code":22487,"language":2241,"meta":1357},[2239],"\"AAAAABBC\"  -> freq A=5 B=2 C=1; len(code[A]) = 1, len(code[C]) = 2\n\"AAAA\"      -> code[A] = \"0\"\nKhông mã nào là tiền tố của mã khác (viết hàm isPrefixFree để kiểm)\n",[992,22489,22487],{"__ignoreMap":1357},[981,22491,22493],{"id":22492},"bài-2-mã-hóa-và-giải-mã","Bài 2: Mã hóa và giải mã",[1099,22495,22496,22504],{},[1102,22497,22498],{},[1105,22499,22500,22502],{},[1108,22501,1566],{},[1108,22503,2547],{},[1118,22505,22506,22522,22532],{},[1105,22507,22508,22513],{},[1123,22509,22510],{},[992,22511,22512],{},"std::string encode(const std::string &text, const Codes &c)",[1123,22514,22515,22516,2461,22519],{},"Trả chuỗi ",[992,22517,22518],{},"'0'",[992,22520,22521],{},"'1'",[1105,22523,22524,22529],{},[1123,22525,22526],{},[992,22527,22528],{},"std::string decode(const std::string &bits, const HNode *root)",[1123,22530,22531],{},"Đi từ gốc theo bit, gặp lá thì xuất ký tự",[1105,22533,22534,22539],{},[1123,22535,22536],{},[992,22537,22538],{},"double avgBits(const std::string &text, const Codes &c)",[1123,22540,22541],{},"Số bit trung bình mỗi ký tự",[1352,22543,22546],{"className":22544,"code":22545,"language":2241,"meta":1357},[2239],"decode(encode(t)) == t với mọi t (test 100 chuỗi ngẫu nhiên)\n\"abracadabra\": avgBits ~ 2.09, so với 8 bit ASCII\n",[992,22547,22545],{"__ignoreMap":1357},[981,22549,22551],{"id":22550},"bài-3-nén-file-thật-nâng-cao","Bài 3: Nén file thật (nâng cao)",[973,22553,22554,22555,1509,22558,1517],{},"Viết 2 lệnh: ",[992,22556,22557],{},"huff c input.txt out.huf",[992,22559,22560],{},"huff d out.huf back.txt",[973,22562,22563,22564,22567],{},"File ",[992,22565,22566],{},".huf"," gồm: 256 số tần suất (mỗi số 8 byte), tổng số ký tự gốc (8 byte), rồi các bit đã đóng gói 8 bit vào 1 byte.",[1352,22569,22572],{"className":22570,"code":22571,"language":2241,"meta":1357},[2239],"Test: back.txt giống hệt input.txt (so bằng cmp hoặc diff)\nIn: kích thước gốc, kích thước nén, tỉ lệ nén\n",[992,22573,22571],{"__ignoreMap":1357},[973,22575,22576,22577,22579],{},"Chạy trên 3 file: văn bản tiếng Việt, file toàn chữ ",[992,22578,6207],{},", file byte ngẫu nhiên. Giải thích vì sao file ngẫu nhiên không nén được.",[981,22581,2711],{"id":2710},[986,22583,22585,22594,22600,22606],{"className":22584},[2715],[989,22586,22588,8082,22590,22593],{"className":22587},[2719],[2721,22589],{"disabled":2723,"type":2724},[992,22591,22592],{},"decode(encode(t)) == t"," với 100 chuỗi ngẫu nhiên.",[989,22595,22597,22599],{"className":22596},[2719],[2721,22598],{"disabled":2723,"type":2724}," Trường hợp 1 ký tự và chuỗi rỗng không crash.",[989,22601,22603,22605],{"className":22602},[2719],[2721,22604],{"disabled":2723,"type":2724}," Bài 3 nén rồi giải nén trả lại file giống hệt.",[989,22607,22609,22611],{"className":22608},[2719],[2721,22610],{"disabled":2723,"type":2724}," Sanitizer sạch, cây được giải phóng.",[968,22613,2890],{"id":2889},[986,22615,22616,22619,22622,22625],{},[989,22617,22618],{},"Vì sao chữ hay gặp được mã ngắn?",[989,22620,22621],{},"Mỗi lượt Huffman gộp mấy nút nào?",[989,22623,22624],{},"Min-heap giúp gì ở đây?",[989,22626,22627],{},"Mã tiền tố nghĩa là gì?",[3014,22629],{},[973,22631,22632],{},"🌕 Bạn đã hoàn thành ngày 27. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,22634,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":22636},[22637,22638,22643,22644,22650],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":22639},[22640,22641,22642],{"id":22245,"depth":73,"text":22246},{"id":22263,"depth":73,"text":22264},{"id":22284,"depth":73,"text":22285},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":22645},[22646,22647,22648,22649],{"id":22434,"depth":73,"text":22435},{"id":22492,"depth":73,"text":22493},{"id":22550,"depth":73,"text":22551},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây cây mã tiền tố tối ưu từ tần suất ký tự bằng thuật toán tham lam bottom-up với min-heap.",{},[3050,15144],{"title":190,"description":22651},[15148,22656],"compression","_mJk1nthHnKuZh_LECIBOf5elPH_7U0rpHbAQkNunnU",{"id":22659,"title":195,"body":22660,"category":5189,"day":198,"description":23079,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":23080,"navigation":2723,"outcomes":3047,"path":196,"prerequisites":23081,"seo":23082,"stem":197,"tags":23083,"__hash__":23086},"challenges\u002Fchallenges\u002F28.command-co-ban.md",{"type":965,"value":22661,"toc":23063},[22662,22664,22667,22669,22673,22687,22691,22705,22709,22723,22760,22762,22770,22772,22779,22783,22831,22899,22924,22930,22940,22944,22971,22975,23000,23006,23008,23040,23042,23056,23058,23061],[968,22663,971],{"id":970},[973,22665,22666],{},"Bài này học cách gói yêu cầu thành món đồ. Bạn tách nút bấm khỏi máy làm.",[968,22668,979],{"id":978},[981,22670,22672],{"id":22671},"gói-yêu-cầu-thành-đối-tượng","Gói yêu cầu thành đối tượng",[986,22674,22675,22678,22681,22684],{},[989,22676,22677],{},"Mỗi yêu cầu là 1 món lệnh riêng.",[989,22679,22680],{},"Lệnh biết gọi đúng máy đúng việc.",[989,22682,22683],{},"Nhờ đó lưu, xếp hàng, ghi nhật ký được.",[989,22685,22686],{},"Ví dụ đời thường: phiếu gọi món trong quán.",[981,22688,22690],{"id":22689},"remote-7-khe-và-4-vai","Remote 7 khe và 4 vai",[986,22692,22693,22696,22699,22702],{},[989,22694,22695],{},"Khe chỉ giữ 2 lệnh bật và tắt.",[989,22697,22698],{},"Lệnh giữ máy thật bên trong.",[989,22700,22701],{},"Máy chỉ lo làm, không biết remote.",[989,22703,22704],{},"Ví dụ đời thường: ổ cắm không biết cắm quạt hay đèn.",[981,22706,22708],{"id":22707},"ba-nhịp-bấm-nút","Ba nhịp bấm nút",[986,22710,22711,22714,22717,22720],{},[989,22712,22713],{},"Tay bấm nút ở khe.",[989,22715,22716],{},"Khe gọi lệnh đang cắm.",[989,22718,22719],{},"Lệnh gọi đúng máy của nó.",[989,22721,22722],{},"Ví dụ đời thường: bấm công tắc, dây gọi bóng đèn.",[1099,22724,22725,22734],{},[1102,22726,22727],{},[1105,22728,22729,22731],{},[1108,22730,7111],{},[1108,22732,22733],{},"Thêm máy mới",[1118,22735,22736,22744,22752],{},[1105,22737,22738,22741],{},[1123,22739,22740],{},"Gọi thẳng máy",[1123,22742,22743],{},"Mở remote ra sửa",[1105,22745,22746,22749],{},[1123,22747,22748],{},"Qua lệnh",[1123,22750,22751],{},"Cắm thêm lệnh mới",[1105,22753,22754,22757],{},[1123,22755,22756],{},"Khe trống",[1123,22758,22759],{},"Cắm lệnh rỗng cho êm",[968,22761,1433],{"id":1432},[986,22763,22764,22767],{},[989,22765,22766],{},"Input: bấm bật ở khe đèn. Output: đèn sáng, máy khác im.",[989,22768,22769],{},"Giải thích: khe chỉ gọi lệnh, lệnh gọi đúng đèn.",[968,22771,1482],{"id":1481},[973,22773,1485,22774,4801,22776,1517],{},[1487,22775,4800],{},[992,22777,22778],{},"day-028\u002F",[981,22780,22782],{"id":22781},"bài-1-remote-7-khe","Bài 1: Remote 7 khe",[1352,22784,22786],{"className":1393,"code":22785,"language":1395,"meta":1357,"style":1357},"struct Command { virtual void execute() = 0; virtual std::string name() const = 0; virtual ~Command() = default; };\nclass RemoteControl {\n public:\n  RemoteControl();   \u002F\u002F 7 khe, mặc định cắm NoCommand\n  void setCommand(int slot, std::shared_ptr\u003CCommand> on, std::shared_ptr\u003CCommand> off);\n  void onButtonPressed(int slot);\n  void offButtonPressed(int slot);\n  std::string toString() const;   \u002F\u002F liệt kê 7 khe\n};\n",[992,22787,22788,22793,22798,22802,22807,22812,22817,22822,22827],{"__ignoreMap":1357},[1023,22789,22790],{"class":1362,"line":63},[1023,22791,22792],{},"struct Command { virtual void execute() = 0; virtual std::string name() const = 0; virtual ~Command() = default; };\n",[1023,22794,22795],{"class":1362,"line":68},[1023,22796,22797],{},"class RemoteControl {\n",[1023,22799,22800],{"class":1362,"line":73},[1023,22801,4836],{},[1023,22803,22804],{"class":1362,"line":78},[1023,22805,22806],{},"  RemoteControl();   \u002F\u002F 7 khe, mặc định cắm NoCommand\n",[1023,22808,22809],{"class":1362,"line":83},[1023,22810,22811],{},"  void setCommand(int slot, std::shared_ptr\u003CCommand> on, std::shared_ptr\u003CCommand> off);\n",[1023,22813,22814],{"class":1362,"line":88},[1023,22815,22816],{},"  void onButtonPressed(int slot);\n",[1023,22818,22819],{"class":1362,"line":93},[1023,22820,22821],{},"  void offButtonPressed(int slot);\n",[1023,22823,22824],{"class":1362,"line":98},[1023,22825,22826],{},"  std::string toString() const;   \u002F\u002F liệt kê 7 khe\n",[1023,22828,22829],{"class":1362,"line":103},[1023,22830,4866],{},[1099,22832,22833,22842],{},[1102,22834,22835],{},[1105,22836,22837,22840],{},[1108,22838,22839],{},"Máy (receiver)",[1108,22841,1566],{},[1118,22843,22844,22862,22881],{},[1105,22845,22846,22851],{},[1123,22847,22848],{},[992,22849,22850],{},"Light(room)",[1123,22852,22853,1656,22856,1656,22859],{},[992,22854,22855],{},"on()",[992,22857,22858],{},"off()",[992,22860,22861],{},"isOn()",[1105,22863,22864,22869],{},[1123,22865,22866],{},[992,22867,22868],{},"Stereo",[1123,22870,22871,1656,22873,1656,22875,1656,22878],{},[992,22872,22855],{},[992,22874,22858],{},[992,22876,22877],{},"setCD()",[992,22879,22880],{},"setVolume(int)",[1105,22882,22883,22888],{},[1123,22884,22885],{},[992,22886,22887],{},"GarageDoor",[1123,22889,22890,1656,22893,1656,22896],{},[992,22891,22892],{},"up()",[992,22894,22895],{},"down()",[992,22897,22898],{},"isOpen()",[973,22900,22901,22902,1656,22905,1656,22908,22911,22912,1656,22915,1656,22918,1656,22921,1517],{},"Viết lệnh: ",[992,22903,22904],{},"LightOn",[992,22906,22907],{},"LightOff",[992,22909,22910],{},"StereoOnWithCD"," (bật, chọn CD, âm lượng 11), ",[992,22913,22914],{},"StereoOff",[992,22916,22917],{},"GarageDoorUp",[992,22919,22920],{},"GarageDoorDown",[992,22922,22923],{},"NoCommand",[1352,22925,22928],{"className":22926,"code":22927,"language":2241,"meta":1357},[2239],"setCommand(0, LightOn(phòng khách), LightOff(phòng khách))\nonButtonPressed(0)  -> phòng khách sáng\nonButtonPressed(6)  -> khe trống, không làm gì, không crash\nonButtonPressed(9)  -> ném out_of_range\n",[992,22929,22927],{"__ignoreMap":1357},[973,22931,22932,2308,22934,15871,22937,22939],{},[1487,22933,6076],{},[992,22935,22936],{},"RemoteControl",[992,22938,5026],{}," bất kỳ receiver nào.",[981,22941,22943],{"id":22942},"bài-2-lệnh-bằng-lambda-và-máy-mới","Bài 2: Lệnh bằng lambda và máy mới",[2273,22945,22946,22952],{},[989,22947,1505,22948,22951],{},[992,22949,22950],{},"LambdaCommand(std::string name, std::function\u003Cvoid()> f)",". Cắm lệnh bật quạt mà không cần viết lớp riêng.",[989,22953,5030,22954,7386,22957,1656,22960,1656,22963,1656,22966,22968,22969,1517],{},[992,22955,22956],{},"CeilingFan",[992,22958,22959],{},"high()",[992,22961,22962],{},"medium()",[992,22964,22965],{},"low()",[992,22967,22858],{},". Thêm vào remote mà không sửa ",[992,22970,22936],{},[981,22972,22974],{"id":22973},"bài-3-hàng-đợi-lệnh-và-nhật-ký-nâng-cao","Bài 3: Hàng đợi lệnh và nhật ký (nâng cao)",[2273,22976,22977,22987,22997],{},[989,22978,22979,22982,22983,22986],{},[992,22980,22981],{},"CommandQueue"," nhận lệnh từ nhiều nơi, ",[992,22984,22985],{},"runAll()"," chạy theo thứ tự FIFO.",[989,22988,22989,22992,22993,22996],{},[992,22990,22991],{},"LoggingCommand"," bọc một lệnh khác, ghi ",[992,22994,22995],{},"\"[time] name\""," vào vector trước khi chạy.",[989,22998,22999],{},"Viết kịch bản: 5 lệnh được đưa vào hàng đợi, chạy hết, in nhật ký.",[1352,23001,23004],{"className":23002,"code":23003,"language":2241,"meta":1357},[2239],"queue: LightOn, GarageDoorUp, StereoOnWithCD, LightOff, GarageDoorDown\nlog sau runAll -> 5 dòng đúng thứ tự\n",[992,23005,23003],{"__ignoreMap":1357},[981,23007,2711],{"id":2710},[986,23009,23011,23016,23022,23034],{"className":23010},[2715],[989,23012,23014,11986],{"className":23013},[2719],[2721,23015],{"disabled":2723,"type":2724},[989,23017,23019,23021],{"className":23018},[2719],[2721,23020],{"disabled":2723,"type":2724}," Remote không phụ thuộc receiver cụ thể.",[989,23023,23025,23027,23028,23030,23031,23033],{"className":23024},[2719],[2721,23026],{"disabled":2723,"type":2724}," Khe trống dùng ",[992,23029,22923],{},", không có kiểm tra ",[992,23032,15884],{}," rải rác.",[989,23035,23037,23039],{"className":23036},[2719],[2721,23038],{"disabled":2723,"type":2724}," Vẽ sơ đồ 4 vai: Client, Invoker, Command, Receiver.",[968,23041,2890],{"id":2889},[986,23043,23044,23047,23050,23053],{},[989,23045,23046],{},"Command là gì, nói 1 câu?",[989,23048,23049],{},"Remote gồm 4 vai nào?",[989,23051,23052],{},"Vì sao khe không cần biết máy?",[989,23054,23055],{},"Gói thành món đồ được lợi gì?",[3014,23057],{},[973,23059,23060],{},"🌕 Bạn đã hoàn thành ngày 28. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,23062,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":23064},[23065,23066,23071,23072,23078],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":23067},[23068,23069,23070],{"id":22671,"depth":73,"text":22672},{"id":22689,"depth":73,"text":22690},{"id":22707,"depth":73,"text":22708},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":23073},[23074,23075,23076,23077],{"id":22781,"depth":73,"text":22782},{"id":22942,"depth":73,"text":22943},{"id":22973,"depth":73,"text":22974},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Command, chiếc remote bảy khe, và cách tách bên bấm nút khỏi bên làm việc bằng đối tượng lệnh.",{},[5194,5195],{"title":195,"description":23079},[23084,23085],"command","remote","0z6BXIYU8Bm1Na_UZL0KOj1ajISmiBRxeQRpJI9hVJk",{"id":23088,"title":200,"body":23089,"category":3041,"day":203,"description":23647,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":23648,"navigation":2723,"outcomes":3047,"path":201,"prerequisites":23649,"seo":23650,"stem":202,"tags":23651,"__hash__":23653},"challenges\u002Fchallenges\u002F29.treap-co-ban.md",{"type":965,"value":23090,"toc":23631},[23091,23093,23096,23098,23102,23116,23120,23134,23138,23329,23379,23381,23389,23391,23408,23412,23447,23453,23459,23463,23548,23554,23558,23565,23568,23574,23576,23608,23610,23624,23626,23629],[968,23092,971],{"id":970},[973,23094,23095],{},"Bài này học cây lai vừa tìm nhanh vừa lấy khẩn. Bạn quản kho tạp hóa 2 tiêu chí.",[968,23097,979],{"id":978},[981,23099,23101],{"id":23100},"bài-toán-2-tiêu-chí","Bài toán 2 tiêu chí",[986,23103,23104,23107,23110,23113],{},[989,23105,23106],{},"Cần tìm hàng theo tên thật nhanh.",[989,23108,23109],{},"Cần lấy món sắp hết hàng ngay.",[989,23111,23112],{},"1 cấu trúc đơn không cân cả 2.",[989,23114,23115],{},"Ví dụ đời thường: tìm sách theo tên và theo lượt mượn.",[981,23117,23119],{"id":23118},"hai-luật-trong-1-cây","Hai luật trong 1 cây",[986,23121,23122,23125,23128,23131],{},[989,23123,23124],{},"Ngang theo tên: trái nhỏ, phải lớn.",[989,23126,23127],{},"Dọc theo tồn: cha ít hàng hơn con.",[989,23129,23130],{},"Món cạn nhất luôn nằm ở gốc.",[989,23132,23133],{},"Ví dụ đời thường: xếp tên A-Z, ai gấp lên trước.",[981,23135,23137],{"id":23136},"phép-xoay-giữ-thứ-tự","Phép xoay giữ thứ tự",[986,23139,23140,23143,23146,23149,23152,23227],{},[989,23141,23142],{},"Xoay nâng con lên làm gốc cây con.",[989,23144,23145],{},"Thứ tự tên trái-phải vẫn đúng nguyên.",[989,23147,23148],{},"Quan hệ khẩn cha-con được sửa đúng.",[989,23150,23151],{},"Ví dụ đời thường: đổi đội trưởng nhưng giữ hàng ngũ.",[989,23153,23154,23155,7386,23198,23226],{},"Tìm kiếm đi hệt BST, tốn ",[1023,23156,23158,23177],{"className":23157},[1026],[1023,23159,23161],{"className":23160},[1030],[1032,23162,23163],{"xmlns":1034},[1036,23164,23165,23175],{},[1039,23166,23167,23169,23171,23173],{},[1042,23168,1044],{},[1046,23170,1049],{"stretchy":1048},[1042,23172,7908],{},[1046,23174,1056],{"stretchy":1048},[1058,23176,7913],{"encoding":1060},[1023,23178,23180],{"className":23179,"ariaHidden":1066},[1065],[1023,23181,23183,23186,23189,23192,23195],{"className":23182},[1070],[1023,23184],{"className":23185,"style":1075},[1074],[1023,23187,1044],{"className":23188,"style":1081},[1079,1080],[1023,23190,1049],{"className":23191},[1085],[1023,23193,7908],{"className":23194},[1079,1080],[1023,23196,1056],{"className":23197},[1092],[1023,23199,23201,23214],{"className":23200},[1026],[1023,23202,23204],{"className":23203},[1030],[1032,23205,23206],{"xmlns":1034},[1036,23207,23208,23212],{},[1039,23209,23210],{},[1042,23211,7908],{},[1058,23213,7908],{"encoding":1060},[1023,23215,23217],{"className":23216,"ariaHidden":1066},[1065],[1023,23218,23220,23223],{"className":23219},[1070],[1023,23221],{"className":23222,"style":22079},[1074],[1023,23224,7908],{"className":23225},[1079,1080]," là chiều cao.",[989,23228,23229,23230,23273,23274,1517],{},"Ưu tiên theo tồn kho không đảm bảo cây cân bằng: có thể lệch tới ",[1023,23231,23233,23252],{"className":23232},[1026],[1023,23234,23236],{"className":23235},[1030],[1032,23237,23238],{"xmlns":1034},[1036,23239,23240,23250],{},[1039,23241,23242,23244,23246,23248],{},[1042,23243,1044],{},[1046,23245,1049],{"stretchy":1048},[1042,23247,1262],{},[1046,23249,1056],{"stretchy":1048},[1058,23251,1267],{"encoding":1060},[1023,23253,23255],{"className":23254,"ariaHidden":1066},[1065],[1023,23256,23258,23261,23264,23267,23270],{"className":23257},[1070],[1023,23259],{"className":23260,"style":1075},[1074],[1023,23262,1044],{"className":23263,"style":1081},[1079,1080],[1023,23265,1049],{"className":23266},[1085],[1023,23268,1262],{"className":23269},[1079,1080],[1023,23271,1056],{"className":23272},[1092],". Ưu tiên ngẫu nhiên (ngày 65) mới cho chiều cao kỳ vọng ",[1023,23275,23277,23300],{"className":23276},[1026],[1023,23278,23280],{"className":23279},[1030],[1032,23281,23282],{"xmlns":1034},[1036,23283,23284,23298],{},[1039,23285,23286,23288,23290,23292,23294,23296],{},[1042,23287,1044],{},[1046,23289,1049],{"stretchy":1048},[1042,23291,8397],{},[1046,23293,8400],{},[1042,23295,1262],{},[1046,23297,1056],{"stretchy":1048},[1058,23299,8407],{"encoding":1060},[1023,23301,23303],{"className":23302,"ariaHidden":1066},[1065],[1023,23304,23306,23309,23312,23315,23320,23323,23326],{"className":23305},[1070],[1023,23307],{"className":23308,"style":1075},[1074],[1023,23310,1044],{"className":23311,"style":1081},[1079,1080],[1023,23313,1049],{"className":23314},[1085],[1023,23316,8427,23318],{"className":23317},[8426],[1023,23319,7690],{"style":8430},[1023,23321],{"className":23322,"style":8434},[2354],[1023,23324,1262],{"className":23325},[1079,1080],[1023,23327,1056],{"className":23328},[1092],[1099,23330,23331,23344],{},[1102,23332,23333],{},[1105,23334,23335,23338,23341],{},[1108,23336,23337],{},"Chiều",[1108,23339,23340],{},"Luật",[1108,23342,23343],{},"Dùng để gì",[1118,23345,23346,23357,23368],{},[1105,23347,23348,23351,23354],{},[1123,23349,23350],{},"Ngang",[1123,23352,23353],{},"Trái nhỏ phải lớn",[1123,23355,23356],{},"Tìm theo tên",[1105,23358,23359,23362,23365],{},[1123,23360,23361],{},"Dọc",[1123,23363,23364],{},"Cha khẩn hơn con",[1123,23366,23367],{},"Lấy món cạn nhất",[1105,23369,23370,23373,23376],{},[1123,23371,23372],{},"Xoay",[1123,23374,23375],{},"Giữ ngang, sửa dọc",[1123,23377,23378],{},"Sửa vi phạm",[968,23380,1433],{"id":1432},[986,23382,23383,23386],{},[989,23384,23385],{},"Input: treap gốc Flour tồn 10, tìm Water. Output: rẽ phải tới đúng nút Water.",[989,23387,23388],{},"Giải thích: tìm theo tên đi hệt cây tìm kiếm.",[968,23390,1482],{"id":1481},[973,23392,1485,23393,5599,23395,7807,23398,23401,23402,23404,23405,21702],{},[1487,23394,1493],{},[992,23396,23397],{},"day-029\u002F",[992,23399,23400],{},"std::string"," (tên hàng), ưu tiên là ",[992,23403,1516],{}," (số tồn kho). Min-treap: cha có tồn kho ",[1487,23406,23407],{},"nhỏ hơn hoặc bằng",[981,23409,23411],{"id":23410},"bài-1-phép-xoay-và-tìm-kiếm","Bài 1: Phép xoay và tìm kiếm",[1352,23413,23415],{"className":1393,"code":23414,"language":1395,"meta":1357,"style":1357},"struct TNode { std::string key; int priority; TNode *left = nullptr, *right = nullptr; };\nTNode *rotateRight(TNode *y);   \u002F\u002F con trái lên làm gốc\nTNode *rotateLeft(TNode *x);    \u002F\u002F con phải lên làm gốc\nTNode *search(TNode *root, const std::string &key);\nbool   checkBST(const TNode *root);\nbool   checkHeap(const TNode *root);\n",[992,23416,23417,23422,23427,23432,23437,23442],{"__ignoreMap":1357},[1023,23418,23419],{"class":1362,"line":63},[1023,23420,23421],{},"struct TNode { std::string key; int priority; TNode *left = nullptr, *right = nullptr; };\n",[1023,23423,23424],{"class":1362,"line":68},[1023,23425,23426],{},"TNode *rotateRight(TNode *y);   \u002F\u002F con trái lên làm gốc\n",[1023,23428,23429],{"class":1362,"line":73},[1023,23430,23431],{},"TNode *rotateLeft(TNode *x);    \u002F\u002F con phải lên làm gốc\n",[1023,23433,23434],{"class":1362,"line":78},[1023,23435,23436],{},"TNode *search(TNode *root, const std::string &key);\n",[1023,23438,23439],{"class":1362,"line":83},[1023,23440,23441],{},"bool   checkBST(const TNode *root);\n",[1023,23443,23444],{"class":1362,"line":88},[1023,23445,23446],{},"bool   checkHeap(const TNode *root);\n",[973,23448,23449,23450,23452],{},"Tự dựng tay cây 5 nút vi phạm luật heap ở 1 cạnh. Gọi xoay đúng một lần để sửa. In ",[992,23451,7946],{}," trước và sau xoay: phải giống nhau.",[1352,23454,23457],{"className":23455,"code":23456,"language":2241,"meta":1357},[2239],"inorder trước xoay == inorder sau xoay\ncheckHeap: false trước, true sau\n",[992,23458,23456],{"__ignoreMap":1357},[981,23460,23462],{"id":23461},"bài-2-chèn-vào-treap","Bài 2: Chèn vào treap",[1099,23464,23465,23473],{},[1102,23466,23467],{},[1105,23468,23469,23471],{},[1108,23470,1566],{},[1108,23472,2547],{},[1118,23474,23475,23485,23539],{},[1105,23476,23477,23482],{},[1123,23478,23479],{},[992,23480,23481],{},"TNode *insert(TNode *root, const std::string &key, int priority)",[1123,23483,23484],{},"Chèn như BST rồi xoay ngược lên khi vi phạm heap. Khóa đã có thì cập nhật priority và sửa vị trí",[1105,23486,23487,23492],{},[1123,23488,23489],{},[992,23490,23491],{},"const TNode *top(const TNode *root)",[1123,23493,23494,23495,23538],{},"Món có tồn kho ít nhất (",[1023,23496,23498,23517],{"className":23497},[1026],[1023,23499,23501],{"className":23500},[1030],[1032,23502,23503],{"xmlns":1034},[1036,23504,23505,23515],{},[1039,23506,23507,23509,23511,23513],{},[1042,23508,1044],{},[1046,23510,1049],{"stretchy":1048},[1051,23512,1053],{},[1046,23514,1056],{"stretchy":1048},[1058,23516,1061],{"encoding":1060},[1023,23518,23520],{"className":23519,"ariaHidden":1066},[1065],[1023,23521,23523,23526,23529,23532,23535],{"className":23522},[1070],[1023,23524],{"className":23525,"style":1075},[1074],[1023,23527,1044],{"className":23528,"style":1081},[1079,1080],[1023,23530,1049],{"className":23531},[1085],[1023,23533,1053],{"className":23534},[1079],[1023,23536,1056],{"className":23537},[1092],", là gốc)",[1105,23540,23541,23546],{},[1123,23542,23543],{},[992,23544,23545],{},"int height(const TNode *root)",[1123,23547],{},[1352,23549,23552],{"className":23550,"code":23551,"language":2241,"meta":1357},[2239],"insert (Flour,10) (Butter,76) (Water,32) (Sugar,47) (Eggs,9) (Milk,55) (Yeast,5)\n-> top = Yeast(5); checkBST && checkHeap = true\nsearch(\"Water\") -> tìm thấy, priority 32\n",[992,23553,23551],{"__ignoreMap":1357},[981,23555,23557],{"id":23556},"bài-3-treap-ngẫu-nhiên-giữ-cân-bằng-nâng-cao","Bài 3: Treap ngẫu nhiên giữ cân bằng (nâng cao)",[973,23559,23560,23561,23564],{},"Dùng treap làm BST cân bằng: priority lấy ",[1487,23562,23563],{},"ngẫu nhiên"," thay vì tồn kho.",[973,23566,23567],{},"Chèn 1..10^5 theo thứ tự tăng dần vào 2 cây: BST thường (ngày 7) và treap ngẫu nhiên. In chiều cao 2 cây. Chạy 5 seed khác nhau, in chiều cao treap mỗi lần.",[1352,23569,23572],{"className":23570,"code":23571,"language":2241,"meta":1357},[2239],"Kỳ vọng: BST thường cao 99999; treap cao khoảng 30-45\n",[992,23573,23571],{"__ignoreMap":1357},[981,23575,2711],{"id":2710},[986,23577,23579,23591,23597,23603],{"className":23578},[2715],[989,23580,23582,8082,23584,1509,23587,23590],{"className":23581},[2719],[2721,23583],{"disabled":2723,"type":2724},[992,23585,23586],{},"checkBST",[992,23588,23589],{},"checkHeap"," đúng sau mọi thao tác.",[989,23592,23594,23596],{"className":23593},[2719],[2721,23595],{"disabled":2723,"type":2724}," Vẽ tay được 1 phép xoay: trước, sau, và các con trỏ đổi.",[989,23598,23600,23602],{"className":23599},[2719],[2721,23601],{"disabled":2723,"type":2724}," Bảng chiều cao Bài 3 có số thật từ 5 seed.",[989,23604,23606,6299],{"className":23605},[2719],[2721,23607],{"disabled":2723,"type":2724},[968,23609,2890],{"id":2889},[986,23611,23612,23615,23618,23621],{},[989,23613,23614],{},"Vì sao 1 cấu trúc đơn không đủ cho kho?",[989,23616,23617],{},"Treap giữ 2 luật nào?",[989,23619,23620],{},"Xoay để làm gì?",[989,23622,23623],{},"Tìm kiếm trên treap đi thế nào?",[3014,23625],{},[973,23627,23628],{},"🌕 Bạn đã hoàn thành ngày 29. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,23630,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":23632},[23633,23634,23639,23640,23646],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":23635},[23636,23637,23638],{"id":23100,"depth":73,"text":23101},{"id":23118,"depth":73,"text":23119},{"id":23136,"depth":73,"text":23137},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":23641},[23642,23643,23644,23645],{"id":23410,"depth":73,"text":23411},{"id":23461,"depth":73,"text":23462},{"id":23556,"depth":73,"text":23557},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Khám phá cấu trúc lai giữa cây tìm kiếm và heap qua bài toán đa chỉ mục, phép xoay và tìm kiếm.",{},[3050,8149,18469],{"title":200,"description":23647},[23652,8153],"treap","HzVQS9iyJcNJrbF5qbYSv9AEcf3-OhgrgftkBY5eZcA",{"id":23655,"title":205,"body":23656,"category":3041,"day":208,"description":24336,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":24337,"navigation":2723,"outcomes":3047,"path":206,"prerequisites":24338,"seo":24339,"stem":207,"tags":24340,"__hash__":24342},"challenges\u002Fchallenges\u002F30.bo-loc-bloom.md",{"type":965,"value":23657,"toc":24319},[23658,23660,23663,23665,23669,23683,23687,23704,23708,23725,23771,23775,23847,23858,23860,23868,23903,23905,23912,23916,23963,23981,23987,23991,24002,24189,24195,24217,24221,24230,24267,24269,24296,24298,24312,24314,24317],[968,23659,971],{"id":970},[973,23661,23662],{},"Bài này học bộ lọc siêu nhẹ kiểm tra tồn tại. Bạn chặn nhanh cái chắc chắn không có.",[968,23664,979],{"id":978},[981,23666,23668],{"id":23667},"bài-toán-danh-bạ","Bài toán danh bạ",[986,23670,23671,23674,23677,23680],{},[989,23672,23673],{},"Mỗi lần gửi mail cần hỏi có trong danh bạ không.",[989,23675,23676],{},"Gọi kho cũ mỗi lần thì quá chậm.",[989,23678,23679],{},"Tải cả danh bạ về máy rồi hỏi cục bộ.",[989,23681,23682],{},"Ví dụ đời thường: danh sách đen dán ở cửa.",[981,23684,23686],{"id":23685},"mảng-bit-và-k-hàm-băm","Mảng bit và k hàm băm",[986,23688,23689,23692,23695,23698,23701],{},[989,23690,23691],{},"Bắt đầu mảng toàn số 0 dài m bit.",[989,23693,23694],{},"Lưu 1 món thì băm k lần, bật k bit lên 1.",[989,23696,23697],{},"Hỏi 1 món thì đọc k bit đó.",[989,23699,23700],{},"Ví dụ đời thường: đóng k dấu mực lên thẻ.",[989,23702,23703],{},"Thiếu 1 bit 1 là chắc chắn không có.",[981,23705,23707],{"id":23706},"sai-được-1-chiều","Sai được 1 chiều",[986,23709,23710,23713,23716,23719,23722],{},[989,23711,23712],{},"Báo không thì luôn đúng, tin được.",[989,23714,23715],{},"Báo có thì có thể nhầm vì bit dùng chung.",[989,23717,23718],{},"Nhầm này gọi là dương tính giả.",[989,23720,23721],{},"Ví dụ đời thường: thấy dấu mực nhưng nhầm chủ.",[989,23723,23724],{},"Quy tắc: báo không thì thôi, báo có thì kiểm lại.",[1099,23726,23727,23737],{},[1102,23728,23729],{},[1105,23730,23731,23734],{},[1108,23732,23733],{},"Hỏi món",[1108,23735,23736],{},"Kết luận",[1118,23738,23739,23747,23755,23763],{},[1105,23740,23741,23744],{},[1123,23742,23743],{},"Thiếu bit 1",[1123,23745,23746],{},"Chắc chắn không có",[1105,23748,23749,23752],{},[1123,23750,23751],{},"Đủ k bit 1",[1123,23753,23754],{},"Có thể có, cần kiểm lại",[1105,23756,23757,23760],{},[1123,23758,23759],{},"Kho rỗng",[1123,23761,23762],{},"Luôn báo không",[1105,23764,23765,23768],{},[1123,23766,23767],{},"Kho quá đầy",[1123,23769,23770],{},"Hay báo có nhầm",[981,23772,23774],{"id":23773},"các-biến-thể-của-bloom-filter","Các biến thể của Bloom filter",[1099,23776,23777,23790],{},[1102,23778,23779],{},[1105,23780,23781,23784,23787],{},[1108,23782,23783],{},"Biến thể",[1108,23785,23786],{},"Thêm gì",[1108,23788,23789],{},"Dùng khi",[1118,23791,23792,23803,23814,23825,23836],{},[1105,23793,23794,23797,23800],{},[1123,23795,23796],{},"Counting Bloom",[1123,23798,23799],{},"Bộ đếm nhỏ thay cho bit",[1123,23801,23802],{},"Cần xóa phần tử",[1105,23804,23805,23808,23811],{},[1123,23806,23807],{},"Scalable Bloom",[1123,23809,23810],{},"Chuỗi nhiều bộ lọc, bộ sau lớn hơn",[1123,23812,23813],{},"Không biết trước số phần tử",[1105,23815,23816,23819,23822],{},[1123,23817,23818],{},"Layered Bloom",[1123,23820,23821],{},"Nhiều tầng bộ lọc",[1123,23823,23824],{},"Đếm số lần một khóa đã xuất hiện",[1105,23826,23827,23830,23833],{},[1123,23828,23829],{},"Compressed Bloom",[1123,23831,23832],{},"Nén mảng bit khi gửi qua mạng",[1123,23834,23835],{},"Bộ lọc phải truyền đi nhiều",[1105,23837,23838,23841,23844],{},[1123,23839,23840],{},"Bloomier filter",[1123,23842,23843],{},"Lưu thêm giá trị kèm khóa",[1123,23845,23846],{},"Cần ánh xạ khóa sang giá trị nhỏ",[986,23848,23849],{},[989,23850,23851,23852,23854,23855,23857],{},"Ghép hai bộ lọc cùng ",[992,23853,15437],{},", cùng ",[992,23856,4022],{}," hàm băm: phép OR cho bộ lọc của hợp hai tập.",[968,23859,1433],{"id":1432},[986,23861,23862,23865],{},[989,23863,23864],{},"Input: lưu số 2 bật 2 bit, hỏi số 3 lạ mà trùng 2 bit. Output: báo có nhầm.",[989,23866,23867],{},"Giải thích: bit không ghi tên ai nên bị trùng.",[1352,23869,23871],{"className":3538,"code":23870,"language":3540,"meta":1357,"style":1357},"bits = [0] * 8  # mảng bit ban đầu\ndef add(h1, h2):  # lưu: bật 2 bit\n    bits[h1] = 1\n    bits[h2] = 1\ndef ask(h1, h2):  # hỏi: đủ 2 bit 1 mới báo có\n    return bits[h1] == 1 and bits[h2] == 1\n",[992,23872,23873,23878,23883,23888,23893,23898],{"__ignoreMap":1357},[1023,23874,23875],{"class":1362,"line":63},[1023,23876,23877],{},"bits = [0] * 8  # mảng bit ban đầu\n",[1023,23879,23880],{"class":1362,"line":68},[1023,23881,23882],{},"def add(h1, h2):  # lưu: bật 2 bit\n",[1023,23884,23885],{"class":1362,"line":73},[1023,23886,23887],{},"    bits[h1] = 1\n",[1023,23889,23890],{"class":1362,"line":78},[1023,23891,23892],{},"    bits[h2] = 1\n",[1023,23894,23895],{"class":1362,"line":83},[1023,23896,23897],{},"def ask(h1, h2):  # hỏi: đủ 2 bit 1 mới báo có\n",[1023,23899,23900],{"class":1362,"line":88},[1023,23901,23902],{},"    return bits[h1] == 1 and bits[h2] == 1\n",[968,23904,1482],{"id":1481},[973,23906,1485,23907,5599,23909,1517],{},[1487,23908,1493],{},[992,23910,23911],{},"day-030\u002F",[981,23913,23915],{"id":23914},"bài-1-bloom-filter","Bài 1: Bloom filter",[1352,23917,23919],{"className":1393,"code":23918,"language":1395,"meta":1357,"style":1357},"class BloomFilter {\n public:\n  BloomFilter(size_t m, int k);           \u002F\u002F m bit, k hàm băm\n  void add(const std::string &s);\n  bool mightContain(const std::string &s) const;\n  double fillRatio() const;               \u002F\u002F tỉ lệ bit đang là 1\n private:\n  std::vector\u003Cuint64_t> bits;             \u002F\u002F tự đóng gói bit, không dùng std::vector\u003Cbool>\n};\n",[992,23920,23921,23926,23930,23935,23940,23945,23950,23954,23959],{"__ignoreMap":1357},[1023,23922,23923],{"class":1362,"line":63},[1023,23924,23925],{},"class BloomFilter {\n",[1023,23927,23928],{"class":1362,"line":68},[1023,23929,4836],{},[1023,23931,23932],{"class":1362,"line":73},[1023,23933,23934],{},"  BloomFilter(size_t m, int k);           \u002F\u002F m bit, k hàm băm\n",[1023,23936,23937],{"class":1362,"line":78},[1023,23938,23939],{},"  void add(const std::string &s);\n",[1023,23941,23942],{"class":1362,"line":83},[1023,23943,23944],{},"  bool mightContain(const std::string &s) const;\n",[1023,23946,23947],{"class":1362,"line":88},[1023,23948,23949],{},"  double fillRatio() const;               \u002F\u002F tỉ lệ bit đang là 1\n",[1023,23951,23952],{"class":1362,"line":93},[1023,23953,16301],{},[1023,23955,23956],{"class":1362,"line":98},[1023,23957,23958],{},"  std::vector\u003Cuint64_t> bits;             \u002F\u002F tự đóng gói bit, không dùng std::vector\u003Cbool>\n",[1023,23960,23961],{"class":1362,"line":103},[1023,23962,4866],{},[973,23964,23965,23968,23969,1656,23972,23975,23976,13710,23978,1517],{},[1487,23966,23967],{},"Hàm băm:"," double hashing. Tính ",[992,23970,23971],{},"h1 = FNV-1a(s)",[992,23973,23974],{},"h2 = murmur-style mix(h1) | 1",". Hàm thứ ",[992,23977,1837],{},[992,23979,23980],{},"(h1 + i * h2) % m",[1352,23982,23985],{"className":23983,"code":23984,"language":2241,"meta":1357},[2239],"m=1000, k=3; add \"a@x.com\", \"b@y.com\"\nmightContain(\"a@x.com\")  -> true (luôn luôn)\nbộ lọc rỗng              -> mọi truy vấn trả false\n",[992,23986,23984],{"__ignoreMap":1357},[981,23988,23990],{"id":23989},"bài-2-đo-false-positive","Bài 2: Đo false positive",[973,23992,23993,23994,23997,23998,24001],{},"Với ",[992,23995,23996],{},"n = 10000"," email đã thêm, thử 100.000 email ",[1487,23999,24000],{},"chưa thêm",". In tỉ lệ dương tính giả thực tế và so với công thức:",[973,24003,24004],{},[1023,24005,24007,24055],{"className":24006},[1026],[1023,24008,24010],{"className":24009},[1030],[1032,24011,24012],{"xmlns":1034},[1036,24013,24014,24052],{},[1039,24015,24016,24018,24021],{},[1042,24017,973],{},[1046,24019,24020],{},"≈",[2327,24022,24023,24050],{},[1039,24024,24025,24027,24029,24031,24048],{},[1046,24026,1049],{"fence":1066},[1051,24028,1053],{},[1046,24030,17698],{},[2327,24032,24033,24036],{},[1042,24034,24035],{},"e",[1039,24037,24038,24040,24042,24044,24046],{},[1046,24039,17698],{},[1042,24041,4022],{},[1042,24043,1262],{},[1042,24045,2461],{"mathvariant":2460},[1042,24047,15437],{},[1046,24049,1056],{"fence":1066},[1042,24051,4022],{},[1058,24053,24054],{"encoding":1060},"p \\approx \\left(1 - e^{-kn\u002Fm}\\right)^k",[1023,24056,24058,24077],{"className":24057,"ariaHidden":1066},[1065],[1023,24059,24061,24065,24068,24071,24074],{"className":24060},[1070],[1023,24062],{"className":24063,"style":24064},[1074],"height:0.6776em;vertical-align:-0.1944em;",[1023,24066,973],{"className":24067},[1079,1080],[1023,24069],{"className":24070,"style":2355},[2354],[1023,24072,24020],{"className":24073},[2359],[1023,24075],{"className":24076,"style":2355},[2354],[1023,24078,24080,24084],{"className":24079},[1070],[1023,24081],{"className":24082,"style":24083},[1074],"height:1.477em;vertical-align:-0.35em;",[1023,24085,24088,24164],{"className":24086},[24087],"minner",[1023,24089,24091,24101,24104,24107,24110,24113,24158],{"className":24090},[24087],[1023,24092,24096],{"className":24093,"style":24095},[1085,24094],"delimcenter","top:0em;",[1023,24097,1049],{"className":24098},[24099,24100],"delimsizing","size1",[1023,24102,1053],{"className":24103},[1079],[1023,24105],{"className":24106,"style":13790},[2354],[1023,24108,17698],{"className":24109},[13794],[1023,24111],{"className":24112,"style":13790},[2354],[1023,24114,24116,24119],{"className":24115},[1079],[1023,24117,24035],{"className":24118},[1079,1080],[1023,24120,24122],{"className":24121},[2383],[1023,24123,24125],{"className":24124},[2387],[1023,24126,24128],{"className":24127},[2391],[1023,24129,24132],{"className":24130,"style":24131},[2395],"height:0.888em;",[1023,24133,24134,24137],{"style":2398},[1023,24135],{"className":24136,"style":2403},[2402],[1023,24138,24140],{"className":24139},[2407,2408,2409,2410],[1023,24141,24143,24146,24149,24152,24155],{"className":24142},[1079,2410],[1023,24144,17698],{"className":24145},[1079,2410],[1023,24147,4022],{"className":24148,"style":4066},[1079,1080,2410],[1023,24150,1262],{"className":24151},[1079,1080,2410],[1023,24153,2461],{"className":24154},[1079,2410],[1023,24156,15437],{"className":24157},[1079,1080,2410],[1023,24159,24161],{"className":24160,"style":24095},[1092,24094],[1023,24162,1056],{"className":24163},[24099,24100],[1023,24165,24167],{"className":24166},[2383],[1023,24168,24170],{"className":24169},[2387],[1023,24171,24173],{"className":24172},[2391],[1023,24174,24177],{"className":24175,"style":24176},[2395],"height:1.127em;",[1023,24178,24180,24183],{"style":24179},"top:-3.3409em;margin-right:0.05em;",[1023,24181],{"className":24182,"style":2403},[2402],[1023,24184,24186],{"className":24185},[2407,2408,2409,2410],[1023,24187,4022],{"className":24188,"style":4066},[1079,1080,2410],[1352,24190,24193],{"className":24191,"code":24192,"language":2241,"meta":1357},[2239],"m        k    thực_tế    lý_thuyết\n50000    1    ...        0.181\n50000    3    ...        ...\n100000   7    ...        0.008\n",[992,24194,24192],{"__ignoreMap":1357},[973,24196,24197,24198,15881,24201,1509,24204,24207,24208,15944,24211,24213,24214,1517],{},"Viết hàm ",[992,24199,24200],{},"optimalParams(n, p)",[992,24202,24203],{},"m = -n ln p \u002F (ln 2)^2",[992,24205,24206],{},"k = (m\u002Fn) ln 2",". Kiểm tra với ",[992,24209,24210],{},"n = 10^6, p = 0.01",[992,24212,15437],{}," khoảng 9,6 triệu bit, ",[992,24215,24216],{},"k = 7",[981,24218,24220],{"id":24219},"bài-3-lọc-trước-khi-hỏi-kho-chậm-nâng-cao","Bài 3: Lọc trước khi hỏi kho chậm (nâng cao)",[973,24222,24223,24224,5059,24227,24229],{},"Giả lập kho dữ liệu chậm: ",[992,24225,24226],{},"SlowDB::exists(email)",[992,24228,16417],{}," 1 ms.",[2273,24231,24232,24245,24251],{},[989,24233,24234,24235,24238,24239,24241,24242,1517],{},"Hàm ",[992,24236,24237],{},"checkEmail(email)",": hỏi Bloom trước. Bloom nói \"không\" thì trả ",[992,24240,1048],{}," ngay. Nói \"có\" thì hỏi ",[992,24243,24244],{},"SlowDB",[989,24246,24247,24248,24250],{},"Chạy 10.000 truy vấn, 90% là email không có. In số lần gọi ",[992,24249,24244],{}," và tổng thời gian, có và không có Bloom.",[989,24252,1505,24253,24256,24257,24260,24261,15881,24264,24266],{},[992,24254,24255],{},"CountingBloom"," dùng bộ đếm 4 bit thay cho 1 bit, hỗ trợ ",[992,24258,24259],{},"remove",". Test: thêm rồi xóa thì ",[992,24262,24263],{},"mightContain",[992,24265,1048],{}," (nếu không đụng phần tử khác).",[981,24268,2711],{"id":2710},[986,24270,24272,24278,24284,24290],{"className":24271},[2715],[989,24273,24275,24277],{"className":24274},[2719],[2721,24276],{"disabled":2723,"type":2724}," Không bao giờ có âm tính giả (test 10.000 phần tử đã thêm).",[989,24279,24281,24283],{"className":24280},[2719],[2721,24282],{"disabled":2723,"type":2724}," Bảng Bài 2 có số thật lệch lý thuyết không quá vài phần trăm.",[989,24285,24287,24289],{"className":24286},[2719],[2721,24288],{"disabled":2723,"type":2724}," Bài 3 cho thấy số lần gọi kho chậm giảm rõ rệt.",[989,24291,24293,24295],{"className":24292},[2719],[2721,24294],{"disabled":2723,"type":2724}," Giải thích được vì sao Bloom filter thường không xóa được phần tử.",[968,24297,2890],{"id":2889},[986,24299,24300,24303,24306,24309],{},[989,24301,24302],{},"Bloom filter dùng để hỏi gì?",[989,24304,24305],{},"Lưu và hỏi làm mấy bước băm?",[989,24307,24308],{},"Báo không và báo có bên nào chắc chắn?",[989,24310,24311],{},"Muốn chính xác hơn thì chỉnh gì?",[3014,24313],{},[973,24315,24316],{},"🌕 Bạn đã hoàn thành ngày 30. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,24318,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":24320},[24321,24322,24328,24329,24335],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":24323},[24324,24325,24326,24327],{"id":23667,"depth":73,"text":23668},{"id":23685,"depth":73,"text":23686},{"id":23706,"depth":73,"text":23707},{"id":23773,"depth":73,"text":23774},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":24330},[24331,24332,24333,24334],{"id":23914,"depth":73,"text":23915},{"id":23989,"depth":73,"text":23990},{"id":24219,"depth":73,"text":24220},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu bộ lọc Bloom qua bài toán danh bạ, cơ chế mảng bit và k hàm băm, công thức dương tính giả và các biến thể.",{},[3050,18469],{"title":205,"description":24336},[24341],"bloom-filter","vq0T7KXKGkdNjXIleBMKm9-66eXwY8hD4Bn0bkPiPso",{"id":24344,"title":210,"body":24345,"category":5189,"day":213,"description":24843,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":24844,"navigation":2723,"outcomes":3047,"path":211,"prerequisites":24845,"seo":24846,"stem":212,"tags":24847,"__hash__":24851},"challenges\u002Fchallenges\u002F31.facade-pattern.md",{"type":965,"value":24346,"toc":24827},[24347,24349,24352,24354,24358,24372,24376,24397,24437,24441,24458,24507,24509,24528,24530,24542,24546,24658,24691,24697,24705,24709,24712,24727,24734,24738,24754,24759,24772,24775,24777,24804,24806,24820,24822,24825],[968,24348,971],{"id":970},[973,24350,24351],{},"Bài này học Facade gom hệ phức tạp thành nút bấm đơn giản.\nMặt tiền này giúp dùng rạp hát tại gia dễ dàng.",[968,24353,979],{"id":978},[981,24355,24357],{"id":24356},"facade-là-gì","Facade là gì",[986,24359,24360,24363,24366,24369],{},[989,24361,24362],{},"Facade là lớp mặt tiền đơn giản trước hệ con phức tạp.",[989,24364,24365],{},"Người dùng gọi mặt tiền thay vì gọi từng thiết bị.",[989,24367,24368],{},"Ví dụ đời thường: điều khiển tivi có một nút xem phim.",[989,24370,24371],{},"Dùng khi nhiều bước phải chạy đúng thứ tự.",[981,24373,24375],{"id":24374},"rạp-hát-hai-nút-bấm","Rạp hát hai nút bấm",[986,24377,24378,24381,24388,24394],{},[989,24379,24380],{},"Xem phim phải bật 6 thiết bị theo đúng thứ tự.",[989,24382,24383,24384,24387],{},"Nút ",[992,24385,24386],{},"xemPhim()"," chạy đủ 10 bước nhỏ tự động.",[989,24389,24383,24390,24393],{},[992,24391,24392],{},"ketThuc()"," tắt ngược lại cho an toàn.",[989,24395,24396],{},"Ví dụ đời thường: bấm một nút là đèn tắt, phim chạy.",[1352,24398,24400],{"className":3538,"code":24399,"language":3540,"meta":1357,"style":1357},"# Mặt tiền gom nhiều bước thành 1 nút\nclass HomeTheater:\n    def xem_phim(self):\n        self.bap_nuoc()  # bước 1: bật máy bắp\n        self.ha_den()    # bước 2: hạ đèn\n        self.bat_may_chieu()  # bước 3: bật máy chiếu\n        self.bat_phim()  # bước 4: chạy phim\n",[992,24401,24402,24407,24412,24417,24422,24427,24432],{"__ignoreMap":1357},[1023,24403,24404],{"class":1362,"line":63},[1023,24405,24406],{},"# Mặt tiền gom nhiều bước thành 1 nút\n",[1023,24408,24409],{"class":1362,"line":68},[1023,24410,24411],{},"class HomeTheater:\n",[1023,24413,24414],{"class":1362,"line":73},[1023,24415,24416],{},"    def xem_phim(self):\n",[1023,24418,24419],{"class":1362,"line":78},[1023,24420,24421],{},"        self.bap_nuoc()  # bước 1: bật máy bắp\n",[1023,24423,24424],{"class":1362,"line":83},[1023,24425,24426],{},"        self.ha_den()    # bước 2: hạ đèn\n",[1023,24428,24429],{"class":1362,"line":88},[1023,24430,24431],{},"        self.bat_may_chieu()  # bước 3: bật máy chiếu\n",[1023,24433,24434],{"class":1362,"line":93},[1023,24435,24436],{},"        self.bat_phim()  # bước 4: chạy phim\n",[981,24438,24440],{"id":24439},"least-knowledge-nói-với-bạn-thân","Least Knowledge nói với bạn thân",[986,24442,24443,24446,24452,24455],{},[989,24444,24445],{},"Chỉ gọi đối tượng mình giữ trực tiếp.",[989,24447,24448,24449,1517],{},"Không gọi dây chuyền kiểu ",[992,24450,24451],{},"a.b.c.bat()",[989,24453,24454],{},"Ví dụ đời thường: nhờ lễ tân, không tự vào kho.",[989,24456,24457],{},"Chuỗi gọi dài làm đổi một chỗ vỡ cả chuỗi.",[1099,24459,24460,24473],{},[1102,24461,24462],{},[1105,24463,24464,24467,24470],{},[1108,24465,24466],{},"Khía cạnh",[1108,24468,24469],{},"Adapter",[1108,24471,24472],{},"Facade",[1118,24474,24475,24486,24497],{},[1105,24476,24477,24480,24483],{},[1123,24478,24479],{},"Mục đích",[1123,24481,24482],{},"Dịch 1 giao diện",[1123,24484,24485],{},"Gom cả hệ con",[1105,24487,24488,24491,24494],{},[1123,24489,24490],{},"Giao diện cũ",[1123,24492,24493],{},"Ẩn đi",[1123,24495,24496],{},"Vẫn mở cho ai cần",[1105,24498,24499,24501,24504],{},[1123,24500,14145],{},[1123,24502,24503],{},"Thường 1 bước",[1123,24505,24506],{},"Nhiều bước đúng thứ tự",[968,24508,1433],{"id":1432},[986,24510,24511,24517,24520,24525],{},[989,24512,24513,24514,24516],{},"Input: bấm ",[992,24515,24386],{}," khi mọi máy đang tắt -> Output: phim chạy, đèn hạ, máy chiếu bật.",[989,24518,24519],{},"Câu này chứng minh mười bước gom thành một nút.",[989,24521,24513,24522,24524],{},[992,24523,24392],{}," sau khi xem -> Output: mọi máy tắt theo thứ tự ngược.",[989,24526,24527],{},"Câu này chứng minh tắt máy cũng an toàn và gọn.",[968,24529,1482],{"id":1481},[973,24531,1485,24532,4801,24534,24537,24538,24541],{},[1487,24533,4800],{},[992,24535,24536],{},"day-031\u002F",". Mỗi thiết bị ghi hành động vào một ",[992,24539,24540],{},"std::vector\u003Cstd::string> &log"," chung để test thứ tự.",[981,24543,24545],{"id":24544},"bài-1-home-theater-facade","Bài 1: Home Theater Facade",[1099,24547,24548,24557],{},[1102,24549,24550],{},[1105,24551,24552,24555],{},[1108,24553,24554],{},"Thiết bị",[1108,24556,1566],{},[1118,24558,24559,24580,24599,24615,24628,24642],{},[1105,24560,24561,24566],{},[1123,24562,24563],{},[992,24564,24565],{},"Amplifier",[1123,24567,24568,1656,24570,1656,24572,1656,24575,1656,24578],{},[992,24569,22855],{},[992,24571,22858],{},[992,24573,24574],{},"setStreamingPlayer(StreamingPlayer&)",[992,24576,24577],{},"setSurroundSound()",[992,24579,22880],{},[1105,24581,24582,24587],{},[1123,24583,24584],{},[992,24585,24586],{},"StreamingPlayer",[1123,24588,24589,1656,24591,1656,24593,1656,24596],{},[992,24590,22855],{},[992,24592,22858],{},[992,24594,24595],{},"play(movie)",[992,24597,24598],{},"stop()",[1105,24600,24601,24606],{},[1123,24602,24603],{},[992,24604,24605],{},"Projector",[1123,24607,24608,1656,24610,1656,24612],{},[992,24609,22855],{},[992,24611,22858],{},[992,24613,24614],{},"wideScreenMode()",[1105,24616,24617,24622],{},[1123,24618,24619],{},[992,24620,24621],{},"Screen",[1123,24623,24624,1656,24626],{},[992,24625,22895],{},[992,24627,22892],{},[1105,24629,24630,24635],{},[1123,24631,24632],{},[992,24633,24634],{},"TheaterLights",[1123,24636,24637,1656,24639],{},[992,24638,22855],{},[992,24640,24641],{},"dim(int percent)",[1105,24643,24644,24649],{},[1123,24645,24646],{},[992,24647,24648],{},"PopcornPopper",[1123,24650,24651,1656,24653,1656,24655],{},[992,24652,22855],{},[992,24654,22858],{},[992,24656,24657],{},"pop()",[1352,24659,24661],{"className":1393,"code":24660,"language":1395,"meta":1357,"style":1357},"class HomeTheaterFacade {\n public:\n  HomeTheaterFacade(Amplifier&, StreamingPlayer&, Projector&, Screen&, TheaterLights&, PopcornPopper&);\n  void watchMovie(const std::string &movie);  \u002F\u002F đủ các bước theo đúng thứ tự log bên dưới\n  void endMovie();                            \u002F\u002F tắt ngược lại\n};\n",[992,24662,24663,24668,24672,24677,24682,24687],{"__ignoreMap":1357},[1023,24664,24665],{"class":1362,"line":63},[1023,24666,24667],{},"class HomeTheaterFacade {\n",[1023,24669,24670],{"class":1362,"line":68},[1023,24671,4836],{},[1023,24673,24674],{"class":1362,"line":73},[1023,24675,24676],{},"  HomeTheaterFacade(Amplifier&, StreamingPlayer&, Projector&, Screen&, TheaterLights&, PopcornPopper&);\n",[1023,24678,24679],{"class":1362,"line":78},[1023,24680,24681],{},"  void watchMovie(const std::string &movie);  \u002F\u002F đủ các bước theo đúng thứ tự log bên dưới\n",[1023,24683,24684],{"class":1362,"line":83},[1023,24685,24686],{},"  void endMovie();                            \u002F\u002F tắt ngược lại\n",[1023,24688,24689],{"class":1362,"line":88},[1023,24690,4866],{},[1352,24692,24695],{"className":24693,"code":24694,"language":2241,"meta":1357},[2239],"watchMovie(\"Dune\") -> log:\npopper.on, popper.pop, lights.dim(10), screen.down, projector.on,\nprojector.wideScreenMode, amp.on, amp.setStreamingPlayer, amp.setSurroundSound, amp.setVolume(5),\nplayer.on, player.play(Dune)\nendMovie() -> popper.off, lights.on, screen.up, projector.off, amp.off, player.stop, player.off\n",[992,24696,24694],{"__ignoreMap":1357},[973,24698,24699,16792,24701,24704],{},[1487,24700,6076],{},[992,24702,24703],{},"watchMovie"," 2 lần liên tiếp không bật lại thiết bị đang bật (Facade nhớ trạng thái).",[981,24706,24708],{"id":24707},"bài-2-sửa-vi-phạm-least-knowledge","Bài 2: Sửa vi phạm Least Knowledge",[973,24710,24711],{},"Code sau vi phạm nguyên lý:",[1352,24713,24715],{"className":1393,"code":24714,"language":1395,"meta":1357,"style":1357},"double Station::temperature() { return thermometer.getSensor().getReading().celsius(); }\nstd::string Order::customerCity() { return customer.getAddress().getCity().getName(); }\n",[992,24716,24717,24722],{"__ignoreMap":1357},[1023,24718,24719],{"class":1362,"line":63},[1023,24720,24721],{},"double Station::temperature() { return thermometer.getSensor().getReading().celsius(); }\n",[1023,24723,24724],{"class":1362,"line":68},[1023,24725,24726],{},"std::string Order::customerCity() { return customer.getAddress().getCity().getName(); }\n",[973,24728,24729,24730,24733],{},"Viết lại để mỗi hàm chỉ gọi \"bạn thân\". Viết 2 câu cho mỗi hàm: nếu lớp ",[992,24731,24732],{},"Reading"," đổi thì bản cũ vỡ ở đâu, bản mới vỡ ở đâu.",[981,24735,24737],{"id":24736},"bài-3-facade-cho-thư-viện-phức-tạp-nâng-cao","Bài 3: Facade cho thư viện phức tạp (nâng cao)",[973,24739,24740,24741,1656,24744,1656,24747,1656,24750,24753],{},"Giả lập hệ đặt vé với 4 lớp: ",[992,24742,24743],{},"SeatService",[992,24745,24746],{},"PaymentGateway",[992,24748,24749],{},"EmailService",[992,24751,24752],{},"LoyaltyService",". Đặt vé cần: giữ ghế, thanh toán, cộng điểm, gửi email.",[973,24755,1505,24756,4437],{},[992,24757,24758],{},"BookingFacade::book(userId, showId, seatCount)",[986,24760,24761,24764,24767],{},[989,24762,24763],{},"Thanh toán lỗi: nhả ghế đã giữ, không cộng điểm, không gửi email.",[989,24765,24766],{},"Gửi email lỗi: vé vẫn hợp lệ, ghi cảnh báo.",[989,24768,6693,24769,1517],{},[992,24770,24771],{},"BookingResult { bool ok; std::string reason; }",[973,24773,24774],{},"Viết 3 test cho 3 kịch bản: thành công, thanh toán lỗi, email lỗi.",[981,24776,2711],{"id":2710},[986,24778,24780,24786,24792,24798],{"className":24779},[2715],[989,24781,24783,24785],{"className":24782},[2719],[2721,24784],{"disabled":2723,"type":2724}," Test thứ tự log của Bài 1 pass.",[989,24787,24789,24791],{"className":24788},[2719],[2721,24790],{"disabled":2723,"type":2724}," Client vẫn gọi thẳng được từng thiết bị nếu cần (Facade không khóa hệ con).",[989,24793,24795,24797],{"className":24794},[2719],[2721,24796],{"disabled":2723,"type":2724}," Bài 3 có 3 test, thanh toán lỗi thì ghế được nhả.",[989,24799,24801,24803],{"className":24800},[2719],[2721,24802],{"disabled":2723,"type":2724}," Phân biệt được Facade, Adapter, Decorator bằng một câu mỗi pattern.",[968,24805,2890],{"id":2889},[986,24807,24808,24811,24814,24817],{},[989,24809,24810],{},"Facade là gì và mặt tiền giúp gì?",[989,24812,24813],{},"Nút xem phim gom những bước nào?",[989,24815,24816],{},"Least Knowledge cấm kiểu gọi nào?",[989,24818,24819],{},"Khi nào không nên dùng Facade?",[3014,24821],{},[973,24823,24824],{},"🌕 Bạn đã hoàn thành ngày 31. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,24826,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":24828},[24829,24830,24835,24836,24842],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":24831},[24832,24833,24834],{"id":24356,"depth":73,"text":24357},{"id":24374,"depth":73,"text":24375},{"id":24439,"depth":73,"text":24440},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":24837},[24838,24839,24840,24841],{"id":24544,"depth":73,"text":24545},{"id":24707,"depth":73,"text":24708},{"id":24736,"depth":73,"text":24737},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Facade, quy trình xem phim mười bước gom thành một nút, và nguyên lý chỉ nói chuyện với bạn thân.",{},[5194,5195],{"title":210,"description":24843},[24848,24849,24850],"facade","home-theater","least-knowledge","Ul5jJKy6pCuj1bO8a1uxbzL4cghMDohP7u0nZs8XFW4",{"id":24853,"title":215,"body":24854,"category":3041,"day":218,"description":25475,"difficulty":5191,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":25476,"navigation":2723,"outcomes":3047,"path":216,"prerequisites":25477,"seo":25478,"stem":217,"tags":25479,"__hash__":25481},"challenges\u002Fchallenges\u002F32.disjoint-set-co-ban.md",{"type":965,"value":24855,"toc":25459},[24856,24858,24861,24863,24867,24881,24885,24908,24912,25018,25078,25080,25097,25099,25109,25113,25156,25162,25166,25187,25201,25205,25216,25388,25394,25396,25436,25438,25452,25454,25457],[968,24857,971],{"id":970},[973,24859,24860],{},"Bài này học disjoint set để gom nhóm và hỏi cùng nhóm.\nCấu trúc này giúp gộp cộng đồng nhanh và gọn.",[968,24862,979],{"id":978},[981,24864,24866],{"id":24865},"bài-toán-gom-nhóm","Bài toán gom nhóm",[986,24868,24869,24872,24875,24878],{},[989,24870,24871],{},"Mỗi phần tử thuộc đúng một nhóm tại mỗi thời điểm.",[989,24873,24874],{},"Cần hỏi hai người có cùng nhóm không.",[989,24876,24877],{},"Cần gộp hai nhóm thành một khi kết bạn.",[989,24879,24880],{},"Ví dụ đời thường: gộp hai nhóm chat thành một nhóm.",[981,24882,24884],{"id":24883},"api-ba-thao-tác","API ba thao tác",[986,24886,24887,24893,24899,24905],{},[989,24888,24889,24892],{},[992,24890,24891],{},"makeSet(x)",": tạo nhóm riêng chỉ chứa x.",[989,24894,24895,24898],{},[992,24896,24897],{},"find(x)",": trả về đại diện nhóm của x.",[989,24900,24901,24904],{},[992,24902,24903],{},"union(a, b)",": gộp nhóm của a và b.",[989,24906,24907],{},"Ví dụ đời thường: hỏi cùng lớp, rồi chuyển hai bạn về chung lớp.",[981,24909,24911],{"id":24910},"cài-đặt-ngây-thơ","Cài đặt ngây thơ",[986,24913,24914,24917,24966,25015],{},[989,24915,24916],{},"Mỗi phần tử lưu trực tiếp id nhóm trong dict.",[989,24918,24919,24922,24923,1517],{},[992,24920,24921],{},"find"," chỉ đọc dict nên rất nhanh ",[1023,24924,24926,24945],{"className":24925},[1026],[1023,24927,24929],{"className":24928},[1030],[1032,24930,24931],{"xmlns":1034},[1036,24932,24933,24943],{},[1039,24934,24935,24937,24939,24941],{},[1042,24936,1044],{},[1046,24938,1049],{"stretchy":1048},[1051,24940,1053],{},[1046,24942,1056],{"stretchy":1048},[1058,24944,1061],{"encoding":1060},[1023,24946,24948],{"className":24947,"ariaHidden":1066},[1065],[1023,24949,24951,24954,24957,24960,24963],{"className":24950},[1070],[1023,24952],{"className":24953,"style":1075},[1074],[1023,24955,1044],{"className":24956,"style":1081},[1079,1080],[1023,24958,1049],{"className":24959},[1085],[1023,24961,1053],{"className":24962},[1079],[1023,24964,1056],{"className":24965},[1092],[989,24967,24968,24971,24972,1517],{},[992,24969,24970],{},"union"," phải duyệt viết lại id cả nhóm nên ",[1023,24973,24975,24994],{"className":24974},[1026],[1023,24976,24978],{"className":24977},[1030],[1032,24979,24980],{"xmlns":1034},[1036,24981,24982,24992],{},[1039,24983,24984,24986,24988,24990],{},[1042,24985,1044],{},[1046,24987,1049],{"stretchy":1048},[1042,24989,1262],{},[1046,24991,1056],{"stretchy":1048},[1058,24993,1267],{"encoding":1060},[1023,24995,24997],{"className":24996,"ariaHidden":1066},[1065],[1023,24998,25000,25003,25006,25009,25012],{"className":24999},[1070],[1023,25001],{"className":25002,"style":1075},[1074],[1023,25004,1044],{"className":25005,"style":1081},[1079,1080],[1023,25007,1049],{"className":25008},[1085],[1023,25010,1262],{"className":25011},[1079,1080],[1023,25013,1056],{"className":25014},[1092],[989,25016,25017],{},"Ví dụ đời thường: đổi tên lớp phải sửa thẻ từng học sinh.",[1352,25019,25021],{"className":3538,"code":25020,"language":3540,"meta":1357,"style":1357},"# Cài đặt ngây thơ: find nhanh, union chậm\nparent = {}  # mỗi người -> id nhóm\ndef find(x):\n    return parent[x]  # đọc trực tiếp\ndef union(a, b):\n    ida, idb = parent[a], parent[b]  # lấy 2 id\n    if ida == idb: return False  # đã cùng nhóm\n    for k in parent:  # duyệt hết để viết lại\n        if parent[k] == idb:\n            parent[k] = ida\n    return True\n",[992,25022,25023,25028,25033,25038,25043,25048,25053,25058,25063,25068,25073],{"__ignoreMap":1357},[1023,25024,25025],{"class":1362,"line":63},[1023,25026,25027],{},"# Cài đặt ngây thơ: find nhanh, union chậm\n",[1023,25029,25030],{"class":1362,"line":68},[1023,25031,25032],{},"parent = {}  # mỗi người -> id nhóm\n",[1023,25034,25035],{"class":1362,"line":73},[1023,25036,25037],{},"def find(x):\n",[1023,25039,25040],{"class":1362,"line":78},[1023,25041,25042],{},"    return parent[x]  # đọc trực tiếp\n",[1023,25044,25045],{"class":1362,"line":83},[1023,25046,25047],{},"def union(a, b):\n",[1023,25049,25050],{"class":1362,"line":88},[1023,25051,25052],{},"    ida, idb = parent[a], parent[b]  # lấy 2 id\n",[1023,25054,25055],{"class":1362,"line":93},[1023,25056,25057],{},"    if ida == idb: return False  # đã cùng nhóm\n",[1023,25059,25060],{"class":1362,"line":98},[1023,25061,25062],{},"    for k in parent:  # duyệt hết để viết lại\n",[1023,25064,25065],{"class":1362,"line":103},[1023,25066,25067],{},"        if parent[k] == idb:\n",[1023,25069,25070],{"class":1362,"line":108},[1023,25071,25072],{},"            parent[k] = ida\n",[1023,25074,25075],{"class":1362,"line":113},[1023,25076,25077],{},"    return True\n",[968,25079,1433],{"id":1432},[986,25081,25082,25085,25088,25094],{},[989,25083,25084],{},"Input: 5 người riêng lẻ, hỏi 1 và 2 -> Output: khác nhóm.",[989,25086,25087],{},"Câu này cho thấy lúc đầu ai cũng một mình.",[989,25089,9878,25090,25093],{},[992,25091,25092],{},"union(1,2)"," rồi hỏi 1 và 2 -> Output: cùng nhóm, trả True.",[989,25095,25096],{},"Câu này cho thấy gộp xong thì hỏi ra cùng nhóm.",[968,25098,1482],{"id":1481},[973,25100,1485,25101,5599,25103,25106,25107,1517],{},[1487,25102,1493],{},[992,25104,25105],{},"day-032\u002F",". Phần tử là số nguyên ",[992,25108,20260],{},[981,25110,25112],{"id":25111},"bài-1-disjoint-set-ngây-thơ-quick-find","Bài 1: Disjoint set ngây thơ (quick-find)",[1352,25114,25116],{"className":1393,"code":25115,"language":1395,"meta":1357,"style":1357},"class QuickFind {\n public:\n  explicit QuickFind(int n);           \u002F\u002F makeSet cho 0..n-1\n  int  find(int x) const;              \u002F\u002F O(1)\n  bool unite(int a, int b);            \u002F\u002F O(n), trả false nếu đã cùng nhóm\n  bool connected(int a, int b) const;\n  int  count() const;                  \u002F\u002F số nhóm hiện tại\n};\n",[992,25117,25118,25123,25127,25132,25137,25142,25147,25152],{"__ignoreMap":1357},[1023,25119,25120],{"class":1362,"line":63},[1023,25121,25122],{},"class QuickFind {\n",[1023,25124,25125],{"class":1362,"line":68},[1023,25126,4836],{},[1023,25128,25129],{"class":1362,"line":73},[1023,25130,25131],{},"  explicit QuickFind(int n);           \u002F\u002F makeSet cho 0..n-1\n",[1023,25133,25134],{"class":1362,"line":78},[1023,25135,25136],{},"  int  find(int x) const;              \u002F\u002F O(1)\n",[1023,25138,25139],{"class":1362,"line":83},[1023,25140,25141],{},"  bool unite(int a, int b);            \u002F\u002F O(n), trả false nếu đã cùng nhóm\n",[1023,25143,25144],{"class":1362,"line":88},[1023,25145,25146],{},"  bool connected(int a, int b) const;\n",[1023,25148,25149],{"class":1362,"line":93},[1023,25150,25151],{},"  int  count() const;                  \u002F\u002F số nhóm hiện tại\n",[1023,25153,25154],{"class":1362,"line":98},[1023,25155,4866],{},[1352,25157,25160],{"className":25158,"code":25159,"language":2241,"meta":1357},[2239],"n=5                           -> count = 5, connected(1,2) = false\nunite(1,2); unite(3,4)        -> count = 3\nunite(2,1)                    -> false (đã cùng nhóm)\nunite(1,4)                    -> connected(2,3) = true, count = 2\nfind(9)                       -> ném out_of_range\n",[992,25161,25159],{"__ignoreMap":1357},[981,25163,25165],{"id":25164},"bài-2-quick-union-không-tối-ưu","Bài 2: Quick-union không tối ưu",[973,25167,1505,25168,25171,25172,1838,25175,25177,25178,25181,25182,25184,25185,1517],{},[992,25169,25170],{},"QuickUnion"," lưu mảng ",[992,25173,25174],{},"parent",[992,25176,24921],{}," đi lên tới gốc. ",[992,25179,25180],{},"unite"," nối gốc của ",[992,25183,6207],{}," vào gốc của ",[992,25186,17703],{},[973,25188,25189,25190,25193,25194,25197,25198,25200],{},"Tạo dãy thao tác xấu: ",[992,25191,25192],{},"unite(0,1), unite(1,2), ..., unite(n-2, n-1)"," rồi gọi ",[992,25195,25196],{},"find(0)",". Đếm số bước ",[992,25199,24921],{}," đi. In độ cao cây.",[981,25202,25204],{"id":25203},"bài-3-bài-toán-mạng-bạn-bè-nâng-cao","Bài 3: Bài toán mạng bạn bè (nâng cao)",[973,25206,25207,25208,25211,25212,25215],{},"Đọc file ",[992,25209,25210],{},"friends.txt",", mỗi dòng ",[992,25213,25214],{},"a b"," là quan hệ bạn bè:",[2273,25217,25218,25221,25224,25230],{},[989,25219,25220],{},"In số nhóm bạn bè (thành phần liên thông).",[989,25222,25223],{},"In kích thước nhóm lớn nhất.",[989,25225,25226,25227,25229],{},"Trả lời truy vấn ",[992,25228,25214],{},": có cùng nhóm không.",[989,25231,25232,25233,25318,25319,25381,25382,1509,25385,25387],{},"Sinh ",[1023,25234,25236,25259],{"className":25235},[1026],[1023,25237,25239],{"className":25238},[1030],[1032,25240,25241],{"xmlns":1034},[1036,25242,25243,25256],{},[1039,25244,25245,25247,25249],{},[1042,25246,1262],{},[1046,25248,2325],{},[2327,25250,25251,25253],{},[1051,25252,2331],{},[1051,25254,25255],{},"4",[1058,25257,25258],{"encoding":1060},"n = 10^4",[1023,25260,25262,25280],{"className":25261,"ariaHidden":1066},[1065],[1023,25263,25265,25268,25271,25274,25277],{"className":25264},[1070],[1023,25266],{"className":25267,"style":2347},[1074],[1023,25269,1262],{"className":25270},[1079,1080],[1023,25272],{"className":25273,"style":2355},[2354],[1023,25275,2325],{"className":25276},[2359],[1023,25278],{"className":25279,"style":2355},[2354],[1023,25281,25283,25286,25289],{"className":25282},[1070],[1023,25284],{"className":25285,"style":2369},[1074],[1023,25287,1053],{"className":25288},[1079],[1023,25290,25292,25295],{"className":25291},[1079],[1023,25293,2379],{"className":25294},[1079],[1023,25296,25298],{"className":25297},[2383],[1023,25299,25301],{"className":25300},[2387],[1023,25302,25304],{"className":25303},[2391],[1023,25305,25307],{"className":25306,"style":2369},[2395],[1023,25308,25309,25312],{"style":2398},[1023,25310],{"className":25311,"style":2403},[2402],[1023,25313,25315],{"className":25314},[2407,2408,2409,2410],[1023,25316,25255],{"className":25317},[1079,2410]," người, ",[1023,25320,25322,25340],{"className":25321},[1026],[1023,25323,25325],{"className":25324},[1030],[1032,25326,25327],{"xmlns":1034},[1036,25328,25329,25337],{},[1039,25330,25331],{},[2327,25332,25333,25335],{},[1051,25334,2331],{},[1051,25336,25255],{},[1058,25338,25339],{"encoding":1060},"10^4",[1023,25341,25343],{"className":25342,"ariaHidden":1066},[1065],[1023,25344,25346,25349,25352],{"className":25345},[1070],[1023,25347],{"className":25348,"style":2369},[1074],[1023,25350,1053],{"className":25351},[1079],[1023,25353,25355,25358],{"className":25354},[1079],[1023,25356,2379],{"className":25357},[1079],[1023,25359,25361],{"className":25360},[2383],[1023,25362,25364],{"className":25363},[2387],[1023,25365,25367],{"className":25366},[2391],[1023,25368,25370],{"className":25369,"style":2369},[2395],[1023,25371,25372,25375],{"style":2398},[1023,25373],{"className":25374,"style":2403},[2402],[1023,25376,25378],{"className":25377},[2407,2408,2409,2410],[1023,25379,25255],{"className":25380},[1079,2410]," cạnh ngẫu nhiên. Đo thời gian ",[992,25383,25384],{},"QuickFind",[992,25386,25170],{},". Ghi kết quả để so với bản tối ưu ngày 33.",[1352,25389,25392],{"className":25390,"code":25391,"language":2241,"meta":1357},[2239],"friends: 0-1, 1-2, 3-4\n-> 3 nhóm với n=6 ({0,1,2}, {3,4}, {5}), nhóm lớn nhất 3\n",[992,25393,25391],{"__ignoreMap":1357},[981,25395,2711],{"id":2710},[986,25397,25399,25409,25419,25425],{"className":25398},[2715],[989,25400,25402,25404,25405,1509,25407,1517],{"className":25401},[2719],[2721,25403],{"disabled":2723,"type":2724}," Test mẫu pass cho cả ",[992,25406,25384],{},[992,25408,25170],{},[989,25410,25412,25414,25415,25418],{"className":25411},[2719],[2721,25413],{"disabled":2723,"type":2724}," Bài 2 cho thấy độ cao cây bằng ",[992,25416,25417],{},"n - 1"," với dãy xấu.",[989,25420,25422,25424],{"className":25421},[2719],[2721,25423],{"disabled":2723,"type":2724}," Bảng thời gian Bài 3 có số thật.",[989,25426,25428,25430,25431,1509,25433,25435],{"className":25427},[2719],[2721,25429],{"disabled":2723,"type":2724}," Nêu được độ phức tạp ",[992,25432,24921],{},[992,25434,25180],{}," của 2 cách cài.",[968,25437,2890],{"id":2889},[986,25439,25440,25443,25446,25449],{},[989,25441,25442],{},"Bài toán gom nhóm cần hỏi gì và gộp gì?",[989,25444,25445],{},"API disjoint set gồm 3 thao tác nào?",[989,25447,25448],{},"Vì sao cài đặt ngây thơ gộp rất chậm?",[989,25450,25451],{},"Khi nào hai phần tử được coi cùng nhóm?",[3014,25453],{},[973,25455,25456],{},"🌕 Bạn đã hoàn thành ngày 32. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,25458,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":25460},[25461,25462,25467,25468,25474],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":25463},[25464,25465,25466],{"id":24865,"depth":73,"text":24866},{"id":24883,"depth":73,"text":24884},{"id":24910,"depth":73,"text":24911},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":25469},[25470,25471,25472,25473],{"id":25111,"depth":73,"text":25112},{"id":25164,"depth":73,"text":25165},{"id":25203,"depth":73,"text":25204},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Làm quen tập rời nhau qua bài toán gom nhóm, hợp đồng API và cài đặt ngây thơ làm mốc so sánh.",{},[3050,4669],{"title":215,"description":25475},[25480],"disjoint-set","ECt9Gcos0brp2IzdZeAo6Z1fN1hXQSgi16g2Aml-A9E",{"id":25483,"title":220,"body":25484,"category":8797,"day":223,"description":26304,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":26305,"navigation":2723,"outcomes":3047,"path":221,"prerequisites":26306,"seo":26307,"stem":222,"tags":26308,"__hash__":26310},"challenges\u002Fchallenges\u002F33.union-find-va-kruskal.md",{"type":965,"value":25485,"toc":26288},[25486,25488,25491,25493,25497,25513,25517,25534,25616,25620,25634,25927,25929,25945,25947,25954,25958,26001,26013,26019,26026,26030,26045,26048,26054,26058,26164,26170,26172,26265,26267,26281,26283,26286],[968,25487,971],{"id":970},[973,25489,25490],{},"Bài này học Union-Find nhanh bằng cây và hai mẹo nén.\nMẹo này giúp Kruskal tìm đường nối rẻ nhất.",[968,25492,979],{"id":978},[981,25494,25496],{"id":25495},"từ-danh-sách-sang-cây","Từ danh sách sang cây",[986,25498,25499,25502,25505,25510],{},[989,25500,25501],{},"Mỗi nhóm là một cây, gốc cây là đại diện.",[989,25503,25504],{},"Mỗi nút chỉ giữ con trỏ tới cha của nó.",[989,25506,25507,25509],{},[992,25508,24970],{}," chỉ nối gốc này sang gốc kia.",[989,25511,25512],{},"Ví dụ đời thường: sáp nhập lớp chỉ cần đổi biển lớp trưởng.",[981,25514,25516],{"id":25515},"nén-đường-đi-và-hợp-theo-hạng","Nén đường đi và hợp theo hạng",[986,25518,25519,25525,25528,25531],{},[989,25520,25521,25522,25524],{},"Nén đường đi: lúc ",[992,25523,24921],{}," thì nối thẳng mọi nút về gốc.",[989,25526,25527],{},"Hợp theo hạng: cây nhỏ chui dưới gốc cây lớn.",[989,25529,25530],{},"Mỗi gốc giữ con số hạng để so lớn nhỏ.",[989,25532,25533],{},"Ví dụ đời thường: đường tắt mới mở thì lần sau đi nhanh.",[1352,25535,25537],{"className":3538,"code":25536,"language":3540,"meta":1357,"style":1357},"# Union-Find có nén đường đi + hợp theo hạng\ncha = {}  # nút -> cha\nhang = {}  # gốc -> hạng\ndef find(x):\n    if cha[x] != x:  # chưa tới gốc\n        cha[x] = find(cha[x])  # nối thẳng về gốc\n    return cha[x]\ndef union(a, b):\n    ra, rb = find(a), find(b)  # tìm 2 gốc\n    if ra == rb: return False  # đã cùng nhóm\n    if hang[ra] \u003C hang[rb]:  # cây nhỏ chui dưới\n        ra, rb = rb, ra\n    cha[rb] = ra  # nối gốc nhỏ vào gốc lớn\n    if hang[ra] == hang[rb]:  # bằng hạng thì gốc mới cao thêm 1\n        hang[ra] += 1\n    return True\n",[992,25538,25539,25544,25549,25554,25558,25563,25568,25573,25577,25582,25587,25592,25597,25602,25607,25612],{"__ignoreMap":1357},[1023,25540,25541],{"class":1362,"line":63},[1023,25542,25543],{},"# Union-Find có nén đường đi + hợp theo hạng\n",[1023,25545,25546],{"class":1362,"line":68},[1023,25547,25548],{},"cha = {}  # nút -> cha\n",[1023,25550,25551],{"class":1362,"line":73},[1023,25552,25553],{},"hang = {}  # gốc -> hạng\n",[1023,25555,25556],{"class":1362,"line":78},[1023,25557,25037],{},[1023,25559,25560],{"class":1362,"line":83},[1023,25561,25562],{},"    if cha[x] != x:  # chưa tới gốc\n",[1023,25564,25565],{"class":1362,"line":88},[1023,25566,25567],{},"        cha[x] = find(cha[x])  # nối thẳng về gốc\n",[1023,25569,25570],{"class":1362,"line":93},[1023,25571,25572],{},"    return cha[x]\n",[1023,25574,25575],{"class":1362,"line":98},[1023,25576,25047],{},[1023,25578,25579],{"class":1362,"line":103},[1023,25580,25581],{},"    ra, rb = find(a), find(b)  # tìm 2 gốc\n",[1023,25583,25584],{"class":1362,"line":108},[1023,25585,25586],{},"    if ra == rb: return False  # đã cùng nhóm\n",[1023,25588,25589],{"class":1362,"line":113},[1023,25590,25591],{},"    if hang[ra] \u003C hang[rb]:  # cây nhỏ chui dưới\n",[1023,25593,25594],{"class":1362,"line":118},[1023,25595,25596],{},"        ra, rb = rb, ra\n",[1023,25598,25599],{"class":1362,"line":123},[1023,25600,25601],{},"    cha[rb] = ra  # nối gốc nhỏ vào gốc lớn\n",[1023,25603,25604],{"class":1362,"line":128},[1023,25605,25606],{},"    if hang[ra] == hang[rb]:  # bằng hạng thì gốc mới cao thêm 1\n",[1023,25608,25609],{"class":1362,"line":133},[1023,25610,25611],{},"        hang[ra] += 1\n",[1023,25613,25614],{"class":1362,"line":138},[1023,25615,25077],{},[981,25617,25619],{"id":25618},"thuật-toán-kruskal","Thuật toán Kruskal",[986,25621,25622,25625,25628,25631],{},[989,25623,25624],{},"Sắp xếp mọi cạnh theo trọng số tăng dần.",[989,25626,25627],{},"Duyệt từng cạnh, chưa cùng nhóm thì nhận và gộp.",[989,25629,25630],{},"Cùng nhóm rồi thì bỏ qua để tránh chu trình.",[989,25632,25633],{},"Ví dụ đời thường: nối các trạm điện bằng ít dây nhất.",[1099,25635,25636,25648],{},[1102,25637,25638],{},[1105,25639,25640,25642,25645],{},[1108,25641,5414],{},[1108,25643,25644],{},"Ngây thơ",[1108,25646,25647],{},"Cây + 2 mẹo",[1118,25649,25650,25746,25843],{},[1105,25651,25652,25655,25700],{},[1123,25653,25654],{},"Tìm",[1123,25656,25657],{},[1023,25658,25660,25679],{"className":25659},[1026],[1023,25661,25663],{"className":25662},[1030],[1032,25664,25665],{"xmlns":1034},[1036,25666,25667,25677],{},[1039,25668,25669,25671,25673,25675],{},[1042,25670,1044],{},[1046,25672,1049],{"stretchy":1048},[1051,25674,1053],{},[1046,25676,1056],{"stretchy":1048},[1058,25678,1061],{"encoding":1060},[1023,25680,25682],{"className":25681,"ariaHidden":1066},[1065],[1023,25683,25685,25688,25691,25694,25697],{"className":25684},[1070],[1023,25686],{"className":25687,"style":1075},[1074],[1023,25689,1044],{"className":25690,"style":1081},[1079,1080],[1023,25692,1049],{"className":25693},[1085],[1023,25695,1053],{"className":25696},[1079],[1023,25698,1056],{"className":25699},[1092],[1123,25701,25702,25703],{},"Gần ",[1023,25704,25706,25725],{"className":25705},[1026],[1023,25707,25709],{"className":25708},[1030],[1032,25710,25711],{"xmlns":1034},[1036,25712,25713,25723],{},[1039,25714,25715,25717,25719,25721],{},[1042,25716,1044],{},[1046,25718,1049],{"stretchy":1048},[1051,25720,1053],{},[1046,25722,1056],{"stretchy":1048},[1058,25724,1061],{"encoding":1060},[1023,25726,25728],{"className":25727,"ariaHidden":1066},[1065],[1023,25729,25731,25734,25737,25740,25743],{"className":25730},[1070],[1023,25732],{"className":25733,"style":1075},[1074],[1023,25735,1044],{"className":25736,"style":1081},[1079,1080],[1023,25738,1049],{"className":25739},[1085],[1023,25741,1053],{"className":25742},[1079],[1023,25744,1056],{"className":25745},[1092],[1105,25747,25748,25751,25797],{},[1123,25749,25750],{},"Gộp",[1123,25752,25753,25796],{},[1023,25754,25756,25775],{"className":25755},[1026],[1023,25757,25759],{"className":25758},[1030],[1032,25760,25761],{"xmlns":1034},[1036,25762,25763,25773],{},[1039,25764,25765,25767,25769,25771],{},[1042,25766,1044],{},[1046,25768,1049],{"stretchy":1048},[1042,25770,1262],{},[1046,25772,1056],{"stretchy":1048},[1058,25774,1267],{"encoding":1060},[1023,25776,25778],{"className":25777,"ariaHidden":1066},[1065],[1023,25779,25781,25784,25787,25790,25793],{"className":25780},[1070],[1023,25782],{"className":25783,"style":1075},[1074],[1023,25785,1044],{"className":25786,"style":1081},[1079,1080],[1023,25788,1049],{"className":25789},[1085],[1023,25791,1262],{"className":25792},[1079,1080],[1023,25794,1056],{"className":25795},[1092]," viết lại",[1123,25798,25702,25799,25842],{},[1023,25800,25802,25821],{"className":25801},[1026],[1023,25803,25805],{"className":25804},[1030],[1032,25806,25807],{"xmlns":1034},[1036,25808,25809,25819],{},[1039,25810,25811,25813,25815,25817],{},[1042,25812,1044],{},[1046,25814,1049],{"stretchy":1048},[1051,25816,1053],{},[1046,25818,1056],{"stretchy":1048},[1058,25820,1061],{"encoding":1060},[1023,25822,25824],{"className":25823,"ariaHidden":1066},[1065],[1023,25825,25827,25830,25833,25836,25839],{"className":25826},[1070],[1023,25828],{"className":25829,"style":1075},[1074],[1023,25831,1044],{"className":25832,"style":1081},[1079,1080],[1023,25834,1049],{"className":25835},[1085],[1023,25837,1053],{"className":25838},[1079],[1023,25840,1056],{"className":25841},[1092]," nối gốc",[1105,25844,25845,25848,25924],{},[1123,25846,25847],{},"Dãy dài",[1123,25849,25850,25851],{},"Phình ",[1023,25852,25854,25877],{"className":25853},[1026],[1023,25855,25857],{"className":25856},[1030],[1032,25858,25859],{"xmlns":1034},[1036,25860,25861,25875],{},[1039,25862,25863,25865,25867,25873],{},[1042,25864,1044],{},[1046,25866,1049],{"stretchy":1048},[2327,25868,25869,25871],{},[1042,25870,1262],{},[1051,25872,2457],{},[1046,25874,1056],{"stretchy":1048},[1058,25876,2839],{"encoding":1060},[1023,25878,25880],{"className":25879,"ariaHidden":1066},[1065],[1023,25881,25883,25886,25889,25892,25921],{"className":25882},[1070],[1023,25884],{"className":25885,"style":2476},[1074],[1023,25887,1044],{"className":25888,"style":1081},[1079,1080],[1023,25890,1049],{"className":25891},[1085],[1023,25893,25895,25898],{"className":25894},[1079],[1023,25896,1262],{"className":25897},[1079,1080],[1023,25899,25901],{"className":25900},[2383],[1023,25902,25904],{"className":25903},[2387],[1023,25905,25907],{"className":25906},[2391],[1023,25908,25910],{"className":25909,"style":2369},[2395],[1023,25911,25912,25915],{"style":2398},[1023,25913],{"className":25914,"style":2403},[2402],[1023,25916,25918],{"className":25917},[2407,2408,2409,2410],[1023,25919,2457],{"className":25920},[1079,2410],[1023,25922,1056],{"className":25923},[1092],[1123,25925,25926],{},"Gần tuyến tính",[968,25928,1433],{"id":1432},[986,25930,25931,25934,25937,25942],{},[989,25932,25933],{},"Input: tam giác cạnh 1, 2, 3 -> Output: nhận cạnh 1 và 2, tổng 3.",[989,25935,25936],{},"Câu này cho thấy cạnh 3 bị loại vì tạo vòng tròn.",[989,25938,9878,25939,25941],{},[992,25940,24921],{}," hai lần trên nhánh sâu -> Output: lần 2 chỉ 1 bước.",[989,25943,25944],{},"Câu này cho thấy nén đường đi phát huy tác dụng.",[968,25946,1482],{"id":1481},[973,25948,1485,25949,5599,25951,1517],{},[1487,25950,1493],{},[992,25952,25953],{},"day-033\u002F",[981,25955,25957],{"id":25956},"bài-1-union-find-tối-ưu","Bài 1: Union-Find tối ưu",[1352,25959,25961],{"className":1393,"code":25960,"language":1395,"meta":1357,"style":1357},"class DSU {\n public:\n  explicit DSU(int n);\n  int  find(int x);          \u002F\u002F nén đường đi\n  bool unite(int a, int b);  \u002F\u002F hợp theo rank, bằng rank thì gốc mới tăng rank 1\n  int  size(int x);          \u002F\u002F kích thước nhóm chứa x\n  int  count() const;\n};\n",[992,25962,25963,25968,25972,25977,25982,25987,25992,25997],{"__ignoreMap":1357},[1023,25964,25965],{"class":1362,"line":63},[1023,25966,25967],{},"class DSU {\n",[1023,25969,25970],{"class":1362,"line":68},[1023,25971,4836],{},[1023,25973,25974],{"class":1362,"line":73},[1023,25975,25976],{},"  explicit DSU(int n);\n",[1023,25978,25979],{"class":1362,"line":78},[1023,25980,25981],{},"  int  find(int x);          \u002F\u002F nén đường đi\n",[1023,25983,25984],{"class":1362,"line":83},[1023,25985,25986],{},"  bool unite(int a, int b);  \u002F\u002F hợp theo rank, bằng rank thì gốc mới tăng rank 1\n",[1023,25988,25989],{"class":1362,"line":88},[1023,25990,25991],{},"  int  size(int x);          \u002F\u002F kích thước nhóm chứa x\n",[1023,25993,25994],{"class":1362,"line":93},[1023,25995,25996],{},"  int  count() const;\n",[1023,25998,25999],{"class":1362,"line":98},[1023,26000,4866],{},[973,26002,11480,26003,26005,26006,26009,26010,16014],{},[992,26004,24921],{}," bản ",[1487,26007,26008],{},"vòng lặp"," (không đệ quy) dùng kỹ thuật chia đôi đường đi (",[992,26011,26012],{},"parent[x] = parent[parent[x]]",[1352,26014,26017],{"className":26015,"code":26016,"language":2241,"meta":1357},[2239],"Dãy xấu ngày 32 với n = 10^6 -> find(0) chạy tức thì, không tràn stack\nunite(0,1); unite(2,3); unite(0,3) -> size(1) = 4\n",[992,26018,26016],{"__ignoreMap":1357},[973,26020,26021,26022,26025],{},"Chạy lại benchmark ngày 32 với ",[992,26023,26024],{},"DSU",". In bảng 3 cách cài.",[981,26027,26029],{"id":26028},"bài-2-kruskal","Bài 2: Kruskal",[1352,26031,26033],{"className":1393,"code":26032,"language":1395,"meta":1357,"style":1357},"struct Edge { int u, v; long long w; };\nstd::pair\u003Clong long, std::vector\u003CEdge>> kruskal(int n, std::vector\u003CEdge> edges);\n",[992,26034,26035,26040],{"__ignoreMap":1357},[1023,26036,26037],{"class":1362,"line":63},[1023,26038,26039],{},"struct Edge { int u, v; long long w; };\n",[1023,26041,26042],{"class":1362,"line":68},[1023,26043,26044],{},"std::pair\u003Clong long, std::vector\u003CEdge>> kruskal(int n, std::vector\u003CEdge> edges);\n",[973,26046,26047],{},"Đồ thị không liên thông thì trả rừng khung nhỏ nhất và in cảnh báo.",[1352,26049,26052],{"className":26050,"code":26051,"language":2241,"meta":1357},[2239],"Tam giác (0,1,1) (1,2,2) (0,2,3)   -> tổng 3, nhận 2 cạnh đầu\nn=4, cạnh (0,1,10) (0,2,6) (0,3,5) (1,3,15) (2,3,4) -> tổng 19\nn=3, 1 cạnh (0,1,5)                -> rừng, tổng 5, cảnh báo không liên thông\n",[992,26053,26051],{"__ignoreMap":1357},[981,26055,26057],{"id":26056},"bài-3-ứng-dụng-nâng-cao","Bài 3: Ứng dụng (nâng cao)",[2273,26059,26060,26123,26158],{},[989,26061,26062,26065,26066,2461,26068,26070,26071,26122],{},[1487,26063,26064],{},"Đếm đảo:"," lưới ",[992,26067,22521],{},[992,26069,22518],{}," cỡ ",[1023,26072,26074,26092],{"className":26073},[1026],[1023,26075,26077],{"className":26076},[1030],[1032,26078,26079],{"xmlns":1034},[1036,26080,26081,26089],{},[1039,26082,26083,26085,26087],{},[1051,26084,9989],{},[1046,26086,13768],{},[1051,26088,9989],{},[1058,26090,26091],{"encoding":1060},"1000 \\times 1000",[1023,26093,26095,26113],{"className":26094,"ariaHidden":1066},[1065],[1023,26096,26098,26101,26104,26107,26110],{"className":26097},[1070],[1023,26099],{"className":26100,"style":18148},[1074],[1023,26102,9989],{"className":26103},[1079],[1023,26105],{"className":26106,"style":13790},[2354],[1023,26108,13768],{"className":26109},[13794],[1023,26111],{"className":26112,"style":13790},[2354],[1023,26114,26116,26119],{"className":26115},[1070],[1023,26117],{"className":26118,"style":10020},[1074],[1023,26120,9989],{"className":26121},[1079],". Đếm số đảo bằng DSU (không dùng DFS).",[989,26124,26125,26128,26129,26157],{},[1487,26126,26127],{},"Cạnh thừa:"," cho cây ",[1023,26130,26132,26145],{"className":26131},[1026],[1023,26133,26135],{"className":26134},[1030],[1032,26136,26137],{"xmlns":1034},[1036,26138,26139,26143],{},[1039,26140,26141],{},[1042,26142,1262],{},[1058,26144,1262],{"encoding":1060},[1023,26146,26148],{"className":26147,"ariaHidden":1066},[1065],[1023,26149,26151,26154],{"className":26150},[1070],[1023,26152],{"className":26153,"style":2347},[1074],[1023,26155,1262],{"className":26156},[1079,1080]," nút cộng thêm đúng 1 cạnh. Tìm cạnh gây chu trình xuất hiện cuối cùng trong input.",[989,26159,26160,26163],{},[1487,26161,26162],{},"Gom cụm bằng Kruskal:"," cho 30 điểm 2D, chạy Kruskal nhưng dừng khi còn đúng 3 nhóm. In nhãn nhóm từng điểm.",[1352,26165,26168],{"className":26166,"code":26167,"language":2241,"meta":1357},[2239],"cạnh thừa: [(1,2),(1,3),(2,3)] -> (2,3)\n",[992,26169,26167],{"__ignoreMap":1357},[981,26171,2711],{"id":2710},[986,26173,26175,26181,26187,26193],{"className":26174},[2715],[989,26176,26178,26180],{"className":26177},[2719],[2721,26179],{"disabled":2723,"type":2724}," Test mẫu pass. Kết quả Kruskal khớp với Prim hoặc vét cạn trên đồ thị nhỏ ngẫu nhiên.",[989,26182,26184,26186],{"className":26183},[2719],[2721,26185],{"disabled":2723,"type":2724}," Bảng so sánh 3 cách cài Union-Find có số thật.",[989,26188,26190,26192],{"className":26189},[2719],[2721,26191],{"disabled":2723,"type":2724}," Giải thích được vì sao Kruskal cần Union-Find để phát hiện chu trình.",[989,26194,26196,26198,26199,1517],{"className":26195},[2719],[2721,26197],{"disabled":2723,"type":2724}," Nêu độ phức tạp Kruskal: ",[1023,26200,26202,26229],{"className":26201},[1026],[1023,26203,26205],{"className":26204},[1030],[1032,26206,26207],{"xmlns":1034},[1036,26208,26209,26226],{},[1039,26210,26211,26213,26215,26218,26220,26222,26224],{},[1042,26212,1044],{},[1046,26214,1049],{"stretchy":1048},[1042,26216,26217],{},"E",[1042,26219,8397],{},[1046,26221,8400],{},[1042,26223,26217],{},[1046,26225,1056],{"stretchy":1048},[1058,26227,26228],{"encoding":1060},"O(E \\log E)",[1023,26230,26232],{"className":26231,"ariaHidden":1066},[1065],[1023,26233,26235,26238,26241,26244,26248,26251,26256,26259,26262],{"className":26234},[1070],[1023,26236],{"className":26237,"style":1075},[1074],[1023,26239,1044],{"className":26240,"style":1081},[1079,1080],[1023,26242,1049],{"className":26243},[1085],[1023,26245,26217],{"className":26246,"style":26247},[1079,1080],"margin-right:0.0576em;",[1023,26249],{"className":26250,"style":8434},[2354],[1023,26252,8427,26254],{"className":26253},[8426],[1023,26255,7690],{"style":8430},[1023,26257],{"className":26258,"style":8434},[2354],[1023,26260,26217],{"className":26261,"style":26247},[1079,1080],[1023,26263,1056],{"className":26264},[1092],[968,26266,2890],{"id":2889},[986,26268,26269,26272,26275,26278],{},[989,26270,26271],{},"Vì sao biểu diễn cây giúp gộp nhanh hơn?",[989,26273,26274],{},"Nén đường đi làm gì trong lúc tìm?",[989,26276,26277],{},"Hợp theo hạng chọn cây nào làm gốc?",[989,26279,26280],{},"Kruskal xét cạnh theo thứ tự nào?",[3014,26282],{},[973,26284,26285],{},"🌕 Bạn đã hoàn thành ngày 33. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,26287,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":26289},[26290,26291,26296,26297,26303],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":26292},[26293,26294,26295],{"id":25495,"depth":73,"text":25496},{"id":25515,"depth":73,"text":25516},{"id":25618,"depth":73,"text":25619},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":26298},[26299,26300,26301,26302],{"id":25956,"depth":73,"text":25957},{"id":26028,"depth":73,"text":26029},{"id":26056,"depth":73,"text":26057},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nâng disjoint set bằng cây, nén đường đi và hợp theo hạng, rồi dùng nó xây cây khung nhỏ nhất bằng Kruskal.",{},[3050,15144],{"title":220,"description":26304},[25480,26309],"mst","CPzy4Eky87ikai1S2qkiJQtl8t7DPaXBlKhjl_4Om9k",{"id":26312,"title":225,"body":26313,"category":5189,"day":228,"description":26797,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":26798,"navigation":2723,"outcomes":3047,"path":226,"prerequisites":26799,"seo":26800,"stem":227,"tags":26801,"__hash__":26804},"challenges\u002Fchallenges\u002F34.template-method.md",{"type":965,"value":26314,"toc":26781},[26315,26317,26320,26322,26326,26340,26344,26358,26403,26407,26421,26468,26470,26484,26486,26498,26502,26563,26617,26626,26632,26646,26650,26680,26690,26696,26700,26705,26726,26728,26758,26760,26774,26776,26779],[968,26316,971],{"id":970},[973,26318,26319],{},"Bài này học Template Method giữ khung chung cho nhiều món.\nKhung này giúp thêm món mới mà không sửa code cũ.",[968,26321,979],{"id":978},[981,26323,26325],{"id":26324},"khung-giữ-cấu-trúc","Khung giữ cấu trúc",[986,26327,26328,26331,26334,26337],{},[989,26329,26330],{},"Template Method là khung thuật toán nằm ở lớp cha.",[989,26332,26333],{},"Lớp con chỉ điền bước riêng, không đổi thứ tự.",[989,26335,26336],{},"Ví dụ đời thường: khuôn làm bánh quyết định các bước chung.",[989,26338,26339],{},"Dùng khi nhiều quy trình giống nhau 80%.",[981,26341,26343],{"id":26342},"trà-và-cà-phê-bốn-bước","Trà và cà phê bốn bước",[986,26345,26346,26349,26352,26355],{},[989,26347,26348],{},"Cả hai cùng trình tự: đun, pha, rót, thêm gia vị.",[989,26350,26351],{},"Đun và rót giống nhau nên viết sẵn ở lớp cha.",[989,26353,26354],{},"Pha và thêm gia vị khác nhau nên để lớp con viết.",[989,26356,26357],{},"Ví dụ đời thường: trà hãm lá, cà phê pha phin.",[1352,26359,26361],{"className":3538,"code":26360,"language":3540,"meta":1357,"style":1357},"# Khung pha chế: cha giữ thứ tự, con điền bước\nclass DoUong:\n    def pha_che(self):  # khung 4 bước cố định\n        self.dun_nuoc()  # bước chung viết sẵn\n        self.pha()       # bước riêng con tự viết\n        self.rot()       # bước chung viết sẵn\n        if self.muốn_gia_vi():  # móc treo hỏi ý\n            self.them_gia_vi()\n",[992,26362,26363,26368,26373,26378,26383,26388,26393,26398],{"__ignoreMap":1357},[1023,26364,26365],{"class":1362,"line":63},[1023,26366,26367],{},"# Khung pha chế: cha giữ thứ tự, con điền bước\n",[1023,26369,26370],{"class":1362,"line":68},[1023,26371,26372],{},"class DoUong:\n",[1023,26374,26375],{"class":1362,"line":73},[1023,26376,26377],{},"    def pha_che(self):  # khung 4 bước cố định\n",[1023,26379,26380],{"class":1362,"line":78},[1023,26381,26382],{},"        self.dun_nuoc()  # bước chung viết sẵn\n",[1023,26384,26385],{"class":1362,"line":83},[1023,26386,26387],{},"        self.pha()       # bước riêng con tự viết\n",[1023,26389,26390],{"class":1362,"line":88},[1023,26391,26392],{},"        self.rot()       # bước chung viết sẵn\n",[1023,26394,26395],{"class":1362,"line":93},[1023,26396,26397],{},"        if self.muốn_gia_vi():  # móc treo hỏi ý\n",[1023,26399,26400],{"class":1362,"line":98},[1023,26401,26402],{},"            self.them_gia_vi()\n",[981,26404,26406],{"id":26405},"móc-treo-và-hollywood","Móc treo và Hollywood",[986,26408,26409,26412,26415,26418],{},[989,26410,26411],{},"Móc treo là bước có sẵn đáp án mặc định.",[989,26413,26414],{},"Lớp con có thể ghi đè hoặc bỏ qua móc.",[989,26416,26417],{},"Hollywood: con ngồi chờ, khung gọi đúng lúc.",[989,26419,26420],{},"Ví dụ đời thường: khách kiêng đường thì bỏ qua bước đường.",[1099,26422,26423,26435],{},[1102,26424,26425],{},[1105,26426,26427,26429,26432],{},[1108,26428,24466],{},[1108,26430,26431],{},"Bước trừu tượng",[1108,26433,26434],{},"Móc treo",[1118,26436,26437,26448,26458],{},[1105,26438,26439,26442,26445],{},[1123,26440,26441],{},"Lớp con",[1123,26443,26444],{},"Bắt buộc viết",[1123,26446,26447],{},"Tùy chọn ghi đè",[1105,26449,26450,26453,26455],{},[1123,26451,26452],{},"Khung có sẵn",[1123,26454,20726],{},[1123,26456,26457],{},"Có đáp án mặc định",[1105,26459,26460,26462,26465],{},[1123,26461,23789],{},[1123,26463,26464],{},"Bước nào cũng khác",[1123,26466,26467],{},"Hiếm khi ngoại lệ",[968,26469,1433],{"id":1432},[986,26471,26472,26475,26478,26481],{},[989,26473,26474],{},"Input: pha trà chanh -> Output: 4 bước chạy đủ, gia vị là chanh.",[989,26476,26477],{},"Câu này cho thấy bước chung và riêng phối hợp.",[989,26479,26480],{},"Input: pha cà phê kiêng đường -> Output: bỏ bước đường, 3 bước còn lại chạy.",[989,26482,26483],{},"Câu này cho thấy móc treo giúp bỏ qua linh hoạt.",[968,26485,1482],{"id":1481},[973,26487,1485,26488,4801,26490,26493,26494,26497],{},[1487,26489,4800],{},[992,26491,26492],{},"day-034\u002F",". Mỗi bước ghi vào ",[992,26495,26496],{},"std::vector\u003Cstd::string> log"," để test thứ tự.",[981,26499,26501],{"id":26500},"bài-1-trà-và-cà-phê","Bài 1: Trà và cà phê",[1352,26503,26505],{"className":1393,"code":26504,"language":1395,"meta":1357,"style":1357},"class CaffeineBeverage {\n public:\n  void prepareRecipe();                 \u002F\u002F final: đun, pha, rót, (móc) thêm gia vị\n  const std::vector\u003Cstd::string> &log() const;\n  virtual ~CaffeineBeverage() = default;\n protected:\n  virtual void brew() = 0;\n  virtual void addCondiments() = 0;\n  virtual bool customerWantsCondiments() { return true; }   \u002F\u002F hook\n private:\n  void boilWater(); void pourInCup();\n};\n",[992,26506,26507,26512,26516,26521,26526,26531,26535,26540,26545,26550,26554,26559],{"__ignoreMap":1357},[1023,26508,26509],{"class":1362,"line":63},[1023,26510,26511],{},"class CaffeineBeverage {\n",[1023,26513,26514],{"class":1362,"line":68},[1023,26515,4836],{},[1023,26517,26518],{"class":1362,"line":73},[1023,26519,26520],{},"  void prepareRecipe();                 \u002F\u002F final: đun, pha, rót, (móc) thêm gia vị\n",[1023,26522,26523],{"class":1362,"line":78},[1023,26524,26525],{},"  const std::vector\u003Cstd::string> &log() const;\n",[1023,26527,26528],{"class":1362,"line":83},[1023,26529,26530],{},"  virtual ~CaffeineBeverage() = default;\n",[1023,26532,26533],{"class":1362,"line":88},[1023,26534,11747],{},[1023,26536,26537],{"class":1362,"line":93},[1023,26538,26539],{},"  virtual void brew() = 0;\n",[1023,26541,26542],{"class":1362,"line":98},[1023,26543,26544],{},"  virtual void addCondiments() = 0;\n",[1023,26546,26547],{"class":1362,"line":103},[1023,26548,26549],{},"  virtual bool customerWantsCondiments() { return true; }   \u002F\u002F hook\n",[1023,26551,26552],{"class":1362,"line":108},[1023,26553,16301],{},[1023,26555,26556],{"class":1362,"line":113},[1023,26557,26558],{},"  void boilWater(); void pourInCup();\n",[1023,26560,26561],{"class":1362,"line":118},[1023,26562,4866],{},[1099,26564,26565,26581],{},[1102,26566,26567],{},[1105,26568,26569,26571,26576],{},[1108,26570,4881],{},[1108,26572,26573],{},[992,26574,26575],{},"brew()",[1108,26577,26578],{},[992,26579,26580],{},"addCondiments()",[1118,26582,26583,26600],{},[1105,26584,26585,26590,26595],{},[1123,26586,26587],{},[992,26588,26589],{},"Tea",[1123,26591,26592],{},[992,26593,26594],{},"\"ngâm trà\"",[1123,26596,26597],{},[992,26598,26599],{},"\"thêm chanh\"",[1105,26601,26602,26607,26612],{},[1123,26603,26604],{},[992,26605,26606],{},"Coffee",[1123,26608,26609],{},[992,26610,26611],{},"\"lọc cà phê\"",[1123,26613,26614],{},[992,26615,26616],{},"\"thêm đường và sữa\"",[973,26618,26619,5016,26622,26625],{},[992,26620,26621],{},"CoffeeWithHook",[992,26623,26624],{},"bool wantSugar"," qua constructor và ghi đè hook.",[1352,26627,26630],{"className":26628,"code":26629,"language":2241,"meta":1357},[2239],"Tea            -> [đun nước, ngâm trà, rót ra cốc, thêm chanh]\nCoffee         -> [đun nước, lọc cà phê, rót ra cốc, thêm đường và sữa]\nCoffeeWithHook(false) -> [đun nước, lọc cà phê, rót ra cốc]\n",[992,26631,26629],{"__ignoreMap":1357},[973,26633,26634,2308,26636,15871,26639,26641,26642,26645],{},[1487,26635,6076],{},[992,26637,26638],{},"prepareRecipe",[992,26640,20909],{}," (hoặc ",[992,26643,26644],{},"final"," trong Java). Lớp con không đổi được thứ tự.",[981,26647,26649],{"id":26648},"bài-2-khung-xử-lý-file-dữ-liệu","Bài 2: Khung xử lý file dữ liệu",[973,26651,1505,26652,26655,26656,26659,26660,26663,26664,26659,26667,26659,26670,26673,26674,26677,26678,1517],{},[992,26653,26654],{},"DataImporter::run(path)"," với các bước cố định: ",[992,26657,26658],{},"open"," → ",[992,26661,26662],{},"parseLine"," cho từng dòng → ",[992,26665,26666],{},"validate",[992,26668,26669],{},"save",[992,26671,26672],{},"report",". Hook ",[992,26675,26676],{},"bool skipHeader()"," mặc định ",[992,26679,1066],{},[973,26681,1505,26682,26685,26686,26689],{},[992,26683,26684],{},"CsvImporter"," (tách bằng dấu phẩy) và ",[992,26687,26688],{},"TsvImporter"," (tách bằng tab). Dòng không hợp lệ bị bỏ qua và đếm lại.",[1352,26691,26694],{"className":26692,"code":26693,"language":2241,"meta":1357},[2239],"users.csv có 1 header + 4 dòng, 1 dòng thiếu cột -> report: \"3 hợp lệ, 1 lỗi\"\n",[992,26695,26693],{"__ignoreMap":1357},[981,26697,26699],{"id":26698},"bài-3-hollywood-trong-sắp-xếp-nâng-cao","Bài 3: Hollywood trong sắp xếp (nâng cao)",[973,26701,26702,26704],{},[992,26703,9956],{}," là một Template Method: khung sắp xếp cố định, bạn chỉ cung cấp phép so sánh.",[2273,26706,26707,26717,26723],{},[989,26708,13735,26709,26712,26713,26716],{},[992,26710,26711],{},"template\u003Cclass T> void mySort(std::vector\u003CT>&, bool (*less)(const T&, const T&))"," (insertion sort). Dùng cho ",[992,26714,26715],{},"struct Duck { std::string name; int weight; }"," sắp theo cân nặng.",[989,26718,26719,26720,26722],{},"Viết 3 câu trong ",[992,26721,2513],{},": điểm giống và khác giữa cách này và Template Method dùng kế thừa.",[989,26724,26725],{},"So sánh Template Method với Strategy: bảng 3 dòng (cơ chế, lúc nào đổi được hành vi, ai giữ khung).",[981,26727,2711],{"id":2710},[986,26729,26731,26737,26746,26752],{"className":26730},[2715],[989,26732,26734,26736],{"className":26733},[2719],[2721,26735],{"disabled":2723,"type":2724}," Test thứ tự log Bài 1 pass cho cả 3 lớp.",[989,26738,26740,9191,26742,26745],{"className":26739},[2719],[2721,26741],{"disabled":2723,"type":2724},[992,26743,26744],{},"JsonLinesImporter"," chỉ cần 1 file mới.",[989,26747,26749,26751],{"className":26748},[2719],[2721,26750],{"disabled":2723,"type":2724}," Bài 3 có bảng so sánh với Strategy.",[989,26753,26755,26757],{"className":26754},[2719],[2721,26756],{"disabled":2723,"type":2724}," Giải thích được nguyên lý Hollywood bằng một ví dụ trong code của mình.",[968,26759,2890],{"id":2889},[986,26761,26762,26765,26768,26771],{},[989,26763,26764],{},"Template Method giữ cái gì và nhả cái gì?",[989,26766,26767],{},"Hai bước nào của trà và cà phê giống nhau?",[989,26769,26770],{},"Móc treo khác bước trừu tượng thế nào?",[989,26772,26773],{},"Hollywood principle nghĩa là ai gọi ai?",[3014,26775],{},[973,26777,26778],{},"🌕 Bạn đã hoàn thành ngày 34. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,26780,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":26782},[26783,26784,26789,26790,26796],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":26785},[26786,26787,26788],{"id":26324,"depth":73,"text":26325},{"id":26342,"depth":73,"text":26343},{"id":26405,"depth":73,"text":26406},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":26791},[26792,26793,26794,26795],{"id":26500,"depth":73,"text":26501},{"id":26648,"depth":73,"text":26649},{"id":26698,"depth":73,"text":26699},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Template Method, khung pha trà cà phê với móc treo, và nguyên tắc đừng gọi chúng tôi chúng tôi sẽ gọi bạn.",{},[5194],{"title":225,"description":26797},[26802,26803],"template-method","hollywood","0YjDfB-QCTu41b4awpYrUinMjTDN4h_vE2Q3zPDF9cU",{"id":26806,"title":230,"body":26807,"category":3041,"day":233,"description":27238,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":27239,"navigation":2723,"outcomes":3047,"path":231,"prerequisites":27240,"seo":27241,"stem":232,"tags":27242,"__hash__":27244},"challenges\u002Fchallenges\u002F35.trie-co-ban.md",{"type":965,"value":26808,"toc":27222},[26809,26811,26814,26816,26820,26834,26838,26852,26897,26901,26915,26917,26931,26933,26945,26949,27007,27085,27091,27095,27105,27121,27134,27138,27162,27168,27170,27199,27201,27215,27217,27220],[968,26810,971],{"id":970},[973,26812,26813],{},"Bài này học Trie lưu từ điển bằng cách chia sẻ tiền tố.\nCây này giúp tra từ và gợi ý rất nhanh.",[968,26815,979],{"id":978},[981,26817,26819],{"id":26818},"trie-là-gì","Trie là gì",[986,26821,26822,26825,26828,26831],{},[989,26823,26824],{},"Trie là cây mà mỗi cạnh mang một ký tự.",[989,26826,26827],{},"Mỗi nút đánh dấu có phải kết thúc từ không.",[989,26829,26830],{},"Các từ chung tiền tố thì đi chung đoạn đường đầu.",[989,26832,26833],{},"Ví dụ đời thường: ant và anthem chung đường a-n-t.",[981,26835,26837],{"id":26836},"tìm-kiếm-và-chèn","Tìm kiếm và chèn",[986,26839,26840,26843,26846,26849],{},[989,26841,26842],{},"Tìm: đi từ gốc theo từng ký tự của khóa.",[989,26844,26845],{},"Hết chuỗi mà nút có đánh dấu thì báo có từ.",[989,26847,26848],{},"Chèn: đi theo đường cũ, thiếu tới đâu tạo nhánh mới.",[989,26850,26851],{},"Ví dụ đời thường: tra từ điển bằng cách lật từng chữ.",[1352,26853,26855],{"className":3538,"code":26854,"language":3540,"meta":1357,"style":1357},"# Tìm trong trie: đi theo từng ký tự\ndef tim(goc, tu):\n    nut = goc  # bắt đầu từ gốc\n    for ch in tu:  # xét từng ký tự\n        if ch not in nut.con:  # không có cạnh\n            return False  # từ không tồn tại\n        nut = nut.con[ch]  # bước sang nút con\n    return nut.het_tu  # phải là kết thúc từ\n",[992,26856,26857,26862,26867,26872,26877,26882,26887,26892],{"__ignoreMap":1357},[1023,26858,26859],{"class":1362,"line":63},[1023,26860,26861],{},"# Tìm trong trie: đi theo từng ký tự\n",[1023,26863,26864],{"class":1362,"line":68},[1023,26865,26866],{},"def tim(goc, tu):\n",[1023,26868,26869],{"class":1362,"line":73},[1023,26870,26871],{},"    nut = goc  # bắt đầu từ gốc\n",[1023,26873,26874],{"class":1362,"line":78},[1023,26875,26876],{},"    for ch in tu:  # xét từng ký tự\n",[1023,26878,26879],{"class":1362,"line":83},[1023,26880,26881],{},"        if ch not in nut.con:  # không có cạnh\n",[1023,26883,26884],{"class":1362,"line":88},[1023,26885,26886],{},"            return False  # từ không tồn tại\n",[1023,26888,26889],{"class":1362,"line":93},[1023,26890,26891],{},"        nut = nut.con[ch]  # bước sang nút con\n",[1023,26893,26894],{"class":1362,"line":98},[1023,26895,26896],{},"    return nut.het_tu  # phải là kết thúc từ\n",[981,26898,26900],{"id":26899},"xóa-và-gợi-ý-tiền-tố","Xóa và gợi ý tiền tố",[986,26902,26903,26906,26909,26912],{},[989,26904,26905],{},"Xóa: bỏ đánh dấu, rồi tỉa nhánh thừa từ lá lên.",[989,26907,26908],{},"Dừng tỉa khi gặp nút còn dùng chung từ khác.",[989,26910,26911],{},"Gợi ý: tới nút tiền tố rồi liệt kê cả cây con.",[989,26913,26914],{},"Ví dụ đời thường: gõ \"ant\" hiện ra anthem, antler.",[968,26916,1433],{"id":1432},[986,26918,26919,26922,26925,26928],{},[989,26920,26921],{},"Input: trie có anthem, tra ant -> Output: False.",[989,26923,26924],{},"Câu này phân biệt tiền tố với từ hoàn chỉnh.",[989,26926,26927],{},"Input: xóa ant khỏi trie có ant và anthem -> Output: anthem còn nguyên.",[989,26929,26930],{},"Câu này cho thấy nhánh chung không bị cắt nhầm.",[968,26932,1482],{"id":1481},[973,26934,1485,26935,5599,26937,26940,26941,26944],{},[1487,26936,1493],{},[992,26938,26939],{},"day-035\u002F",". Chỉ xét chữ thường ",[992,26942,26943],{},"a-z"," cho Bài 1-2.",[981,26946,26948],{"id":26947},"bài-1-trie-cơ-bản","Bài 1: Trie cơ bản",[1352,26950,26952],{"className":1393,"code":26951,"language":1395,"meta":1357,"style":1357},"struct TrieNode { std::array\u003CTrieNode*, 26> child{}; bool isEnd = false; int passCount = 0; };\nclass Trie {\n public:\n  void insert(const std::string &w);\n  bool search(const std::string &w) const;       \u002F\u002F đúng từ\n  bool startsWith(const std::string &p) const;   \u002F\u002F có từ nào bắt đầu bằng p\n  bool remove(const std::string &w);             \u002F\u002F tỉa nhánh thừa, trả false nếu không có\n  int  countPrefix(const std::string &p) const;  \u002F\u002F số từ có tiền tố p, O(|p|) nhờ passCount\n  size_t nodeCount() const;\n  ~Trie();\n};\n",[992,26953,26954,26959,26964,26968,26973,26978,26983,26988,26993,26998,27003],{"__ignoreMap":1357},[1023,26955,26956],{"class":1362,"line":63},[1023,26957,26958],{},"struct TrieNode { std::array\u003CTrieNode*, 26> child{}; bool isEnd = false; int passCount = 0; };\n",[1023,26960,26961],{"class":1362,"line":68},[1023,26962,26963],{},"class Trie {\n",[1023,26965,26966],{"class":1362,"line":73},[1023,26967,4836],{},[1023,26969,26970],{"class":1362,"line":78},[1023,26971,26972],{},"  void insert(const std::string &w);\n",[1023,26974,26975],{"class":1362,"line":83},[1023,26976,26977],{},"  bool search(const std::string &w) const;       \u002F\u002F đúng từ\n",[1023,26979,26980],{"class":1362,"line":88},[1023,26981,26982],{},"  bool startsWith(const std::string &p) const;   \u002F\u002F có từ nào bắt đầu bằng p\n",[1023,26984,26985],{"class":1362,"line":93},[1023,26986,26987],{},"  bool remove(const std::string &w);             \u002F\u002F tỉa nhánh thừa, trả false nếu không có\n",[1023,26989,26990],{"class":1362,"line":98},[1023,26991,26992],{},"  int  countPrefix(const std::string &p) const;  \u002F\u002F số từ có tiền tố p, O(|p|) nhờ passCount\n",[1023,26994,26995],{"class":1362,"line":103},[1023,26996,26997],{},"  size_t nodeCount() const;\n",[1023,26999,27000],{"class":1362,"line":108},[1023,27001,27002],{},"  ~Trie();\n",[1023,27004,27005],{"class":1362,"line":113},[1023,27006,4866],{},[1099,27008,27009,27017],{},[1102,27010,27011],{},[1105,27012,27013,27015],{},[1108,27014,1110],{},[1108,27016,1113],{},[1118,27018,27019],{},[1105,27020,27021,27036],{},[1123,27022,27023,1656,27025,1656,27028,1656,27030,1656,27033],{},[992,27024,2251],{},[992,27026,27027],{},"search",[992,27029,24259],{},[992,27031,27032],{},"startsWith",[992,27034,27035],{},"countPrefix",[1123,27037,27038,7386,27082,27084],{},[1023,27039,27041,27061],{"className":27040},[1026],[1023,27042,27044],{"className":27043},[1030],[1032,27045,27046],{"xmlns":1034},[1036,27047,27048,27058],{},[1039,27049,27050,27052,27054,27056],{},[1042,27051,1044],{},[1046,27053,1049],{"stretchy":1048},[1042,27055,4772],{},[1046,27057,1056],{"stretchy":1048},[1058,27059,27060],{"encoding":1060},"O(L)",[1023,27062,27064],{"className":27063,"ariaHidden":1066},[1065],[1023,27065,27067,27070,27073,27076,27079],{"className":27066},[1070],[1023,27068],{"className":27069,"style":1075},[1074],[1023,27071,1044],{"className":27072,"style":1081},[1079,1080],[1023,27074,1049],{"className":27075},[1085],[1023,27077,4772],{"className":27078},[1079,1080],[1023,27080,1056],{"className":27081},[1092],[992,27083,4772],{}," là độ dài chuỗi",[1352,27086,27089],{"className":27087,"code":27088,"language":2241,"meta":1357},[2239],"insert ant, anthem, antique, bee\nsearch(\"ant\") -> true; search(\"anth\") -> false; startsWith(\"anth\") -> true\ncountPrefix(\"ant\") -> 3\nremove(\"ant\") -> anthem, antique vẫn tìm thấy; search(\"ant\") = false\nremove(\"bee\") -> nodeCount giảm đúng 3 nút (b, e, e)\nremove(\"cat\") -> false\n",[992,27090,27088],{"__ignoreMap":1357},[981,27092,27094],{"id":27093},"bài-2-gợi-ý-theo-tiền-tố","Bài 2: Gợi ý theo tiền tố",[973,27096,27097,27100,27101,27104],{},[992,27098,27099],{},"std::vector\u003Cstd::string> suggest(const std::string &prefix, int limit)",": trả tối đa ",[992,27102,27103],{},"limit"," từ theo thứ tự alphabet.",[973,27106,27107,27108,27111,27112,1656,27115,1656,27118,1517],{},"Nạp file từ điển tiếng Anh (khoảng 100.000 từ, ví dụ ",[992,27109,27110],{},"\u002Fusr\u002Fshare\u002Fdict\u002Fwords"," đã lọc chữ thường). In 10 gợi ý cho ",[992,27113,27114],{},"\"pre\"",[992,27116,27117],{},"\"xyl\"",[992,27119,27120],{},"\"qqq\"",[973,27122,21956,27123,27126,27127,27130,27131,16014],{},[992,27124,27125],{},"suggest"," với cách quét toàn bộ ",[992,27128,27129],{},"std::vector\u003Cstd::string>"," đã sắp xếp (dùng ",[992,27132,27133],{},"lower_bound",[981,27135,27137],{"id":27136},"bài-3-trie-cho-unicode-và-bộ-nhớ-nâng-cao","Bài 3: Trie cho Unicode và bộ nhớ (nâng cao)",[2273,27139,27140,27153,27156],{},[989,27141,15916,27142,15919,27145,27148,27149,27152],{},[992,27143,27144],{},"child",[992,27146,27147],{},"std::unordered_map\u003Cchar32_t, TrieNode*>"," để hỗ trợ tiếng Việt có dấu. Chuyển UTF-8 sang ",[992,27150,27151],{},"char32_t"," trước khi chèn.",[989,27154,27155],{},"Nạp 10.000 từ tiếng Việt. In số nút và ước lượng bộ nhớ của 2 cách cài (mảng 26 và map).",[989,27157,1505,27158,27161],{},[992,27159,27160],{},"longestCommonPrefix()"," của mọi từ trong trie.",[1352,27163,27166],{"className":27164,"code":27165,"language":2241,"meta":1357},[2239],"[\"flower\", \"flow\", \"flight\"] -> \"fl\"\n[\"đường\", \"đương\", \"đi\"]     -> \"đ\"\n",[992,27167,27165],{"__ignoreMap":1357},[981,27169,2711],{"id":2710},[986,27171,27173,27181,27187,27193],{"className":27172},[2715],[989,27174,27176,8082,27178,27180],{"className":27175},[2719],[2721,27177],{"disabled":2723,"type":2724},[992,27179,24259],{}," không làm hỏng từ dùng chung tiền tố.",[989,27182,27184,27186],{"className":27183},[2719],[2721,27185],{"disabled":2723,"type":2724}," Bảng thời gian Bài 2 có số thật.",[989,27188,27190,27192],{"className":27189},[2719],[2721,27191],{"disabled":2723,"type":2724}," Bài 3 xử lý đúng từ có dấu.",[989,27194,27196,27198],{"className":27195},[2719],[2721,27197],{"disabled":2723,"type":2724}," Sanitizer sạch sau khi xóa hết từ.",[968,27200,2890],{"id":2889},[986,27202,27203,27206,27209,27212],{},[989,27204,27205],{},"Trie chia sẻ tiền tố chung thế nào?",[989,27207,27208],{},"Tìm kiếm đi theo ký tự ra sao?",[989,27210,27211],{},"Chèn từ mới tạo nhánh lúc nào?",[989,27213,27214],{},"Xóa từ mà giữ từ chung nhánh thế nào?",[3014,27216],{},[973,27218,27219],{},"🌕 Bạn đã hoàn thành ngày 35. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,27221,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":27223},[27224,27225,27230,27231,27237],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":27226},[27227,27228,27229],{"id":26818,"depth":73,"text":26819},{"id":26836,"depth":73,"text":26837},{"id":26899,"depth":73,"text":26900},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":27232},[27233,27234,27235,27236],{"id":26947,"depth":73,"text":26948},{"id":27093,"depth":73,"text":27094},{"id":27136,"depth":73,"text":27137},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Học cây tiền tố lưu chuỗi theo ký tự chung qua bài toán kiểm tra chính tả, cùng bốn thao tác và hai truy vấn tiền tố.",{},[3050,4669],{"title":230,"description":27238},[27243],"trie","UWkRYdUuaEfgsiJ3lEaQgjjKKhIJ38G-Cs8luYPm_cg",{"id":27246,"title":235,"body":27247,"category":3041,"day":238,"description":27643,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":27644,"navigation":2723,"outcomes":3047,"path":236,"prerequisites":27645,"seo":27646,"stem":237,"tags":27647,"__hash__":27649},"challenges\u002Fchallenges\u002F36.radix-trie-va-ung-dung.md",{"type":965,"value":27248,"toc":27627},[27249,27251,27254,27256,27260,27274,27278,27292,27296,27310,27432,27434,27448,27450,27457,27461,27502,27505,27511,27515,27532,27538,27545,27549,27562,27567,27573,27575,27604,27606,27620,27622,27625],[968,27250,971],{"id":970},[973,27252,27253],{},"Bài này học radix trie nén trie thường cho gọn bộ nhớ.\nCây gọn này giúp gợi ý từ cực nhanh.",[968,27255,979],{"id":978},[981,27257,27259],{"id":27258},"nén-cạnh-đơn","Nén cạnh đơn",[986,27261,27262,27265,27268,27271],{},[989,27263,27264],{},"Nhánh chỉ có một con thì nén thành một cạnh dài.",[989,27266,27267],{},"Nhãn cạnh là chuỗi, không còn là một ký tự.",[989,27269,27270],{},"Ví dụ đời thường: gộp 3 chặng đường thẳng thành một chặng.",[989,27272,27273],{},"Càng nhiều hậu tố riêng thì nén càng tiết kiệm.",[981,27275,27277],{"id":27276},"chèn-phải-tách-cạnh","Chèn phải tách cạnh",[986,27279,27280,27283,27286,27289],{},[989,27281,27282],{},"Tìm: so phần còn lại của khóa với nhãn cạnh.",[989,27284,27285],{},"Khớp hết nhãn thì đi tiếp, khớp một phần thì không có.",[989,27287,27288],{},"Chèn gặp khớp một phần thì tách cạnh làm đôi.",[989,27290,27291],{},"Ví dụ đời thường: cây có anthem, chèn ant thì tách tại ant.",[981,27293,27295],{"id":27294},"autocomplete-hai-bước","Autocomplete hai bước",[986,27297,27298,27301,27304,27307],{},[989,27299,27300],{},"Bước 1: đi theo tiền tố tới nút tương ứng.",[989,27302,27303],{},"Bước 2: duyệt cây con liệt kê mọi từ bên dưới.",[989,27305,27306],{},"Chi phí không phụ thuộc kích thước từ điển.",[989,27308,27309],{},"Ví dụ đời thường: gõ một chữ hiện ngay gợi ý.",[1099,27311,27312,27325],{},[1102,27313,27314],{},[1105,27315,27316,27319,27322],{},[1108,27317,27318],{},"Ứng dụng",[1108,27320,27321],{},"Việc làm",[1108,27323,27324],{},"Điểm mạnh",[1118,27326,27327,27338,27421],{},[1105,27328,27329,27332,27335],{},[1123,27330,27331],{},"Autocomplete",[1123,27333,27334],{},"Liệt kê cây con",[1123,27336,27337],{},"Nhanh theo tiền tố",[1105,27339,27340,27343,27418],{},[1123,27341,27342],{},"Spell-check",[1123,27344,27345,27346,7386,27389,27084],{},"Tra ",[1023,27347,27349,27368],{"className":27348},[1026],[1023,27350,27352],{"className":27351},[1030],[1032,27353,27354],{"xmlns":1034},[1036,27355,27356,27366],{},[1039,27357,27358,27360,27362,27364],{},[1042,27359,1044],{},[1046,27361,1049],{"stretchy":1048},[1042,27363,4772],{},[1046,27365,1056],{"stretchy":1048},[1058,27367,27060],{"encoding":1060},[1023,27369,27371],{"className":27370,"ariaHidden":1066},[1065],[1023,27372,27374,27377,27380,27383,27386],{"className":27373},[1070],[1023,27375],{"className":27376,"style":1075},[1074],[1023,27378,1044],{"className":27379,"style":1081},[1079,1080],[1023,27381,1049],{"className":27382},[1085],[1023,27384,4772],{"className":27385},[1079,1080],[1023,27387,1056],{"className":27388},[1092],[1023,27390,27392,27405],{"className":27391},[1026],[1023,27393,27395],{"className":27394},[1030],[1032,27396,27397],{"xmlns":1034},[1036,27398,27399,27403],{},[1039,27400,27401],{},[1042,27402,4772],{},[1058,27404,4772],{"encoding":1060},[1023,27406,27408],{"className":27407,"ariaHidden":1066},[1065],[1023,27409,27411,27415],{"className":27410},[1070],[1023,27412],{"className":27413,"style":27414},[1074],"height:0.6833em;",[1023,27416,4772],{"className":27417},[1079,1080],[1123,27419,27420],{},"Gợi ý từ gần đúng",[1105,27422,27423,27426,27429],{},[1123,27424,27425],{},"Sắp xếp chuỗi",[1123,27427,27428],{},"Duyệt alphabet",[1123,27430,27431],{},"Không cần so cặp",[968,27433,1433],{"id":1432},[986,27435,27436,27439,27442,27445],{},[989,27437,27438],{},"Input: radix trie một từ duy nhất -> Output: một cạnh từ gốc tới lá.",[989,27440,27441],{},"Câu này cho thấy nén gom cả từ vào một cạnh.",[989,27443,27444],{},"Input: gõ tiền tố không tồn tại -> Output: danh sách gợi ý rỗng.",[989,27446,27447],{},"Câu này cho thấy dừng ngay sau đúng độ dài tiền tố.",[968,27449,1482],{"id":1481},[973,27451,1485,27452,5599,27454,1517],{},[1487,27453,1493],{},[992,27455,27456],{},"day-036\u002F",[981,27458,27460],{"id":27459},"bài-1-radix-trie","Bài 1: Radix trie",[1352,27462,27464],{"className":1393,"code":27463,"language":1395,"meta":1357,"style":1357},"struct RNode { std::map\u003Cchar, std::pair\u003Cstd::string, RNode*>> edges; bool isEnd = false; };\nclass RadixTrie {\n public:\n  void insert(const std::string &w);\n  bool search(const std::string &w) const;\n  bool remove(const std::string &w);     \u002F\u002F gộp lại cạnh khi nút chỉ còn 1 con và không phải cuối từ\n  size_t nodeCount() const;\n};\n",[992,27465,27466,27471,27476,27480,27484,27489,27494,27498],{"__ignoreMap":1357},[1023,27467,27468],{"class":1362,"line":63},[1023,27469,27470],{},"struct RNode { std::map\u003Cchar, std::pair\u003Cstd::string, RNode*>> edges; bool isEnd = false; };\n",[1023,27472,27473],{"class":1362,"line":68},[1023,27474,27475],{},"class RadixTrie {\n",[1023,27477,27478],{"class":1362,"line":73},[1023,27479,4836],{},[1023,27481,27482],{"class":1362,"line":78},[1023,27483,26972],{},[1023,27485,27486],{"class":1362,"line":83},[1023,27487,27488],{},"  bool search(const std::string &w) const;\n",[1023,27490,27491],{"class":1362,"line":88},[1023,27492,27493],{},"  bool remove(const std::string &w);     \u002F\u002F gộp lại cạnh khi nút chỉ còn 1 con và không phải cuối từ\n",[1023,27495,27496],{"class":1362,"line":93},[1023,27497,26997],{},[1023,27499,27500],{"class":1362,"line":98},[1023,27501,4866],{},[973,27503,27504],{},"Mỗi cạnh được đánh chỉ mục bằng ký tự đầu của nhãn, nên tối đa 1 cạnh mỗi ký tự đầu.",[1352,27506,27509],{"className":27507,"code":27508,"language":2241,"meta":1357},[2239],"insert \"romane\"                   -> 1 cạnh \"romane\"\ninsert \"romanus\"                  -> tách: \"roman\" -> {\"e\", \"us\"}\ninsert \"romulus\"                  -> tách: \"rom\" -> {\"an\" -> {\"e\",\"us\"}, \"ulus\"}\ninsert \"rom\"                      -> nút \"rom\" đánh dấu isEnd\nsearch(\"roma\") -> false; search(\"rom\") -> true\nremove(\"romanus\")                 -> \"an\" -> \"e\" gộp lại thành \"ane\"\n",[992,27510,27508],{"__ignoreMap":1357},[981,27512,27514],{"id":27513},"bài-2-autocomplete","Bài 2: Autocomplete",[973,27516,27517,27520,27521,27524,27525,27528,27529,16014],{},[992,27518,27519],{},"std::vector\u003Cstd::string> complete(const std::string &prefix, int limit)",". Tiền tố có thể kết thúc ",[1487,27522,27523],{},"giữa"," một nhãn cạnh (ví dụ ",[992,27526,27527],{},"\"roma\""," nằm giữa cạnh ",[992,27530,27531],{},"\"an\"",[1352,27533,27536],{"className":27534,"code":27535,"language":2241,"meta":1357},[2239],"complete(\"ro\", 10)    -> [rom, romane, romulus, ...]\ncomplete(\"roma\", 10)  -> [romane]\ncomplete(\"x\", 10)     -> []\n",[992,27537,27535],{"__ignoreMap":1357},[973,27539,27540,27541,27544],{},"Nạp 100.000 từ. So số nút và thời gian ",[992,27542,27543],{},"complete"," với trie ngày 35.",[981,27546,27548],{"id":27547},"bài-3-spell-check-đơn-giản-nâng-cao","Bài 3: Spell-check đơn giản (nâng cao)",[973,27550,27551,27554,27555,27558,27559,1517],{},[992,27552,27553],{},"std::vector\u003Cstd::string> suggestFix(const std::string &w, int maxDist)",": trả các từ trong trie có khoảng cách Levenshtein với ",[992,27556,27557],{},"w"," không quá ",[992,27560,27561],{},"maxDist",[973,27563,27564,27565,1517],{},"Không tính khoảng cách với từng từ trong từ điển. Duyệt trie và giữ một hàng của bảng DP cho mỗi nút, cắt nhánh khi giá trị nhỏ nhất của hàng vượt ",[992,27566,27561],{},[1352,27568,27571],{"className":27569,"code":27570,"language":2241,"meta":1357},[2239],"từ điển có \"hello\", \"help\", \"shell\"; suggestFix(\"helo\", 1) -> [hello, help]\n",[992,27572,27570],{"__ignoreMap":1357},[981,27574,2711],{"id":2710},[986,27576,27578,27584,27592,27598],{"className":27577},[2715],[989,27579,27581,27583],{"className":27580},[2719],[2721,27582],{"disabled":2723,"type":2724}," Test tách cạnh và gộp cạnh pass.",[989,27585,27587,2308,27589,27591],{"className":27586},[2719],[2721,27588],{"disabled":2723,"type":2724},[992,27590,27543],{}," đúng khi tiền tố dừng giữa nhãn.",[989,27593,27595,27597],{"className":27594},[2719],[2721,27596],{"disabled":2723,"type":2724}," Bảng so sánh số nút với trie thường có số thật.",[989,27599,27601,27603],{"className":27600},[2719],[2721,27602],{"disabled":2723,"type":2724}," Bài 3 cắt nhánh đúng, nhanh hơn rõ so với duyệt hết từ điển.",[968,27605,2890],{"id":2889},[986,27607,27608,27611,27614,27617],{},[989,27609,27610],{},"Radix trie nén cạnh đơn thế nào?",[989,27612,27613],{},"Tách cạnh xảy ra khi nào khi chèn?",[989,27615,27616],{},"Autocomplete gồm 2 bước nào?",[989,27618,27619],{},"Vì sao gợi ý nhanh dù từ điển lớn?",[3014,27621],{},[973,27623,27624],{},"🌕 Bạn đã hoàn thành ngày 36. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,27626,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":27628},[27629,27630,27635,27636,27642],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":27631},[27632,27633,27634],{"id":27258,"depth":73,"text":27259},{"id":27276,"depth":73,"text":27277},{"id":27294,"depth":73,"text":27295},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":27637},[27638,27639,27640,27641],{"id":27459,"depth":73,"text":27460},{"id":27513,"depth":73,"text":27514},{"id":27547,"depth":73,"text":27548},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nén trie thành radix trie gọn nhẹ, rồi khai thác autocomplete, kiểm tra chính tả, T9 và sắp xếp chuỗi.",{},[3050],{"title":235,"description":27643},[27648],"radix-trie","Rn6KgQ9NUGM2FgbJ9ORi_bpKsiinUn9WeDsVHj9tu4A",{"id":27651,"title":240,"body":27652,"category":5189,"day":243,"description":28095,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":28096,"navigation":2723,"outcomes":3047,"path":241,"prerequisites":28097,"seo":28098,"stem":242,"tags":28099,"__hash__":28102},"challenges\u002Fchallenges\u002F37.iterator-pattern.md",{"type":965,"value":27653,"toc":28079},[27654,27656,27659,27661,27665,27679,27683,27697,27727,27731,27745,27794,27796,27810,27812,27819,27823,27843,27918,27933,27939,27953,27957,27984,27990,27994,28012,28015,28018,28020,28056,28058,28072,28074,28077],[968,27655,971],{"id":970},[973,27657,27658],{},"Bài này học Iterator duyệt nhiều cấu trúc bằng một cách chung.\nMẫu này giúp giấu cách lưu để đổi tự do.",[968,27660,979],{"id":978},[981,27662,27664],{"id":27663},"iterator-là-gì","Iterator là gì",[986,27666,27667,27670,27673,27676],{},[989,27668,27669],{},"Iterator cho cách duyệt tuần tự mà giấu cách lưu.",[989,27671,27672],{},"Mỗi thực đơn tự tạo bộ duyệt hiểu cấu trúc của nó.",[989,27674,27675],{},"Phục vụ chỉ dùng giao diện chung: còn món, lấy tiếp.",[989,27677,27678],{},"Ví dụ đời thường: một remote dùng chung nhiều đầu máy.",[981,27680,27682],{"id":27681},"hai-quán-hai-cách-lưu","Hai quán hai cách lưu",[986,27684,27685,27688,27691,27694],{},[989,27686,27687],{},"Quán bánh lưu danh sách động vì món đổi theo mùa.",[989,27689,27690],{},"Quán tối lưu mảng cố định vì món ổn định.",[989,27692,27693],{},"Không Iterator: phục vụ phải học cả hai cách duyệt.",[989,27695,27696],{},"Có Iterator: phục vụ xin bộ duyệt rồi duyệt như nhau.",[1352,27698,27700],{"className":3538,"code":27699,"language":3540,"meta":1357,"style":1357},"# Phục vụ duyệt chung không cần biết cách lưu\ndef in_thuc_don(duyet_a, duyet_b):\n    for duyet in (duyet_a, duyet_b):  # 2 quán\n        while duyet.con_mon():  # hỏi còn món không\n            print(duyet.lay_tiep())  # lấy món tiếp\n",[992,27701,27702,27707,27712,27717,27722],{"__ignoreMap":1357},[1023,27703,27704],{"class":1362,"line":63},[1023,27705,27706],{},"# Phục vụ duyệt chung không cần biết cách lưu\n",[1023,27708,27709],{"class":1362,"line":68},[1023,27710,27711],{},"def in_thuc_don(duyet_a, duyet_b):\n",[1023,27713,27714],{"class":1362,"line":73},[1023,27715,27716],{},"    for duyet in (duyet_a, duyet_b):  # 2 quán\n",[1023,27718,27719],{"class":1362,"line":78},[1023,27720,27721],{},"        while duyet.con_mon():  # hỏi còn món không\n",[1023,27723,27724],{"class":1362,"line":83},[1023,27725,27726],{},"            print(duyet.lay_tiep())  # lấy món tiếp\n",[981,27728,27730],{"id":27729},"đơn-trách-nhiệm","Đơn trách nhiệm",[986,27732,27733,27736,27739,27742],{},[989,27734,27735],{},"Thực đơn chỉ lo giữ món ăn.",[989,27737,27738],{},"Bộ duyệt chỉ lo đi từng món.",[989,27740,27741],{},"Phục vụ chỉ lo in và tiếp khách.",[989,27743,27744],{},"Ví dụ đời thường: bếp nấu, bồi bàn bưng, thu ngân tính.",[1099,27746,27747,27759],{},[1102,27748,27749],{},[1105,27750,27751,27753,27756],{},[1108,27752,5414],{},[1108,27754,27755],{},"Tự duyệt",[1108,27757,27758],{},"Qua bộ duyệt",[1118,27760,27761,27772,27783],{},[1105,27762,27763,27766,27769],{},[1123,27764,27765],{},"Biết cách lưu",[1123,27767,27768],{},"Biết hết",[1123,27770,27771],{},"Không cần biết",[1105,27773,27774,27777,27780],{},[1123,27775,27776],{},"Đổi cách lưu",[1123,27778,27779],{},"Sửa phục vụ",[1123,27781,27782],{},"Sửa đúng bộ duyệt",[1105,27784,27785,27788,27791],{},[1123,27786,27787],{},"Thêm quán mới",[1123,27789,27790],{},"Mở phục vụ",[1123,27792,27793],{},"Thêm bộ duyệt mới",[968,27795,1433],{"id":1432},[986,27797,27798,27801,27804,27807],{},[989,27799,27800],{},"Input: in thực đơn chung 2 quán -> Output: đủ món, đúng thứ tự, không lặp.",[989,27802,27803],{},"Câu này cho thấy một vòng lặp duyệt cả hai quán.",[989,27805,27806],{},"Input: đổi cách lưu quán tối -> Output: thực đơn in ra y hệt, phục vụ không sửa.",[989,27808,27809],{},"Câu này cho thấy giấu cách lưu rất lợi.",[968,27811,1482],{"id":1481},[973,27813,1485,27814,4801,27816,1517],{},[1487,27815,4800],{},[992,27817,27818],{},"day-037\u002F",[981,27820,27822],{"id":27821},"bài-1-hai-quán-một-phục-vụ","Bài 1: Hai quán, một phục vụ",[1352,27824,27826],{"className":1393,"code":27825,"language":1395,"meta":1357,"style":1357},"struct MenuItem { std::string name; double price; bool vegetarian; };\ntemplate \u003Cclass T> struct Iterator { virtual bool hasNext() const = 0; virtual T next() = 0; virtual ~Iterator() = default; };\nstruct Menu { virtual std::unique_ptr\u003CIterator\u003CMenuItem>> createIterator() const = 0; virtual ~Menu() = default; };\n",[992,27827,27828,27833,27838],{"__ignoreMap":1357},[1023,27829,27830],{"class":1362,"line":63},[1023,27831,27832],{},"struct MenuItem { std::string name; double price; bool vegetarian; };\n",[1023,27834,27835],{"class":1362,"line":68},[1023,27836,27837],{},"template \u003Cclass T> struct Iterator { virtual bool hasNext() const = 0; virtual T next() = 0; virtual ~Iterator() = default; };\n",[1023,27839,27840],{"class":1362,"line":73},[1023,27841,27842],{},"struct Menu { virtual std::unique_ptr\u003CIterator\u003CMenuItem>> createIterator() const = 0; virtual ~Menu() = default; };\n",[1099,27844,27845,27857],{},[1102,27846,27847],{},[1105,27848,27849,27851,27854],{},[1108,27850,4881],{},[1108,27852,27853],{},"Cách lưu",[1108,27855,27856],{},"Iterator",[1118,27858,27859,27876,27901],{},[1105,27860,27861,27866,27871],{},[1123,27862,27863],{},[992,27864,27865],{},"PancakeHouseMenu",[1123,27867,27868],{},[992,27869,27870],{},"std::vector\u003CMenuItem>",[1123,27872,27873],{},[992,27874,27875],{},"VectorIterator",[1105,27877,27878,27883,27892],{},[1123,27879,27880],{},[992,27881,27882],{},"DinerMenu",[1123,27884,27885,27888,27889],{},[992,27886,27887],{},"MenuItem items[6]"," + ",[992,27890,27891],{},"int count",[1123,27893,27894,27897,27898],{},[992,27895,27896],{},"ArrayIterator",", dừng ở ",[992,27899,27900],{},"count",[1105,27902,27903,27908,27913],{},[1123,27904,27905],{},[992,27906,27907],{},"CafeMenu",[1123,27909,27910],{},[992,27911,27912],{},"std::unordered_map\u003Cstd::string, MenuItem>",[1123,27914,27915],{},[992,27916,27917],{},"MapIterator",[973,27919,27920,5016,27923,27926,27927,1509,27930,1517],{},[992,27921,27922],{},"Waitress",[992,27924,27925],{},"std::vector\u003Cconst Menu*>",". Có ",[992,27928,27929],{},"printMenu()",[992,27931,27932],{},"printVegetarianMenu()",[1352,27934,27937],{"className":27935,"code":27936,"language":2241,"meta":1357},[2239],"printMenu() -> in đủ món 3 quán, mỗi quán theo thứ tự lưu của nó\nDinerMenu thêm món thứ 7 -> ném length_error\nnext() khi hết món      -> ném out_of_range\n",[992,27938,27936],{"__ignoreMap":1357},[973,27940,27941,2308,27943,27945,27946,27948,27949,27952],{},[1487,27942,6076],{},[992,27944,27922],{}," không biết ",[992,27947,2535],{},", mảng hay ",[992,27950,27951],{},"map"," nào.",[981,27954,27956],{"id":27955},"bài-2-iterator-theo-chuẩn-c","Bài 2: Iterator theo chuẩn C++",[973,27958,27959,27960,27963,27964,27967,27968,1656,27971,27974,27975,1656,27978,1656,27981,1517],{},"Viết lớp ",[992,27961,27962],{},"Range(int start, int stop, int step)"," dùng được trong ",[992,27965,27966],{},"for (int x : Range(0, 10, 3))",". Cần ",[992,27969,27970],{},"begin()",[992,27972,27973],{},"end()",", iterator có ",[992,27976,27977],{},"operator*",[992,27979,27980],{},"operator++",[992,27982,27983],{},"operator!=",[1352,27985,27988],{"className":27986,"code":27987,"language":2241,"meta":1357},[2239],"Range(0, 10, 3)   -> 0 3 6 9\nRange(10, 0, -4)  -> 10 6 2\nRange(0, 0, 1)    -> không in gì\nstep = 0          -> ném invalid_argument\n",[992,27989,27987],{"__ignoreMap":1357},[981,27991,27993],{"id":27992},"bài-3-iterator-lười-và-lọc-nâng-cao","Bài 3: Iterator lười và lọc (nâng cao)",[973,27995,1505,27996,27999,28000,28002,28003,7423,28005,28008,28009,28011],{},[992,27997,27998],{},"FilterIterator\u003CT>"," bọc một iterator khác và một hàm ",[992,28001,13646],{},", chỉ trả phần tử thỏa ",[992,28004,13646],{},[992,28006,28007],{},"TakeIterator\u003CT>"," chỉ trả ",[992,28010,1262],{}," phần tử đầu.",[973,28013,28014],{},"Dùng chúng để in 3 món chay đầu tiên của cả 3 quán mà không tạo vector trung gian.",[973,28016,28017],{},"Viết 3 câu: Iterator giúp giữ nguyên lý đơn trách nhiệm như thế nào trong bài này.",[981,28019,2711],{"id":2710},[986,28021,28023,28028,28041,28050],{"className":28022},[2715],[989,28024,28026,11986],{"className":28025},[2719],[2721,28027],{"disabled":2723,"type":2724},[989,28029,28031,28033,28034,15919,28036,5034,28038,28040],{"className":28030},[2719],[2721,28032],{"disabled":2723,"type":2724}," Đổi cách lưu ",[992,28035,27882],{},[992,28037,3567],{},[992,28039,27922],{}," không sửa.",[989,28042,28044,2308,28046,28049],{"className":28043},[2719],[2721,28045],{"disabled":2723,"type":2724},[992,28047,28048],{},"Range"," dùng được với range-based for.",[989,28051,28053,28055],{"className":28052},[2719],[2721,28054],{"disabled":2723,"type":2724}," Bài 3 không cấp phát vector trung gian.",[968,28057,2890],{"id":2889},[986,28059,28060,28063,28066,28069],{},[989,28061,28062],{},"Iterator giấu cách lưu thế nào?",[989,28064,28065],{},"Hai quán lưu thực đơn khác nhau ra sao?",[989,28067,28068],{},"Ai tạo bộ duyệt, ai dùng bộ duyệt?",[989,28070,28071],{},"Khi nào không cần dùng Iterator?",[3014,28073],{},[973,28075,28076],{},"🌕 Bạn đã hoàn thành ngày 37. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,28078,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":28080},[28081,28082,28087,28088,28094],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":28083},[28084,28085,28086],{"id":27663,"depth":73,"text":27664},{"id":27681,"depth":73,"text":27682},{"id":27729,"depth":73,"text":27730},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":28089},[28090,28091,28092,28093],{"id":27821,"depth":73,"text":27822},{"id":27955,"depth":73,"text":27956},{"id":27992,"depth":73,"text":27993},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Iterator, hai quán ăn hai cách lưu thực đơn, và cách tách trách nhiệm duyệt khỏi trách nhiệm phục vụ.",{},[5194,5195],{"title":240,"description":28095},[28100,28101],"iterator","srp","X_1XVkr_cmuLOPKxA0AUnq0D1hjzTHl3Z8OpdVoUo3o",{"id":28104,"title":245,"body":28105,"category":3041,"day":248,"description":28656,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":28657,"navigation":2723,"outcomes":3047,"path":246,"prerequisites":28658,"seo":28659,"stem":247,"tags":28660,"__hash__":28661},"challenges\u002Fchallenges\u002F38.hash-table-nang-cao.md",{"type":965,"value":28106,"toc":28640},[28107,28109,28155,28157,28161,28175,28179,28193,28197,28211,28361,28363,28377,28379,28394,28398,28457,28467,28473,28477,28487,28493,28497,28587,28589,28619,28621,28635,28637],[968,28108,971],{"id":970},[973,28110,28111,28112,1517],{},"Bài này học hàm băm tốt và cách xử lý xung đột.\nKiến thức này giúp bảng băm luôn nhanh ",[1023,28113,28115,28134],{"className":28114},[1026],[1023,28116,28118],{"className":28117},[1030],[1032,28119,28120],{"xmlns":1034},[1036,28121,28122,28132],{},[1039,28123,28124,28126,28128,28130],{},[1042,28125,1044],{},[1046,28127,1049],{"stretchy":1048},[1051,28129,1053],{},[1046,28131,1056],{"stretchy":1048},[1058,28133,1061],{"encoding":1060},[1023,28135,28137],{"className":28136,"ariaHidden":1066},[1065],[1023,28138,28140,28143,28146,28149,28152],{"className":28139},[1070],[1023,28141],{"className":28142,"style":1075},[1074],[1023,28144,1044],{"className":28145,"style":1081},[1079,1080],[1023,28147,1049],{"className":28148},[1085],[1023,28150,1053],{"className":28151},[1079],[1023,28153,1056],{"className":28154},[1092],[968,28156,979],{"id":978},[981,28158,28160],{"id":28159},"hàm-băm-tốt","Hàm băm tốt",[986,28162,28163,28166,28169,28172],{},[989,28164,28165],{},"Xác định: cùng đầu vào luôn cho cùng đầu ra.",[989,28167,28168],{},"Đều: khóa rải khắp các ô, không dồn một chỗ.",[989,28170,28171],{},"Nhanh: tính trong tích tắc vì gọi rất nhiều lần.",[989,28173,28174],{},"Ví dụ đời thường: chia đều thư vào các hộc tủ.",[981,28176,28178],{"id":28177},"hai-họ-xử-lý-xung-đột","Hai họ xử lý xung đột",[986,28180,28181,28184,28187,28190],{},[989,28182,28183],{},"Móc nối: mỗi ô giữ danh sách các khóa cùng rơi vào.",[989,28185,28186],{},"Địa chỉ mở: ô đầy thì dò ô trống lân cận theo quy tắc.",[989,28188,28189],{},"Móc nối xóa dễ, chịu tải cao; địa chỉ mở gọn cache.",[989,28191,28192],{},"Ví dụ đời thường: hai xe trùng chỗ, một xếp chồng, một đậu chỗ bên.",[981,28194,28196],{"id":28195},"hệ-số-tải-và-băm-lại","Hệ số tải và băm lại",[986,28198,28199,28202,28205,28208],{},[989,28200,28201],{},"Hệ số tải = số phần tử chia số ô.",[989,28203,28204],{},"Tải cao thì xung đột nhiều, mọi thứ chậm dần.",[989,28206,28207],{},"Vượt ngưỡng 0.75 thì băm lại sang bảng gấp đôi.",[989,28209,28210],{},"Ví dụ đời thường: tủ đầy thì mua tủ to gấp đôi.",[1099,28212,28213,28226],{},[1102,28214,28215],{},[1105,28216,28217,28220,28223],{},[1108,28218,28219],{},"Lựa chọn",[1108,28221,28222],{},"Mạnh",[1108,28224,28225],{},"Yếu",[1118,28227,28228,28281,28350],{},[1105,28229,28230,28233,28278],{},[1123,28231,28232],{},"Bảng băm",[1123,28234,28235,1230],{},[1023,28236,28238,28257],{"className":28237},[1026],[1023,28239,28241],{"className":28240},[1030],[1032,28242,28243],{"xmlns":1034},[1036,28244,28245,28255],{},[1039,28246,28247,28249,28251,28253],{},[1042,28248,1044],{},[1046,28250,1049],{"stretchy":1048},[1051,28252,1053],{},[1046,28254,1056],{"stretchy":1048},[1058,28256,1061],{"encoding":1060},[1023,28258,28260],{"className":28259,"ariaHidden":1066},[1065],[1023,28261,28263,28266,28269,28272,28275],{"className":28262},[1070],[1023,28264],{"className":28265,"style":1075},[1074],[1023,28267,1044],{"className":28268,"style":1081},[1079,1080],[1023,28270,1049],{"className":28271},[1085],[1023,28273,1053],{"className":28274},[1079],[1023,28276,1056],{"className":28277},[1092],[1123,28279,28280],{},"Mất thứ tự",[1105,28282,28283,28286,28347],{},[1123,28284,28285],{},"Cây tìm kiếm",[1123,28287,28288,28289],{},"Giữ thứ tự, ",[1023,28290,28292,28317],{"className":28291},[1026],[1023,28293,28295],{"className":28294},[1030],[1032,28296,28297],{"xmlns":1034},[1036,28298,28299,28315],{},[1039,28300,28301,28303,28305,28307,28309,28311,28313],{},[1042,28302,1044],{},[1046,28304,1049],{"stretchy":1048},[1042,28306,7684],{},[1042,28308,7687],{},[1042,28310,7690],{},[1042,28312,1262],{},[1046,28314,1056],{"stretchy":1048},[1058,28316,7697],{"encoding":1060},[1023,28318,28320],{"className":28319,"ariaHidden":1066},[1065],[1023,28321,28323,28326,28329,28332,28335,28338,28341,28344],{"className":28322},[1070],[1023,28324],{"className":28325,"style":1075},[1074],[1023,28327,1044],{"className":28328,"style":1081},[1079,1080],[1023,28330,1049],{"className":28331},[1085],[1023,28333,7684],{"className":28334,"style":7716},[1079,1080],[1023,28336,7687],{"className":28337},[1079,1080],[1023,28339,7690],{"className":28340,"style":7723},[1079,1080],[1023,28342,1262],{"className":28343},[1079,1080],[1023,28345,1056],{"className":28346},[1092],[1123,28348,28349],{},"Chậm hơn băm",[1105,28351,28352,28355,28358],{},[1123,28353,28354],{},"Bloom filter",[1123,28356,28357],{},"Siêu nhẹ",[1123,28359,28360],{},"Có dương tính giả",[968,28362,1433],{"id":1432},[986,28364,28365,28368,28371,28374],{},[989,28366,28367],{},"Input: chèn 5 khóa vào bảng 8 ô có 1 cặp xung đột -> Output: cặp đó nằm chung xô móc nối.",[989,28369,28370],{},"Câu này cho thấy xung đột là bình thường và xử lý được.",[989,28372,28373],{},"Input: chèn vượt ngưỡng 0.75 -> Output: kích hoạt băm lại, mọi khóa vẫn tìm thấy.",[989,28375,28376],{},"Câu này cho thấy giám sát tải rất quan trọng.",[968,28378,1482],{"id":1481},[973,28380,1485,28381,2256,28383,5599,28385,28388,28389,28391,28392,1517],{},[1487,28382,1493],{},[992,28384,6637],{},[992,28386,28387],{},"day-038\u002F",". Khóa ",[992,28390,23400],{},", giá trị ",[992,28393,1516],{},[981,28395,28397],{"id":28396},"bài-1-hash-map-móc-nối-separate-chaining","Bài 1: Hash map móc nối (separate chaining)",[1099,28399,28400,28408],{},[1102,28401,28402],{},[1105,28403,28404,28406],{},[1108,28405,1566],{},[1108,28407,2547],{},[1118,28409,28410,28420,28429,28438,28448],{},[1105,28411,28412,28417],{},[1123,28413,28414],{},[992,28415,28416],{},"void put(const std::string &k, int v)",[1123,28418,28419],{},"Có rồi thì ghi đè",[1105,28421,28422,28427],{},[1123,28423,28424],{},[992,28425,28426],{},"std::optional\u003Cint> get(const std::string &k) const",[1123,28428],{},[1105,28430,28431,28436],{},[1123,28432,28433],{},[992,28434,28435],{},"bool erase(const std::string &k)",[1123,28437],{},[1105,28439,28440,28446],{},[1123,28441,28442,1656,28444],{},[992,28443,6813],{},[992,28445,6816],{},[1123,28447],{},[1105,28449,28450,28452],{},[1123,28451,6823],{},[1123,28453,28454,28456],{},[992,28455,6829],{}," thì gấp đôi số bucket",[973,28458,28459,28460,28463,28464,1517],{},"Hàm băm: tự cài ",[1487,28461,28462],{},"FNV-1a 64 bit",". Số bucket là lũy thừa của 2, chỉ số là ",[992,28465,28466],{},"hash & (buckets - 1)",[1352,28468,28471],{"className":28469,"code":28470,"language":2241,"meta":1357},[2239],"put(\"an\",1), put(\"binh\",2), put(\"an\",5) -> size 2, get(\"an\") = 5\nerase(\"binh\"); get(\"binh\")              -> nullopt\nput 10.000 khóa                         -> loadFactor \u003C= 0.75, mọi khóa get đúng\n",[992,28472,28470],{"__ignoreMap":1357},[981,28474,28476],{"id":28475},"bài-2-địa-chỉ-mở-dò-tuyến-tính","Bài 2: Địa chỉ mở dò tuyến tính",[973,28478,1505,28479,28482,28483,28486],{},[992,28480,28481],{},"OpenAddressingMap"," cùng API. Xóa dùng ",[1487,28484,28485],{},"bia mộ"," (tombstone). Ngưỡng rehash 0.5, tính cả bia mộ.",[1352,28488,28491],{"className":28489,"code":28490,"language":2241,"meta":1357},[2239],"put A, B, C cùng rơi vào ô 3 (dùng hàm băm giả để test) -> nằm ở ô 3, 4, 5\nerase B; get C                                         -> vẫn tìm thấy (nhờ bia mộ)\nput D rơi vào ô 3                                      -> dùng lại ô 4 của B\n",[992,28492,28490],{"__ignoreMap":1357},[981,28494,28496],{"id":28495},"bài-3-đo-và-tấn-công-hàm-băm-nâng-cao","Bài 3: Đo và tấn công hàm băm (nâng cao)",[2273,28498,28499,28573,28580],{},[989,28500,28501,28502,1509,28505,2308,28508,28569,28570,28572],{},"Đo ",[992,28503,28504],{},"put",[992,28506,28507],{},"get",[1023,28509,28511,28528],{"className":28510},[1026],[1023,28512,28514],{"className":28513},[1030],[1032,28515,28516],{"xmlns":1034},[1036,28517,28518,28526],{},[1039,28519,28520],{},[2327,28521,28522,28524],{},[1051,28523,2331],{},[1051,28525,6866],{},[1058,28527,6869],{"encoding":1060},[1023,28529,28531],{"className":28530,"ariaHidden":1066},[1065],[1023,28532,28534,28537,28540],{"className":28533},[1070],[1023,28535],{"className":28536,"style":2369},[1074],[1023,28538,1053],{"className":28539},[1079],[1023,28541,28543,28546],{"className":28542},[1079],[1023,28544,2379],{"className":28545},[1079],[1023,28547,28549],{"className":28548},[2383],[1023,28550,28552],{"className":28551},[2387],[1023,28553,28555],{"className":28554},[2391],[1023,28556,28558],{"className":28557,"style":2369},[2395],[1023,28559,28560,28563],{"style":2398},[1023,28561],{"className":28562,"style":2403},[2402],[1023,28564,28566],{"className":28565},[2407,2408,2409,2410],[1023,28567,6866],{"className":28568},[1079,2410]," khóa ngẫu nhiên cho 2 cách cài và ",[992,28571,6637],{},". In bảng.",[989,28574,28575,28576,28579],{},"Vẽ độ dài chuỗi dài nhất theo hệ số tải ",[992,28577,28578],{},"0.25, 0.5, 0.75, 1, 2"," cho bản móc nối.",[989,28581,28582,28583,28586],{},"Thay hàm băm bằng hàm tệ ",[992,28584,28585],{},"h(s) = s.size()",". Đo lại và giải thích vì sao chậm hẳn. Viết 2 câu về tấn công HashDoS.",[981,28588,2711],{"id":2710},[986,28590,28592,28601,28607,28613],{"className":28591},[2715],[989,28593,28595,28597,28598,1517],{"className":28594},[2719],[2721,28596],{"disabled":2723,"type":2724}," Test mẫu pass cho cả 2 cách cài. Có test ngẫu nhiên so với ",[992,28599,28600],{},"std::map",[989,28602,28604,28606],{"className":28603},[2719],[2721,28605],{"disabled":2723,"type":2724}," Bia mộ hoạt động: xóa rồi vẫn tìm được khóa phía sau.",[989,28608,28610,28612],{"className":28609},[2719],[2721,28611],{"disabled":2723,"type":2724}," Bảng đo Bài 3 có số thật.",[989,28614,28616,28618],{"className":28615},[2719],[2721,28617],{"disabled":2723,"type":2724}," Giải thích được ưu nhược của móc nối và địa chỉ mở (cache, xóa, tải cao).",[968,28620,2890],{"id":2889},[986,28622,28623,28626,28629,28632],{},[989,28624,28625],{},"3 tính chất của hàm băm tốt là gì?",[989,28627,28628],{},"Móc nối và địa chỉ mở khác nhau sao?",[989,28630,28631],{},"Hệ số tải cao gây hại gì?",[989,28633,28634],{},"Khi nào chọn cây thay vì bảng băm?",[3014,28636],{},[973,28638,28639],{},"🌕 Bạn đã hoàn thành ngày 38. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":28641},[28642,28643,28648,28649,28655],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":28644},[28645,28646,28647],{"id":28159,"depth":73,"text":28160},{"id":28177,"depth":73,"text":28178},{"id":28195,"depth":73,"text":28196},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":28650},[28651,28652,28653,28654],{"id":28396,"depth":73,"text":28397},{"id":28475,"depth":73,"text":28476},{"id":28495,"depth":73,"text":28496},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đào sâu hàm băm tốt, hai họ xử lý xung đột, hệ số tải và nghệ thuật so sánh bảng băm với cây và Bloom filter.",{},[3050,17499],{"title":245,"description":28656},[7036],"B9Sqlzl8u5YzBztn3yRq13zkJSvR1zArGsMjJrY9g5E",{"id":28663,"title":250,"body":28664,"category":3041,"day":253,"description":29120,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":29121,"navigation":2723,"outcomes":3047,"path":251,"prerequisites":29122,"seo":29123,"stem":252,"tags":29124,"__hash__":29126},"challenges\u002Fchallenges\u002F39.lru-cache.md",{"type":965,"value":28665,"toc":29104},[28666,28668,28671,28673,28677,28691,28695,28709,28713,28771,28816,28818,28832,28834,28847,28851,28893,28958,28964,28969,28973,29011,29015,29047,29049,29081,29083,29097,29099,29102],[968,28667,971],{"id":970},[973,28669,28670],{},"Bài này học cache ghi nhớ kết quả để trả lời nhanh.\nCache này giúp vượt trần 3.5 giây của bài tóm tắt.",[968,28672,979],{"id":978},[981,28674,28676],{"id":28675},"vì-sao-cần-cache","Vì sao cần cache",[986,28678,28679,28682,28685,28688],{},[989,28680,28681],{},"Tính tóm tắt tốn 250ms mỗi nguồn, dễ vượt 3.5 giây.",[989,28683,28684],{},"Mỗi công ty mỗi ngày chỉ cần một bản tóm tắt.",[989,28686,28687],{},"Tính một lần rồi cất lại, lần sau đọc ra ngay.",[989,28689,28690],{},"Ví dụ đời thường: photo tài liệu một lần, lần sau lấy bản photo.",[981,28692,28694],{"id":28693},"tươi-mới-và-đang-tải","Tươi mới và đang tải",[986,28696,28697,28700,28703,28706],{},[989,28698,28699],{},"Dữ liệu có hạn dùng, qua ngày mới phải tính lại.",[989,28701,28702],{},"Nhiều luồng cùng hỏi khóa chưa có thì dễ tính trùng.",[989,28704,28705],{},"Cờ đang tải: một luồng tính, các luồng khác chờ.",[989,28707,28708],{},"Ví dụ đời thường: một người xếp hàng mua, cả nhóm chờ chia nhau.",[981,28710,28712],{"id":28711},"lru-đuổi-kẻ-cũ-nhất","LRU đuổi kẻ cũ nhất",[986,28714,28715,28718,28765,28768],{},[989,28716,28717],{},"Bộ nhớ đầy thì đuổi món lâu nhất không dùng.",[989,28719,28720,28721,28764],{},"Cài đặt: dict tra ",[1023,28722,28724,28743],{"className":28723},[1026],[1023,28725,28727],{"className":28726},[1030],[1032,28728,28729],{"xmlns":1034},[1036,28730,28731,28741],{},[1039,28732,28733,28735,28737,28739],{},[1042,28734,1044],{},[1046,28736,1049],{"stretchy":1048},[1051,28738,1053],{},[1046,28740,1056],{"stretchy":1048},[1058,28742,1061],{"encoding":1060},[1023,28744,28746],{"className":28745,"ariaHidden":1066},[1065],[1023,28747,28749,28752,28755,28758,28761],{"className":28748},[1070],[1023,28750],{"className":28751,"style":1075},[1074],[1023,28753,1044],{"className":28754,"style":1081},[1079,1080],[1023,28756,1049],{"className":28757},[1085],[1023,28759,1053],{"className":28760},[1079],[1023,28762,1056],{"className":28763},[1092]," cộng danh sách đôi giữ thứ tự.",[989,28766,28767],{},"Trúng thì nhấc lên đầu, thêm mới thì cắt đuôi.",[989,28769,28770],{},"Ví dụ đời thường: tủ lạnh đầy thì bỏ món cũ nhất.",[1352,28772,28774],{"className":3538,"code":28773,"language":3540,"meta":1357,"style":1357},"# Ý tưởng LRU: mới dùng thì lên đầu\nfrom collections import OrderedDict\ncache = OrderedDict()  # giữ thứ tự dùng\ndef lay(k):\n    if k in cache:  # trúng cache\n        cache.move_to_end(k, last=False)  # nhấc lên đầu\n        return cache[k]\n    return None  # trượt thì đi tính thật\n",[992,28775,28776,28781,28786,28791,28796,28801,28806,28811],{"__ignoreMap":1357},[1023,28777,28778],{"class":1362,"line":63},[1023,28779,28780],{},"# Ý tưởng LRU: mới dùng thì lên đầu\n",[1023,28782,28783],{"class":1362,"line":68},[1023,28784,28785],{},"from collections import OrderedDict\n",[1023,28787,28788],{"class":1362,"line":73},[1023,28789,28790],{},"cache = OrderedDict()  # giữ thứ tự dùng\n",[1023,28792,28793],{"class":1362,"line":78},[1023,28794,28795],{},"def lay(k):\n",[1023,28797,28798],{"class":1362,"line":83},[1023,28799,28800],{},"    if k in cache:  # trúng cache\n",[1023,28802,28803],{"class":1362,"line":88},[1023,28804,28805],{},"        cache.move_to_end(k, last=False)  # nhấc lên đầu\n",[1023,28807,28808],{"class":1362,"line":93},[1023,28809,28810],{},"        return cache[k]\n",[1023,28812,28813],{"class":1362,"line":98},[1023,28814,28815],{},"    return None  # trượt thì đi tính thật\n",[968,28817,1433],{"id":1432},[986,28819,28820,28823,28826,28829],{},[989,28821,28822],{},"Input: cache rỗng, hỏi khóa A -> Output: miss, đi tính thật rồi ghi lại.",[989,28824,28825],{},"Câu này cho thấy lần đầu luôn chậm để làm ấm.",[989,28827,28828],{},"Input: cache đầy 3 khóa, thêm khóa thứ 4 -> Output: khóa cũ nhất bị đuổi.",[989,28830,28831],{},"Câu này cho thấy quy tắc cắt đuôi hoạt động.",[968,28833,1482],{"id":1481},[973,28835,1485,28836,28838,28839,28841,28842,5599,28844,1517],{},[1487,28837,1493],{},". Tự cài danh sách đôi và dùng ",[992,28840,6637],{}," cho tra cứu. Không dùng ",[992,28843,3567],{},[992,28845,28846],{},"day-039\u002F",[981,28848,28850],{"id":28849},"bài-1-lru-cache","Bài 1: LRU cache",[1352,28852,28854],{"className":1393,"code":28853,"language":1395,"meta":1357,"style":1357},"class LRUCache {\n public:\n  explicit LRUCache(size_t capacity);       \u002F\u002F capacity = 0 thì ném invalid_argument\n  std::optional\u003Cint> get(int key);          \u002F\u002F trúng thì đưa lên đầu\n  void put(int key, int value);             \u002F\u002F có rồi thì cập nhật và đưa lên đầu; đầy thì đuổi đuôi\n  size_t size() const;\n  std::vector\u003Cint> keysMostRecentFirst() const;   \u002F\u002F để test thứ tự\n};\n",[992,28855,28856,28861,28865,28870,28875,28880,28884,28889],{"__ignoreMap":1357},[1023,28857,28858],{"class":1362,"line":63},[1023,28859,28860],{},"class LRUCache {\n",[1023,28862,28863],{"class":1362,"line":68},[1023,28864,4836],{},[1023,28866,28867],{"class":1362,"line":73},[1023,28868,28869],{},"  explicit LRUCache(size_t capacity);       \u002F\u002F capacity = 0 thì ném invalid_argument\n",[1023,28871,28872],{"class":1362,"line":78},[1023,28873,28874],{},"  std::optional\u003Cint> get(int key);          \u002F\u002F trúng thì đưa lên đầu\n",[1023,28876,28877],{"class":1362,"line":83},[1023,28878,28879],{},"  void put(int key, int value);             \u002F\u002F có rồi thì cập nhật và đưa lên đầu; đầy thì đuổi đuôi\n",[1023,28881,28882],{"class":1362,"line":88},[1023,28883,7853],{},[1023,28885,28886],{"class":1362,"line":93},[1023,28887,28888],{},"  std::vector\u003Cint> keysMostRecentFirst() const;   \u002F\u002F để test thứ tự\n",[1023,28890,28891],{"class":1362,"line":98},[1023,28892,4866],{},[1099,28894,28895,28903],{},[1102,28896,28897],{},[1105,28898,28899,28901],{},[1108,28900,1110],{},[1108,28902,1113],{},[1118,28904,28905],{},[1105,28906,28907,28913],{},[1123,28908,28909,1656,28911],{},[992,28910,28507],{},[992,28912,28504],{},[1123,28914,28915],{},[1023,28916,28918,28937],{"className":28917},[1026],[1023,28919,28921],{"className":28920},[1030],[1032,28922,28923],{"xmlns":1034},[1036,28924,28925,28935],{},[1039,28926,28927,28929,28931,28933],{},[1042,28928,1044],{},[1046,28930,1049],{"stretchy":1048},[1051,28932,1053],{},[1046,28934,1056],{"stretchy":1048},[1058,28936,1061],{"encoding":1060},[1023,28938,28940],{"className":28939,"ariaHidden":1066},[1065],[1023,28941,28943,28946,28949,28952,28955],{"className":28942},[1070],[1023,28944],{"className":28945,"style":1075},[1074],[1023,28947,1044],{"className":28948,"style":1081},[1079,1080],[1023,28950,1049],{"className":28951},[1085],[1023,28953,1053],{"className":28954},[1079],[1023,28956,1056],{"className":28957},[1092],[1352,28959,28962],{"className":28960,"code":28961,"language":2241,"meta":1357},[2239],"cap=2: put(1,1), put(2,2), get(1) -> 1\nput(3,3)                          -> đuổi key 2\nget(2)                            -> nullopt\nput(4,4)                          -> đuổi key 1\nget(1) -> nullopt; get(3) -> 3; get(4) -> 4\nkeysMostRecentFirst()             -> [4, 3]\n",[992,28963,28961],{"__ignoreMap":1357},[2245,28965,28966],{},[973,28967,28968],{},"Dùng nút gác đầu và gác đuôi (sentinel) để khỏi xét trường hợp danh sách rỗng khi chèn và gỡ.",[981,28970,28972],{"id":28971},"bài-2-cache-có-hạn-dùng-và-thống-kê","Bài 2: Cache có hạn dùng và thống kê",[2273,28974,28975,28993,29004],{},[989,28976,5030,28977,1838,28980,28982,28983,28986,28987,28990,28991,1517],{},[992,28978,28979],{},"put(key, value, ttlMs)",[992,28981,28507],{}," gặp mục hết hạn thì xóa và trả ",[992,28984,28985],{},"nullopt",". Dùng đồng hồ giả ",[992,28988,28989],{},"Clock&"," để test không cần ",[992,28992,16417],{},[989,28994,5030,28995,1656,28998,1656,29001,1517],{},[992,28996,28997],{},"hits()",[992,28999,29000],{},"misses()",[992,29002,29003],{},"hitRate()",[989,29005,29006,29007,29010],{},"Bọc hàm chậm ",[992,29008,29009],{},"long long slowSummary(int companyId)"," (sleep 250 ms) bằng cache. Chạy 100 truy vấn theo phân bố Zipf trên 20 công ty. In hit rate và tổng thời gian có và không có cache.",[981,29012,29014],{"id":29013},"bài-3-cache-nhiều-luồng-nâng-cao","Bài 3: Cache nhiều luồng (nâng cao)",[2273,29016,29017,29030],{},[989,29018,29019,29020,29022,29023,2461,29025,29027,29028,1517],{},"Khóa cache bằng ",[992,29021,16240],{},". 8 luồng cùng ",[992,29024,28507],{},[992,29026,28504],{}," 10^5 lần, không lỗi dưới ",[992,29029,16513],{},[989,29031,29032,29035,29036,29039,29040,29043,29044,29046],{},[1487,29033,29034],{},"Chống tính trùng:"," 10 luồng cùng hỏi 1 khóa chưa có. Chỉ 1 luồng gọi ",[992,29037,29038],{},"slowSummary",", 9 luồng còn lại chờ kết quả. Dùng ",[992,29041,29042],{},"std::shared_future",". Kiểm tra số lần gọi ",[992,29045,29038],{}," bằng 1.",[981,29048,2711],{"id":2710},[986,29050,29052,29058,29066,29075],{"className":29051},[2715],[989,29053,29055,29057],{"className":29054},[2719],[2721,29056],{"disabled":2723,"type":2724}," Test mẫu pass. Test ngẫu nhiên so với bản LRU chậm dùng vector.",[989,29059,29061,29063,29064,1517],{"className":29060},[2719],[2721,29062],{"disabled":2723,"type":2724}," TTL test bằng đồng hồ giả, không dùng ",[992,29065,16417],{},[989,29067,29069,29071,29072,29074],{"className":29068},[2719],[2721,29070],{"disabled":2723,"type":2724}," Bài 3 không có data race, và ",[992,29073,29038],{}," chỉ chạy 1 lần.",[989,29076,29078,29080],{"className":29077},[2719],[2721,29079],{"disabled":2723,"type":2724}," Giải thích được vì sao cần cả hash map lẫn danh sách đôi.",[968,29082,2890],{"id":2889},[986,29084,29085,29088,29091,29094],{},[989,29086,29087],{},"Cache ghi nhớ kết quả giúp gì?",[989,29089,29090],{},"Hạn dùng tươi mới xử lý sao?",[989,29092,29093],{},"Cờ đang tải chống tính trùng thế nào?",[989,29095,29096],{},"LRU chọn nạn nhân nào để đuổi?",[3014,29098],{},[973,29100,29101],{},"🌕 Bạn đã hoàn thành ngày 39. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,29103,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":29105},[29106,29107,29112,29113,29119],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":29108},[29109,29110,29111],{"id":28675,"depth":73,"text":28676},{"id":28693,"depth":73,"text":28694},{"id":28711,"depth":73,"text":28712},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":29114},[29115,29116,29117,29118],{"id":28849,"depth":73,"text":28850},{"id":28971,"depth":73,"text":28972},{"id":29013,"depth":73,"text":29014},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây cache ghi nhớ kết quả qua bài toán tóm tắt mạng xã hội, xử lý tươi mới, bất đồng bộ và đuổi cũ nhất.",{},[3050,4669],{"title":250,"description":29120},[29125],"cache","wBeu6MUe1TfgCj0-R351kXQd3ZJOJlomzdTGYYEIqGk",{"id":29128,"title":255,"body":29129,"category":8797,"day":258,"description":29781,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":29782,"navigation":2723,"outcomes":3047,"path":256,"prerequisites":29783,"seo":29784,"stem":257,"tags":29785,"__hash__":29788},"challenges\u002Fchallenges\u002F40.do-thi-va-bfs.md",{"type":965,"value":29130,"toc":29765},[29131,29133,29136,29138,29142,29156,29160,29174,29239,29243,29257,29259,29273,29275,29282,29286,29329,29527,29531,29592,29598,29668,29672,29705,29711,29713,29742,29744,29758,29760,29763],[968,29132,971],{"id":970},[973,29134,29135],{},"Bài này học biểu diễn đồ thị và thuật toán BFS.\nBFS này giúp tìm đường ít chặng nhất.",[968,29137,979],{"id":978},[981,29139,29141],{"id":29140},"đồ-thị-và-danh-sách-kề","Đồ thị và danh sách kề",[986,29143,29144,29147,29150,29153],{},[989,29145,29146],{},"Đồ thị gồm đỉnh nối nhau bằng cạnh.",[989,29148,29149],{},"Vô hướng như bạn bè, có hướng như theo dõi.",[989,29151,29152],{},"Danh sách kề: mỗi đỉnh lưu tập đỉnh kề nó.",[989,29154,29155],{},"Ví dụ đời thường: danh bạ lưu bạn của từng người.",[981,29157,29159],{"id":29158},"bfs-lan-theo-lớp","BFS lan theo lớp",[986,29161,29162,29165,29168,29171],{},[989,29163,29164],{},"Dùng hàng đợi FIFO: vào trước xét trước.",[989,29166,29167],{},"Cần tập đã thăm để tránh quay vòng.",[989,29169,29170],{},"Thăm hết lớp gần rồi mới sang lớp xa.",[989,29172,29173],{},"Ví dụ đời thường: sóng nước lan tròn từ tâm.",[1352,29175,29177],{"className":3538,"code":29176,"language":3540,"meta":1357,"style":1357},"# BFS: hàng đợi + tập đã thăm\nfrom collections import deque\ndef bfs(graph, start):\n    tham = {start}  # đánh dấu đã thăm\n    q = deque([start])  # hàng đợi lớp hiện tại\n    while q:  # còn nút là còn lan\n        u = q.popleft()  # lấy đầu hàng\n        for v in graph[u]:  # xét từng lân cận\n            if v not in tham:  # chưa thăm\n                tham.add(v)  # đánh dấu\n                q.append(v)  # xếp cuối hàng\n    return tham\n",[992,29178,29179,29184,29189,29194,29199,29204,29209,29214,29219,29224,29229,29234],{"__ignoreMap":1357},[1023,29180,29181],{"class":1362,"line":63},[1023,29182,29183],{},"# BFS: hàng đợi + tập đã thăm\n",[1023,29185,29186],{"class":1362,"line":68},[1023,29187,29188],{},"from collections import deque\n",[1023,29190,29191],{"class":1362,"line":73},[1023,29192,29193],{},"def bfs(graph, start):\n",[1023,29195,29196],{"class":1362,"line":78},[1023,29197,29198],{},"    tham = {start}  # đánh dấu đã thăm\n",[1023,29200,29201],{"class":1362,"line":83},[1023,29202,29203],{},"    q = deque([start])  # hàng đợi lớp hiện tại\n",[1023,29205,29206],{"class":1362,"line":88},[1023,29207,29208],{},"    while q:  # còn nút là còn lan\n",[1023,29210,29211],{"class":1362,"line":93},[1023,29212,29213],{},"        u = q.popleft()  # lấy đầu hàng\n",[1023,29215,29216],{"class":1362,"line":98},[1023,29217,29218],{},"        for v in graph[u]:  # xét từng lân cận\n",[1023,29220,29221],{"class":1362,"line":103},[1023,29222,29223],{},"            if v not in tham:  # chưa thăm\n",[1023,29225,29226],{"class":1362,"line":108},[1023,29227,29228],{},"                tham.add(v)  # đánh dấu\n",[1023,29230,29231],{"class":1362,"line":113},[1023,29232,29233],{},"                q.append(v)  # xếp cuối hàng\n",[1023,29235,29236],{"class":1362,"line":118},[1023,29237,29238],{},"    return tham\n",[981,29240,29242],{"id":29241},"vì-sao-ra-đường-ngắn-nhất","Vì sao ra đường ngắn nhất",[986,29244,29245,29248,29251,29254],{},[989,29246,29247],{},"Lớp gần được xét trước nên chạm trước là gần nhất.",[989,29249,29250],{},"Muốn đường cụ thể thì lưu thêm cha mỗi nút.",[989,29252,29253],{},"Thời gian tuyến tính theo đỉnh cộng cạnh.",[989,29255,29256],{},"Ví dụ đời thường: tìm bạn chung 1 cầu trước khi tìm 2 cầu.",[968,29258,1433],{"id":1432},[986,29260,29261,29264,29267,29270],{},[989,29262,29263],{},"Input: mạng 6 người, BFS từ Amin -> Output: thăm đủ 6 người theo lớp.",[989,29265,29266],{},"Câu này cho thấy sóng lan lớp 1, lớp 2, lớp 3.",[989,29268,29269],{},"Input: đồ thị 2 vùng rời, BFS từ vùng 1 -> Output: chỉ thăm vùng 1.",[989,29271,29272],{},"Câu này cho thấy BFS không bay qua vùng rời.",[968,29274,1482],{"id":1481},[973,29276,1485,29277,5599,29279,1517],{},[1487,29278,1493],{},[992,29280,29281],{},"day-040\u002F",[981,29283,29285],{"id":29284},"bài-1-đồ-thị-danh-sách-kề","Bài 1: Đồ thị danh sách kề",[1352,29287,29289],{"className":1393,"code":29288,"language":1395,"meta":1357,"style":1357},"class Graph {\n public:\n  Graph(int n, bool directed);\n  void addEdge(int u, int v);\n  const std::vector\u003Cint> &neighbors(int u) const;\n  int n() const;\n  static Graph fromFile(const std::string &path);   \u002F\u002F dòng đầu \"n m directed\", m dòng \"u v\"\n};\n",[992,29290,29291,29296,29300,29305,29310,29315,29320,29325],{"__ignoreMap":1357},[1023,29292,29293],{"class":1362,"line":63},[1023,29294,29295],{},"class Graph {\n",[1023,29297,29298],{"class":1362,"line":68},[1023,29299,4836],{},[1023,29301,29302],{"class":1362,"line":73},[1023,29303,29304],{},"  Graph(int n, bool directed);\n",[1023,29306,29307],{"class":1362,"line":78},[1023,29308,29309],{},"  void addEdge(int u, int v);\n",[1023,29311,29312],{"class":1362,"line":83},[1023,29313,29314],{},"  const std::vector\u003Cint> &neighbors(int u) const;\n",[1023,29316,29317],{"class":1362,"line":88},[1023,29318,29319],{},"  int n() const;\n",[1023,29321,29322],{"class":1362,"line":93},[1023,29323,29324],{},"  static Graph fromFile(const std::string &path);   \u002F\u002F dòng đầu \"n m directed\", m dòng \"u v\"\n",[1023,29326,29327],{"class":1362,"line":98},[1023,29328,4866],{},[973,29330,11480,29331,29334,29335,29337,29338,1656,29421,1517],{},[992,29332,29333],{},"std::vector\u003Cstd::vector\u003Cbool>> toMatrix()",". Ghi vào ",[992,29336,2513],{}," bộ nhớ của 2 cách lưu với ",[1023,29339,29341,29362],{"className":29340},[1026],[1023,29342,29344],{"className":29343},[1030],[1032,29345,29346],{"xmlns":1034},[1036,29347,29348,29360],{},[1039,29349,29350,29352,29354],{},[1042,29351,1262],{},[1046,29353,2325],{},[2327,29355,29356,29358],{},[1051,29357,2331],{},[1051,29359,2334],{},[1058,29361,2337],{"encoding":1060},[1023,29363,29365,29383],{"className":29364,"ariaHidden":1066},[1065],[1023,29366,29368,29371,29374,29377,29380],{"className":29367},[1070],[1023,29369],{"className":29370,"style":2347},[1074],[1023,29372,1262],{"className":29373},[1079,1080],[1023,29375],{"className":29376,"style":2355},[2354],[1023,29378,2325],{"className":29379},[2359],[1023,29381],{"className":29382,"style":2355},[2354],[1023,29384,29386,29389,29392],{"className":29385},[1070],[1023,29387],{"className":29388,"style":2369},[1074],[1023,29390,1053],{"className":29391},[1079],[1023,29393,29395,29398],{"className":29394},[1079],[1023,29396,2379],{"className":29397},[1079],[1023,29399,29401],{"className":29400},[2383],[1023,29402,29404],{"className":29403},[2387],[1023,29405,29407],{"className":29406},[2391],[1023,29408,29410],{"className":29409,"style":2369},[2395],[1023,29411,29412,29415],{"style":2398},[1023,29413],{"className":29414,"style":2403},[2402],[1023,29416,29418],{"className":29417},[2407,2408,2409,2410],[1023,29419,2334],{"className":29420},[1079,2410],[1023,29422,29424,29450],{"className":29423},[1026],[1023,29425,29427],{"className":29426},[1030],[1032,29428,29429],{"xmlns":1034},[1036,29430,29431,29447],{},[1039,29432,29433,29435,29437,29439,29441],{},[1042,29434,15437],{},[1046,29436,2325],{},[1051,29438,2334],{},[1046,29440,18118],{},[2327,29442,29443,29445],{},[1051,29444,2331],{},[1051,29446,2334],{},[1058,29448,29449],{"encoding":1060},"m = 5 \\cdot 10^5",[1023,29451,29453,29471,29489],{"className":29452,"ariaHidden":1066},[1065],[1023,29454,29456,29459,29462,29465,29468],{"className":29455},[1070],[1023,29457],{"className":29458,"style":2347},[1074],[1023,29460,15437],{"className":29461},[1079,1080],[1023,29463],{"className":29464,"style":2355},[2354],[1023,29466,2325],{"className":29467},[2359],[1023,29469],{"className":29470,"style":2355},[2354],[1023,29472,29474,29477,29480,29483,29486],{"className":29473},[1070],[1023,29475],{"className":29476,"style":10020},[1074],[1023,29478,2334],{"className":29479},[1079],[1023,29481],{"className":29482,"style":13790},[2354],[1023,29484,18118],{"className":29485},[13794],[1023,29487],{"className":29488,"style":13790},[2354],[1023,29490,29492,29495,29498],{"className":29491},[1070],[1023,29493],{"className":29494,"style":2369},[1074],[1023,29496,1053],{"className":29497},[1079],[1023,29499,29501,29504],{"className":29500},[1079],[1023,29502,2379],{"className":29503},[1079],[1023,29505,29507],{"className":29506},[2383],[1023,29508,29510],{"className":29509},[2387],[1023,29511,29513],{"className":29512},[2391],[1023,29514,29516],{"className":29515,"style":2369},[2395],[1023,29517,29518,29521],{"style":2398},[1023,29519],{"className":29520,"style":2403},[2402],[1023,29522,29524],{"className":29523},[2407,2408,2409,2410],[1023,29525,2334],{"className":29526},[1079,2410],[981,29528,29530],{"id":29529},"bài-2-bfs-và-đường-đi-ngắn-nhất","Bài 2: BFS và đường đi ngắn nhất",[1099,29532,29533,29541],{},[1102,29534,29535],{},[1105,29536,29537,29539],{},[1108,29538,1566],{},[1108,29540,2547],{},[1118,29542,29543,29555,29565,29582],{},[1105,29544,29545,29550],{},[1123,29546,29547],{},[992,29548,29549],{},"std::vector\u003Cint> bfsDist(const Graph&, int s)",[1123,29551,29552,29553],{},"Khoảng cách theo số cạnh, không tới được là ",[992,29554,12548],{},[1105,29556,29557,29562],{},[1123,29558,29559],{},[992,29560,29561],{},"std::vector\u003Cint> bfsParent(const Graph&, int s)",[1123,29563,29564],{},"Cha trên cây BFS",[1105,29566,29567,29572],{},[1123,29568,29569],{},[992,29570,29571],{},"std::vector\u003Cint> shortestPath(const Graph&, int s, int t)",[1123,29573,29574,29575,10880,29578,29581],{},"Dãy đỉnh từ ",[992,29576,29577],{},"s",[992,29579,29580],{},"t",", không có đường thì rỗng",[1105,29583,29584,29589],{},[1123,29585,29586],{},[992,29587,29588],{},"int components(const Graph&)",[1123,29590,29591],{},"Số thành phần liên thông (đồ thị vô hướng)",[1352,29593,29596],{"className":29594,"code":29595,"language":2241,"meta":1357},[2239],"Cạnh vô hướng: 0-1, 0-2, 1-3, 2-3, 3-4, 5-6\nbfsDist(0)          -> [0,1,1,2,3,-1,-1]\nshortestPath(0, 4)  -> [0,1,3,4]\nshortestPath(0, 6)  -> []\ncomponents          -> 2\n",[992,29597,29595],{"__ignoreMap":1357},[973,29599,29600,29601,1517],{},"Độ phức tạp phải là ",[1023,29602,29604,29629],{"className":29603},[1026],[1023,29605,29607],{"className":29606},[1030],[1032,29608,29609],{"xmlns":1034},[1036,29610,29611,29626],{},[1039,29612,29613,29615,29617,29620,29622,29624],{},[1042,29614,1044],{},[1046,29616,1049],{"stretchy":1048},[1042,29618,29619],{},"V",[1046,29621,21881],{},[1042,29623,26217],{},[1046,29625,1056],{"stretchy":1048},[1058,29627,29628],{"encoding":1060},"O(V + E)",[1023,29630,29632,29656],{"className":29631,"ariaHidden":1066},[1065],[1023,29633,29635,29638,29641,29644,29647,29650,29653],{"className":29634},[1070],[1023,29636],{"className":29637,"style":1075},[1074],[1023,29639,1044],{"className":29640,"style":1081},[1079,1080],[1023,29642,1049],{"className":29643},[1085],[1023,29645,29619],{"className":29646,"style":13790},[1079,1080],[1023,29648],{"className":29649,"style":13790},[2354],[1023,29651,21881],{"className":29652},[13794],[1023,29654],{"className":29655,"style":13790},[2354],[1023,29657,29659,29662,29665],{"className":29658},[1070],[1023,29660],{"className":29661,"style":1075},[1074],[1023,29663,26217],{"className":29664,"style":26247},[1079,1080],[1023,29666,1056],{"className":29667},[1092],[981,29669,29671],{"id":29670},"bài-3-bfs-trên-lưới-nâng-cao","Bài 3: BFS trên lưới (nâng cao)",[2273,29673,29674,29689,29699],{},[989,29675,29676,29677,29679,29680,29682,29683,29685,29686,1517],{},"Mê cung đọc từ file, ",[992,29678,15983],{}," là tường, ",[992,29681,4757],{}," bắt đầu, ",[992,29684,26217],{}," kết thúc. In độ dài đường ngắn nhất và vẽ đường đi bằng ",[992,29687,29688],{},"*",[989,29690,29691,29694,29695,29698],{},[1487,29692,29693],{},"Multi-source BFS:"," lưới có nhiều ô ",[992,29696,29697],{},"F"," là đám cháy. Tính mỗi ô cách đám cháy gần nhất bao nhiêu bước.",[989,29700,29701,29704],{},[1487,29702,29703],{},"Bipartite:"," kiểm tra đồ thị có tô được 2 màu không bằng BFS.",[1352,29706,29709],{"className":29707,"code":29708,"language":2241,"meta":1357},[2239],"S . . #\n# # . #\n. . . E   -> độ dài 5\n",[992,29710,29708],{"__ignoreMap":1357},[981,29712,2711],{"id":2710},[986,29714,29716,29721,29730,29736],{"className":29715},[2715],[989,29717,29719,11986],{"className":29718},[2719],[2721,29720],{"disabled":2723,"type":2724},[989,29722,29724,2308,29726,29729],{"className":29723},[2719],[2721,29725],{"disabled":2723,"type":2724},[992,29727,29728],{},"shortestPath"," dựng lại đường từ mảng cha đúng.",[989,29731,29733,29735],{"className":29732},[2719],[2721,29734],{"disabled":2723,"type":2724}," Bài 3 in mê cung có vẽ đường.",[989,29737,29739,29741],{"className":29738},[2719],[2721,29740],{"disabled":2723,"type":2724}," Chứng minh bằng lời vì sao BFS cho đường ngắn nhất trên đồ thị không trọng số.",[968,29743,2890],{"id":2889},[986,29745,29746,29749,29752,29755],{},[989,29747,29748],{},"Danh sách kề lưu đồ thị thế nào?",[989,29750,29751],{},"BFS dùng cấu trúc gì để lan lớp?",[989,29753,29754],{},"Vì sao cần tập đã thăm?",[989,29756,29757],{},"Khi nào BFS không còn đúng nữa?",[3014,29759],{},[973,29761,29762],{},"🌕 Bạn đã hoàn thành ngày 40. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,29764,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":29766},[29767,29768,29773,29774,29780],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":29769},[29770,29771,29772],{"id":29140,"depth":73,"text":29141},{"id":29158,"depth":73,"text":29159},{"id":29241,"depth":73,"text":29242},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":29775},[29776,29777,29778,29779],{"id":29284,"depth":73,"text":29285},{"id":29529,"depth":73,"text":29530},{"id":29670,"depth":73,"text":29671},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Biểu diễn đồ thị bằng danh sách kề, cài đặt BFS theo lớp và dùng nó tìm đường ngắn nhất trên đồ thị không trọng số.",{},[3050,3049],{"title":255,"description":29781},[29786,29787],"graph","bfs","w50fQhDYRNyhNG4CrCTORqik5pmGdzyY5hydvXeGww4",{"id":29790,"title":260,"body":29791,"category":8797,"day":263,"description":30446,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":30447,"navigation":2723,"outcomes":3047,"path":261,"prerequisites":30448,"seo":30449,"stem":262,"tags":30450,"__hash__":30452},"challenges\u002Fchallenges\u002F41.dfs-va-so-sanh.md",{"type":965,"value":29792,"toc":30430},[29793,29795,29798,29800,29804,29818,29822,29836,29871,29875,29889,30078,30080,30094,30096,30108,30112,30158,30164,30173,30177,30219,30225,30229,30359,30365,30367,30407,30409,30423,30425,30428],[968,29794,971],{"id":970},[973,29796,29797],{},"Bài này học DFS đào sâu rồi quay lui.\nThuật toán này giúp giải mê cung và sắp lịch.",[968,29799,979],{"id":978},[981,29801,29803],{"id":29802},"dfs-đào-sâu","DFS đào sâu",[986,29805,29806,29809,29812,29815],{},[989,29807,29808],{},"Dùng ngăn xếp LIFO: vào sau ra trước.",[989,29810,29811],{},"Đâm sâu một nhánh tới lá rồi mới quay lui.",[989,29813,29814],{},"Thời gian tuyến tính, nhớ theo đường sâu nhất.",[989,29816,29817],{},"Ví dụ đời thường: đi mê cung tới ngõ cụt rồi quay lại.",[981,29819,29821],{"id":29820},"đệ-quy-và-cờ-đã-thăm","Đệ quy và cờ đã thăm",[986,29823,29824,29827,29830,29833],{},[989,29825,29826],{},"Đệ quy: đánh dấu rồi gọi sang lân cận chưa thăm.",[989,29828,29829],{},"Quên cờ đã thăm thì hai nút trỏ nhau gây treo vô hạn.",[989,29831,29832],{},"Stack tường minh tương đương đệ quy nhưng không sợ tràn.",[989,29834,29835],{},"Ví dụ đời thường: đánh dấu phòng đã vào để khỏi lặp.",[1352,29837,29839],{"className":3538,"code":29838,"language":3540,"meta":1357,"style":1357},"# DFS đệ quy gọn nhất\ndef dfs(graph, u, tham):\n    tham.add(u)  # đánh dấu đã thăm\n    for v in graph[u]:  # xét từng lân cận\n        if v not in tham:  # chưa thăm mới đi\n            dfs(graph, v, tham)  # đào sâu tiếp\n",[992,29840,29841,29846,29851,29856,29861,29866],{"__ignoreMap":1357},[1023,29842,29843],{"class":1362,"line":63},[1023,29844,29845],{},"# DFS đệ quy gọn nhất\n",[1023,29847,29848],{"class":1362,"line":68},[1023,29849,29850],{},"def dfs(graph, u, tham):\n",[1023,29852,29853],{"class":1362,"line":73},[1023,29854,29855],{},"    tham.add(u)  # đánh dấu đã thăm\n",[1023,29857,29858],{"class":1362,"line":78},[1023,29859,29860],{},"    for v in graph[u]:  # xét từng lân cận\n",[1023,29862,29863],{"class":1362,"line":83},[1023,29864,29865],{},"        if v not in tham:  # chưa thăm mới đi\n",[1023,29867,29868],{"class":1362,"line":88},[1023,29869,29870],{},"            dfs(graph, v, tham)  # đào sâu tiếp\n",[981,29872,29874],{"id":29873},"bfs-so-với-dfs","BFS so với DFS",[986,29876,29877,29880,29883,29886],{},[989,29878,29879],{},"BFS dùng hàng đợi, lan lớp; DFS dùng stack, đâm nhánh.",[989,29881,29882],{},"BFS cho đường ngắn nhất, DFS thì không đảm bảo.",[989,29884,29885],{},"BFS nhớ lớp rộng nhất, DFS nhớ nhánh sâu nhất.",[989,29887,29888],{},"Ví dụ đời thường: BFS như sóng lan, DFS như khoan sâu.",[1099,29890,29891,29903],{},[1102,29892,29893],{},[1105,29894,29895,29897,29900],{},[1108,29896,5414],{},[1108,29898,29899],{},"BFS",[1108,29901,29902],{},"DFS",[1118,29904,29905,29916,29927,29938],{},[1105,29906,29907,29910,29913],{},[1123,29908,29909],{},"Cấu trúc",[1123,29911,29912],{},"Hàng đợi FIFO",[1123,29914,29915],{},"Ngăn xếp LIFO",[1105,29917,29918,29921,29924],{},[1123,29919,29920],{},"Thứ tự",[1123,29922,29923],{},"Lớp gần trước",[1123,29925,29926],{},"Nhánh sâu trước",[1105,29928,29929,29932,29935],{},[1123,29930,29931],{},"Thắng ở",[1123,29933,29934],{},"Đường ngắn nhất",[1123,29936,29937],{},"Topo, mê cung",[1105,29939,29940,29943,30011],{},[1123,29941,29942],{},"Thời gian",[1123,29944,29945],{},[1023,29946,29948,29972],{"className":29947},[1026],[1023,29949,29951],{"className":29950},[1030],[1032,29952,29953],{"xmlns":1034},[1036,29954,29955,29969],{},[1039,29956,29957,29959,29961,29963,29965,29967],{},[1042,29958,1044],{},[1046,29960,1049],{"stretchy":1048},[1042,29962,29619],{},[1046,29964,21881],{},[1042,29966,26217],{},[1046,29968,1056],{"stretchy":1048},[1058,29970,29971],{"encoding":1060},"O(V+E)",[1023,29973,29975,29999],{"className":29974,"ariaHidden":1066},[1065],[1023,29976,29978,29981,29984,29987,29990,29993,29996],{"className":29977},[1070],[1023,29979],{"className":29980,"style":1075},[1074],[1023,29982,1044],{"className":29983,"style":1081},[1079,1080],[1023,29985,1049],{"className":29986},[1085],[1023,29988,29619],{"className":29989,"style":13790},[1079,1080],[1023,29991],{"className":29992,"style":13790},[2354],[1023,29994,21881],{"className":29995},[13794],[1023,29997],{"className":29998,"style":13790},[2354],[1023,30000,30002,30005,30008],{"className":30001},[1070],[1023,30003],{"className":30004,"style":1075},[1074],[1023,30006,26217],{"className":30007,"style":26247},[1079,1080],[1023,30009,1056],{"className":30010},[1092],[1123,30012,30013],{},[1023,30014,30016,30039],{"className":30015},[1026],[1023,30017,30019],{"className":30018},[1030],[1032,30020,30021],{"xmlns":1034},[1036,30022,30023,30037],{},[1039,30024,30025,30027,30029,30031,30033,30035],{},[1042,30026,1044],{},[1046,30028,1049],{"stretchy":1048},[1042,30030,29619],{},[1046,30032,21881],{},[1042,30034,26217],{},[1046,30036,1056],{"stretchy":1048},[1058,30038,29971],{"encoding":1060},[1023,30040,30042,30066],{"className":30041,"ariaHidden":1066},[1065],[1023,30043,30045,30048,30051,30054,30057,30060,30063],{"className":30044},[1070],[1023,30046],{"className":30047,"style":1075},[1074],[1023,30049,1044],{"className":30050,"style":1081},[1079,1080],[1023,30052,1049],{"className":30053},[1085],[1023,30055,29619],{"className":30056,"style":13790},[1079,1080],[1023,30058],{"className":30059,"style":13790},[2354],[1023,30061,21881],{"className":30062},[13794],[1023,30064],{"className":30065,"style":13790},[2354],[1023,30067,30069,30072,30075],{"className":30068},[1070],[1023,30070],{"className":30071,"style":1075},[1074],[1023,30073,26217],{"className":30074,"style":26247},[1079,1080],[1023,30076,1056],{"className":30077},[1092],[968,30079,1433],{"id":1432},[986,30081,30082,30085,30088,30091],{},[989,30083,30084],{},"Input: mạng 6 người, DFS từ Amin -> Output: Amin, Wasim, Imran, Faras rồi quay lui.",[989,30086,30087],{},"Câu này cho thấy đào sâu khác hẳn lan lớp.",[989,30089,30090],{},"Input: tam giác 3 nút mà quên tập đã thăm -> Output: gọi qua lại vô hạn.",[989,30092,30093],{},"Câu này cho thấy cờ đã thăm là sống còn.",[968,30095,1482],{"id":1481},[973,30097,1485,30098,30100,30101,30104,30105,1517],{},[1487,30099,1493],{},". Dùng lại ",[992,30102,30103],{},"Graph"," ngày 40. Nộp vào ",[992,30106,30107],{},"day-041\u002F",[981,30109,30111],{"id":30110},"bài-1-dfs-hai-cách","Bài 1: DFS hai cách",[1099,30113,30114,30122],{},[1102,30115,30116],{},[1105,30117,30118,30120],{},[1108,30119,1566],{},[1108,30121,2547],{},[1118,30123,30124,30134,30148],{},[1105,30125,30126,30131],{},[1123,30127,30128],{},[992,30129,30130],{},"std::vector\u003Cint> dfsRecursive(const Graph&, int s)",[1123,30132,30133],{},"Thứ tự thăm, lân cận xét theo thứ tự tăng dần",[1105,30135,30136,30141],{},[1123,30137,30138],{},[992,30139,30140],{},"std::vector\u003Cint> dfsIterative(const Graph&, int s)",[1123,30142,30143,30144,30147],{},"Stack tường minh, ",[1487,30145,30146],{},"cùng thứ tự"," với bản đệ quy",[1105,30149,30150,30155],{},[1123,30151,30152],{},[992,30153,30154],{},"std::vector\u003Cint> discovery, finish",[1123,30156,30157],{},"Ghi thời điểm vào và ra mỗi đỉnh (bản đệ quy)",[1352,30159,30162],{"className":30160,"code":30161,"language":2241,"meta":1357},[2239],"Cạnh vô hướng: 0-1, 0-2, 1-3, 2-3, 3-4\ndfsRecursive(0) -> [0,1,3,2,4]\ndfsIterative(0) -> [0,1,3,2,4]\nĐường thẳng 10^6 đỉnh: dfsRecursive có thể tràn stack, dfsIterative chạy bình thường\n",[992,30163,30161],{"__ignoreMap":1357},[2245,30165,30166],{},[973,30167,30168,30169,30172],{},"Để bản stack cùng thứ tự với đệ quy, đẩy lân cận vào stack theo thứ tự ",[1487,30170,30171],{},"ngược"," và đánh dấu thăm lúc lấy ra, không phải lúc đẩy vào.",[981,30174,30176],{"id":30175},"bài-2-ứng-dụng-dfs","Bài 2: Ứng dụng DFS",[1099,30178,30179,30187],{},[1102,30180,30181],{},[1105,30182,30183,30185],{},[1108,30184,1566],{},[1108,30186,2547],{},[1118,30188,30189,30199,30209],{},[1105,30190,30191,30196],{},[1123,30192,30193],{},[992,30194,30195],{},"bool hasCycleUndirected(const Graph&)",[1123,30197,30198],{},"Gặp đỉnh đã thăm mà không phải cha thì có chu trình",[1105,30200,30201,30206],{},[1123,30202,30203],{},[992,30204,30205],{},"bool hasCycleDirected(const Graph&)",[1123,30207,30208],{},"3 màu: trắng, xám (đang trên stack), đen",[1105,30210,30211,30216],{},[1123,30212,30213],{},[992,30214,30215],{},"std::vector\u003Cint> topoSort(const Graph&)",[1123,30217,30218],{},"Đồ thị có hướng không chu trình, sắp theo thời điểm ra giảm dần. Có chu trình thì ném lỗi",[1352,30220,30223],{"className":30221,"code":30222,"language":2241,"meta":1357},[2239],"Môn học: 0->1, 0->2, 1->3, 2->3 -> topoSort hợp lệ, 0 đứng đầu, 3 đứng cuối\nThêm 3->0                       -> hasCycleDirected = true, topoSort ném lỗi\n",[992,30224,30222],{"__ignoreMap":1357},[981,30226,30228],{"id":30227},"bài-3-so-sánh-bfs-và-dfs-nâng-cao","Bài 3: So sánh BFS và DFS (nâng cao)",[2273,30230,30231,30234,30299],{},[989,30232,30233],{},"Giải mê cung ngày 40 bằng DFS. So độ dài đường DFS tìm được với BFS.",[989,30235,30236,30237,30298],{},"Sinh cây nhị phân đầy đủ độ sâu 20 và đồ thị đường thẳng ",[1023,30238,30240,30257],{"className":30239},[1026],[1023,30241,30243],{"className":30242},[1030],[1032,30244,30245],{"xmlns":1034},[1036,30246,30247,30255],{},[1039,30248,30249],{},[2327,30250,30251,30253],{},[1051,30252,2331],{},[1051,30254,6866],{},[1058,30256,6869],{"encoding":1060},[1023,30258,30260],{"className":30259,"ariaHidden":1066},[1065],[1023,30261,30263,30266,30269],{"className":30262},[1070],[1023,30264],{"className":30265,"style":2369},[1074],[1023,30267,1053],{"className":30268},[1079],[1023,30270,30272,30275],{"className":30271},[1079],[1023,30273,2379],{"className":30274},[1079],[1023,30276,30278],{"className":30277},[2383],[1023,30279,30281],{"className":30280},[2387],[1023,30282,30284],{"className":30283},[2391],[1023,30285,30287],{"className":30286,"style":2369},[2395],[1023,30288,30289,30292],{"style":2398},[1023,30290],{"className":30291,"style":2403},[2402],[1023,30293,30295],{"className":30294},[2407,2408,2409,2410],[1023,30296,6866],{"className":30297},[1079,2410]," đỉnh. Đo bộ nhớ lớn nhất của hàng đợi BFS và stack DFS (số phần tử tối đa).",[989,30300,30301,30302,10880,30304,30306,30307,30358],{},"Liệt kê mọi đường đi từ ",[992,30303,4757],{},[992,30305,26217],{}," trong lưới ",[1023,30308,30310,30328],{"className":30309},[1026],[1023,30311,30313],{"className":30312},[1030],[1032,30314,30315],{"xmlns":1034},[1036,30316,30317,30325],{},[1039,30318,30319,30321,30323],{},[1051,30320,25255],{},[1046,30322,13768],{},[1051,30324,25255],{},[1058,30326,30327],{"encoding":1060},"4 \\times 4",[1023,30329,30331,30349],{"className":30330,"ariaHidden":1066},[1065],[1023,30332,30334,30337,30340,30343,30346],{"className":30333},[1070],[1023,30335],{"className":30336,"style":18148},[1074],[1023,30338,25255],{"className":30339},[1079],[1023,30341],{"className":30342,"style":13790},[2354],[1023,30344,13768],{"className":30345},[13794],[1023,30347],{"className":30348,"style":13790},[2354],[1023,30350,30352,30355],{"className":30351},[1070],[1023,30353],{"className":30354,"style":10020},[1074],[1023,30356,25255],{"className":30357},[1079]," không có tường bằng DFS quay lui. In số đường.",[1352,30360,30363],{"className":30361,"code":30362,"language":2241,"meta":1357},[2239],"Lưới 4x4, chỉ đi phải hoặc xuống -> 20 đường\n",[992,30364,30362],{"__ignoreMap":1357},[981,30366,2711],{"id":2710},[986,30368,30370,30376,30395,30401],{"className":30369},[2715],[989,30371,30373,30375],{"className":30372},[2719],[2721,30374],{"disabled":2723,"type":2724}," 2 bản DFS cho cùng thứ tự thăm trên 100 đồ thị ngẫu nhiên.",[989,30377,30379,2308,30381,30384,30385,5059,30388,30391,30392,1517],{"className":30378},[2719],[2721,30380],{"disabled":2723,"type":2724},[992,30382,30383],{},"topoSort"," pass kiểm tra: mọi cạnh ",[992,30386,30387],{},"u->v",[992,30389,30390],{},"u"," đứng trước ",[992,30393,30394],{},"v",[989,30396,30398,30400],{"className":30397},[2719],[2721,30399],{"disabled":2723,"type":2724}," Bảng bộ nhớ BFS và DFS có số thật.",[989,30402,30404,30406],{"className":30403},[2719],[2721,30405],{"disabled":2723,"type":2724}," Nêu được khi nào chọn BFS, khi nào chọn DFS.",[968,30408,2890],{"id":2889},[986,30410,30411,30414,30417,30420],{},[989,30412,30413],{},"DFS dùng cấu trúc gì để đào sâu?",[989,30415,30416],{},"Vì sao quên cờ đã thăm gây treo?",[989,30418,30419],{},"BFS và DFS khác nhau ở thứ tự nào?",[989,30421,30422],{},"Bài nào nên dùng DFS thay vì BFS?",[3014,30424],{},[973,30426,30427],{},"🌕 Bạn đã hoàn thành ngày 41. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,30429,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":30431},[30432,30433,30438,30439,30445],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":30434},[30435,30436,30437],{"id":29802,"depth":73,"text":29803},{"id":29820,"depth":73,"text":29821},{"id":29873,"depth":73,"text":29874},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":30440},[30441,30442,30443,30444],{"id":30110,"depth":73,"text":30111},{"id":30175,"depth":73,"text":30176},{"id":30227,"depth":73,"text":30228},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hiểu DFS đào sâu bằng ngăn xếp và đệ quy, truy vết quay lui, và bảng so sánh toàn diện với BFS.",{},[8149,4669],{"title":260,"description":30446},[29786,30451],"dfs","dqlogJuW8QAEhLlvj4yoDmLc4rxcM9BT2f9mXaOky_0",{"id":30454,"title":265,"body":30455,"category":8797,"day":268,"description":31162,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":31163,"navigation":2723,"outcomes":3047,"path":266,"prerequisites":31164,"seo":31165,"stem":267,"tags":31166,"__hash__":31168},"challenges\u002Fchallenges\u002F42.dijkstra-voi-heap.md",{"type":965,"value":30456,"toc":31146},[30457,30459,30462,30464,30468,30482,30486,30500,30504,30620,30660,30706,30708,30722,30724,30735,30739,30769,30773,30796,30802,30806,30886,30889,30895,31065,31069,31091,31093,31123,31125,31139,31141,31144],[968,30458,971],{"id":970},[973,30460,30461],{},"Bài này học Dijkstra tìm đường rẻ nhất có trọng số.\nThuật toán này mở rộng BFS nhờ heap lấy đỉnh gần nhất.",[968,30463,979],{"id":978},[981,30465,30467],{"id":30466},"vì-sao-bfs-thua","Vì sao BFS thua",[986,30469,30470,30473,30476,30479],{},[989,30471,30472],{},"BFS đếm số cạnh nên chọn đường 1 chặng kẹt xe.",[989,30474,30475],{},"Thực tế cần tổng thời gian nhỏ nhất, không phải ít chặng.",[989,30477,30478],{},"Ví dụ đời thường: cao tốc 2 chặng 20 phút thắng tắt 1 chặng 60 phút.",[989,30480,30481],{},"Cạnh có trọng số thì phải dùng Dijkstra.",[981,30483,30485],{"id":30484},"vòng-lặp-dijkstra","Vòng lặp Dijkstra",[986,30487,30488,30491,30494,30497],{},[989,30489,30490],{},"Giữ bảng khoảng cách tốt nhất, nguồn bằng 0, còn lại vô cùng.",[989,30492,30493],{},"Lặp: lấy đỉnh chưa chốt gần nhất rồi chốt nó.",[989,30495,30496],{},"Nới lỏng lân cận: qua đỉnh mới mà rẻ hơn thì cập nhật.",[989,30498,30499],{},"Ví dụ đời thường: chốt quán gần nhất rồi dò đường từ đó đi tiếp.",[981,30501,30503],{"id":30502},"heap-và-cấm-cạnh-âm","Heap và cấm cạnh âm",[986,30505,30506,30611,30614,30617],{},[989,30507,30508,30509,30552,30553,1517],{},"Quét tìm đỉnh gần nhất tốn ",[1023,30510,30512,30531],{"className":30511},[1026],[1023,30513,30515],{"className":30514},[1030],[1032,30516,30517],{"xmlns":1034},[1036,30518,30519,30529],{},[1039,30520,30521,30523,30525,30527],{},[1042,30522,1044],{},[1046,30524,1049],{"stretchy":1048},[1042,30526,1262],{},[1046,30528,1056],{"stretchy":1048},[1058,30530,1267],{"encoding":1060},[1023,30532,30534],{"className":30533,"ariaHidden":1066},[1065],[1023,30535,30537,30540,30543,30546,30549],{"className":30536},[1070],[1023,30538],{"className":30539,"style":1075},[1074],[1023,30541,1044],{"className":30542,"style":1081},[1079,1080],[1023,30544,1049],{"className":30545},[1085],[1023,30547,1262],{"className":30548},[1079,1080],[1023,30550,1056],{"className":30551},[1092],", heap chỉ tốn ",[1023,30554,30556,30581],{"className":30555},[1026],[1023,30557,30559],{"className":30558},[1030],[1032,30560,30561],{"xmlns":1034},[1036,30562,30563,30579],{},[1039,30564,30565,30567,30569,30571,30573,30575,30577],{},[1042,30566,1044],{},[1046,30568,1049],{"stretchy":1048},[1042,30570,7684],{},[1042,30572,7687],{},[1042,30574,7690],{},[1042,30576,1262],{},[1046,30578,1056],{"stretchy":1048},[1058,30580,7697],{"encoding":1060},[1023,30582,30584],{"className":30583,"ariaHidden":1066},[1065],[1023,30585,30587,30590,30593,30596,30599,30602,30605,30608],{"className":30586},[1070],[1023,30588],{"className":30589,"style":1075},[1074],[1023,30591,1044],{"className":30592,"style":1081},[1079,1080],[1023,30594,1049],{"className":30595},[1085],[1023,30597,7684],{"className":30598,"style":7716},[1079,1080],[1023,30600,7687],{"className":30601},[1079,1080],[1023,30603,7690],{"className":30604,"style":7723},[1079,1080],[1023,30606,1262],{"className":30607},[1079,1080],[1023,30609,1056],{"className":30610},[1092],[989,30612,30613],{},"Nới lỏng thành công thì cập nhật giảm vị trí trên heap.",[989,30615,30616],{},"Cạnh âm phá bẫy chốt: đã chốt vẫn có thể rẻ hơn nữa.",[989,30618,30619],{},"Ví dụ đời thường: nợ âm làm mọi tính toán tiền sai lệch.",[1352,30621,30623],{"className":3538,"code":30622,"language":3540,"meta":1357,"style":1357},"# Ý tưởng nới lỏng trong Dijkstra\nINF = float('inf')  # vô cùng ban đầu\ndist = {s: 0}  # nguồn bằng 0\n# lấy đỉnh gần nhất từ heap rồi xét\nfor v, w in ke[u]:  # từng lân cận của u\n    if dist[u] + w \u003C dist.get(v, INF):  # đi qua u rẻ hơn\n        dist[v] = dist[u] + w  # cập nhật rẻ hơn\n",[992,30624,30625,30630,30635,30640,30645,30650,30655],{"__ignoreMap":1357},[1023,30626,30627],{"class":1362,"line":63},[1023,30628,30629],{},"# Ý tưởng nới lỏng trong Dijkstra\n",[1023,30631,30632],{"class":1362,"line":68},[1023,30633,30634],{},"INF = float('inf')  # vô cùng ban đầu\n",[1023,30636,30637],{"class":1362,"line":73},[1023,30638,30639],{},"dist = {s: 0}  # nguồn bằng 0\n",[1023,30641,30642],{"class":1362,"line":78},[1023,30643,30644],{},"# lấy đỉnh gần nhất từ heap rồi xét\n",[1023,30646,30647],{"class":1362,"line":83},[1023,30648,30649],{},"for v, w in ke[u]:  # từng lân cận của u\n",[1023,30651,30652],{"class":1362,"line":88},[1023,30653,30654],{},"    if dist[u] + w \u003C dist.get(v, INF):  # đi qua u rẻ hơn\n",[1023,30656,30657],{"class":1362,"line":93},[1023,30658,30659],{},"        dist[v] = dist[u] + w  # cập nhật rẻ hơn\n",[1099,30661,30662,30673],{},[1102,30663,30664],{},[1105,30665,30666,30668,30670],{},[1108,30667,5414],{},[1108,30669,29899],{},[1108,30671,30672],{},"Dijkstra",[1118,30674,30675,30686,30695],{},[1105,30676,30677,30680,30683],{},[1123,30678,30679],{},"Bài toán",[1123,30681,30682],{},"Ít cạnh nhất",[1123,30684,30685],{},"Rẻ nhất có trọng số",[1105,30687,30688,30690,30693],{},[1123,30689,29909],{},[1123,30691,30692],{},"Hàng đợi",[1123,30694,21277],{},[1105,30696,30697,30700,30703],{},[1123,30698,30699],{},"Điều kiện",[1123,30701,30702],{},"Cạnh bằng nhau",[1123,30704,30705],{},"Không cạnh âm",[968,30707,1433],{"id":1432},[986,30709,30710,30713,30716,30719],{},[989,30711,30712],{},"Input: 2 đỉnh 1 cạnh trọng số 7 -> Output: khoảng cách đích bằng 7.",[989,30714,30715],{},"Câu này cho thấy chỉ cần một lần nới lỏng.",[989,30717,30718],{},"Input: đồ thị có cạnh âm mà chạy Dijkstra -> Output: đáp án sai ở bước chốt đầu.",[989,30720,30721],{},"Câu này cho thấy điều kiện không âm là bắt buộc.",[968,30723,1482],{"id":1481},[973,30725,1485,30726,5599,30728,30731,30732,30734],{},[1487,30727,1493],{},[992,30729,30730],{},"day-042\u002F",". Trọng số là ",[992,30733,11700],{}," không âm.",[981,30736,30738],{"id":30737},"bài-1-dijkstra-với-heap","Bài 1: Dijkstra với heap",[1352,30740,30742],{"className":1393,"code":30741,"language":1395,"meta":1357,"style":1357},"struct WEdge { int to; long long w; };\nusing WGraph = std::vector\u003Cstd::vector\u003CWEdge>>;\nstruct Result { std::vector\u003Clong long> dist; std::vector\u003Cint> parent; };\nResult dijkstra(const WGraph &g, int s);                 \u002F\u002F dùng std::priority_queue, lazy deletion\nstd::vector\u003Cint> path(const Result &r, int t);           \u002F\u002F rỗng nếu không tới được\n",[992,30743,30744,30749,30754,30759,30764],{"__ignoreMap":1357},[1023,30745,30746],{"class":1362,"line":63},[1023,30747,30748],{},"struct WEdge { int to; long long w; };\n",[1023,30750,30751],{"class":1362,"line":68},[1023,30752,30753],{},"using WGraph = std::vector\u003Cstd::vector\u003CWEdge>>;\n",[1023,30755,30756],{"class":1362,"line":73},[1023,30757,30758],{},"struct Result { std::vector\u003Clong long> dist; std::vector\u003Cint> parent; };\n",[1023,30760,30761],{"class":1362,"line":78},[1023,30762,30763],{},"Result dijkstra(const WGraph &g, int s);                 \u002F\u002F dùng std::priority_queue, lazy deletion\n",[1023,30765,30766],{"class":1362,"line":83},[1023,30767,30768],{},"std::vector\u003Cint> path(const Result &r, int t);           \u002F\u002F rỗng nếu không tới được\n",[973,30770,30771],{},[1487,30772,2194],{},[986,30774,30775,30785,30791],{},[989,30776,30777,30778,30781,30782,16014],{},"Không tới được thì ",[992,30779,30780],{},"dist = LLONG_MAX"," (hoặc hằng ",[992,30783,30784],{},"INF",[989,30786,30787,30788,1517],{},"Bỏ qua mục cũ trong heap khi ",[992,30789,30790],{},"d > dist[u]",[989,30792,30793,30794,1517],{},"Gặp cạnh âm thì ném ",[992,30795,15891],{},[1352,30797,30800],{"className":30798,"code":30799,"language":2241,"meta":1357},[2239],"Cạnh có hướng: 0->1 (4), 0->2 (1), 2->1 (2), 1->3 (1), 2->3 (5)\ndist từ 0     -> [0, 3, 1, 4]\npath(3)       -> [0, 2, 1, 3]\n",[992,30801,30799],{"__ignoreMap":1357},[981,30803,30805],{"id":30804},"bài-2-so-với-cách-quét-mảng","Bài 2: So với cách quét mảng",[973,30807,1505,30808,30811,30812,1517],{},[992,30809,30810],{},"dijkstraArray"," không dùng heap: mỗi lượt quét tìm đỉnh chưa chốt gần nhất, ",[1023,30813,30815,30839],{"className":30814},[1026],[1023,30816,30818],{"className":30817},[1030],[1032,30819,30820],{"xmlns":1034},[1036,30821,30822,30836],{},[1039,30823,30824,30826,30828,30834],{},[1042,30825,1044],{},[1046,30827,1049],{"stretchy":1048},[2327,30829,30830,30832],{},[1042,30831,29619],{},[1051,30833,2457],{},[1046,30835,1056],{"stretchy":1048},[1058,30837,30838],{"encoding":1060},"O(V^2)",[1023,30840,30842],{"className":30841,"ariaHidden":1066},[1065],[1023,30843,30845,30848,30851,30854,30883],{"className":30844},[1070],[1023,30846],{"className":30847,"style":2476},[1074],[1023,30849,1044],{"className":30850,"style":1081},[1079,1080],[1023,30852,1049],{"className":30853},[1085],[1023,30855,30857,30860],{"className":30856},[1079],[1023,30858,29619],{"className":30859,"style":13790},[1079,1080],[1023,30861,30863],{"className":30862},[2383],[1023,30864,30866],{"className":30865},[2387],[1023,30867,30869],{"className":30868},[2391],[1023,30870,30872],{"className":30871,"style":2369},[2395],[1023,30873,30874,30877],{"style":2398},[1023,30875],{"className":30876,"style":2403},[2402],[1023,30878,30880],{"className":30879},[2407,2408,2409,2410],[1023,30881,2457],{"className":30882},[1079,2410],[1023,30884,1056],{"className":30885},[1092],[973,30887,30888],{},"Đo 2 bản trên 2 loại đồ thị:",[1352,30890,30893],{"className":30891,"code":30892,"language":2241,"meta":1357},[2239],"loại         V        E           heap(ms)   array(ms)\nthưa         10^4     5*10^4      ...        ...\ndày          2000     4*10^6\u002F2    ...        ...\n",[992,30894,30892],{"__ignoreMap":1357},[973,30896,30897,30898,1509,30992,1517],{},"Kết luận: đồ thị nào hợp bản nào, giải thích bằng ",[1023,30899,30901,30935],{"className":30900},[1026],[1023,30902,30904],{"className":30903},[1030],[1032,30905,30906],{"xmlns":1034},[1036,30907,30908,30932],{},[1039,30909,30910,30912,30914,30916,30918,30920,30922,30924,30926,30928,30930],{},[1042,30911,1044],{},[1046,30913,1049],{"stretchy":1048},[1046,30915,1049],{"stretchy":1048},[1042,30917,29619],{},[1046,30919,21881],{},[1042,30921,26217],{},[1046,30923,1056],{"stretchy":1048},[1042,30925,8397],{},[1046,30927,8400],{},[1042,30929,29619],{},[1046,30931,1056],{"stretchy":1048},[1058,30933,30934],{"encoding":1060},"O((V+E)\\log V)",[1023,30936,30938,30963],{"className":30937,"ariaHidden":1066},[1065],[1023,30939,30941,30944,30947,30951,30954,30957,30960],{"className":30940},[1070],[1023,30942],{"className":30943,"style":1075},[1074],[1023,30945,1044],{"className":30946,"style":1081},[1079,1080],[1023,30948,30950],{"className":30949},[1085],"((",[1023,30952,29619],{"className":30953,"style":13790},[1079,1080],[1023,30955],{"className":30956,"style":13790},[2354],[1023,30958,21881],{"className":30959},[13794],[1023,30961],{"className":30962,"style":13790},[2354],[1023,30964,30966,30969,30972,30975,30978,30983,30986,30989],{"className":30965},[1070],[1023,30967],{"className":30968,"style":1075},[1074],[1023,30970,26217],{"className":30971,"style":26247},[1079,1080],[1023,30973,1056],{"className":30974},[1092],[1023,30976],{"className":30977,"style":8434},[2354],[1023,30979,8427,30981],{"className":30980},[8426],[1023,30982,7690],{"style":8430},[1023,30984],{"className":30985,"style":8434},[2354],[1023,30987,29619],{"className":30988,"style":13790},[1079,1080],[1023,30990,1056],{"className":30991},[1092],[1023,30993,30995,31018],{"className":30994},[1026],[1023,30996,30998],{"className":30997},[1030],[1032,30999,31000],{"xmlns":1034},[1036,31001,31002,31016],{},[1039,31003,31004,31006,31008,31014],{},[1042,31005,1044],{},[1046,31007,1049],{"stretchy":1048},[2327,31009,31010,31012],{},[1042,31011,29619],{},[1051,31013,2457],{},[1046,31015,1056],{"stretchy":1048},[1058,31017,30838],{"encoding":1060},[1023,31019,31021],{"className":31020,"ariaHidden":1066},[1065],[1023,31022,31024,31027,31030,31033,31062],{"className":31023},[1070],[1023,31025],{"className":31026,"style":2476},[1074],[1023,31028,1044],{"className":31029,"style":1081},[1079,1080],[1023,31031,1049],{"className":31032},[1085],[1023,31034,31036,31039],{"className":31035},[1079],[1023,31037,29619],{"className":31038,"style":13790},[1079,1080],[1023,31040,31042],{"className":31041},[2383],[1023,31043,31045],{"className":31044},[2387],[1023,31046,31048],{"className":31047},[2391],[1023,31049,31051],{"className":31050,"style":2369},[2395],[1023,31052,31053,31056],{"style":2398},[1023,31054],{"className":31055,"style":2403},[2402],[1023,31057,31059],{"className":31058},[2407,2408,2409,2410],[1023,31060,2457],{"className":31061},[1079,2410],[1023,31063,1056],{"className":31064},[1092],[981,31066,31068],{"id":31067},"bài-3-bản-đồ-thật-và-cạnh-âm-nâng-cao","Bài 3: Bản đồ thật và cạnh âm (nâng cao)",[2273,31070,31071,31082,31088],{},[989,31072,31073,31074,31077,31078,31081],{},"Đọc file đường phố ",[992,31075,31076],{},"u v phút"," (tự tạo 30 nút hoặc tải dữ liệu DIMACS nhỏ). Trả lời 10 truy vấn ",[992,31079,31080],{},"s t",": thời gian và đường đi.",[989,31083,31084,31085,31087],{},"Dừng sớm khi đích ",[992,31086,29580],{}," được chốt. Đếm số đỉnh đã chốt, so với chạy hết.",[989,31089,31090],{},"Dựng đồ thị 4 đỉnh có 1 cạnh âm mà Dijkstra (bỏ kiểm tra cạnh âm) cho đáp án sai. Chạy Bellman-Ford để có đáp án đúng. Giải thích bước chốt nào bị sai.",[981,31092,2711],{"id":2710},[986,31094,31096,31105,31111,31117],{"className":31095},[2715],[989,31097,31099,31101,31102,31104],{"className":31098},[2719],[2721,31100],{"disabled":2723,"type":2724}," Test mẫu pass. Kết quả khớp ",[992,31103,30810],{}," trên 100 đồ thị ngẫu nhiên.",[989,31106,31108,31110],{"className":31107},[2719],[2721,31109],{"disabled":2723,"type":2724}," Bảng Bài 2 có số thật và kết luận.",[989,31112,31114,31116],{"className":31113},[2719],[2721,31115],{"disabled":2723,"type":2724}," Bài 3 có ví dụ cạnh âm cụ thể kèm giải thích.",[989,31118,31120,31122],{"className":31119},[2719],[2721,31121],{"disabled":2723,"type":2724}," Giải thích được vì sao mỗi đỉnh chỉ cần chốt 1 lần khi trọng số không âm.",[968,31124,2890],{"id":2889},[986,31126,31127,31130,31133,31136],{},[989,31128,31129],{},"Vì sao BFS chọn nhầm trên đồ thị trọng số?",[989,31131,31132],{},"Vòng lặp Dijkstra gồm 2 việc gì?",[989,31134,31135],{},"Heap giúp Dijkstra nhanh ở chỗ nào?",[989,31137,31138],{},"Vì sao cấm cạnh âm với Dijkstra?",[3014,31140],{},[973,31142,31143],{},"🌕 Bạn đã hoàn thành ngày 42. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,31145,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":31147},[31148,31149,31154,31155,31161],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":31150},[31151,31152,31153],{"id":30466,"depth":73,"text":30467},{"id":30484,"depth":73,"text":30485},{"id":30502,"depth":73,"text":30503},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":31156},[31157,31158,31159,31160],{"id":30737,"depth":73,"text":30738},{"id":30804,"depth":73,"text":30805},{"id":31067,"depth":73,"text":31068},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mở rộng BFS sang cạnh có trọng số bằng Dijkstra, dùng heap lấy đỉnh gần nhất và nới lỏng khoảng cách.",{},[3050],{"title":265,"description":31162},[29786,31167],"shortest-path","YIww3ybcsLYohyDP2YmzELqDV7wTHfb5OHjxpO_R-q0",{"id":31170,"title":270,"body":31171,"category":8797,"day":273,"description":31495,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":31496,"navigation":2723,"outcomes":3047,"path":271,"prerequisites":31497,"seo":31498,"stem":272,"tags":31499,"__hash__":31502},"challenges\u002Fchallenges\u002F43.a-star-va-prim.md",{"type":965,"value":31172,"toc":31479},[31173,31175,31178,31180,31184,31198,31202,31216,31220,31234,31280,31282,31296,31298,31305,31309,31317,31377,31383,31387,31396,31402,31405,31409,31420,31422,31456,31458,31472,31474,31477],[968,31174,971],{"id":970},[973,31176,31177],{},"Bài này học A* đi thẳng tới đích nhờ heuristic.\nBài cũng học Prim nối mọi đỉnh rẻ nhất.",[968,31179,979],{"id":978},[981,31181,31183],{"id":31182},"a-thêm-la-bàn","A* thêm la bàn",[986,31185,31186,31189,31192,31195],{},[989,31187,31188],{},"Dijkstra lan đều mọi hướng nên lãng phí khi biết đích.",[989,31190,31191],{},"A* ưu tiên theo f = g + h, g là đã đi, h là đoán còn lại.",[989,31193,31194],{},"h bằng 0 thì thành Dijkstra, g bằng 0 thì thành tham lam.",[989,31196,31197],{},"Ví dụ đời thường: đi giao hàng nhìn biển chỉ đường thay vì đi vòng.",[981,31199,31201],{"id":31200},"heuristic-tốt","Heuristic tốt",[986,31203,31204,31207,31210,31213],{},[989,31205,31206],{},"Chấp nhận được: không bao giờ đoán vượt quá thật.",[989,31208,31209],{},"Nhất quán: đoán ở đây không vượt cạnh sang cộng đoán bên kia.",[989,31211,31212],{},"Ví dụ đời thường: đường chim bay luôn ngắn hơn đường bộ quanh co.",[989,31214,31215],{},"Đoán vượt quá thì nhanh nhưng đường ra không tối ưu.",[981,31217,31219],{"id":31218},"prim-nuôi-một-cây","Prim nuôi một cây",[986,31221,31222,31225,31228,31231],{},[989,31223,31224],{},"Bắt đầu từ một đỉnh, mỗi bước kết nạp đỉnh rẻ nhất.",[989,31226,31227],{},"Dùng heap lưu chi phí nối rẻ nhất từ cây ra ngoài.",[989,31229,31230],{},"Dựa trên lát cắt: cạnh nhẹ nhất qua cắt thuộc MST.",[989,31232,31233],{},"Ví dụ đời thường: kéo điện nối mọi nhà bằng ít dây nhất.",[1099,31235,31236,31246],{},[1102,31237,31238],{},[1105,31239,31240,31242,31244],{},[1108,31241,9446],{},[1108,31243,17404],{},[1108,31245,29909],{},[1118,31247,31248,31258,31269],{},[1105,31249,31250,31252,31255],{},[1123,31251,30672],{},[1123,31253,31254],{},"Đường rẻ từ nguồn",[1123,31256,31257],{},"Heap theo khoảng cách",[1105,31259,31260,31263,31266],{},[1123,31261,31262],{},"A*",[1123,31264,31265],{},"Đường rẻ tới đích",[1123,31267,31268],{},"Heap theo g + h",[1105,31270,31271,31274,31277],{},[1123,31272,31273],{},"Prim",[1123,31275,31276],{},"Cây nối mọi đỉnh",[1123,31278,31279],{},"Heap theo cạnh nối",[968,31281,1433],{"id":1432},[986,31283,31284,31287,31290,31293],{},[989,31285,31286],{},"Input: A-B 2, B-C 3, A-C 10, đích C -> Output: đường A-B-C tổng 5.",[989,31288,31289],{},"Câu này cho thấy A* không bị dụ bởi cạnh tắt đắt.",[989,31291,31292],{},"Input: hình vuông cạnh 1, chéo 3 -> Output: MST tổng 3 gồm 3 cạnh vuông.",[989,31294,31295],{},"Câu này cho thấy Prim bỏ chéo đắt để lấy cạnh rẻ.",[968,31297,1482],{"id":1481},[973,31299,1485,31300,5599,31302,1517],{},[1487,31301,1493],{},[992,31303,31304],{},"day-043\u002F",[981,31306,31308],{"id":31307},"bài-1-a-trên-lưới","Bài 1: A* trên lưới",[973,31310,15400,31311,1656,31314,31316],{},[992,31312,31313],{},"R x C",[992,31315,15983],{}," là tường. Đi 4 hướng, mỗi bước chi phí 1.",[1099,31318,31319,31327],{},[1102,31320,31321],{},[1105,31322,31323,31325],{},[1108,31324,1566],{},[1108,31326,2547],{},[1118,31328,31329,31345,31354,31364],{},[1105,31330,31331,31336],{},[1123,31332,31333],{},[992,31334,31335],{},"int astar(const Grid&, Pos s, Pos t, Heuristic h, int &expanded)",[1123,31337,31338,31339,1838,31341,31344],{},"Trả độ dài ngắn nhất, không có đường trả ",[992,31340,12548],{},[992,31342,31343],{},"expanded"," đếm số ô lấy ra khỏi heap",[1105,31346,31347,31352],{},[1123,31348,31349],{},[992,31350,31351],{},"int manhattan(Pos a, Pos b)",[1123,31353],{},[1105,31355,31356,31361],{},[1123,31357,31358],{},[992,31359,31360],{},"int zero(Pos, Pos)",[1123,31362,31363],{},"Luôn 0, biến A* thành Dijkstra",[1105,31365,31366,31371],{},[1123,31367,31368],{},[992,31369,31370],{},"int overestimate(Pos a, Pos b)",[1123,31372,31373,31376],{},[992,31374,31375],{},"3 * manhattan",", không chấp nhận được",[1352,31378,31381],{"className":31379,"code":31380,"language":2241,"meta":1357},[2239],"Lưới 50x50 trống, S=(0,0), E=(49,49):\nh = zero        -> 98, expanded ~ 2500\nh = manhattan   -> 98, expanded ít hơn nhiều\nh = overestimate-> có thể > 98 khi có tường chắn: dựng 1 lưới chứng minh\n",[992,31382,31380],{"__ignoreMap":1357},[981,31384,31386],{"id":31385},"bài-2-prim-với-heap","Bài 2: Prim với heap",[1352,31388,31390],{"className":1393,"code":31389,"language":1395,"meta":1357,"style":1357},"std::pair\u003Clong long, std::vector\u003Cstd::pair\u003Cint,int>>> prim(const WGraph &g);  \u002F\u002F vô hướng\n",[992,31391,31392],{"__ignoreMap":1357},[1023,31393,31394],{"class":1362,"line":63},[1023,31395,31389],{},[1352,31397,31400],{"className":31398,"code":31399,"language":2241,"meta":1357},[2239],"Hình vuông 0-1(1), 1-2(1), 2-3(1), 3-0(1), chéo 0-2(3), 1-3(3) -> tổng 3\nA-B 2, B-C 3, A-C 10 -> tổng 5\n",[992,31401,31399],{"__ignoreMap":1357},[973,31403,31404],{},"Kiểm tra: tổng trọng số Prim bằng Kruskal (ngày 33) trên 100 đồ thị liên thông ngẫu nhiên.",[981,31406,31408],{"id":31407},"bài-3-tìm-đường-trên-bản-đồ-có-tọa-độ-nâng-cao","Bài 3: Tìm đường trên bản đồ có tọa độ (nâng cao)",[2273,31410,31411,31414,31417],{},[989,31412,31413],{},"Sinh 5000 điểm ngẫu nhiên trên mặt phẳng. Nối mỗi điểm với 6 điểm gần nhất, trọng số là khoảng cách Euclid.",[989,31415,31416],{},"Chạy Dijkstra và A* (heuristic Euclid) cho 100 cặp ngẫu nhiên. In độ dài trung bình và số đỉnh mở rộng trung bình của mỗi thuật toán. Độ dài phải bằng nhau.",[989,31418,31419],{},"Viết 3 câu: vì sao heuristic Euclid chấp nhận được trong bài này.",[981,31421,2711],{"id":2710},[986,31423,31425,31438,31444,31450],{"className":31424},[2715],[989,31426,31428,31430,31431,31434,31435,1517],{"className":31427},[2719],[2721,31429],{"disabled":2723,"type":2724}," A* với ",[992,31432,31433],{},"manhattan"," luôn cho cùng độ dài với ",[992,31436,31437],{},"zero",[989,31439,31441,31443],{"className":31440},[2719],[2721,31442],{"disabled":2723,"type":2724}," Có lưới chứng minh heuristic đoán vượt cho đường không tối ưu.",[989,31445,31447,31449],{"className":31446},[2719],[2721,31448],{"disabled":2723,"type":2724}," Prim khớp Kruskal trên 100 đồ thị.",[989,31451,31453,31455],{"className":31452},[2719],[2721,31454],{"disabled":2723,"type":2724}," Bảng số đỉnh mở rộng Bài 3 có số thật.",[968,31457,2890],{"id":2889},[986,31459,31460,31463,31466,31469],{},[989,31461,31462],{},"Công thức f trong A* gồm gì?",[989,31464,31465],{},"Heuristic chấp nhận được nghĩa là gì?",[989,31467,31468],{},"Prim mỗi bước chọn cạnh nào?",[989,31470,31471],{},"Khi nào A* thành Dijkstra?",[3014,31473],{},[973,31475,31476],{},"🌕 Bạn đã hoàn thành ngày 43. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,31478,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":31480},[31481,31482,31487,31488,31494],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":31483},[31484,31485,31486],{"id":31182,"depth":73,"text":31183},{"id":31200,"depth":73,"text":31201},{"id":31218,"depth":73,"text":31219},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":31489},[31490,31491,31492,31493],{"id":31307,"depth":73,"text":31308},{"id":31385,"depth":73,"text":31386},{"id":31407,"depth":73,"text":31408},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật toán A* với hàm heuristic chấp nhận được, so sánh với Dijkstra, và thuật toán Prim tìm cây khung nhỏ nhất bằng tính chất lát cắt.",{},[3050,15144],{"title":270,"description":31495},[29786,26309,31500,31501],"a-star","prim","yX5lFcxH5XpeE2ZhnPoV3yr0eRlxNAszXcq3ZfNdsMc",{"id":31504,"title":275,"body":31505,"category":8797,"day":278,"description":32317,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":32318,"navigation":2723,"outcomes":3047,"path":276,"prerequisites":32319,"seo":32320,"stem":277,"tags":32321,"__hash__":32325},"challenges\u002Fchallenges\u002F44.centrality-va-egonet.md",{"type":965,"value":31506,"toc":32301},[31507,31509,31512,31514,31518,31532,31536,31550,31554,31571,31631,31633,31647,31649,31669,31673,31865,31871,31875,32219,32225,32229,32232,32249,32251,32280,32282,32296,32298],[968,31508,971],{"id":970},[973,31510,31511],{},"Bài này học egonet nhìn mạng từ một người trung tâm.\nBài cũng học 4 cách đo ai quan trọng nhất.",[968,31513,979],{"id":978},[981,31515,31517],{"id":31516},"egonet-là-gì","Egonet là gì",[986,31519,31520,31523,31526,31529],{},[989,31521,31522],{},"Ego là đỉnh trung tâm, alter là bạn trực tiếp.",[989,31524,31525],{},"Egonet 1 bước chỉ lấy bạn trực tiếp.",[989,31527,31528],{},"Egonet 2 bước lấy thêm bạn của bạn.",[989,31530,31531],{},"Ví dụ đời thường: soi 2 vòng bạn quanh tài khoản đáng ngờ.",[981,31533,31535],{"id":31534},"tam-giác-và-mật-độ","Tam giác và mật độ",[986,31537,31538,31541,31544,31547],{},[989,31539,31540],{},"Tam giác là 3 đỉnh đôi một kề nhau.",[989,31542,31543],{},"Tam giác nhiều nghĩa là cộng đồng gắn kết.",[989,31545,31546],{},"Mật độ là số cạnh thật chia số cặp có thể.",[989,31548,31549],{},"Ví dụ đời thường: nhóm lừa đảo hay giao dịch vòng tròn khép kín.",[981,31551,31553],{"id":31552},"bốn-độ-đo-quan-trọng","Bốn độ đo quan trọng",[986,31555,31556,31559,31562,31565,31568],{},[989,31557,31558],{},"Degree: số bạn trực tiếp, tìm người nổi tiếng.",[989,31560,31561],{},"Betweenness: số đường đi ngắn nhất giữa các cặp đỉnh khác phải đi qua mình, tìm gác cổng.",[989,31563,31564],{},"Closeness: nghịch đảo tổng khoảng cách, tìm nơi lan tin nhanh.",[989,31566,31567],{},"Eigenvector: chơi với người lớn thì mình cũng lớn.",[989,31569,31570],{},"Ví dụ đời thường: cầu duy nhất nối hai làng thì degree thấp nhưng betweenness cao.",[1099,31572,31573,31585],{},[1102,31574,31575],{},[1105,31576,31577,31580,31583],{},[1108,31578,31579],{},"Độ đo",[1108,31581,31582],{},"Hỏi gì",[1108,31584,23789],{},[1118,31586,31587,31598,31609,31620],{},[1105,31588,31589,31592,31595],{},[1123,31590,31591],{},"Degree",[1123,31593,31594],{},"Nhiều bạn không",[1123,31596,31597],{},"Tìm nổi tiếng",[1105,31599,31600,31603,31606],{},[1123,31601,31602],{},"Betweenness",[1123,31604,31605],{},"Gác cổng không",[1123,31607,31608],{},"Tìm nút thắt",[1105,31610,31611,31614,31617],{},[1123,31612,31613],{},"Closeness",[1123,31615,31616],{},"Gần mọi người không",[1123,31618,31619],{},"Chọn nơi phát tin",[1105,31621,31622,31625,31628],{},[1123,31623,31624],{},"Eigenvector",[1123,31626,31627],{},"Bạn có lớn không",[1123,31629,31630],{},"Xếp hạng uy tín",[968,31632,1433],{"id":1432},[986,31634,31635,31638,31641,31644],{},[989,31636,31637],{},"Input: sao 1 trung tâm nối 5 lá -> Output: trung tâm degree 5, lá betweenness 0.",[989,31639,31640],{},"Câu này cho thấy trung tâm nắm hết luồng đi.",[989,31642,31643],{},"Input: đường thẳng 4 đỉnh -> Output: 2 đỉnh giữa betweenness cao hơn 2 đầu.",[989,31645,31646],{},"Câu này cho thấy gác cổng nằm ở giữa đường.",[968,31648,1482],{"id":1481},[973,31650,1485,31651,31653,31654,31657,31658,31661,31662,31665,31666,1517],{},[1487,31652,13531],{}," (được dùng ",[992,31655,31656],{},"collections",", không dùng ",[992,31659,31660],{},"networkx"," trừ khi đối chiếu kết quả). Nộp vào ",[992,31663,31664],{},"day-044\u002F",". Đồ thị vô hướng, lưu ",[992,31667,31668],{},"dict[int, set[int]]",[981,31670,31672],{"id":31671},"bài-1-egonet-và-tam-giác","Bài 1: Egonet và tam giác",[1099,31674,31675,31683],{},[1102,31676,31677],{},[1105,31678,31679,31681],{},[1108,31680,1566],{},[1108,31682,2547],{},[1118,31684,31685,31699,31709,31852],{},[1105,31686,31687,31692],{},[1123,31688,31689],{},[992,31690,31691],{},"egonet(G, ego, radius=1)",[1123,31693,31694,31695,31698],{},"Trả đồ thị con gồm ego và các đỉnh cách ego tối đa ",[992,31696,31697],{},"radius"," bước",[1105,31700,31701,31706],{},[1123,31702,31703],{},[992,31704,31705],{},"count_triangles(G)",[1123,31707,31708],{},"Đếm tam giác, mỗi tam giác đếm 1 lần",[1105,31710,31711,31716],{},[1123,31712,31713],{},[992,31714,31715],{},"density(G)",[1123,31717,31718],{},[1023,31719,31721,31755],{"className":31720},[1026],[1023,31722,31724],{"className":31723},[1030],[1032,31725,31726],{"xmlns":1034},[1036,31727,31728,31752],{},[1039,31729,31730],{},[18110,31731,31732,31738],{},[1039,31733,31734,31736],{},[1051,31735,2457],{},[1042,31737,15437],{},[1039,31739,31740,31742,31744,31746,31748,31750],{},[1042,31741,1262],{},[1046,31743,1049],{"stretchy":1048},[1042,31745,1262],{},[1046,31747,17698],{},[1051,31749,1053],{},[1046,31751,1056],{"stretchy":1048},[1058,31753,31754],{"encoding":1060},"\\frac{2m}{n(n-1)}",[1023,31756,31758],{"className":31757,"ariaHidden":1066},[1065],[1023,31759,31761,31765],{"className":31760},[1070],[1023,31762],{"className":31763,"style":31764},[1074],"height:1.3651em;vertical-align:-0.52em;",[1023,31766,31768,31771,31849],{"className":31767},[1079],[1023,31769],{"className":31770},[1085,18174],[1023,31772,31774],{"className":31773},[18110],[1023,31775,31777,31841],{"className":31776},[2387,17732],[1023,31778,31780,31838],{"className":31779},[2391],[1023,31781,31784,31813,31821],{"className":31782,"style":31783},[2395],"height:0.8451em;",[1023,31785,31786,31789],{"style":18190},[1023,31787],{"className":31788,"style":18194},[2402],[1023,31790,31792],{"className":31791},[2407,2408,2409,2410],[1023,31793,31795,31798,31801,31804,31807,31810],{"className":31794},[1079,2410],[1023,31796,1262],{"className":31797},[1079,1080,2410],[1023,31799,1049],{"className":31800},[1085,2410],[1023,31802,1262],{"className":31803},[1079,1080,2410],[1023,31805,17698],{"className":31806},[13794,2410],[1023,31808,1053],{"className":31809},[1079,2410],[1023,31811,1056],{"className":31812},[1092,2410],[1023,31814,31815,31818],{"style":18221},[1023,31816],{"className":31817,"style":18194},[2402],[1023,31819],{"className":31820,"style":18229},[18228],[1023,31822,31823,31826],{"style":18232},[1023,31824],{"className":31825,"style":18194},[2402],[1023,31827,31829],{"className":31828},[2407,2408,2409,2410],[1023,31830,31832,31835],{"className":31831},[1079,2410],[1023,31833,2457],{"className":31834},[1079,2410],[1023,31836,15437],{"className":31837},[1079,1080,2410],[1023,31839,17797],{"className":31840},[17796],[1023,31842,31844],{"className":31843},[2391],[1023,31845,31847],{"className":31846,"style":18260},[2395],[1023,31848],{},[1023,31850],{"className":31851},[1092,18174],[1105,31853,31854,31859],{},[1123,31855,31856],{},[992,31857,31858],{},"clustering(G, v)",[1123,31860,31861,31862,31864],{},"Tỉ lệ cặp bạn của ",[992,31863,30394],{}," cũng là bạn nhau",[1352,31866,31869],{"className":31867,"code":31868,"language":2241,"meta":1357},[2239],"Sao 1 tâm nối 5 lá      -> triangles 0, density 0.333, clustering(tâm) 0\nĐồ thị đầy đủ K4        -> triangles 4, density 1.0\n",[992,31870,31868],{"__ignoreMap":1357},[981,31872,31874],{"id":31873},"bài-2-bốn-độ-đo-trung-tâm","Bài 2: Bốn độ đo trung tâm",[1099,31876,31877,31885],{},[1102,31878,31879],{},[1105,31880,31881,31883],{},[1108,31882,1566],{},[1108,31884,17652],{},[1118,31886,31887,31987,32152,32209],{},[1105,31888,31889,31894],{},[1123,31890,31891],{},[992,31892,31893],{},"degree_centrality(G)",[1123,31895,31896],{},[1023,31897,31899,31934],{"className":31898},[1026],[1023,31900,31902],{"className":31901},[1030],[1032,31903,31904],{"xmlns":1034},[1036,31905,31906,31931],{},[1039,31907,31908,31911,31913,31915,31917,31919,31921,31923,31925,31927,31929],{},[1042,31909,31910],{},"deg",[1046,31912,8400],{},[1046,31914,1049],{"stretchy":1048},[1042,31916,30394],{},[1046,31918,1056],{"stretchy":1048},[1042,31920,2461],{"mathvariant":2460},[1046,31922,1049],{"stretchy":1048},[1042,31924,1262],{},[1046,31926,17698],{},[1051,31928,1053],{},[1046,31930,1056],{"stretchy":1048},[1058,31932,31933],{"encoding":1060},"\\deg(v) \u002F (n-1)",[1023,31935,31937,31975],{"className":31936,"ariaHidden":1066},[1065],[1023,31938,31940,31943,31948,31951,31954,31957,31960,31963,31966,31969,31972],{"className":31939},[1070],[1023,31941],{"className":31942,"style":1075},[1074],[1023,31944,3043,31946],{"className":31945},[8426],[1023,31947,7690],{"style":8430},[1023,31949,1049],{"className":31950},[1085],[1023,31952,30394],{"className":31953,"style":7723},[1079,1080],[1023,31955,1056],{"className":31956},[1092],[1023,31958,2461],{"className":31959},[1079],[1023,31961,1049],{"className":31962},[1085],[1023,31964,1262],{"className":31965},[1079,1080],[1023,31967],{"className":31968,"style":13790},[2354],[1023,31970,17698],{"className":31971},[13794],[1023,31973],{"className":31974,"style":13790},[2354],[1023,31976,31978,31981,31984],{"className":31977},[1070],[1023,31979],{"className":31980,"style":1075},[1074],[1023,31982,1053],{"className":31983},[1079],[1023,31985,1056],{"className":31986},[1092],[1105,31988,31989,31994],{},[1123,31990,31991],{},[992,31992,31993],{},"closeness(G)",[1123,31995,31996,32151],{},[1023,31997,31999,32041],{"className":31998},[1026],[1023,32000,32002],{"className":32001},[1030],[1032,32003,32004],{"xmlns":1034},[1036,32005,32006,32038],{},[1039,32007,32008,32010,32012,32014,32016,32018,32020,32026,32028,32030,32032,32034,32036],{},[1046,32009,1049],{"stretchy":1048},[1042,32011,1262],{},[1046,32013,17698],{},[1051,32015,1053],{},[1046,32017,1056],{"stretchy":1048},[1042,32019,2461],{"mathvariant":2460},[17690,32021,32022,32024],{},[1046,32023,17686],{},[1042,32025,30390],{},[1042,32027,12999],{},[1046,32029,1049],{"stretchy":1048},[1042,32031,30394],{},[1046,32033,13897],{"separator":1066},[1042,32035,30390],{},[1046,32037,1056],{"stretchy":1048},[1058,32039,32040],{"encoding":1060},"(n-1) \u002F \\sum_u d(v,u)",[1023,32042,32044,32065],{"className":32043,"ariaHidden":1066},[1065],[1023,32045,32047,32050,32053,32056,32059,32062],{"className":32046},[1070],[1023,32048],{"className":32049,"style":1075},[1074],[1023,32051,1049],{"className":32052},[1085],[1023,32054,1262],{"className":32055},[1079,1080],[1023,32057],{"className":32058,"style":13790},[2354],[1023,32060,17698],{"className":32061},[13794],[1023,32063],{"className":32064,"style":13790},[2354],[1023,32066,32068,32072,32075,32078,32081,32084,32127,32130,32133,32136,32139,32142,32145,32148],{"className":32067},[1070],[1023,32069],{"className":32070,"style":32071},[1074],"height:1.0497em;vertical-align:-0.2997em;",[1023,32073,1053],{"className":32074},[1079],[1023,32076,1056],{"className":32077},[1092],[1023,32079,2461],{"className":32080},[1079],[1023,32082],{"className":32083,"style":8434},[2354],[1023,32085,32087,32090],{"className":32086},[8426],[1023,32088,17686],{"className":32089,"style":17758},[8426,17756,17757],[1023,32091,32093],{"className":32092},[2383],[1023,32094,32096,32118],{"className":32095},[2387,17732],[1023,32097,32099,32115],{"className":32098},[2391],[1023,32100,32103],{"className":32101,"style":32102},[2395],"height:0.0017em;",[1023,32104,32106,32109],{"style":32105},"top:-2.4003em;margin-left:0em;margin-right:0.05em;",[1023,32107],{"className":32108,"style":2403},[2402],[1023,32110,32112],{"className":32111},[2407,2408,2409,2410],[1023,32113,30390],{"className":32114},[1079,1080,2410],[1023,32116,17797],{"className":32117},[17796],[1023,32119,32121],{"className":32120},[2391],[1023,32122,32125],{"className":32123,"style":32124},[2395],"height:0.2997em;",[1023,32126],{},[1023,32128],{"className":32129,"style":8434},[2354],[1023,32131,12999],{"className":32132},[1079,1080],[1023,32134,1049],{"className":32135},[1085],[1023,32137,30394],{"className":32138,"style":7723},[1079,1080],[1023,32140,13897],{"className":32141},[13943],[1023,32143],{"className":32144,"style":8434},[2354],[1023,32146,30390],{"className":32147},[1079,1080],[1023,32149,1056],{"className":32150},[1092],", dùng BFS",[1105,32153,32154,32159],{},[1123,32155,32156],{},[992,32157,32158],{},"betweenness(G)",[1123,32160,32161,32162],{},"Thuật toán Brandes, ",[1023,32163,32165,32187],{"className":32164},[1026],[1023,32166,32168],{"className":32167},[1030],[1032,32169,32170],{"xmlns":1034},[1036,32171,32172,32184],{},[1039,32173,32174,32176,32178,32180,32182],{},[1042,32175,1044],{},[1046,32177,1049],{"stretchy":1048},[1042,32179,1262],{},[1042,32181,15437],{},[1046,32183,1056],{"stretchy":1048},[1058,32185,32186],{"encoding":1060},"O(nm)",[1023,32188,32190],{"className":32189,"ariaHidden":1066},[1065],[1023,32191,32193,32196,32199,32202,32206],{"className":32192},[1070],[1023,32194],{"className":32195,"style":1075},[1074],[1023,32197,1044],{"className":32198,"style":1081},[1079,1080],[1023,32200,1049],{"className":32201},[1085],[1023,32203,32205],{"className":32204},[1079,1080],"nm",[1023,32207,1056],{"className":32208},[1092],[1105,32210,32211,32216],{},[1123,32212,32213],{},[992,32214,32215],{},"eigenvector(G, iters=100)",[1123,32217,32218],{},"Lặp lũy thừa, chuẩn hóa vector mỗi vòng",[1352,32220,32223],{"className":32221,"code":32222,"language":2241,"meta":1357},[2239],"Đường thẳng 0-1-2-3: betweenness (không chuẩn hóa) -> [0, 2, 2, 0]\nSao 1 tâm 5 lá:      betweenness tâm = 10, lá = 0\n",[992,32224,32222],{"__ignoreMap":1357},[981,32226,32228],{"id":32227},"bài-3-phân-tích-mạng-thật-nâng-cao","Bài 3: Phân tích mạng thật (nâng cao)",[973,32230,32231],{},"Tải mạng Zachary's Karate Club (34 đỉnh, 78 cạnh, có trong nhiều nguồn công khai).",[2273,32233,32234,32237,32246],{},[989,32235,32236],{},"In top 5 đỉnh theo từng độ đo. Chỉ ra đỉnh nào là \"gác cổng\" và vì sao.",[989,32238,32239,32240,32242,32243,1517],{},"So kết quả với ",[992,32241,31660],{}," để kiểm tra, sai số dưới ",[992,32244,32245],{},"1e-6",[989,32247,32248],{},"Vẽ đồ thị (matplotlib) với kích thước đỉnh tỉ lệ betweenness.",[981,32250,2711],{"id":2710},[986,32252,32254,32259,32268,32274],{"className":32253},[2715],[989,32255,32257,11986],{"className":32256},[2719],[2721,32258],{"disabled":2723,"type":2724},[989,32260,32262,32264,32265,32267],{"className":32261},[2719],[2721,32263],{"disabled":2723,"type":2724}," Betweenness khớp ",[992,32266,31660],{}," trên Karate Club.",[989,32269,32271,32273],{"className":32270},[2719],[2721,32272],{"disabled":2723,"type":2724}," Bảng top 5 kèm nhận xét cho từng độ đo.",[989,32275,32277,32279],{"className":32276},[2719],[2721,32278],{"disabled":2723,"type":2724}," Giải thích được khác biệt giữa degree và betweenness bằng một ví dụ.",[968,32281,2890],{"id":2889},[986,32283,32284,32287,32290,32293],{},[989,32285,32286],{},"Egonet 1 bước và 2 bước khác nhau sao?",[989,32288,32289],{},"Tam giác và mật độ nói lên gì?",[989,32291,32292],{},"Betweenness khác degree ở chỗ nào?",[989,32294,32295],{},"Muốn lan tin nhanh thì dùng độ đo nào?",[3014,32297],{},[973,32299,32300],{},"🌕 Bạn đã hoàn thành ngày 44. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":32302},[32303,32304,32309,32310,32316],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":32305},[32306,32307,32308],{"id":31516,"depth":73,"text":31517},{"id":31534,"depth":73,"text":31535},{"id":31552,"depth":73,"text":31553},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":32311},[32312,32313,32314,32315],{"id":31671,"depth":73,"text":31672},{"id":31873,"depth":73,"text":31874},{"id":32227,"depth":73,"text":32228},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mạng lưới lấy ego làm trung tâm, vùng lân cận một và hai bước, tam giác, mật độ, và bốn độ đo centrality kèm quy trình phân tích chung.",{},[3049],{"title":275,"description":32317},[29786,32322,32323,32324],"sna","centrality","egonet","OqeUv4yZdEeG0sX3ahy3TMmj6qTuzAi5ntBsOVTlexI",{"id":32327,"title":280,"body":32328,"category":3041,"day":283,"description":33125,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":33126,"navigation":2723,"outcomes":3047,"path":281,"prerequisites":33127,"seo":33128,"stem":282,"tags":33129,"__hash__":33132},"challenges\u002Fchallenges\u002F45.kd-tree-co-ban.md",{"type":965,"value":32329,"toc":33109},[32330,32332,32335,32337,32341,32355,32359,32373,32408,32412,32528,32530,32544,32546,32563,32567,32615,32623,32629,32744,32748,32958,32962,32972,32978,33043,33045,33086,33088,33102,33104,33107],[968,32331,971],{"id":970},[973,32333,32334],{},"Bài này học k-d tree lưu điểm nhiều chiều.\nCây này giúp tìm điểm gần nhất rất nhanh.",[968,32336,979],{"id":978},[981,32338,32340],{"id":32339},"luân-phiên-chiều","Luân phiên chiều",[986,32342,32343,32346,32349,32352],{},[989,32344,32345],{},"Mỗi mức chỉ chia theo một chiều duy nhất.",[989,32347,32348],{},"Mặt phẳng: mức chẵn chia x, mức lẻ chia y.",[989,32350,32351],{},"Lên k chiều: mức d dùng chiều d chia k lấy dư.",[989,32353,32354],{},"Ví dụ đời thường: gấp giấy xen kẽ dọc rồi ngang.",[981,32356,32358],{"id":32357},"bất-biến-và-cân-bằng","Bất biến và cân bằng",[986,32360,32361,32364,32367,32370],{},[989,32362,32363],{},"Nút chia x: trái có x nhỏ hơn, phải có x lớn hơn.",[989,32365,32366],{},"Sai bất biến thì rẽ nhánh sai hết.",[989,32368,32369],{},"Xây cân bằng: chọn trung vị làm nút chia, đệ quy 2 nửa.",[989,32371,32372],{},"Ví dụ đời thường: xếp giữa lớp làm tổ trưởng rồi chia 2 nhóm đều.",[1352,32374,32376],{"className":3538,"code":32375,"language":3540,"meta":1357,"style":1357},"# Rẽ nhánh k-d tree theo chiều của nút\ndef re_nhanh(diem, nut):\n    chieu = nut.chieu  # 0 là x, 1 là y\n    if diem[chieu] \u003C nut.nguong:  # so đúng 1 tọa độ\n        return nut.trai  # sang trái\n    return nut.phai  # ngược lại sang phải\n",[992,32377,32378,32383,32388,32393,32398,32403],{"__ignoreMap":1357},[1023,32379,32380],{"class":1362,"line":63},[1023,32381,32382],{},"# Rẽ nhánh k-d tree theo chiều của nút\n",[1023,32384,32385],{"class":1362,"line":68},[1023,32386,32387],{},"def re_nhanh(diem, nut):\n",[1023,32389,32390],{"class":1362,"line":73},[1023,32391,32392],{},"    chieu = nut.chieu  # 0 là x, 1 là y\n",[1023,32394,32395],{"class":1362,"line":78},[1023,32396,32397],{},"    if diem[chieu] \u003C nut.nguong:  # so đúng 1 tọa độ\n",[1023,32399,32400],{"class":1362,"line":83},[1023,32401,32402],{},"        return nut.trai  # sang trái\n",[1023,32404,32405],{"class":1362,"line":88},[1023,32406,32407],{},"    return nut.phai  # ngược lại sang phải\n",[981,32409,32411],{"id":32410},"tìm-và-chèn","Tìm và chèn",[986,32413,32414,32417,32420,32525],{},[989,32415,32416],{},"Tìm: từ gốc rẽ đúng một tọa độ mỗi mức tới lá.",[989,32418,32419],{},"Chèn: đi như tìm tới chỗ trống rồi gắn vào.",[989,32421,32422,32423,32481,32482,1517],{},"Cây cân bằng thì tốn ",[1023,32424,32426,32451],{"className":32425},[1026],[1023,32427,32429],{"className":32428},[1030],[1032,32430,32431],{"xmlns":1034},[1036,32432,32433,32449],{},[1039,32434,32435,32437,32439,32441,32443,32445,32447],{},[1042,32436,1044],{},[1046,32438,1049],{"stretchy":1048},[1042,32440,7684],{},[1042,32442,7687],{},[1042,32444,7690],{},[1042,32446,1262],{},[1046,32448,1056],{"stretchy":1048},[1058,32450,7697],{"encoding":1060},[1023,32452,32454],{"className":32453,"ariaHidden":1066},[1065],[1023,32455,32457,32460,32463,32466,32469,32472,32475,32478],{"className":32456},[1070],[1023,32458],{"className":32459,"style":1075},[1074],[1023,32461,1044],{"className":32462,"style":1081},[1079,1080],[1023,32464,1049],{"className":32465},[1085],[1023,32467,7684],{"className":32468,"style":7716},[1079,1080],[1023,32470,7687],{"className":32471},[1079,1080],[1023,32473,7690],{"className":32474,"style":7723},[1079,1080],[1023,32476,1262],{"className":32477},[1079,1080],[1023,32479,1056],{"className":32480},[1092],", cây lệch thành ",[1023,32483,32485,32504],{"className":32484},[1026],[1023,32486,32488],{"className":32487},[1030],[1032,32489,32490],{"xmlns":1034},[1036,32491,32492,32502],{},[1039,32493,32494,32496,32498,32500],{},[1042,32495,1044],{},[1046,32497,1049],{"stretchy":1048},[1042,32499,1262],{},[1046,32501,1056],{"stretchy":1048},[1058,32503,1267],{"encoding":1060},[1023,32505,32507],{"className":32506,"ariaHidden":1066},[1065],[1023,32508,32510,32513,32516,32519,32522],{"className":32509},[1070],[1023,32511],{"className":32512,"style":1075},[1074],[1023,32514,1044],{"className":32515,"style":1081},[1079,1080],[1023,32517,1049],{"className":32518},[1085],[1023,32520,1262],{"className":32521},[1079,1080],[1023,32523,1056],{"className":32524},[1092],[989,32526,32527],{},"Ví dụ đời thường: chèn theo thứ tự tăng dần làm cây nghiêng hẳn.",[968,32529,1433],{"id":1432},[986,32531,32532,32535,32538,32541],{},[989,32533,32534],{},"Input: cây 7 điểm xây bằng trung vị -> Output: cao 3, gốc chia x, con chia y.",[989,32536,32537],{},"Câu này cho thấy cây cân bằng nhờ trung vị.",[989,32539,32540],{},"Input: tìm điểm vừa chèn -> Output: thấy ngay không cần duyệt hết cây.",[989,32542,32543],{},"Câu này cho thấy rẽ nhánh đúng thì tìm nhanh.",[968,32545,1482],{"id":1481},[973,32547,1485,32548,5599,32550,32553,32554,32556,32557,7386,32560,32562],{},[1487,32549,1493],{},[992,32551,32552],{},"day-045\u002F",". Điểm có ",[992,32555,20401],{}," chiều, dùng ",[992,32558,32559],{},"std::array\u003Cdouble, K>",[992,32561,20401],{}," là tham số template.",[981,32564,32566],{"id":32565},"bài-1-xây-k-d-tree-cân-bằng","Bài 1: Xây k-d tree cân bằng",[1352,32568,32570],{"className":1393,"code":32569,"language":1395,"meta":1357,"style":1357},"template \u003Cint K> struct KDNode { std::array\u003Cdouble, K> p; KDNode *left = nullptr, *right = nullptr; };\ntemplate \u003Cint K> class KDTree {\n public:\n  explicit KDTree(std::vector\u003Cstd::array\u003Cdouble, K>> pts);   \u002F\u002F xây bằng trung vị, dùng std::nth_element\n  void insert(const std::array\u003Cdouble, K> &p);\n  bool contains(const std::array\u003Cdouble, K> &p) const;\n  int  height() const;\n  bool checkInvariant() const;    \u002F\u002F mọi nút: cây trái \u003C p[axis] \u003C= cây phải\n};\n",[992,32571,32572,32577,32582,32586,32591,32596,32601,32606,32611],{"__ignoreMap":1357},[1023,32573,32574],{"class":1362,"line":63},[1023,32575,32576],{},"template \u003Cint K> struct KDNode { std::array\u003Cdouble, K> p; KDNode *left = nullptr, *right = nullptr; };\n",[1023,32578,32579],{"class":1362,"line":68},[1023,32580,32581],{},"template \u003Cint K> class KDTree {\n",[1023,32583,32584],{"class":1362,"line":73},[1023,32585,4836],{},[1023,32587,32588],{"class":1362,"line":78},[1023,32589,32590],{},"  explicit KDTree(std::vector\u003Cstd::array\u003Cdouble, K>> pts);   \u002F\u002F xây bằng trung vị, dùng std::nth_element\n",[1023,32592,32593],{"class":1362,"line":83},[1023,32594,32595],{},"  void insert(const std::array\u003Cdouble, K> &p);\n",[1023,32597,32598],{"class":1362,"line":88},[1023,32599,32600],{},"  bool contains(const std::array\u003Cdouble, K> &p) const;\n",[1023,32602,32603],{"class":1362,"line":93},[1023,32604,32605],{},"  int  height() const;\n",[1023,32607,32608],{"class":1362,"line":98},[1023,32609,32610],{},"  bool checkInvariant() const;    \u002F\u002F mọi nút: cây trái \u003C p[axis] \u003C= cây phải\n",[1023,32612,32613],{"class":1362,"line":103},[1023,32614,4866],{},[973,32616,32617,32618,13710,32620,1517],{},"Trục chia ở độ sâu ",[992,32619,12999],{},[992,32621,32622],{},"d % K",[1352,32624,32627],{"className":32625,"code":32626,"language":2241,"meta":1357},[2239],"7 điểm 2D: (2,3) (5,4) (9,6) (4,7) (8,1) (7,2) (6,5)\n-> gốc chia x, height = 2 (tính gốc là 0), checkInvariant = true\ncontains((8,1)) -> true; contains((8,2)) -> false\n",[992,32628,32626],{"__ignoreMap":1357},[2245,32630,32631],{},[973,32632,32633,32636,32637,32680,32681,1517],{},[992,32634,32635],{},"std::nth_element"," chia đoạn quanh trung vị trong ",[1023,32638,32640,32659],{"className":32639},[1026],[1023,32641,32643],{"className":32642},[1030],[1032,32644,32645],{"xmlns":1034},[1036,32646,32647,32657],{},[1039,32648,32649,32651,32653,32655],{},[1042,32650,1044],{},[1046,32652,1049],{"stretchy":1048},[1042,32654,1262],{},[1046,32656,1056],{"stretchy":1048},[1058,32658,1267],{"encoding":1060},[1023,32660,32662],{"className":32661,"ariaHidden":1066},[1065],[1023,32663,32665,32668,32671,32674,32677],{"className":32664},[1070],[1023,32666],{"className":32667,"style":1075},[1074],[1023,32669,1044],{"className":32670,"style":1081},[1079,1080],[1023,32672,1049],{"className":32673},[1085],[1023,32675,1262],{"className":32676},[1079,1080],[1023,32678,1056],{"className":32679},[1092],". Xây cả cây tốn ",[1023,32682,32684,32709],{"className":32683},[1026],[1023,32685,32687],{"className":32686},[1030],[1032,32688,32689],{"xmlns":1034},[1036,32690,32691,32707],{},[1039,32692,32693,32695,32697,32699,32701,32703,32705],{},[1042,32694,1044],{},[1046,32696,1049],{"stretchy":1048},[1042,32698,1262],{},[1042,32700,8397],{},[1046,32702,8400],{},[1042,32704,1262],{},[1046,32706,1056],{"stretchy":1048},[1058,32708,10463],{"encoding":1060},[1023,32710,32712],{"className":32711,"ariaHidden":1066},[1065],[1023,32713,32715,32718,32721,32724,32727,32730,32735,32738,32741],{"className":32714},[1070],[1023,32716],{"className":32717,"style":1075},[1074],[1023,32719,1044],{"className":32720,"style":1081},[1079,1080],[1023,32722,1049],{"className":32723},[1085],[1023,32725,1262],{"className":32726},[1079,1080],[1023,32728],{"className":32729,"style":8434},[2354],[1023,32731,8427,32733],{"className":32732},[8426],[1023,32734,7690],{"style":8430},[1023,32736],{"className":32737,"style":8434},[2354],[1023,32739,1262],{"className":32740},[1079,1080],[1023,32742,1056],{"className":32743},[1092],[981,32745,32747],{"id":32746},"bài-2-cân-bằng-và-lệch","Bài 2: Cân bằng và lệch",[2273,32749,32750,32818,32891],{},[989,32751,32752,32753,32815,32816,1517],{},"Xây cây từ ",[1023,32754,32756,32774],{"className":32755},[1026],[1023,32757,32759],{"className":32758},[1030],[1032,32760,32761],{"xmlns":1034},[1036,32762,32763,32771],{},[1039,32764,32765],{},[2327,32766,32767,32769],{},[1051,32768,2331],{},[1051,32770,2334],{},[1058,32772,32773],{"encoding":1060},"10^5",[1023,32775,32777],{"className":32776,"ariaHidden":1066},[1065],[1023,32778,32780,32783,32786],{"className":32779},[1070],[1023,32781],{"className":32782,"style":2369},[1074],[1023,32784,1053],{"className":32785},[1079],[1023,32787,32789,32792],{"className":32788},[1079],[1023,32790,2379],{"className":32791},[1079],[1023,32793,32795],{"className":32794},[2383],[1023,32796,32798],{"className":32797},[2387],[1023,32799,32801],{"className":32800},[2391],[1023,32802,32804],{"className":32803,"style":2369},[2395],[1023,32805,32806,32809],{"style":2398},[1023,32807],{"className":32808,"style":2403},[2402],[1023,32810,32812],{"className":32811},[2407,2408,2409,2410],[1023,32813,2334],{"className":32814},[1079,2410]," điểm ngẫu nhiên bằng trung vị. In ",[992,32817,7941],{},[989,32819,32820,32821,32882,32883,1509,32885,32888,32889,1517],{},"Chèn lần lượt ",[1023,32822,32824,32841],{"className":32823},[1026],[1023,32825,32827],{"className":32826},[1030],[1032,32828,32829],{"xmlns":1034},[1036,32830,32831,32839],{},[1039,32832,32833],{},[2327,32834,32835,32837],{},[1051,32836,2331],{},[1051,32838,2334],{},[1058,32840,32773],{"encoding":1060},[1023,32842,32844],{"className":32843,"ariaHidden":1066},[1065],[1023,32845,32847,32850,32853],{"className":32846},[1070],[1023,32848],{"className":32849,"style":2369},[1074],[1023,32851,1053],{"className":32852},[1079],[1023,32854,32856,32859],{"className":32855},[1079],[1023,32857,2379],{"className":32858},[1079],[1023,32860,32862],{"className":32861},[2383],[1023,32863,32865],{"className":32864},[2387],[1023,32866,32868],{"className":32867},[2391],[1023,32869,32871],{"className":32870,"style":2369},[2395],[1023,32872,32873,32876],{"style":2398},[1023,32874],{"className":32875,"style":2403},[2402],[1023,32877,32879],{"className":32878},[2407,2408,2409,2410],[1023,32880,2334],{"className":32881},[1079,2410]," điểm có ",[992,32884,3904],{},[992,32886,32887],{},"y"," tăng dần. In ",[992,32890,7941],{},[989,32892,6845,32893,32954,32955,32957],{},[1023,32894,32896,32913],{"className":32895},[1026],[1023,32897,32899],{"className":32898},[1030],[1032,32900,32901],{"xmlns":1034},[1036,32902,32903,32911],{},[1039,32904,32905],{},[2327,32906,32907,32909],{},[1051,32908,2331],{},[1051,32910,2334],{},[1058,32912,32773],{"encoding":1060},[1023,32914,32916],{"className":32915,"ariaHidden":1066},[1065],[1023,32917,32919,32922,32925],{"className":32918},[1070],[1023,32920],{"className":32921,"style":2369},[1074],[1023,32923,1053],{"className":32924},[1079],[1023,32926,32928,32931],{"className":32927},[1079],[1023,32929,2379],{"className":32930},[1079],[1023,32932,32934],{"className":32933},[2383],[1023,32935,32937],{"className":32936},[2387],[1023,32938,32940],{"className":32939},[2391],[1023,32941,32943],{"className":32942,"style":2369},[2395],[1023,32944,32945,32948],{"style":2398},[1023,32946],{"className":32947,"style":2403},[2402],[1023,32949,32951],{"className":32950},[2407,2408,2409,2410],[1023,32952,2334],{"className":32953},[1079,2410]," lần ",[992,32956,6936],{}," trên 2 cây.",[981,32959,32961],{"id":32960},"bài-3-truy-vấn-vùng-chữ-nhật-nâng-cao","Bài 3: Truy vấn vùng chữ nhật (nâng cao)",[973,32963,32964,32967,32968,32971],{},[992,32965,32966],{},"std::vector\u003CPoint> rangeQuery(const Box &b)",": trả mọi điểm nằm trong hộp ",[992,32969,32970],{},"[lo, hi]",". Cắt nhánh khi hộp không giao phía bên kia mặt chia.",[1352,32973,32976],{"className":32974,"code":32975,"language":2241,"meta":1357},[2239],"7 điểm trên, hộp x in [4,8], y in [1,5] -> (5,4), (8,1), (7,2), (6,5)\n",[992,32977,32975],{"__ignoreMap":1357},[973,32979,32980,32981,33042],{},"Đếm số nút đã thăm. So với quét cả ",[1023,32982,32984,33001],{"className":32983},[1026],[1023,32985,32987],{"className":32986},[1030],[1032,32988,32989],{"xmlns":1034},[1036,32990,32991,32999],{},[1039,32992,32993],{},[2327,32994,32995,32997],{},[1051,32996,2331],{},[1051,32998,2334],{},[1058,33000,32773],{"encoding":1060},[1023,33002,33004],{"className":33003,"ariaHidden":1066},[1065],[1023,33005,33007,33010,33013],{"className":33006},[1070],[1023,33008],{"className":33009,"style":2369},[1074],[1023,33011,1053],{"className":33012},[1079],[1023,33014,33016,33019],{"className":33015},[1079],[1023,33017,2379],{"className":33018},[1079],[1023,33020,33022],{"className":33021},[2383],[1023,33023,33025],{"className":33024},[2387],[1023,33026,33028],{"className":33027},[2391],[1023,33029,33031],{"className":33030,"style":2369},[2395],[1023,33032,33033,33036],{"style":2398},[1023,33034],{"className":33035,"style":2403},[2402],[1023,33037,33039],{"className":33038},[2407,2408,2409,2410],[1023,33040,2334],{"className":33041},[1079,2410]," điểm cho 1000 hộp ngẫu nhiên nhỏ.",[981,33044,2711],{"id":2710},[986,33046,33048,33059,33065,33074],{"className":33047},[2715],[989,33049,33051,8082,33053,33056,33057,1517],{"className":33050},[2719],[2721,33052],{"disabled":2723,"type":2724},[992,33054,33055],{},"checkInvariant"," đúng sau mọi ",[992,33058,2251],{},[989,33060,33062,33064],{"className":33061},[2719],[2721,33063],{"disabled":2723,"type":2724}," Bảng chiều cao và thời gian Bài 2 có số thật.",[989,33066,33068,2308,33070,33073],{"className":33067},[2719],[2721,33069],{"disabled":2723,"type":2724},[992,33071,33072],{},"rangeQuery"," khớp quét tuyến tính trên 1000 truy vấn ngẫu nhiên.",[989,33075,33077,33079,33080,1509,33083,1517],{"className":33076},[2719],[2721,33078],{"disabled":2723,"type":2724}," Code chạy được cho cả ",[992,33081,33082],{},"K = 2",[992,33084,33085],{},"K = 3",[968,33087,2890],{"id":2889},[986,33089,33090,33093,33096,33099],{},[989,33091,33092],{},"k-d tree luân phiên chiều thế nào?",[989,33094,33095],{},"Bất biến phân hoạch phát biểu sao?",[989,33097,33098],{},"Vì sao phải chọn trung vị khi xây?",[989,33100,33101],{},"Cây lệch gây hại gì cho truy vấn?",[3014,33103],{},[973,33105,33106],{},"🌕 Bạn đã hoàn thành ngày 45. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,33108,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":33110},[33111,33112,33117,33118,33124],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":33113},[33114,33115,33116],{"id":32339,"depth":73,"text":32340},{"id":32357,"depth":73,"text":32358},{"id":32410,"depth":73,"text":32411},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":33119},[33120,33121,33122,33123],{"id":32565,"depth":73,"text":32566},{"id":32746,"depth":73,"text":32747},{"id":32960,"depth":73,"text":32961},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cây k-d cho dữ liệu nhiều chiều: luân phiên chiều phân hoạch, bất biến cây tìm kiếm, xây dựng cân bằng và tầm quan trọng của cân bằng.",{},[3050,8149],{"title":280,"description":33125},[33130,33131,3041],"kd-tree","spatial-index","TFvjU_P3XSwQwmtnsvJcZk4ThXV9sRhECHT_OJKJdRE",{"id":33134,"title":285,"body":33135,"category":8797,"day":288,"description":33716,"difficulty":5191,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":33717,"navigation":2723,"outcomes":3047,"path":286,"prerequisites":33718,"seo":33719,"stem":287,"tags":33720,"__hash__":33723},"challenges\u002Fchallenges\u002F46.ung-dung-nn-search.md",{"type":965,"value":33136,"toc":33700},[33137,33139,33142,33144,33148,33221,33225,33239,33243,33257,33316,33318,33332,33334,33350,33354,33429,33435,33438,33442,33445,33453,33457,33546,33637,33643,33645,33679,33681,33695,33697],[968,33138,971],{"id":970},[973,33140,33141],{},"Bài này học 4 ứng dụng tìm điểm gần nhất.\nỨng dụng này phủ từ giao hàng tới ảnh và vật lý.",[968,33143,979],{"id":978},[981,33145,33147],{"id":33146},"trạm-gần-nhất-tập-trung","Trạm gần nhất tập trung",[986,33149,33150,33153,33156,33218],{},[989,33151,33152],{},"Mỗi đơn hàng cần trạm gần nhất để giảm phí ship.",[989,33154,33155],{},"Cách tập trung: một máy giữ hết trạm bằng k-d tree.",[989,33157,33158,33159,33217],{},"Truy vấn ",[1023,33160,33162,33187],{"className":33161},[1026],[1023,33163,33165],{"className":33164},[1030],[1032,33166,33167],{"xmlns":1034},[1036,33168,33169,33185],{},[1039,33170,33171,33173,33175,33177,33179,33181,33183],{},[1042,33172,1044],{},[1046,33174,1049],{"stretchy":1048},[1042,33176,7684],{},[1042,33178,7687],{},[1042,33180,7690],{},[1042,33182,1262],{},[1046,33184,1056],{"stretchy":1048},[1058,33186,7697],{"encoding":1060},[1023,33188,33190],{"className":33189,"ariaHidden":1066},[1065],[1023,33191,33193,33196,33199,33202,33205,33208,33211,33214],{"className":33192},[1070],[1023,33194],{"className":33195,"style":1075},[1074],[1023,33197,1044],{"className":33198,"style":1081},[1079,1080],[1023,33200,1049],{"className":33201},[1085],[1023,33203,7684],{"className":33204,"style":7716},[1079,1080],[1023,33206,7687],{"className":33207},[1079,1080],[1023,33209,7690],{"className":33210,"style":7723},[1079,1080],[1023,33212,1262],{"className":33213},[1079,1080],[1023,33215,1056],{"className":33216},[1092],", đơn giản dễ bảo trì.",[989,33219,33220],{},"Ví dụ đời thường: một tổng đài điều hết xe trong thành phố.",[981,33222,33224],{"id":33223},"phân-tán-và-3-rắc-rối","Phân tán và 3 rắc rối",[986,33226,33227,33230,33233,33236],{},[989,33228,33229],{},"Chia bản đồ thành vùng, mỗi máy giữ một vùng.",[989,33231,33232],{},"Tốn độ trễ mạng HTTP khi hỏi nhiều máy.",[989,33234,33235],{},"Khó giữ đồng bộ khi trạm đóng mở liên tục.",[989,33237,33238],{},"Ví dụ đời thường: nhiều chi nhánh thì khó biết chỗ nào còn hàng.",[981,33240,33242],{"id":33241},"giảm-màu-ảnh-và-hạt-vật-lý","Giảm màu ảnh và hạt vật lý",[986,33244,33245,33248,33251,33254],{},[989,33246,33247],{},"Mỗi pixel tìm màu gần nhất trong bảng màu nhỏ.",[989,33249,33250],{},"Tập nhỏ thì duyệt hết, khỏi cần cây phức tạp.",[989,33252,33253],{},"Hạt vật lý: mỗi hạt chỉ tương tác trong bán kính.",[989,33255,33256],{},"Ví dụ đời thường: pha sơn gần nhất với mẫu, bầy cá chỉ nhìn bạn gần.",[1099,33258,33259,33270],{},[1102,33260,33261],{},[1105,33262,33263,33265,33268],{},[1108,33264,27318],{},[1108,33266,33267],{},"Cấu trúc hợp",[1108,33269,1116],{},[1118,33271,33272,33283,33294,33305],{},[1105,33273,33274,33277,33280],{},[1123,33275,33276],{},"Trạm tĩnh ít chiều",[1123,33278,33279],{},"k-d tree",[1123,33281,33282],{},"Cân bằng, nhanh",[1105,33284,33285,33288,33291],{},[1123,33286,33287],{},"Bản đồ động 2D",[1123,33289,33290],{},"R-tree",[1123,33292,33293],{},"Tách gộp cục bộ",[1105,33295,33296,33299,33302],{},[1123,33297,33298],{},"Bảng màu nhỏ",[1123,33300,33301],{},"Duyệt hết",[1123,33303,33304],{},"Vài trăm màu khỏi cây",[1105,33306,33307,33310,33313],{},[1123,33308,33309],{},"Tải cao phân tán",[1123,33311,33312],{},"Chia vùng",[1123,33314,33315],{},"Hết nghẽn một máy",[968,33317,1433],{"id":1432},[986,33319,33320,33323,33326,33329],{},[989,33321,33322],{},"Input: đơn trùng vị trí trạm A -> Output: gán đúng A, khoảng cách 0.",[989,33324,33325],{},"Câu này kiểm tra biên trùng vị trí xử lý đúng.",[989,33327,33328],{},"Input: bán kính tương tác bằng 0 -> Output: không cặp hạt nào tương tác.",[989,33330,33331],{},"Câu này kiểm tra truy vấn vùng ở biên dưới.",[968,33333,1482],{"id":1481},[973,33335,1485,33336,33338,33339,33342,33343,33346,33347,1517],{},[1487,33337,1493],{}," (hoặc Python cho phần ảnh). Dùng ",[992,33340,33341],{},"KDTree"," ngày 45 và thêm hàm ",[992,33344,33345],{},"nearest"," đơn giản (có thể dùng bản của ngày 69 sau này, hôm nay viết bản cơ bản có cắt nhánh). Nộp vào ",[992,33348,33349],{},"day-046\u002F",[981,33351,33353],{"id":33352},"bài-1-gán-đơn-hàng-cho-trạm-gần-nhất","Bài 1: Gán đơn hàng cho trạm gần nhất",[1099,33355,33356,33364],{},[1102,33357,33358],{},[1105,33359,33360,33362],{},[1108,33361,1566],{},[1108,33363,2547],{},[1118,33365,33366,33419],{},[1105,33367,33368,33373],{},[1123,33369,33370],{},[992,33371,33372],{},"int nearestBrute(const std::vector\u003CPoint> &hubs, Point q)",[1123,33374,33375,33376],{},"Quét hết, ",[1023,33377,33379,33398],{"className":33378},[1026],[1023,33380,33382],{"className":33381},[1030],[1032,33383,33384],{"xmlns":1034},[1036,33385,33386,33396],{},[1039,33387,33388,33390,33392,33394],{},[1042,33389,1044],{},[1046,33391,1049],{"stretchy":1048},[1042,33393,1262],{},[1046,33395,1056],{"stretchy":1048},[1058,33397,1267],{"encoding":1060},[1023,33399,33401],{"className":33400,"ariaHidden":1066},[1065],[1023,33402,33404,33407,33410,33413,33416],{"className":33403},[1070],[1023,33405],{"className":33406,"style":1075},[1074],[1023,33408,1044],{"className":33409,"style":1081},[1079,1080],[1023,33411,1049],{"className":33412},[1085],[1023,33414,1262],{"className":33415},[1079,1080],[1023,33417,1056],{"className":33418},[1092],[1105,33420,33421,33426],{},[1123,33422,33423],{},[992,33424,33425],{},"int nearestKD(const KDTree\u003C2> &t, Point q)",[1123,33427,33428],{},"Đi xuống lá rồi quay lui, chỉ thăm nhánh bên kia khi khoảng cách tới mặt chia nhỏ hơn đáp án hiện tại",[1352,33430,33433],{"className":33431,"code":33432,"language":2241,"meta":1357},[2239],"hubs = (0,0) (10,0) (0,10); q=(1,1) -> hub 0; q=(9,2) -> hub 1\nq trùng hub -> khoảng cách 0\n",[992,33434,33432],{"__ignoreMap":1357},[973,33436,33437],{},"Sinh 10.000 trạm và 100.000 đơn ngẫu nhiên. Kiểm tra 2 hàm cho cùng đáp án. In thời gian.",[981,33439,33441],{"id":33440},"bài-2-giảm-màu-ảnh","Bài 2: Giảm màu ảnh",[973,33443,33444],{},"Đọc ảnh PPM (P3 hoặc P6), tự viết bộ đọc. Bảng màu 16 màu cố định (ví dụ bảng màu CGA).",[2273,33446,33447,33450],{},[989,33448,33449],{},"Mỗi pixel đổi thành màu gần nhất trong bảng (khoảng cách Euclid trong RGB). Ghi ra ảnh mới.",[989,33451,33452],{},"So thời gian giữa quét 16 màu và k-d tree 16 màu. Giải thích vì sao tập nhỏ thì quét nhanh hơn.",[981,33454,33456],{"id":33455},"bài-3-hạt-tương-tác-trong-bán-kính-nâng-cao","Bài 3: Hạt tương tác trong bán kính (nâng cao)",[973,33458,33459,33460,33542,33543,4437],{},"Mô phỏng 5000 hạt ngẫu nhiên trong hộp ",[1023,33461,33463,33489],{"className":33462},[1026],[1023,33464,33466],{"className":33465},[1030],[1032,33467,33468],{"xmlns":1034},[1036,33469,33470,33486],{},[1039,33471,33472,33474,33476,33478,33480],{},[1046,33473,14806],{"stretchy":1048},[1051,33475,2379],{},[1046,33477,13897],{"separator":1066},[1051,33479,1053],{},[2327,33481,33482,33484],{},[1046,33483,14817],{"stretchy":1048},[1051,33485,2457],{},[1058,33487,33488],{"encoding":1060},"[0,1]^2",[1023,33490,33492],{"className":33491,"ariaHidden":1066},[1065],[1023,33493,33495,33498,33501,33504,33507,33510,33513],{"className":33494},[1070],[1023,33496],{"className":33497,"style":2476},[1074],[1023,33499,14806],{"className":33500},[1085],[1023,33502,2379],{"className":33503},[1079],[1023,33505,13897],{"className":33506},[13943],[1023,33508],{"className":33509,"style":8434},[2354],[1023,33511,1053],{"className":33512},[1079],[1023,33514,33516,33519],{"className":33515},[1092],[1023,33517,14817],{"className":33518},[1092],[1023,33520,33522],{"className":33521},[2383],[1023,33523,33525],{"className":33524},[2387],[1023,33526,33528],{"className":33527},[2391],[1023,33529,33531],{"className":33530,"style":2369},[2395],[1023,33532,33533,33536],{"style":2398},[1023,33534],{"className":33535,"style":2403},[2402],[1023,33537,33539],{"className":33538},[2407,2408,2409,2410],[1023,33540,2457],{"className":33541},[1079,2410],". Với bán kính ",[992,33544,33545],{},"r = 0.01",[2273,33547,33548,33628,33634],{},[989,33549,33550,33551,33553,33554,33627],{},"Đếm số cặp hạt cách nhau dưới ",[992,33552,12970],{}," bằng 2 cách: quét mọi cặp ",[1023,33555,33557,33580],{"className":33556},[1026],[1023,33558,33560],{"className":33559},[1030],[1032,33561,33562],{"xmlns":1034},[1036,33563,33564,33578],{},[1039,33565,33566,33568,33570,33576],{},[1042,33567,1044],{},[1046,33569,1049],{"stretchy":1048},[2327,33571,33572,33574],{},[1042,33573,1262],{},[1051,33575,2457],{},[1046,33577,1056],{"stretchy":1048},[1058,33579,2839],{"encoding":1060},[1023,33581,33583],{"className":33582,"ariaHidden":1066},[1065],[1023,33584,33586,33589,33592,33595,33624],{"className":33585},[1070],[1023,33587],{"className":33588,"style":2476},[1074],[1023,33590,1044],{"className":33591,"style":1081},[1079,1080],[1023,33593,1049],{"className":33594},[1085],[1023,33596,33598,33601],{"className":33597},[1079],[1023,33599,1262],{"className":33600},[1079,1080],[1023,33602,33604],{"className":33603},[2383],[1023,33605,33607],{"className":33606},[2387],[1023,33608,33610],{"className":33609},[2391],[1023,33611,33613],{"className":33612,"style":2369},[2395],[1023,33614,33615,33618],{"style":2398},[1023,33616],{"className":33617,"style":2403},[2402],[1023,33619,33621],{"className":33620},[2407,2408,2409,2410],[1023,33622,2457],{"className":33623},[1079,2410],[1023,33625,1056],{"className":33626},[1092]," và truy vấn vùng k-d tree.",[989,33629,33630,33631,33633],{},"Cách thứ 3: chia lưới ô cỡ ",[992,33632,12970],{},", chỉ xét 9 ô lân cận.",[989,33635,33636],{},"In số cặp (3 cách phải bằng nhau) và thời gian.",[1352,33638,33641],{"className":33639,"code":33640,"language":2241,"meta":1357},[2239],"r = 0 -> 0 cặp\n",[992,33642,33640],{"__ignoreMap":1357},[981,33644,2711],{"id":2710},[986,33646,33648,33661,33667,33673],{"className":33647},[2715],[989,33649,33651,2308,33653,33656,33657,33660],{"className":33650},[2719],[2721,33652],{"disabled":2723,"type":2724},[992,33654,33655],{},"nearestKD"," khớp ",[992,33658,33659],{},"nearestBrute"," trên 100.000 truy vấn.",[989,33662,33664,33666],{"className":33663},[2719],[2721,33665],{"disabled":2723,"type":2724}," Ảnh giảm màu xuất ra đúng, có ảnh trước và sau trong repo.",[989,33668,33670,33672],{"className":33669},[2719],[2721,33671],{"disabled":2723,"type":2724}," Bài 3: 3 cách cho cùng số cặp, có bảng thời gian.",[989,33674,33676,33678],{"className":33675},[2719],[2721,33677],{"disabled":2723,"type":2724}," Viết được khi nào nên dùng cây, khi nào quét thẳng là đủ.",[968,33680,2890],{"id":2889},[986,33682,33683,33686,33689,33692],{},[989,33684,33685],{},"Cách tập trung tìm trạm gần nhất thế nào?",[989,33687,33688],{},"Phân tán gặp 3 khó khăn nào?",[989,33690,33691],{},"Giảm màu ảnh là tìm gì gần nhất?",[989,33693,33694],{},"Khi nào nên duyệt hết thay vì dùng cây?",[3014,33696],{},[973,33698,33699],{},"🌕 Bạn đã hoàn thành ngày 46. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":33701},[33702,33703,33708,33709,33715],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":33704},[33705,33706,33707],{"id":33146,"depth":73,"text":33147},{"id":33223,"depth":73,"text":33224},{"id":33241,"depth":73,"text":33242},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":33710},[33711,33712,33713,33714],{"id":33352,"depth":73,"text":33353},{"id":33440,"depth":73,"text":33441},{"id":33455,"depth":73,"text":33456},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bốn ứng dụng tìm kiếm lân cận: trạm trung chuyển gần nhất, bài toán tập trung và phân tán, giảm màu ảnh, tương tác hạt và tối ưu truy vấn đa chiều.",{},[14055],{"title":285,"description":33716},[33721,33722],"nn-search","applications","_dN7iyuJfLvZztbdfCmXxafN2VTHk8WFNklH198sAeU",{"id":33725,"title":290,"body":33726,"category":8797,"day":293,"description":34172,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":34173,"navigation":2723,"outcomes":3047,"path":291,"prerequisites":34174,"seo":34175,"stem":292,"tags":34176,"__hash__":34179},"challenges\u002Fchallenges\u002F47.kmeans.md",{"type":965,"value":33727,"toc":34156},[33728,33730,33733,33735,33739,33753,33757,33771,33775,33789,33839,33841,33855,33857,33868,33872,33892,33945,33951,33955,33980,33984,34100,34102,34133,34135,34149,34151,34154],[968,33729,971],{"id":970},[973,33731,33732],{},"Bài này học K-means gom nhóm không cần nhãn.\nThuật toán này giúp phân khúc khách hàng nhanh gọn.",[968,33734,979],{"id":978},[981,33736,33738],{"id":33737},"hai-bước-lặp","Hai bước lặp",[986,33740,33741,33744,33747,33750],{},[989,33742,33743],{},"Bước gán: mỗi điểm về với tâm gần nhất.",[989,33745,33746],{},"Bước cập nhật: mỗi tâm dời về giữa các điểm của nó.",[989,33748,33749],{},"Tổng bình phương khoảng cách tới tâm (inertia) không bao giờ tăng qua mỗi vòng, nên thuật toán chắc chắn dừng.",[989,33751,33752],{},"Ví dụ đời thường: chia lớp rồi dời bàn giáo viên ra giữa lớp.",[981,33754,33756],{"id":33755},"khởi-tạo-và-dừng","Khởi tạo và dừng",[986,33758,33759,33762,33765,33768],{},[989,33760,33761],{},"Khởi tạo xấu thì rơi vào đáp án dở cục bộ.",[989,33763,33764],{},"Nên khởi tạo các tâm cách xa nhau ngay đầu.",[989,33766,33767],{},"Dừng khi tâm không dịch nữa hoặc chạm trần vòng.",[989,33769,33770],{},"Ví dụ đời thường: chạy 5 lần chỗ ngồi khác nhau, giữ lần đẹp nhất.",[981,33772,33774],{"id":33773},"hạn-chế-và-lời-nguyền-chiều","Hạn chế và lời nguyền chiều",[986,33776,33777,33780,33783,33786],{},[989,33778,33779],{},"Phải biết trước k, sai k thì cụm vô nghĩa.",[989,33781,33782],{},"Chỉ hợp cụm tròn đều, thua cụm lưỡi liềm lồng nhau.",[989,33784,33785],{},"Chiều cao thì mọi điểm xa nhau như nhau, gần mất nghĩa.",[989,33787,33788],{},"Ví dụ đời thường: hai vòng tròn lồng nhau là mồ chôn K-means.",[1352,33790,33792],{"className":3538,"code":33791,"language":3540,"meta":1357,"style":1357},"# Khung K-means 2 bước lặp\ndef kmeans(diem, tam):\n    while True:  # lặp tới khi ổn định\n        gan = gan_tam_gan_nhat(diem, tam)  # bước gán\n        tam_moi = trung_binh_theo_nhom(diem, gan)  # bước cập nhật\n        if gan_khac_biet_nho(tam, tam_moi):  # tâm đứng yên\n            break\n        tam = tam_moi\n    return tam\n",[992,33793,33794,33799,33804,33809,33814,33819,33824,33829,33834],{"__ignoreMap":1357},[1023,33795,33796],{"class":1362,"line":63},[1023,33797,33798],{},"# Khung K-means 2 bước lặp\n",[1023,33800,33801],{"class":1362,"line":68},[1023,33802,33803],{},"def kmeans(diem, tam):\n",[1023,33805,33806],{"class":1362,"line":73},[1023,33807,33808],{},"    while True:  # lặp tới khi ổn định\n",[1023,33810,33811],{"class":1362,"line":78},[1023,33812,33813],{},"        gan = gan_tam_gan_nhat(diem, tam)  # bước gán\n",[1023,33815,33816],{"class":1362,"line":83},[1023,33817,33818],{},"        tam_moi = trung_binh_theo_nhom(diem, gan)  # bước cập nhật\n",[1023,33820,33821],{"class":1362,"line":88},[1023,33822,33823],{},"        if gan_khac_biet_nho(tam, tam_moi):  # tâm đứng yên\n",[1023,33825,33826],{"class":1362,"line":93},[1023,33827,33828],{},"            break\n",[1023,33830,33831],{"class":1362,"line":98},[1023,33832,33833],{},"        tam = tam_moi\n",[1023,33835,33836],{"class":1362,"line":103},[1023,33837,33838],{},"    return tam\n",[968,33840,1433],{"id":1432},[986,33842,33843,33846,33849,33852],{},[989,33844,33845],{},"Input: 2 cụm tách xa, k=2 -> Output: phân hoạch đúng hoàn hảo.",[989,33847,33848],{},"Câu này cho thấy cụm rõ thì khởi tạo nào cũng thắng.",[989,33850,33851],{},"Input: k=1 -> Output: tâm là trung bình toàn bộ dữ liệu.",[989,33853,33854],{},"Câu này kiểm tra biên một cụm duy nhất.",[968,33856,1482],{"id":1481},[973,33858,1485,33859,17626,33861,33864,33865,1517],{},[1487,33860,13531],{},[992,33862,33863],{},"sklearn.cluster"," trừ khi đối chiếu. Nộp vào ",[992,33866,33867],{},"day-047\u002F",[981,33869,33871],{"id":33870},"bài-1-k-means-cơ-bản","Bài 1: K-means cơ bản",[1352,33873,33875],{"className":3538,"code":33874,"language":3540,"meta":1357,"style":1357},"def kmeans(X: np.ndarray, k: int, init: str = \"random\", max_iter: int = 100,\n           tol: float = 1e-6, seed: int = 0) -> tuple[np.ndarray, np.ndarray, float]:\n    \"\"\"Trả (centroids k x d, labels n, inertia).\"\"\"\n",[992,33876,33877,33882,33887],{"__ignoreMap":1357},[1023,33878,33879],{"class":1362,"line":63},[1023,33880,33881],{},"def kmeans(X: np.ndarray, k: int, init: str = \"random\", max_iter: int = 100,\n",[1023,33883,33884],{"class":1362,"line":68},[1023,33885,33886],{},"           tol: float = 1e-6, seed: int = 0) -> tuple[np.ndarray, np.ndarray, float]:\n",[1023,33888,33889],{"class":1362,"line":73},[1023,33890,33891],{},"    \"\"\"Trả (centroids k x d, labels n, inertia).\"\"\"\n",[1099,33893,33894,33902],{},[1102,33895,33896],{},[1105,33897,33898,33900],{},[1108,33899,2547],{},[1108,33901,14241],{},[1118,33903,33904,33912,33920,33935],{},[1105,33905,33906,33909],{},[1123,33907,33908],{},"Bước gán",[1123,33910,33911],{},"Vector hóa bằng NumPy, không vòng lặp Python theo điểm",[1105,33913,33914,33917],{},[1123,33915,33916],{},"Bước cập nhật",[1123,33918,33919],{},"Tâm = trung bình điểm của cụm. Cụm rỗng thì đặt lại tâm tại điểm xa nhất",[1105,33921,33922,33925],{},[1123,33923,33924],{},"Dừng",[1123,33926,33927,33928,33931,33932],{},"Tâm dịch dưới ",[992,33929,33930],{},"tol"," hoặc hết ",[992,33933,33934],{},"max_iter",[1105,33936,33937,33942],{},[1123,33938,33939],{},[992,33940,33941],{},"inertia",[1123,33943,33944],{},"Tổng bình phương khoảng cách điểm tới tâm của nó",[1352,33946,33949],{"className":33947,"code":33948,"language":2241,"meta":1357},[2239],"2 cụm Gauss tách xa (tâm (0,0) và (10,10)), k=2 -> gán đúng 100%\nk=1 -> tâm = X.mean(axis=0)\nk > n -> ValueError\n",[992,33950,33948],{"__ignoreMap":1357},[981,33952,33954],{"id":33953},"bài-2-k-means-và-chọn-k","Bài 2: K-means++ và chọn k",[2273,33956,33957,33963,33966],{},[989,33958,1505,33959,33962],{},[992,33960,33961],{},"init=\"kmeans++\"",": tâm đầu ngẫu nhiên, tâm sau chọn với xác suất tỉ lệ bình phương khoảng cách tới tâm gần nhất.",[989,33964,33965],{},"Chạy 20 seed cho mỗi cách khởi tạo trên dữ liệu 5 cụm. In inertia tốt nhất, trung bình, tệ nhất.",[989,33967,33968,33969,33972,33973,33976,33977,33979],{},"Vẽ đường cong ",[1487,33970,33971],{},"elbow",": inertia theo ",[992,33974,33975],{},"k = 1..10",". Chỉ ra ",[992,33978,4022],{}," hợp lý.",[981,33981,33983],{"id":33982},"bài-3-giới-hạn-của-k-means-nâng-cao","Bài 3: Giới hạn của K-means (nâng cao)",[2273,33985,33986,33997,34097],{},[989,33987,33988,33989,33992,33993,33996],{},"Sinh dữ liệu 2 hình trăng lưỡi liềm lồng nhau (tự sinh hoặc ",[992,33990,33991],{},"sklearn.datasets.make_moons"," chỉ để tạo dữ liệu). Chạy K-means ",[992,33994,33995],{},"k=2",", vẽ kết quả sai.",[989,33998,33999,34002,34003,7386,34087,34090,34091,34094,34095,1517],{},[1487,34000,34001],{},"Lời nguyền số chiều:"," sinh 1000 điểm ngẫu nhiên đều trong ",[1023,34004,34006,34032],{"className":34005},[1026],[1023,34007,34009],{"className":34008},[1030],[1032,34010,34011],{"xmlns":1034},[1036,34012,34013,34029],{},[1039,34014,34015,34017,34019,34021,34023],{},[1046,34016,14806],{"stretchy":1048},[1051,34018,2379],{},[1046,34020,13897],{"separator":1066},[1051,34022,1053],{},[2327,34024,34025,34027],{},[1046,34026,14817],{"stretchy":1048},[1042,34028,12999],{},[1058,34030,34031],{"encoding":1060},"[0,1]^d",[1023,34033,34035],{"className":34034,"ariaHidden":1066},[1065],[1023,34036,34038,34042,34045,34048,34051,34054,34057],{"className":34037},[1070],[1023,34039],{"className":34040,"style":34041},[1074],"height:1.0991em;vertical-align:-0.25em;",[1023,34043,14806],{"className":34044},[1085],[1023,34046,2379],{"className":34047},[1079],[1023,34049,13897],{"className":34050},[13943],[1023,34052],{"className":34053,"style":8434},[2354],[1023,34055,1053],{"className":34056},[1079],[1023,34058,34060,34063],{"className":34059},[1092],[1023,34061,14817],{"className":34062},[1092],[1023,34064,34066],{"className":34065},[2383],[1023,34067,34069],{"className":34068},[2387],[1023,34070,34072],{"className":34071},[2391],[1023,34073,34076],{"className":34074,"style":34075},[2395],"height:0.8491em;",[1023,34077,34078,34081],{"style":2398},[1023,34079],{"className":34080,"style":2403},[2402],[1023,34082,34084],{"className":34083},[2407,2408,2409,2410],[1023,34085,12999],{"className":34086},[1079,1080,2410],[992,34088,34089],{},"d = 2, 10, 100, 1000",". Tính tỉ số ",[992,34092,34093],{},"(khoảng cách xa nhất - gần nhất) \u002F gần nhất"," từ 1 điểm tới các điểm còn lại. Vẽ tỉ số theo ",[992,34096,12999],{},[989,34098,34099],{},"Viết 4 câu giải thích hình vẽ.",[981,34101,2711],{"id":2710},[986,34103,34105,34111,34117,34123],{"className":34104},[2715],[989,34106,34108,34110],{"className":34107},[2719],[2721,34109],{"disabled":2723,"type":2724}," Test mẫu pass. Inertia không tăng qua các vòng lặp (assert trong code).",[989,34112,34114,34116],{"className":34113},[2719],[2721,34115],{"disabled":2723,"type":2724}," Bảng so sánh random và k-means++ có số thật.",[989,34118,34120,34122],{"className":34119},[2719],[2721,34121],{"disabled":2723,"type":2724}," Có hình elbow, hình trăng lưỡi liềm và hình lời nguyền số chiều.",[989,34124,34126,34128,34129,34132],{"className":34125},[2719],[2721,34127],{"disabled":2723,"type":2724}," Kết quả khớp ",[992,34130,34131],{},"sklearn.cluster.KMeans"," (cùng init) về inertia trong sai số 1%.",[968,34134,2890],{"id":2889},[986,34136,34137,34140,34143,34146],{},[989,34138,34139],{},"Hai bước gán và cập nhật làm gì?",[989,34141,34142],{},"Vì sao phải chạy nhiều lần khởi tạo?",[989,34144,34145],{},"K-means thua cụm hình dạng nào?",[989,34147,34148],{},"Chiều cao gây hại gì cho khoảng cách?",[3014,34150],{},[973,34152,34153],{},"🌕 Bạn đã hoàn thành ngày 47. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,34155,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":34157},[34158,34159,34164,34165,34171],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":34160},[34161,34162,34163],{"id":33737,"depth":73,"text":33738},{"id":33755,"depth":73,"text":33756},{"id":33773,"depth":73,"text":33774},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":34166},[34167,34168,34169,34170],{"id":33870,"depth":73,"text":33871},{"id":33953,"depth":73,"text":33954},{"id":33982,"depth":73,"text":33983},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật toán gom cụm K-means: logic vòng lặp, khởi tạo centroid, điều kiện dừng, hạn chế, lời nguyền chiều không gian và tăng tốc bằng k-d tree.",{},[15144],{"title":290,"description":34172},[34177,34178],"clustering","k-means","wwLqWK6VzgpQEMVokkMM9_vFEh5-2fsSEpqPxzYnkyo",{"id":34181,"title":295,"body":34182,"category":8797,"day":298,"description":34734,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":34735,"navigation":2723,"outcomes":3047,"path":296,"prerequisites":34736,"seo":34737,"stem":297,"tags":34738,"__hash__":34741},"challenges\u002Fchallenges\u002F48.dbscan.md",{"type":965,"value":34183,"toc":34718},[34184,34186,34189,34191,34195,34209,34213,34227,34231,34245,34294,34296,34310,34312,34322,34326,34351,34397,34403,34418,34422,34545,34638,34642,34663,34665,34695,34697,34711,34713,34716],[968,34185,971],{"id":970},[973,34187,34188],{},"Bài này học DBSCAN gom cụm theo chỗ đông người.\nThuật toán này bắt được cụm méo và tách nhiễu riêng.",[968,34190,979],{"id":978},[981,34192,34194],{"id":34193},"lõi-biên-nhiễu","Lõi biên nhiễu",[986,34196,34197,34200,34203,34206],{},[989,34198,34199],{},"Epsilon là bán kính nhìn quanh, minPts là số bạn tối thiểu.",[989,34201,34202],{},"Lõi: quanh mình đủ minPts điểm trong epsilon.",[989,34204,34205],{},"Biên: không phải lõi nhưng nằm gần một lõi.",[989,34207,34208],{},"Ví dụ đời thường: chợ đông là lõi, người đứng cửa chợ là biên.",[981,34210,34212],{"id":34211},"lan-truyền-mật-độ","Lan truyền mật độ",[986,34214,34215,34218,34221,34224],{},[989,34216,34217],{},"Trực tiếp: q gần p lõi thì q theo p, chiều một hướng.",[989,34219,34220],{},"Lan truyền: nối nhiều bước trực tiếp thành chuỗi qua lõi.",[989,34222,34223],{},"Cùng chuỗi lan truyền thì về chung một cụm.",[989,34225,34226],{},"Ví dụ đời thường: rủ nhau theo dây chuyền bạn của bạn.",[981,34228,34230],{"id":34229},"thuật-toán-mở-rộng","Thuật toán mở rộng",[986,34232,34233,34236,34239,34242],{},[989,34234,34235],{},"Duyệt từng điểm chưa thăm, truy vấn quanh epsilon.",[989,34237,34238],{},"Không đủ bạn thì gắn nhiễu tạm, đủ thì lập cụm mới.",[989,34240,34241],{},"Lõi thì nạp hết hàng xóm vào hàng đợi mở rộng.",[989,34243,34244],{},"Ví dụ đời thường: một người hô, cả xóm đông kéo tới.",[1099,34246,34247,34259],{},[1102,34248,34249],{},[1105,34250,34251,34253,34256],{},[1108,34252,5414],{},[1108,34254,34255],{},"K-means",[1108,34257,34258],{},"DBSCAN",[1118,34260,34261,34272,34283],{},[1105,34262,34263,34266,34269],{},[1123,34264,34265],{},"Số cụm",[1123,34267,34268],{},"Phải cho k trước",[1123,34270,34271],{},"Tự tìm, không cần k",[1105,34273,34274,34277,34280],{},[1123,34275,34276],{},"Hình dạng",[1123,34278,34279],{},"Tròn đều",[1123,34281,34282],{},"Méo lưỡi liềm vẫn bắt",[1105,34284,34285,34288,34291],{},[1123,34286,34287],{},"Nhiễu",[1123,34289,34290],{},"Ép hết vào cụm",[1123,34292,34293],{},"Gắn nhãn nhiễu riêng",[968,34295,1433],{"id":1432},[986,34297,34298,34301,34304,34307],{},[989,34299,34300],{},"Input: điểm đơn độc xa mọi cụm quá epsilon -> Output: gắn nhiễu cuối cùng.",[989,34302,34303],{},"Câu này cho thấy kẻ lạc loài bị tách riêng.",[989,34305,34306],{},"Input: minPts=1 -> Output: mọi điểm thành lõi, mỗi chùm liên thông là một cụm.",[989,34308,34309],{},"Câu này kiểm tra biên suy biến của tham số.",[968,34311,1482],{"id":1481},[973,34313,1485,34314,17626,34316,33864,34319,1517],{},[1487,34315,13531],{},[992,34317,34318],{},"sklearn.cluster.DBSCAN",[992,34320,34321],{},"day-048\u002F",[981,34323,34325],{"id":34324},"bài-1-dbscan-cơ-bản","Bài 1: DBSCAN cơ bản",[1352,34327,34329],{"className":3538,"code":34328,"language":3540,"meta":1357,"style":1357},"NOISE = -1\ndef dbscan(X: np.ndarray, eps: float, min_pts: int) -> np.ndarray:\n    \"\"\"Trả labels: 0, 1, 2... cho cụm, -1 cho nhiễu. min_pts tính cả chính điểm đó.\"\"\"\ndef region_query(X, i, eps) -> list[int]: ...\n",[992,34330,34331,34336,34341,34346],{"__ignoreMap":1357},[1023,34332,34333],{"class":1362,"line":63},[1023,34334,34335],{},"NOISE = -1\n",[1023,34337,34338],{"class":1362,"line":68},[1023,34339,34340],{},"def dbscan(X: np.ndarray, eps: float, min_pts: int) -> np.ndarray:\n",[1023,34342,34343],{"class":1362,"line":73},[1023,34344,34345],{},"    \"\"\"Trả labels: 0, 1, 2... cho cụm, -1 cho nhiễu. min_pts tính cả chính điểm đó.\"\"\"\n",[1023,34347,34348],{"class":1362,"line":78},[1023,34349,34350],{},"def region_query(X, i, eps) -> list[int]: ...\n",[1099,34352,34353,34361],{},[1102,34354,34355],{},[1105,34356,34357,34359],{},[1108,34358,2547],{},[1108,34360,14241],{},[1118,34362,34363,34373,34381,34389],{},[1105,34364,34365,34368],{},[1123,34366,34367],{},"Điểm lõi",[1123,34369,34370],{},[992,34371,34372],{},"len(region_query) >= min_pts",[1105,34374,34375,34378],{},[1123,34376,34377],{},"Mở rộng cụm",[1123,34379,34380],{},"Hàng đợi. Chỉ điểm lõi mới được nạp tiếp hàng xóm",[1105,34382,34383,34386],{},[1123,34384,34385],{},"Điểm biên",[1123,34387,34388],{},"Được gán vào cụm đầu tiên chạm tới nó",[1105,34390,34391,34394],{},[1123,34392,34393],{},"Nhiễu tạm",[1123,34395,34396],{},"Điểm đang là nhiễu mà sau đó chạm lõi thì đổi thành biên",[1352,34398,34401],{"className":34399,"code":34400,"language":2241,"meta":1357},[2239],"3 chùm cách xa + 1 điểm lẻ, eps=0.5, min_pts=4 -> 3 cụm, điểm lẻ = -1\nmin_pts = 1                                      -> không có nhiễu\neps rất nhỏ                                      -> mọi điểm là nhiễu\n",[992,34402,34400],{"__ignoreMap":1357},[973,34404,11480,34405,15881,34408,1656,34411,1656,34414,34417],{},[992,34406,34407],{},"point_types(X, eps, min_pts)",[992,34409,34410],{},"\"core\"",[992,34412,34413],{},"\"border\"",[992,34415,34416],{},"\"noise\""," cho từng điểm.",[981,34419,34421],{"id":34420},"bài-2-tăng-tốc-truy-vấn-vùng","Bài 2: Tăng tốc truy vấn vùng",[973,34423,34424,34427,34428,34471,34472,1517],{},[992,34425,34426],{},"region_query"," quét hết là ",[1023,34429,34431,34450],{"className":34430},[1026],[1023,34432,34434],{"className":34433},[1030],[1032,34435,34436],{"xmlns":1034},[1036,34437,34438,34448],{},[1039,34439,34440,34442,34444,34446],{},[1042,34441,1044],{},[1046,34443,1049],{"stretchy":1048},[1042,34445,1262],{},[1046,34447,1056],{"stretchy":1048},[1058,34449,1267],{"encoding":1060},[1023,34451,34453],{"className":34452,"ariaHidden":1066},[1065],[1023,34454,34456,34459,34462,34465,34468],{"className":34455},[1070],[1023,34457],{"className":34458,"style":1075},[1074],[1023,34460,1044],{"className":34461,"style":1081},[1079,1080],[1023,34463,1049],{"className":34464},[1085],[1023,34466,1262],{"className":34467},[1079,1080],[1023,34469,1056],{"className":34470},[1092],", tổng ",[1023,34473,34475,34498],{"className":34474},[1026],[1023,34476,34478],{"className":34477},[1030],[1032,34479,34480],{"xmlns":1034},[1036,34481,34482,34496],{},[1039,34483,34484,34486,34488,34494],{},[1042,34485,1044],{},[1046,34487,1049],{"stretchy":1048},[2327,34489,34490,34492],{},[1042,34491,1262],{},[1051,34493,2457],{},[1046,34495,1056],{"stretchy":1048},[1058,34497,2839],{"encoding":1060},[1023,34499,34501],{"className":34500,"ariaHidden":1066},[1065],[1023,34502,34504,34507,34510,34513,34542],{"className":34503},[1070],[1023,34505],{"className":34506,"style":2476},[1074],[1023,34508,1044],{"className":34509,"style":1081},[1079,1080],[1023,34511,1049],{"className":34512},[1085],[1023,34514,34516,34519],{"className":34515},[1079],[1023,34517,1262],{"className":34518},[1079,1080],[1023,34520,34522],{"className":34521},[2383],[1023,34523,34525],{"className":34524},[2387],[1023,34526,34528],{"className":34527},[2391],[1023,34529,34531],{"className":34530,"style":2369},[2395],[1023,34532,34533,34536],{"style":2398},[1023,34534],{"className":34535,"style":2403},[2402],[1023,34537,34539],{"className":34538},[2407,2408,2409,2410],[1023,34540,2457],{"className":34541},[1079,2410],[1023,34543,1056],{"className":34544},[1092],[2273,34546,34547,34554],{},[989,34548,34549,34550,34553],{},"Chia lưới ô cỡ ",[992,34551,34552],{},"eps",". Chỉ xét 9 ô lân cận (2D).",[989,34555,34556,34557,34637],{},"Chạy với ",[1023,34558,34560,34589],{"className":34559},[1026],[1023,34561,34563],{"className":34562},[1030],[1032,34564,34565],{"xmlns":1034},[1036,34566,34567,34586],{},[1039,34568,34569,34571,34573,34576,34578,34581,34583],{},[1042,34570,1262],{},[1046,34572,2325],{},[1051,34574,34575],{},"2000",[1046,34577,13897],{"separator":1066},[1051,34579,34580],{},"10000",[1046,34582,13897],{"separator":1066},[1051,34584,34585],{},"50000",[1058,34587,34588],{"encoding":1060},"n = 2000, 10000, 50000",[1023,34590,34592,34610],{"className":34591,"ariaHidden":1066},[1065],[1023,34593,34595,34598,34601,34604,34607],{"className":34594},[1070],[1023,34596],{"className":34597,"style":2347},[1074],[1023,34599,1262],{"className":34600},[1079,1080],[1023,34602],{"className":34603,"style":2355},[2354],[1023,34605,2325],{"className":34606},[2359],[1023,34608],{"className":34609,"style":2355},[2354],[1023,34611,34613,34616,34619,34622,34625,34628,34631,34634],{"className":34612},[1070],[1023,34614],{"className":34615,"style":13936},[1074],[1023,34617,34575],{"className":34618},[1079],[1023,34620,13897],{"className":34621},[13943],[1023,34623],{"className":34624,"style":8434},[2354],[1023,34626,34580],{"className":34627},[1079],[1023,34629,13897],{"className":34630},[13943],[1023,34632],{"className":34633,"style":8434},[2354],[1023,34635,34585],{"className":34636},[1079],". In thời gian 2 cách. Kết quả nhãn phải giống nhau.",[981,34639,34641],{"id":34640},"bài-3-chọn-eps-và-so-với-k-means-nâng-cao","Bài 3: Chọn eps và so với K-means (nâng cao)",[2273,34643,34644,34657,34660],{},[989,34645,34646,34649,34650,34653,34654,34656],{},[1487,34647,34648],{},"k-distance plot:"," với mỗi điểm tính khoảng cách tới hàng xóm thứ ",[992,34651,34652],{},"min_pts",". Sắp xếp giảm dần và vẽ. Chọn ",[992,34655,34552],{}," tại \"khuỷu\".",[989,34658,34659],{},"Chạy DBSCAN và K-means (ngày 47) trên dữ liệu trăng lưỡi liềm và dữ liệu 3 cụm có mật độ khác nhau. Vẽ 4 hình.",[989,34661,34662],{},"Viết bảng: khi nào DBSCAN thắng, khi nào K-means thắng.",[981,34664,2711],{"id":2710},[986,34666,34668,34677,34683,34689],{"className":34667},[2715],[989,34669,34671,34673,34674,34676],{"className":34670},[2719],[2721,34672],{"disabled":2723,"type":2724}," Test mẫu pass. Nhãn khớp ",[992,34675,17633],{}," (sau khi đổi tên cụm) trên 3 bộ dữ liệu.",[989,34678,34680,34682],{"className":34679},[2719],[2721,34681],{"disabled":2723,"type":2724}," Bản lưới cho cùng kết quả và nhanh hơn rõ.",[989,34684,34686,34688],{"className":34685},[2719],[2721,34687],{"disabled":2723,"type":2724}," Có k-distance plot và 4 hình so sánh.",[989,34690,34692,34694],{"className":34691},[2719],[2721,34693],{"disabled":2723,"type":2724}," Giải thích được vì sao \"density-reachable\" không đối xứng.",[968,34696,2890],{"id":2889},[986,34698,34699,34702,34705,34708],{},[989,34700,34701],{},"Điểm lõi, biên, nhiễu định nghĩa sao?",[989,34703,34704],{},"Lan truyền mật độ khác trực tiếp thế nào?",[989,34706,34707],{},"Thuật toán mở rộng cụm chạy ra sao?",[989,34709,34710],{},"DBSCAN thắng K-means ở điểm nào?",[3014,34712],{},[973,34714,34715],{},"🌕 Bạn đã hoàn thành ngày 48. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,34717,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":34719},[34720,34721,34726,34727,34733],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":34722},[34723,34724,34725],{"id":34193,"depth":73,"text":34194},{"id":34211,"depth":73,"text":34212},{"id":34229,"depth":73,"text":34230},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":34728},[34729,34730,34731,34732],{"id":34324,"depth":73,"text":34325},{"id":34420,"depth":73,"text":34421},{"id":34640,"depth":73,"text":34641},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Gom cụm dựa mật độ DBSCAN: điểm lõi biên nhiễu, trực tiếp và lan truyền mật độ, thuật toán, cài đặt và ưu nhược điểm.",{},[15144],{"title":295,"description":34734},[34177,34739,34740],"dbscan","density","deaWcM6aVSqQfm9M2s64z_pQx6vTjVG35ml7sq0UHqM",{"id":34743,"title":300,"body":34744,"category":8797,"day":303,"description":35328,"difficulty":5191,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":35329,"navigation":2723,"outcomes":3047,"path":301,"prerequisites":35330,"seo":35331,"stem":302,"tags":35332,"__hash__":35335},"challenges\u002Fchallenges\u002F49.danh-gia-clustering.md",{"type":965,"value":34745,"toc":35312},[34746,34748,34751,34753,34757,34771,34775,34789,34793,34807,34832,34834,34848,34850,34858,34862,34905,35184,35190,35194,35200,35230,35234,35252,35254,35289,35291,35305,35307,35310],[968,34747,971],{"id":970},[973,34749,34750],{},"Bài này học silhouette chấm điểm gom cụm không nhãn.\nĐiểm này giúp chọn k và so thuật toán công bằng.",[968,34752,979],{"id":978},[981,34754,34756],{"id":34755},"silhouette-một-điểm","Silhouette một điểm",[986,34758,34759,34762,34765,34768],{},[989,34760,34761],{},"a là khoảng cách trung bình tới bạn cùng cụm.",[989,34763,34764],{},"b là khoảng cách trung bình tới cụm hàng xóm gần nhất.",[989,34766,34767],{},"Điểm số = (b - a) \u002F max(a, b), từ -1 tới 1.",[989,34769,34770],{},"Ví dụ đời thường: ở đúng nhà thì điểm cao, ở nhầm nhà thì điểm âm.",[981,34772,34774],{"id":34773},"đọc-điểm-toàn-cục","Đọc điểm toàn cục",[986,34776,34777,34780,34783,34786],{},[989,34778,34779],{},"Trung bình mọi điểm ra điểm toàn cục của phân hoạch.",[989,34781,34782],{},"Trên 0.7 là rõ đẹp, 0.5 tới 0.7 là hợp lý.",[989,34784,34785],{},"0.25 tới 0.5 là yếu, dưới 0.25 là không cấu trúc.",[989,34787,34788],{},"Ví dụ đời thường: lớp nào cũng ngồi đúng chỗ thì điểm cao.",[981,34790,34792],{"id":34791},"chọn-k-và-bẫy","Chọn k và bẫy",[986,34794,34795,34798,34801,34804],{},[989,34796,34797],{},"Chạy k từ 2 tới 10, vẽ đường điểm, chọn đỉnh cao nhất.",[989,34799,34800],{},"Silhouette thiên vị cụm tròn nên chấm oan cụm vòng tròn.",[989,34802,34803],{},"Cụm đẹp về số mà vô nghĩa nghiệp vụ thì vẫn bỏ.",[989,34805,34806],{},"Ví dụ đời thường: chia theo mã bưu điện đẹp mà bán hàng không cần.",[1352,34808,34810],{"className":3538,"code":34809,"language":3540,"meta":1357,"style":1357},"# Ý tưởng silhouette một điểm\ndef silhouette(a, b):\n    # a: gắn kết trong nhà, b: tách biệt nhà bên\n    return (b - a) \u002F max(a, b)  # gần 1 là đúng nhà\n",[992,34811,34812,34817,34822,34827],{"__ignoreMap":1357},[1023,34813,34814],{"class":1362,"line":63},[1023,34815,34816],{},"# Ý tưởng silhouette một điểm\n",[1023,34818,34819],{"class":1362,"line":68},[1023,34820,34821],{},"def silhouette(a, b):\n",[1023,34823,34824],{"class":1362,"line":73},[1023,34825,34826],{},"    # a: gắn kết trong nhà, b: tách biệt nhà bên\n",[1023,34828,34829],{"class":1362,"line":78},[1023,34830,34831],{},"    return (b - a) \u002F max(a, b)  # gần 1 là đúng nhà\n",[968,34833,1433],{"id":1432},[986,34835,34836,34839,34842,34845],{},[989,34837,34838],{},"Input: 2 cụm tách rất xa -> Output: điểm toàn cục trên 0.9, không điểm âm.",[989,34840,34841],{},"Câu này cho thấy cụm rõ thì điểm gần tuyệt đối.",[989,34843,34844],{},"Input: gán nhãn ngẫu nhiên -> Output: điểm quanh 0.",[989,34846,34847],{},"Câu này cho thấy đoán bừa thì điểm lẹt đẹt.",[968,34849,1482],{"id":1481},[973,34851,1485,34852,34854,34855,1517],{},[1487,34853,13531],{}," với NumPy. Dùng K-means ngày 47 và DBSCAN ngày 48. Nộp vào ",[992,34856,34857],{},"day-049\u002F",[981,34859,34861],{"id":34860},"bài-1-silhouette-tự-cài","Bài 1: Silhouette tự cài",[1099,34863,34864,34872],{},[1102,34865,34866],{},[1105,34867,34868,34870],{},[1108,34869,1566],{},[1108,34871,2547],{},[1118,34873,34874,34894],{},[1105,34875,34876,34881],{},[1123,34877,34878],{},[992,34879,34880],{},"silhouette_samples(X, labels)",[1123,34882,34883,34884,34887,34888,34891,34892],{},"Trả mảng ",[992,34885,34886],{},"s(i)",". Điểm ở cụm 1 phần tử có ",[992,34889,34890],{},"s = 0",". Bỏ qua điểm nhiễu ",[992,34893,12548],{},[1105,34895,34896,34901],{},[1123,34897,34898],{},[992,34899,34900],{},"silhouette_score(X, labels)",[1123,34902,10513,34903],{},[992,34904,34886],{},[973,34906,34907,34908,34952,34953,34997,34998,1517],{},"Công thức: ",[1023,34909,34911,34931],{"className":34910},[1026],[1023,34912,34914],{"className":34913},[1030],[1032,34915,34916],{"xmlns":1034},[1036,34917,34918,34928],{},[1039,34919,34920,34922,34924,34926],{},[1042,34921,6207],{},[1046,34923,1049],{"stretchy":1048},[1042,34925,1837],{},[1046,34927,1056],{"stretchy":1048},[1058,34929,34930],{"encoding":1060},"a(i)",[1023,34932,34934],{"className":34933,"ariaHidden":1066},[1065],[1023,34935,34937,34940,34943,34946,34949],{"className":34936},[1070],[1023,34938],{"className":34939,"style":1075},[1074],[1023,34941,6207],{"className":34942},[1079,1080],[1023,34944,1049],{"className":34945},[1085],[1023,34947,1837],{"className":34948},[1079,1080],[1023,34950,1056],{"className":34951},[1092]," là khoảng cách trung bình tới điểm cùng cụm, ",[1023,34954,34956,34976],{"className":34955},[1026],[1023,34957,34959],{"className":34958},[1030],[1032,34960,34961],{"xmlns":1034},[1036,34962,34963,34973],{},[1039,34964,34965,34967,34969,34971],{},[1042,34966,17703],{},[1046,34968,1049],{"stretchy":1048},[1042,34970,1837],{},[1046,34972,1056],{"stretchy":1048},[1058,34974,34975],{"encoding":1060},"b(i)",[1023,34977,34979],{"className":34978,"ariaHidden":1066},[1065],[1023,34980,34982,34985,34988,34991,34994],{"className":34981},[1070],[1023,34983],{"className":34984,"style":1075},[1074],[1023,34986,17703],{"className":34987},[1079,1080],[1023,34989,1049],{"className":34990},[1085],[1023,34992,1837],{"className":34993},[1079,1080],[1023,34995,1056],{"className":34996},[1092]," là trung bình nhỏ nhất tới các cụm khác, ",[1023,34999,35001,35050],{"className":35000},[1026],[1023,35002,35004],{"className":35003},[1030],[1032,35005,35006],{"xmlns":1034},[1036,35007,35008,35047],{},[1039,35009,35010,35012,35014,35016,35018,35020],{},[1042,35011,29577],{},[1046,35013,1049],{"stretchy":1048},[1042,35015,1837],{},[1046,35017,1056],{"stretchy":1048},[1046,35019,2325],{},[18110,35021,35022,35030],{},[1039,35023,35024,35026,35028],{},[1042,35025,17703],{},[1046,35027,17698],{},[1042,35029,6207],{},[1039,35031,35032,35035,35037,35039,35041,35043,35045],{},[1042,35033,35034],{},"max",[1046,35036,8400],{},[1046,35038,1049],{"stretchy":1048},[1042,35040,6207],{},[1046,35042,13897],{"separator":1066},[1042,35044,17703],{},[1046,35046,1056],{"stretchy":1048},[1058,35048,35049],{"encoding":1060},"s(i) = \\frac{b - a}{\\max(a, b)}",[1023,35051,35053,35080],{"className":35052,"ariaHidden":1066},[1065],[1023,35054,35056,35059,35062,35065,35068,35071,35074,35077],{"className":35055},[1070],[1023,35057],{"className":35058,"style":1075},[1074],[1023,35060,29577],{"className":35061},[1079,1080],[1023,35063,1049],{"className":35064},[1085],[1023,35066,1837],{"className":35067},[1079,1080],[1023,35069,1056],{"className":35070},[1092],[1023,35072],{"className":35073,"style":2355},[2354],[1023,35075,2325],{"className":35076},[2359],[1023,35078],{"className":35079,"style":2355},[2354],[1023,35081,35083,35086],{"className":35082},[1070],[1023,35084],{"className":35085,"style":18167},[1074],[1023,35087,35089,35092,35181],{"className":35088},[1079],[1023,35090],{"className":35091},[1085,18174],[1023,35093,35095],{"className":35094},[18110],[1023,35096,35098,35173],{"className":35097},[2387,17732],[1023,35099,35101,35170],{"className":35100},[2391],[1023,35102,35104,35142,35150],{"className":35103,"style":18187},[2395],[1023,35105,35106,35109],{"style":18190},[1023,35107],{"className":35108,"style":18194},[2402],[1023,35110,35112],{"className":35111},[2407,2408,2409,2410],[1023,35113,35115,35127,35130,35133,35136,35139],{"className":35114},[1079,2410],[1023,35116,35118,35121,35124],{"className":35117},[8426,2410],[1023,35119,15437],{"className":35120},[2410],[1023,35122,6207],{"className":35123},[2410],[1023,35125,3904],{"className":35126},[2410],[1023,35128,1049],{"className":35129},[1085,2410],[1023,35131,6207],{"className":35132},[1079,1080,2410],[1023,35134,13897],{"className":35135},[13943,2410],[1023,35137,17703],{"className":35138},[1079,1080,2410],[1023,35140,1056],{"className":35141},[1092,2410],[1023,35143,35144,35147],{"style":18221},[1023,35145],{"className":35146,"style":18194},[2402],[1023,35148],{"className":35149,"style":18229},[18228],[1023,35151,35152,35155],{"style":18232},[1023,35153],{"className":35154,"style":18194},[2402],[1023,35156,35158],{"className":35157},[2407,2408,2409,2410],[1023,35159,35161,35164,35167],{"className":35160},[1079,2410],[1023,35162,17703],{"className":35163},[1079,1080,2410],[1023,35165,17698],{"className":35166},[13794,2410],[1023,35168,6207],{"className":35169},[1079,1080,2410],[1023,35171,17797],{"className":35172},[17796],[1023,35174,35176],{"className":35175},[2391],[1023,35177,35179],{"className":35178,"style":18260},[2395],[1023,35180],{},[1023,35182],{"className":35183},[1092,18174],[1352,35185,35188],{"className":35186,"code":35187,"language":2241,"meta":1357},[2239],"2 cụm tách rất xa         -> score > 0.9, không điểm âm\nNhãn ngẫu nhiên           -> score quanh 0\nChỉ có 1 cụm              -> ValueError\n",[992,35189,35187],{"__ignoreMap":1357},[981,35191,35193],{"id":35192},"bài-2-chọn-k-bằng-silhouette","Bài 2: Chọn k bằng silhouette",[973,35195,35196,35197,1517],{},"Dữ liệu 4 cụm Gauss. Chạy K-means với ",[992,35198,35199],{},"k = 2..10",[2273,35201,35202,35210,35223],{},[989,35203,35204,35205,35207,35208,22123],{},"Vẽ silhouette score theo ",[992,35206,4022],{},". Chọn ",[992,35209,4022],{},[989,35211,35212,35213,2434,35216,35219,35220,35222],{},"Vẽ ",[1487,35214,35215],{},"silhouette plot",[992,35217,35218],{},"k = 3, 4, 5",": mỗi cụm là một dải ",[992,35221,34886],{}," sắp giảm dần.",[989,35224,35225,35226,35229],{},"Chỉ ra cụm có nhiều điểm âm ở ",[992,35227,35228],{},"k = 5"," và giải thích.",[981,35231,35233],{"id":35232},"bài-3-khi-metric-nói-dối-nâng-cao","Bài 3: Khi metric nói dối (nâng cao)",[2273,35235,35236,35239,35246],{},[989,35237,35238],{},"Dữ liệu 2 vòng tròn đồng tâm. DBSCAN tách đúng 2 vòng. K-means cắt đôi. Tính silhouette cả hai. Giải thích vì sao silhouette chấm K-means cao hơn.",[989,35240,35241,35242,35245],{},"Tự cài ",[1487,35243,35244],{},"Davies-Bouldin index"," và so với silhouette trên cùng dữ liệu.",[989,35247,35248,35249,35251],{},"Phân khúc khách hàng: dữ liệu (tuổi, chi tiêu\u002Ftháng, số lần mua). Chọn ",[992,35250,4022],{},", rồi viết mỗi cụm một câu mô tả nghiệp vụ. Nếu không đặt tên được, ghi rõ.",[981,35253,2711],{"id":2710},[986,35255,35257,35268,35277,35283],{"className":35256},[2715],[989,35258,35260,34128,35262,35265,35266,1517],{"className":35259},[2719],[2721,35261],{"disabled":2723,"type":2724},[992,35263,35264],{},"sklearn.metrics.silhouette_score"," với sai số ",[992,35267,32245],{},[989,35269,35271,35273,35274,35276],{"className":35270},[2719],[2721,35272],{"disabled":2723,"type":2724}," Có hình silhouette theo ",[992,35275,4022],{}," và silhouette plot.",[989,35278,35280,35282],{"className":35279},[2719],[2721,35281],{"disabled":2723,"type":2724}," Bài 3 có ví dụ metric chấm sai kèm giải thích.",[989,35284,35286,35288],{"className":35285},[2719],[2721,35287],{"disabled":2723,"type":2724}," Mỗi cụm khách hàng có mô tả nghiệp vụ.",[968,35290,2890],{"id":2889},[986,35292,35293,35296,35299,35302],{},[989,35294,35295],{},"a và b trong silhouette là gì?",[989,35297,35298],{},"Điểm gần 1, gần 0, âm nghĩa là gì?",[989,35300,35301],{},"Dùng silhouette chọn k thế nào?",[989,35303,35304],{},"Bẫy cụm đẹp mà vô nghĩa là sao?",[3014,35306],{},[973,35308,35309],{},"🌕 Bạn đã hoàn thành ngày 49. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,35311,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":35313},[35314,35315,35320,35321,35327],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":35316},[35317,35318,35319],{"id":34755,"depth":73,"text":34756},{"id":34773,"depth":73,"text":34774},{"id":34791,"depth":73,"text":34792},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":35322},[35323,35324,35325,35326],{"id":34860,"depth":73,"text":34861},{"id":35192,"depth":73,"text":35193},{"id":35232,"depth":73,"text":35233},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đo chất lượng gom cụm không nhãn: silhouette từng điểm và toàn cục, diễn giải kết quả, chọn k và bẫy diễn giải sai.",{},[18469],{"title":300,"description":35328},[34177,35333,35334],"evaluation","silhouette","97NmHdJgdMFOzvbtWJLLcLv15p9DmY17M64sGsXftWk",{"id":35337,"title":305,"body":35338,"category":8797,"day":308,"description":35742,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":35743,"navigation":2723,"outcomes":3047,"path":306,"prerequisites":35744,"seo":35745,"stem":307,"tags":35746,"__hash__":35750},"challenges\u002Fchallenges\u002F50.mapreduce-co-ban.md",{"type":965,"value":35339,"toc":35726},[35340,35342,35345,35347,35351,35365,35369,35383,35387,35401,35431,35433,35447,35449,35459,35463,35488,35548,35554,35558,35623,35637,35643,35647,35674,35676,35703,35705,35719,35721,35724],[968,35341,971],{"id":970},[973,35343,35344],{},"Bài này học MapReduce chia việc lớn cho nhiều máy.\nMô hình này giúp đếm triệu phiếu bầu siêu nhanh.",[968,35346,979],{"id":978},[981,35348,35350],{"id":35349},"song-song-và-phân-tán","Song song và phân tán",[986,35352,35353,35356,35359,35362],{},[989,35354,35355],{},"Song song: nhiều luồng chung một bộ nhớ một máy.",[989,35357,35358],{},"Phân tán: nhiều máy riêng bộ nhớ, nói nhau qua mạng.",[989,35360,35361],{},"Phân tán lo thêm máy chết giữa chừng và mạng chậm.",[989,35363,35364],{},"Ví dụ đời thường: một bếp nhiều tay so với nhiều bếp nhiều quán.",[981,35366,35368],{"id":35367},"chuyện-vịt-donald","Chuyện vịt Donald",[986,35370,35371,35374,35377,35380],{},[989,35372,35373],{},"Donald một mình đếm triệu phiếu tới già không xong.",[989,35375,35376],{},"Thuê đàn vịt con mỗi con đếm một thùng riêng.",[989,35378,35379],{},"Mỗi con báo cáo số phiếu từng ứng viên thùng mình.",[989,35381,35382],{},"Ví dụ đời thường: chia lớp chấm thi rồi cộng bảng điểm lại.",[981,35384,35386],{"id":35385},"map-rồi-reduce","Map rồi reduce",[986,35388,35389,35392,35395,35398],{},[989,35390,35391],{},"Map: nhận một mảnh, nhả ra cặp khóa-giá trị trung gian.",[989,35393,35394],{},"Shuffle: gom mọi giá trị cùng khóa về cùng một máy.",[989,35396,35397],{},"Reduce: gộp danh sách giá trị thành kết quả cuối.",[989,35399,35400],{},"Ví dụ đời thường: đếm từ thì map nhả (từ,1), reduce cộng lại.",[1352,35402,35404],{"className":3538,"code":35403,"language":3540,"meta":1357,"style":1357},"# Đếm từ bằng map-reduce thu nhỏ\ndef map_dong(dong):\n    return [(tu, 1) for tu in dong.split()]  # mỗi từ một phiếu\ndef reduce_tu(tu, ds):\n    return (tu, sum(ds))  # cộng hết phiếu cùng từ\n",[992,35405,35406,35411,35416,35421,35426],{"__ignoreMap":1357},[1023,35407,35408],{"class":1362,"line":63},[1023,35409,35410],{},"# Đếm từ bằng map-reduce thu nhỏ\n",[1023,35412,35413],{"class":1362,"line":68},[1023,35414,35415],{},"def map_dong(dong):\n",[1023,35417,35418],{"class":1362,"line":73},[1023,35419,35420],{},"    return [(tu, 1) for tu in dong.split()]  # mỗi từ một phiếu\n",[1023,35422,35423],{"class":1362,"line":78},[1023,35424,35425],{},"def reduce_tu(tu, ds):\n",[1023,35427,35428],{"class":1362,"line":83},[1023,35429,35430],{},"    return (tu, sum(ds))  # cộng hết phiếu cùng từ\n",[968,35432,1433],{"id":1432},[986,35434,35435,35438,35441,35444],{},[989,35436,35437],{},"Input: 3 dòng văn bản đếm từ -> Output: tổng đếm bằng tổng số từ vào.",[989,35439,35440],{},"Câu này kiểm tra không mất không thừa một từ.",[989,35442,35443],{},"Input: đầu vào rỗng -> Output: đầu ra rỗng, không treo.",[989,35445,35446],{},"Câu này kiểm tra biên rỗng xử lý sạch.",[968,35448,1482],{"id":1481},[973,35450,1485,35451,7386,35453,5599,35456,1517],{},[1487,35452,13531],{},[992,35454,35455],{},"multiprocessing",[992,35457,35458],{},"day-050\u002F",[981,35460,35462],{"id":35461},"bài-1-khung-mapreduce-tí-hon","Bài 1: Khung MapReduce tí hon",[1352,35464,35466],{"className":3538,"code":35465,"language":3540,"meta":1357,"style":1357},"def run_mapreduce(inputs: list, mapper, reducer, n_workers: int = 4, combiner=None) -> dict:\n    \"\"\"mapper(item) -> iterable[(key, value)]\n       reducer(key, values: list) -> value\n       Map song song bằng multiprocessing.Pool, shuffle gom theo key, reduce song song.\"\"\"\n",[992,35467,35468,35473,35478,35483],{"__ignoreMap":1357},[1023,35469,35470],{"class":1362,"line":63},[1023,35471,35472],{},"def run_mapreduce(inputs: list, mapper, reducer, n_workers: int = 4, combiner=None) -> dict:\n",[1023,35474,35475],{"class":1362,"line":68},[1023,35476,35477],{},"    \"\"\"mapper(item) -> iterable[(key, value)]\n",[1023,35479,35480],{"class":1362,"line":73},[1023,35481,35482],{},"       reducer(key, values: list) -> value\n",[1023,35484,35485],{"class":1362,"line":78},[1023,35486,35487],{},"       Map song song bằng multiprocessing.Pool, shuffle gom theo key, reduce song song.\"\"\"\n",[1099,35489,35490,35499],{},[1102,35491,35492],{},[1105,35493,35494,35497],{},[1108,35495,35496],{},"Giai đoạn",[1108,35498,2547],{},[1118,35500,35501,35517,35532,35540],{},[1105,35502,35503,35506],{},[1123,35504,35505],{},"Map",[1123,35507,35508,35509,35512,35513,35516],{},"Chia ",[992,35510,35511],{},"inputs"," thành ",[992,35514,35515],{},"n_workers"," phần",[1105,35518,35519,35522],{},[1123,35520,35521],{},"Shuffle",[1123,35523,35524,35525,35528,35529],{},"Gom ",[992,35526,35527],{},"dict[key, list[value]]",", phân key cho reducer bằng ",[992,35530,35531],{},"hash(key) % n_workers",[1105,35533,35534,35537],{},[1123,35535,35536],{},"Reduce",[1123,35538,35539],{},"Chạy song song theo phân vùng",[1105,35541,35542,35545],{},[1123,35543,35544],{},"Combiner",[1123,35546,35547],{},"Nếu có, gộp cục bộ sau Map trước Shuffle",[1352,35549,35552],{"className":35550,"code":35551,"language":2241,"meta":1357},[2239],"Đếm từ 3 dòng \"a b a\", \"b c\", \"a\" -> {a: 3, b: 2, c: 1}\ninputs = []                        -> {}\n",[992,35553,35551],{"__ignoreMap":1357},[981,35555,35557],{"id":35556},"bài-2-đếm-phiếu-của-donald","Bài 2: Đếm phiếu của Donald",[973,35559,35560,35561,35622],{},"Sinh 10 file, mỗi file ",[1023,35562,35564,35581],{"className":35563},[1026],[1023,35565,35567],{"className":35566},[1030],[1032,35568,35569],{"xmlns":1034},[1036,35570,35571,35579],{},[1039,35572,35573],{},[2327,35574,35575,35577],{},[1051,35576,2331],{},[1051,35578,6866],{},[1058,35580,6869],{"encoding":1060},[1023,35582,35584],{"className":35583,"ariaHidden":1066},[1065],[1023,35585,35587,35590,35593],{"className":35586},[1070],[1023,35588],{"className":35589,"style":2369},[1074],[1023,35591,1053],{"className":35592},[1079],[1023,35594,35596,35599],{"className":35595},[1079],[1023,35597,2379],{"className":35598},[1079],[1023,35600,35602],{"className":35601},[2383],[1023,35603,35605],{"className":35604},[2387],[1023,35606,35608],{"className":35607},[2391],[1023,35609,35611],{"className":35610,"style":2369},[2395],[1023,35612,35613,35616],{"style":2398},[1023,35614],{"className":35615,"style":2403},[2402],[1023,35617,35619],{"className":35618},[2407,2408,2409,2410],[1023,35620,6866],{"className":35621},[1079,2410]," dòng, mỗi dòng là tên 1 ứng viên (5 ứng viên, phân bố không đều).",[2273,35624,35625,35628,35634],{},[989,35626,35627],{},"Đếm phiếu bằng khung Bài 1, mapper đọc 1 file.",[989,35629,14627,35630,35633],{},[992,35631,35632],{},"n_workers = 1, 2, 4, 8",". Vẽ tăng tốc.",[989,35635,35636],{},"So số cặp đi qua Shuffle khi có và không có combiner.",[1352,35638,35641],{"className":35639,"code":35640,"language":2241,"meta":1357},[2239],"Kiểm tra: tổng phiếu = 10.000.000\n",[992,35642,35640],{"__ignoreMap":1357},[981,35644,35646],{"id":35645},"bài-3-thêm-các-job-khác-nâng-cao","Bài 3: Thêm các job khác (nâng cao)",[2273,35648,35649,35658,35668],{},[989,35650,35651,35654,35655,1517],{},[1487,35652,35653],{},"Chỉ mục ngược:"," từ nhiều file văn bản, trả ",[992,35656,35657],{},"dict[từ, sorted list[tên file]]",[989,35659,35660,35663,35664,35667],{},[1487,35661,35662],{},"Nhiệt độ lớn nhất theo năm:"," từ file ",[992,35665,35666],{},"năm,nhiệt_độ",", trả max mỗi năm.",[989,35669,35670,35673],{},[1487,35671,35672],{},"Mô phỏng lỗi:"," mapper ném lỗi ngẫu nhiên 10% số lần. Thêm cơ chế chạy lại task lỗi tối đa 3 lần. Kết quả cuối vẫn đúng.",[981,35675,2711],{"id":2710},[986,35677,35679,35685,35691,35697],{"className":35678},[2715],[989,35680,35682,35684],{"className":35681},[2719],[2721,35683],{"disabled":2723,"type":2724}," Test mẫu pass, kết quả giống bản chạy tuần tự.",[989,35686,35688,35690],{"className":35687},[2719],[2721,35689],{"disabled":2723,"type":2724}," Bảng\u002Fbiểu đồ tăng tốc có số thật và giải thích vì sao không tăng tuyến tính.",[989,35692,35694,35696],{"className":35693},[2719],[2721,35695],{"disabled":2723,"type":2724}," Combiner giảm số cặp Shuffle, có số liệu.",[989,35698,35700,35702],{"className":35699},[2719],[2721,35701],{"disabled":2723,"type":2724}," Bài 3 chạy lại task lỗi mà kết quả vẫn đúng.",[968,35704,2890],{"id":2889},[986,35706,35707,35710,35713,35716],{},[989,35708,35709],{},"Song song khác phân tán ở đâu?",[989,35711,35712],{},"Chuyện vịt Donald ánh xạ map reduce sao?",[989,35714,35715],{},"Shuffle gom dữ liệu thế nào?",[989,35717,35718],{},"Bài nào không hợp với MapReduce?",[3014,35720],{},[973,35722,35723],{},"🌕 Bạn đã hoàn thành ngày 50. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,35725,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":35727},[35728,35729,35734,35735,35741],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":35730},[35731,35732,35733],{"id":35349,"depth":73,"text":35350},{"id":35367,"depth":73,"text":35368},{"id":35385,"depth":73,"text":35386},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":35736},[35737,35738,35739,35740],{"id":35461,"depth":73,"text":35462},{"id":35556,"depth":73,"text":35557},{"id":35645,"depth":73,"text":35646},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mô hình MapReduce qua câu chuyện Donald Duck: song song và phân tán, ánh xạ rồi rút gọn, shuffle và những gì ẩn dưới nắp capo.",{},[14055],{"title":305,"description":35742},[35747,35748,35749],"mapreduce","parallel","distributed","n_ReqwzlpNq9HkcLv0jDgFf1gyiZHxJjqJ9qdbh1oJ8",{"id":35752,"title":310,"body":35753,"category":8797,"day":313,"description":36097,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":36098,"navigation":2723,"outcomes":3047,"path":311,"prerequisites":36099,"seo":36100,"stem":312,"tags":36101,"__hash__":36104},"challenges\u002Fchallenges\u002F51.luat-gio-hang.md",{"type":965,"value":35754,"toc":36080},[35755,35757,35760,35762,35766,35780,35784,35798,35802,35816,35853,35857,35868,35870,35884,35886,35900,35904,35953,35959,35963,35983,35999,36005,36008,36012,36030,36032,36057,36059,36073,36075,36078],[968,35756,971],{"id":970},[973,35758,35759],{},"Bài này học luật giỏ hàng để gợi ý mua kèm.\nLuật này giúp tăng giá trị giỏ trung bình.",[968,35761,979],{"id":978},[981,35763,35765],{"id":35764},"ba-thước-đo-luật","Ba thước đo luật",[986,35767,35768,35771,35774,35777],{},[989,35769,35770],{},"Support: tỉ lệ giao dịch chứa cả hai vế.",[989,35772,35773],{},"Confidence: có vế trái thì bao nhiêu phần trăm có vế phải.",[989,35775,35776],{},"Lift: hút nhau (>1), độc lập (=1), đẩy nhau (\u003C1).",[989,35778,35779],{},"Ví dụ đời thường: mua mì thì 70% mua trứng kèm.",[981,35781,35783],{"id":35782},"apriori-cắt-tỉa","Apriori cắt tỉa",[986,35785,35786,35789,35792,35795],{},[989,35787,35788],{},"Đi theo tầng: tìm món đơn phổ biến rồi ghép đôi, ghép ba.",[989,35790,35791],{},"Nguyên lý: cha đã hiếm thì con chứa nó còn hiếm hơn.",[989,35793,35794],{},"Cắt cả nhánh ứng viên mà khỏi cần đếm.",[989,35796,35797],{},"Ví dụ đời thường: bột đã ế thì combo chứa bột cũng ế.",[981,35799,35801],{"id":35800},"fp-growth-nén-cây","FP-growth nén cây",[986,35803,35804,35807,35810,35813],{},[989,35805,35806],{},"Quét 1: đếm tần suất để xếp món theo thứ tự.",[989,35808,35809],{},"Quét 2: chèn giao dịch vào cây FP chia sẻ tiền tố.",[989,35811,35812],{},"Moi mẫu bằng đệ quy từ món hiếm nhất.",[989,35814,35815],{},"Ví dụ đời thường: nén ngàn hóa đơn thành một cái cây gọn.",[1099,35817,35818,35829],{},[1102,35819,35820],{},[1105,35821,35822,35824,35826],{},[1108,35823,9446],{},[1108,35825,7111],{},[1108,35827,35828],{},"Điểm yếu",[1118,35830,35831,35842],{},[1105,35832,35833,35836,35839],{},[1123,35834,35835],{},"Apriori",[1123,35837,35838],{},"Sinh ứng viên tầng",[1123,35840,35841],{},"Quét nhiều, ứng viên phình",[1105,35843,35844,35847,35850],{},[1123,35845,35846],{},"FP-growth",[1123,35848,35849],{},"Nén cây rồi moi",[1123,35851,35852],{},"Cây to thì nặng RAM",[981,35854,35856],{"id":35855},"phân-loại-luật","Phân loại luật",[986,35858,35859,35862,35865],{},[989,35860,35861],{},"Luật hiển nhiên (trivial): ai cũng biết, ví dụ mua bột mì thì mua men. Không đem lại giá trị mới.",[989,35863,35864],{},"Luật khó giải thích (inexplicable): số liệu mạnh nhưng không có lý do hợp lý, cần kiểm tra lại trước khi tin.",[989,35866,35867],{},"Luật hành động được (actionable): mới, có lý, dẫn tới quyết định cụ thể như xếp kệ hay tạo combo. Đây là thứ cần tìm.",[968,35869,1433],{"id":1432},[986,35871,35872,35875,35878,35881],{},[989,35873,35874],{},"Input: 6 giao dịch, tính luật mì -> trứng -> Output: support, confidence, lift cụ thể.",[989,35876,35877],{},"Câu này cho thấy 3 số nói 3 chuyện khác nhau.",[989,35879,35880],{},"Input: nâng ngưỡng support -> Output: tập phổ biến chỉ co lại không nở.",[989,35882,35883],{},"Câu này kiểm tra tính đơn điệu của cắt tỉa.",[968,35885,1482],{"id":1481},[973,35887,1485,35888,2256,35890,33864,35893,35896,35897,1517],{},[1487,35889,13531],{},[992,35891,35892],{},"mlxtend",[992,35894,35895],{},"day-051\u002F",". Giao dịch là ",[992,35898,35899],{},"list[frozenset[str]]",[981,35901,35903],{"id":35902},"bài-1-ba-độ-đo","Bài 1: Ba độ đo",[1099,35905,35906,35914],{},[1102,35907,35908],{},[1105,35909,35910,35912],{},[1108,35911,1566],{},[1108,35913,17652],{},[1118,35915,35916,35929,35941],{},[1105,35917,35918,35923],{},[1123,35919,35920],{},[992,35921,35922],{},"support(T, items)",[1123,35924,35925,35926],{},"Tỉ lệ giao dịch chứa ",[992,35927,35928],{},"items",[1105,35930,35931,35936],{},[1123,35932,35933],{},[992,35934,35935],{},"confidence(T, A, B)",[1123,35937,35938],{},[992,35939,35940],{},"support(A ∪ B) \u002F support(A)",[1105,35942,35943,35948],{},[1123,35944,35945],{},[992,35946,35947],{},"lift(T, A, B)",[1123,35949,35950],{},[992,35951,35952],{},"confidence(A, B) \u002F support(B)",[1352,35954,35957],{"className":35955,"code":35956,"language":2241,"meta":1357},[2239],"T = [{mì,trứng,sữa}, {mì,trứng}, {mì,bia}, {trứng,sữa}, {mì,trứng,bia}, {sữa}]\nsupport({mì,trứng})       -> 3\u002F6 = 0.5\nconfidence({mì}->{trứng}) -> 3\u002F4 = 0.75\nlift({mì}->{trứng})       -> 0.75 \u002F (4\u002F6) = 1.125\n",[992,35958,35956],{"__ignoreMap":1357},[981,35960,35962],{"id":35961},"bài-2-apriori","Bài 2: Apriori",[1352,35964,35966],{"className":3538,"code":35965,"language":3540,"meta":1357,"style":1357},"def apriori(T, min_support: float) -> dict[frozenset, float]: ...\ndef rules(freq: dict, min_conf: float) -> list[tuple[frozenset, frozenset, float, float, float]]:\n    \"\"\"Trả (A, B, support, confidence, lift), sắp theo lift giảm dần.\"\"\"\n",[992,35967,35968,35973,35978],{"__ignoreMap":1357},[1023,35969,35970],{"class":1362,"line":63},[1023,35971,35972],{},"def apriori(T, min_support: float) -> dict[frozenset, float]: ...\n",[1023,35974,35975],{"class":1362,"line":68},[1023,35976,35977],{},"def rules(freq: dict, min_conf: float) -> list[tuple[frozenset, frozenset, float, float, float]]:\n",[1023,35979,35980],{"class":1362,"line":73},[1023,35981,35982],{},"    \"\"\"Trả (A, B, support, confidence, lift), sắp theo lift giảm dần.\"\"\"\n",[973,35984,35985,35987,35988,35991,35992,35994,35995,35998],{},[1487,35986,6076],{}," ở tầng ",[992,35989,35990],{},"k+1",", chỉ sinh ứng viên từ 2 tập phổ biến tầng ",[992,35993,4022],{}," chung ",[992,35996,35997],{},"k-1"," phần tử đầu, và cắt ứng viên có tập con không phổ biến.",[1352,36000,36003],{"className":36001,"code":36002,"language":2241,"meta":1357},[2239],"T trên, min_support=0.5 -> {mì}, {trứng}, {sữa}, {mì,trứng}\nTăng min_support        -> số tập phổ biến không tăng (viết test)\n",[992,36004,36002],{"__ignoreMap":1357},[973,36006,36007],{},"In số ứng viên được đếm ở mỗi tầng, có và không có bước cắt tỉa.",[981,36009,36011],{"id":36010},"bài-3-fp-growth-và-dữ-liệu-thật-nâng-cao","Bài 3: FP-growth và dữ liệu thật (nâng cao)",[2273,36013,36014,36017,36020,36027],{},[989,36015,36016],{},"Cài FP-tree: đếm tần suất, sắp món trong giao dịch theo tần suất giảm dần, chèn vào cây có header table.",[989,36018,36019],{},"Cài FP-growth đệ quy trên conditional pattern base.",[989,36021,36022,36023,36026],{},"Chạy trên bộ dữ liệu giỏ hàng công khai (ví dụ Groceries, khoảng 10.000 giao dịch). So thời gian Apriori và FP-growth với ",[992,36024,36025],{},"min_support = 0.01, 0.005, 0.002",". Kết quả tập phổ biến phải giống nhau.",[989,36028,36029],{},"In 10 luật lift cao nhất và nhận xét 3 luật.",[981,36031,2711],{"id":2710},[986,36033,36035,36040,36046,36051],{"className":36034},[2715],[989,36036,36038,11986],{"className":36037},[2719],[2721,36039],{"disabled":2723,"type":2724},[989,36041,36043,36045],{"className":36042},[2719],[2721,36044],{"disabled":2723,"type":2724}," Apriori và FP-growth cho cùng tập phổ biến.",[989,36047,36049,25424],{"className":36048},[2719],[2721,36050],{"disabled":2723,"type":2724},[989,36052,36054,36056],{"className":36053},[2719],[2721,36055],{"disabled":2723,"type":2724}," Giải thích được vì sao lift \u003C 1 nghĩa là 2 món \"đẩy nhau\".",[968,36058,2890],{"id":2889},[986,36060,36061,36064,36067,36070],{},[989,36062,36063],{},"Support, confidence, lift đo gì?",[989,36065,36066],{},"Nguyên lý Apriori cắt tỉa sao?",[989,36068,36069],{},"FP-growth nén giao dịch vào đâu?",[989,36071,36072],{},"Bẫy lift cao support tí hon là sao?",[3014,36074],{},[973,36076,36077],{},"🌕 Bạn đã hoàn thành ngày 51. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,36079,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":36081},[36082,36083,36089,36090,36096],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":36084},[36085,36086,36087,36088],{"id":35764,"depth":73,"text":35765},{"id":35782,"depth":73,"text":35783},{"id":35800,"depth":73,"text":35801},{"id":35855,"depth":73,"text":35856},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":36091},[36092,36093,36094,36095],{"id":35902,"depth":73,"text":35903},{"id":35961,"depth":73,"text":35962},{"id":36010,"depth":73,"text":36011},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Khai phá luật kết hợp cho giỏ hàng: support confidence lift, ba loại luật, Apriori, hạn chế và FP-growth với cây FP.",{},[3050],{"title":310,"description":36097},[18472,36102,36103],"association-rules","apriori","1gZ_-SjW8b3rXsr4XEN6a8x2qIILCRbLqxrFoNswxAU",{"id":36106,"title":315,"body":36107,"category":8797,"day":318,"description":36486,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":36487,"navigation":2723,"outcomes":3047,"path":316,"prerequisites":36488,"seo":36489,"stem":317,"tags":36490,"__hash__":36493},"challenges\u002Fchallenges\u002F52.supervised-tong-quan.md",{"type":965,"value":36108,"toc":36470},[36109,36111,36114,36116,36120,36134,36138,36152,36156,36170,36219,36221,36235,36237,36248,36252,36258,36263,36267,36368,36374,36380,36384,36387,36410,36413,36415,36449,36451,36465,36467],[968,36110,971],{"id":970},[973,36112,36113],{},"Bài này học học có giám sát đoán từ dữ liệu gắn nhãn.\nKhung này giúp phân biệt phân loại và hồi quy rõ ràng.",[968,36115,979],{"id":978},[981,36117,36119],{"id":36118},"học-có-giám-sát-là-gì","Học có giám sát là gì",[986,36121,36122,36125,36128,36131],{},[989,36123,36124],{},"Vào là cặp dữ liệu kèm nhãn đúng để học theo.",[989,36126,36127],{},"Mục tiêu là đoán đúng trên dữ liệu mới chưa thấy.",[989,36129,36130],{},"Giả thiết: huấn luyện và tương lai cùng phân phối.",[989,36132,36133],{},"Ví dụ đời thường: học từ đề có đáp án rồi thi đề mới.",[981,36135,36137],{"id":36136},"phân-loại-và-hồi-quy","Phân loại và hồi quy",[986,36139,36140,36143,36146,36149],{},[989,36141,36142],{},"Phân loại đoán nhãn rời rạc như rác hay không rác.",[989,36144,36145],{},"Hồi quy đoán số liên tục như giá nhà bao nhiêu.",[989,36147,36148],{},"Phân loại đếm tỉ lệ đúng, hồi quy đo khoảng cách sai.",[989,36150,36151],{},"Ví dụ đời thường: xếp thư vào hộc so với đoán cân nặng.",[981,36153,36155],{"id":36154},"pipeline-và-scaling","Pipeline và scaling",[986,36157,36158,36161,36164,36167],{},[989,36159,36160],{},"Pipeline: làm sạch, mã hóa, tạo đặc trưng, scaling.",[989,36162,36163],{},"Scaling đưa mọi đặc trưng về cùng thang đo.",[989,36165,36166],{},"Học tham số scaling trên train rồi áp y nguyên cho test.",[989,36168,36169],{},"Ví dụ đời thường: đổi mọi tiền về cùng đơn vị trước khi cộng.",[1099,36171,36172,36184],{},[1102,36173,36174],{},[1105,36175,36176,36179,36181],{},[1108,36177,36178],{},"Bước",[1108,36180,27321],{},[1108,36182,36183],{},"Bẫy",[1118,36185,36186,36197,36208],{},[1105,36187,36188,36191,36194],{},[1123,36189,36190],{},"Làm sạch",[1123,36192,36193],{},"Điền thiếu, bỏ ngoại lệ",[1123,36195,36196],{},"Bỏ luôn tín hiệu",[1105,36198,36199,36202,36205],{},[1123,36200,36201],{},"Scaling",[1123,36203,36204],{},"Chuẩn hóa về chung thang",[1123,36206,36207],{},"Tính trên cả test gây rò rỉ",[1105,36209,36210,36213,36216],{},[1123,36211,36212],{},"Chia tập",[1123,36214,36215],{},"Train, valid, test riêng",[1123,36217,36218],{},"Chỉnh trên test là tự lừa",[968,36220,1433],{"id":1432},[986,36222,36223,36226,36229,36232],{},[989,36224,36225],{},"Input: lọc thư rác, giá nhà, chấm tín dụng -> Output: phân loại đúng nhánh mỗi bài.",[989,36227,36228],{},"Câu này kiểm tra nhìn đầu ra là biết nhánh nào.",[989,36230,36231],{},"Input: pipeline chạy 2 lần cùng hạt giống -> Output: điểm số y hệt nhau.",[989,36233,36234],{},"Câu này kiểm tra tính tái lập của pipeline.",[968,36236,1482],{"id":1481},[973,36238,1485,36239,36241,36242,36244,36245,1517],{},[1487,36240,13531],{}," với NumPy và pandas. Bài 3 được dùng ",[992,36243,17633],{}," để đối chiếu. Nộp vào ",[992,36246,36247],{},"day-052\u002F",[981,36249,36251],{"id":36250},"bài-1-phân-loại-bài-toán","Bài 1: Phân loại bài toán",[973,36253,1505,36254,36257],{},[992,36255,36256],{},"problems.md"," phân loại 8 bài toán sau thành phân loại nhị phân, phân loại nhiều lớp, hồi quy. Mỗi bài ghi: đầu vào, nhãn, metric phù hợp.",[2273,36259,36260],{},[989,36261,36262],{},"Lọc thư rác. 2. Đoán giá nhà. 3. Nhận dạng chữ số viết tay. 4. Dự báo doanh thu tuần sau. 5. Duyệt khoản vay. 6. Chấm điểm tín dụng 300-850. 7. Phân loại cảm xúc 3 mức. 8. Đoán thời gian giao hàng (phút).",[981,36264,36266],{"id":36265},"bài-2-tự-cài-các-bước-pipeline","Bài 2: Tự cài các bước pipeline",[1099,36268,36269,36287],{},[1102,36270,36271],{},[1105,36272,36273,36275,36281],{},[1108,36274,4881],{},[1108,36276,36277,36280],{},[992,36278,36279],{},"fit(X)"," học gì",[1108,36282,36283,36286],{},[992,36284,36285],{},"transform(X)"," làm gì",[1118,36288,36289,36305,36320,36333,36349],{},[1105,36290,36291,36296,36299],{},[1123,36292,36293],{},[992,36294,36295],{},"StandardScaler",[1123,36297,36298],{},"mean, std mỗi cột",[1123,36300,36301,36304],{},[992,36302,36303],{},"(x - mean) \u002F std",", cột std = 0 thì giữ 0",[1105,36306,36307,36312,36315],{},[1123,36308,36309],{},[992,36310,36311],{},"MinMaxScaler",[1123,36313,36314],{},"min, max",[1123,36316,36317,36318],{},"về ",[992,36319,18294],{},[1105,36321,36322,36327,36330],{},[1123,36323,36324],{},[992,36325,36326],{},"OneHotEncoder",[1123,36328,36329],{},"tập giá trị mỗi cột phân loại",[1123,36331,36332],{},"cột nhị phân. Giá trị lạ lúc transform thì toàn 0",[1105,36334,36335,36340,36343],{},[1123,36336,36337],{},[992,36338,36339],{},"SimpleImputer",[1123,36341,36342],{},"trung vị mỗi cột",[1123,36344,36345,36346],{},"điền ",[992,36347,36348],{},"NaN",[1105,36350,36351,36356,36363],{},[1123,36352,36353],{},[992,36354,36355],{},"Pipeline(steps)",[1123,36357,36358,36359,36362],{},"gọi ",[992,36360,36361],{},"fit_transform"," lần lượt",[1123,36364,36358,36365,36362],{},[992,36366,36367],{},"transform",[973,36369,1505,36370,36373],{},[992,36371,36372],{},"train_test_split(X, y, test_size, seed)"," tự cài.",[1352,36375,36378],{"className":36376,"code":36377,"language":2241,"meta":1357},[2239],"StandardScaler fit trên [[1],[2],[3]] -> mean 2, std 0.8165; transform [[2]] -> [[0]]\nOneHotEncoder fit [\"đỏ\",\"xanh\"]; transform [\"vàng\"] -> [0, 0]\n",[992,36379,36377],{"__ignoreMap":1357},[981,36381,36383],{"id":36382},"bài-3-rò-rỉ-dữ-liệu-nâng-cao","Bài 3: Rò rỉ dữ liệu (nâng cao)",[973,36385,36386],{},"Dùng bộ dữ liệu giá nhà (ví dụ California Housing).",[2273,36388,36389,36395,36401,36407],{},[989,36390,36391,36394],{},[1487,36392,36393],{},"Sai:"," fit scaler trên toàn bộ dữ liệu rồi mới chia train\u002Ftest.",[989,36396,36397,36400],{},[1487,36398,36399],{},"Đúng:"," chia trước, fit trên train, transform cả hai.",[989,36402,36403,36404,36406],{},"Dùng hồi quy tuyến tính của ",[992,36405,17633],{},". In MSE test của 2 cách. Lặp với 20 seed.",[989,36408,36409],{},"Chạy pipeline 2 lần cùng seed: kết quả phải giống hệt.",[973,36411,36412],{},"Viết 3 câu giải thích vì sao cách 1 là rò rỉ dù chênh lệch nhỏ.",[981,36414,2711],{"id":2710},[986,36416,36418,36426,36437,36443],{"className":36417},[2715],[989,36419,36421,2308,36423,36425],{"className":36420},[2719],[2721,36422],{"disabled":2723,"type":2724},[992,36424,36256],{}," đủ 8 bài.",[989,36427,36429,36431,36432,35265,36434,1517],{"className":36428},[2719],[2721,36430],{"disabled":2723,"type":2724}," Các bước pipeline khớp ",[992,36433,17633],{},[992,36435,36436],{},"1e-9",[989,36438,36440,36442],{"className":36439},[2719],[2721,36441],{"disabled":2723,"type":2724}," Bài 3 có bảng MSE 2 cách qua 20 seed.",[989,36444,36446,36448],{"className":36445},[2719],[2721,36447],{"disabled":2723,"type":2724}," Pipeline tất định khi cố định seed.",[968,36450,2890],{"id":2889},[986,36452,36453,36456,36459,36462],{},[989,36454,36455],{},"Học có giám sát cần dữ liệu dạng gì?",[989,36457,36458],{},"Phân loại khác hồi quy ở đầu ra nào?",[989,36460,36461],{},"Pipeline gồm những bước nào?",[989,36463,36464],{},"Vì sao không scale trên cả tập?",[3014,36466],{},[973,36468,36469],{},"🌕 Bạn đã hoàn thành ngày 52. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":36471},[36472,36473,36478,36479,36485],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":36474},[36475,36476,36477],{"id":36118,"depth":73,"text":36119},{"id":36136,"depth":73,"text":36137},{"id":36154,"depth":73,"text":36155},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":36480},[36481,36482,36483,36484],{"id":36250,"depth":73,"text":36251},{"id":36265,"depth":73,"text":36266},{"id":36382,"depth":73,"text":36383},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tổng quan học có giám sát: điều kiện cho phép, phân biệt phân loại và hồi quy, pipeline đặc trưng, scaling và thử thách classifiers.",{},[15144,18469],{"title":315,"description":36486},[18472,36491,36492],"supervised","pipeline","LOSAGy9Pjv9DrJcFj4cslCjy8soqJ75LAsz72VYLPdk",{"id":36495,"title":320,"body":36496,"category":8797,"day":323,"description":37138,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":37139,"navigation":2723,"outcomes":3047,"path":321,"prerequisites":37140,"seo":37141,"stem":322,"tags":37142,"__hash__":37145},"challenges\u002Fchallenges\u002F53.cay-quyet-dinh.md",{"type":965,"value":36497,"toc":37122},[36498,36500,36503,36505,36509,36523,36527,36541,36545,36559,36604,36606,36620,36622,36632,36636,36988,36994,36998,37033,37039,37043,37064,37066,37099,37101,37115,37117,37120],[968,36499,971],{"id":970},[973,36501,36502],{},"Bài này học cây quyết định hỏi dần rồi đoán nhãn.\nCây này giúp vừa đoán vừa giải thích được luật.",[968,36504,979],{"id":978},[981,36506,36508],{"id":36507},"cây-hỏi-dần","Cây hỏi dần",[986,36510,36511,36514,36517,36520],{},[989,36512,36513],{},"Nút trong là câu hỏi cắt trên một đặc trưng.",[989,36515,36516],{},"Nhánh là đáp án của câu hỏi đó.",[989,36518,36519],{},"Lá là nhãn dự đoán cuối cùng.",[989,36521,36522],{},"Ví dụ đời thường: hỏi sốt không, ho không rồi kết luận bệnh.",[981,36524,36526],{"id":36525},"độ-tạp-và-điểm-cắt","Độ tạp và điểm cắt",[986,36528,36529,36532,36535,36538],{},[989,36530,36531],{},"Độ tạp đo mức lẫn lộn nhãn trong một nút.",[989,36533,36534],{},"Nút một màu thì tạp 0, nửa nọ nửa kia thì tạp max.",[989,36536,36537],{},"Cắt tốt là cắt tách cừu khỏi dê gọn nhất.",[989,36539,36540],{},"Ví dụ đời thường: nhát cắt tách bi đỏ khỏi bi xanh sạch nhất.",[981,36542,36544],{"id":36543},"mạnh-yếu-và-cắt-tỉa","Mạnh yếu và cắt tỉa",[986,36546,36547,36550,36553,36556],{},[989,36548,36549],{},"Mạnh: đọc được luật, khỏi scaling, bắt quan hệ cong.",[989,36551,36552],{},"Yếu: dễ học thuộc lòng, nhạy nhiễu, ranh giới bậc thang.",[989,36554,36555],{},"Cắt tỉa: mọc đầy rồi cắt ngược nhánh vô ích.",[989,36557,36558],{},"Ví dụ đời thường: tỉa cành sâu để cây khỏe hơn.",[1352,36560,36562],{"className":3538,"code":36561,"language":3540,"meta":1357,"style":1357},"# Dự đoán cây: thả từ gốc tới lá\ndef doan(nut, x):\n    while not nut.la:  # chưa tới lá\n        if x[nut.dac_trung] \u003C= nut.nguong:  # hỏi cắt\n            nut = nut.trai  # rẽ trái\n        else:\n            nut = nut.phai  # rẽ phải\n    return nut.nhan  # tới lá lấy nhãn\n",[992,36563,36564,36569,36574,36579,36584,36589,36594,36599],{"__ignoreMap":1357},[1023,36565,36566],{"class":1362,"line":63},[1023,36567,36568],{},"# Dự đoán cây: thả từ gốc tới lá\n",[1023,36570,36571],{"class":1362,"line":68},[1023,36572,36573],{},"def doan(nut, x):\n",[1023,36575,36576],{"class":1362,"line":73},[1023,36577,36578],{},"    while not nut.la:  # chưa tới lá\n",[1023,36580,36581],{"class":1362,"line":78},[1023,36582,36583],{},"        if x[nut.dac_trung] \u003C= nut.nguong:  # hỏi cắt\n",[1023,36585,36586],{"class":1362,"line":83},[1023,36587,36588],{},"            nut = nut.trai  # rẽ trái\n",[1023,36590,36591],{"class":1362,"line":88},[1023,36592,36593],{},"        else:\n",[1023,36595,36596],{"class":1362,"line":93},[1023,36597,36598],{},"            nut = nut.phai  # rẽ phải\n",[1023,36600,36601],{"class":1362,"line":98},[1023,36602,36603],{},"    return nut.nhan  # tới lá lấy nhãn\n",[968,36605,1433],{"id":1432},[986,36607,36608,36611,36614,36617],{},[989,36609,36610],{},"Input: dữ liệu tách thẳng hoàn hảo, cây sâu 1 -> Output: đúng 100% train và test.",[989,36612,36613],{},"Câu này cho thấy bài dễ thì cây nông đã thắng.",[989,36615,36616],{},"Input: nút nửa nọ nửa kia 2 lớp -> Output: Gini bằng 0.5.",[989,36618,36619],{},"Câu này kiểm tra công thức tạp ở biên lẫn nhất.",[968,36621,1482],{"id":1481},[973,36623,1485,36624,17626,36626,33864,36629,1517],{},[1487,36625,13531],{},[992,36627,36628],{},"sklearn.tree",[992,36630,36631],{},"day-053\u002F",[981,36633,36635],{"id":36634},"bài-1-độ-tạp-và-điểm-cắt","Bài 1: Độ tạp và điểm cắt",[1099,36637,36638,36646],{},[1102,36639,36640],{},[1105,36641,36642,36644],{},[1108,36643,1566],{},[1108,36645,2547],{},[1118,36647,36648,36774,36975],{},[1105,36649,36650,36655],{},[1123,36651,36652],{},[992,36653,36654],{},"gini(y)",[1123,36656,36657],{},[1023,36658,36660,36687],{"className":36659},[1026],[1023,36661,36663],{"className":36662},[1030],[1032,36664,36665],{"xmlns":1034},[1036,36666,36667,36684],{},[1039,36668,36669,36671,36673,36675],{},[1051,36670,1053],{},[1046,36672,17698],{},[1046,36674,17686],{},[36676,36677,36678,36680,36682],"msubsup",{},[1042,36679,973],{},[1042,36681,4022],{},[1051,36683,2457],{},[1058,36685,36686],{"encoding":1060},"1 - \\sum p_k^2",[1023,36688,36690,36708],{"className":36689,"ariaHidden":1066},[1065],[1023,36691,36693,36696,36699,36702,36705],{"className":36692},[1070],[1023,36694],{"className":36695,"style":18148},[1074],[1023,36697,1053],{"className":36698},[1079],[1023,36700],{"className":36701,"style":13790},[2354],[1023,36703,17698],{"className":36704},[13794],[1023,36706],{"className":36707,"style":13790},[2354],[1023,36709,36711,36715,36718,36721],{"className":36710},[1070],[1023,36712],{"className":36713,"style":36714},[1074],"height:1.0972em;vertical-align:-0.2831em;",[1023,36716,17686],{"className":36717,"style":17758},[8426,17756,17757],[1023,36719],{"className":36720,"style":8434},[2354],[1023,36722,36724,36727],{"className":36723},[1079],[1023,36725,973],{"className":36726},[1079,1080],[1023,36728,36730],{"className":36729},[2383],[1023,36731,36733,36765],{"className":36732},[2387,17732],[1023,36734,36736,36762],{"className":36735},[2391],[1023,36737,36739,36751],{"className":36738,"style":2369},[2395],[1023,36740,36742,36745],{"style":36741},"top:-2.4169em;margin-left:0em;margin-right:0.05em;",[1023,36743],{"className":36744,"style":2403},[2402],[1023,36746,36748],{"className":36747},[2407,2408,2409,2410],[1023,36749,4022],{"className":36750,"style":4066},[1079,1080,2410],[1023,36752,36753,36756],{"style":2398},[1023,36754],{"className":36755,"style":2403},[2402],[1023,36757,36759],{"className":36758},[2407,2408,2409,2410],[1023,36760,2457],{"className":36761},[1079,2410],[1023,36763,17797],{"className":36764},[17796],[1023,36766,36768],{"className":36767},[2391],[1023,36769,36772],{"className":36770,"style":36771},[2395],"height:0.2831em;",[1023,36773],{},[1105,36775,36776,36781],{},[1123,36777,36778],{},[992,36779,36780],{},"entropy(y)",[1123,36782,36783],{},[1023,36784,36786,36824],{"className":36785},[1026],[1023,36787,36789],{"className":36788},[1030],[1032,36790,36791],{"xmlns":1034},[1036,36792,36793,36821],{},[1039,36794,36795,36797,36799,36805,36815],{},[1046,36796,17698],{},[1046,36798,17686],{},[17690,36800,36801,36803],{},[1042,36802,973],{},[1042,36804,4022],{},[17690,36806,36807,36813],{},[1039,36808,36809,36811],{},[1042,36810,8397],{},[1046,36812,8400],{},[1051,36814,2457],{},[17690,36816,36817,36819],{},[1042,36818,973],{},[1042,36820,4022],{},[1058,36822,36823],{"encoding":1060},"-\\sum p_k \\log_2 p_k",[1023,36825,36827],{"className":36826,"ariaHidden":1066},[1065],[1023,36828,36830,36833,36836,36839,36842,36845,36886,36889,36932,36935],{"className":36829},[1070],[1023,36831],{"className":36832,"style":1075},[1074],[1023,36834,17698],{"className":36835},[1079],[1023,36837],{"className":36838,"style":8434},[2354],[1023,36840,17686],{"className":36841,"style":17758},[8426,17756,17757],[1023,36843],{"className":36844,"style":8434},[2354],[1023,36846,36848,36851],{"className":36847},[1079],[1023,36849,973],{"className":36850},[1079,1080],[1023,36852,36854],{"className":36853},[2383],[1023,36855,36857,36878],{"className":36856},[2387,17732],[1023,36858,36860,36875],{"className":36859},[2391],[1023,36861,36864],{"className":36862,"style":36863},[2395],"height:0.3361em;",[1023,36865,36866,36869],{"style":17783},[1023,36867],{"className":36868,"style":2403},[2402],[1023,36870,36872],{"className":36871},[2407,2408,2409,2410],[1023,36873,4022],{"className":36874,"style":4066},[1079,1080,2410],[1023,36876,17797],{"className":36877},[17796],[1023,36879,36881],{"className":36880},[2391],[1023,36882,36884],{"className":36883,"style":17804},[2395],[1023,36885],{},[1023,36887],{"className":36888,"style":8434},[2354],[1023,36890,36892,36897],{"className":36891},[8426],[1023,36893,8427,36895],{"className":36894},[8426],[1023,36896,7690],{"style":8430},[1023,36898,36900],{"className":36899},[2383],[1023,36901,36903,36924],{"className":36902},[2387,17732],[1023,36904,36906,36921],{"className":36905},[2391],[1023,36907,36910],{"className":36908,"style":36909},[2395],"height:0.207em;",[1023,36911,36912,36915],{"style":21671},[1023,36913],{"className":36914,"style":2403},[2402],[1023,36916,36918],{"className":36917},[2407,2408,2409,2410],[1023,36919,2457],{"className":36920},[1079,2410],[1023,36922,17797],{"className":36923},[17796],[1023,36925,36927],{"className":36926},[2391],[1023,36928,36930],{"className":36929,"style":21690},[2395],[1023,36931],{},[1023,36933],{"className":36934,"style":8434},[2354],[1023,36936,36938,36941],{"className":36937},[1079],[1023,36939,973],{"className":36940},[1079,1080],[1023,36942,36944],{"className":36943},[2383],[1023,36945,36947,36967],{"className":36946},[2387,17732],[1023,36948,36950,36964],{"className":36949},[2391],[1023,36951,36953],{"className":36952,"style":36863},[2395],[1023,36954,36955,36958],{"style":17783},[1023,36956],{"className":36957,"style":2403},[2402],[1023,36959,36961],{"className":36960},[2407,2408,2409,2410],[1023,36962,4022],{"className":36963,"style":4066},[1079,1080,2410],[1023,36965,17797],{"className":36966},[17796],[1023,36968,36970],{"className":36969},[2391],[1023,36971,36973],{"className":36972,"style":17804},[2395],[1023,36974],{},[1105,36976,36977,36982],{},[1123,36978,36979],{},[992,36980,36981],{},"best_split(X, y, criterion)",[1123,36983,36984,36985],{},"Thử mọi cột, mọi ngưỡng là trung điểm giữa 2 giá trị liên tiếp đã sắp. Trả ",[992,36986,36987],{},"(cột, ngưỡng, gain)",[1352,36989,36992],{"className":36990,"code":36991,"language":2241,"meta":1357},[2239],"gini([0,0,1,1]) -> 0.5; gini([1,1,1]) -> 0\nentropy([0,0,1,1]) -> 1.0\nX = [[1],[2],[8],[9]], y = [0,0,1,1] -> cắt cột 0 tại 5.0, gain = 0.5\n",[992,36993,36991],{"__ignoreMap":1357},[981,36995,36997],{"id":36996},"bài-2-cây-quyết-định","Bài 2: Cây quyết định",[1352,36999,37001],{"className":3538,"code":37000,"language":3540,"meta":1357,"style":1357},"class DecisionTree:\n    def __init__(self, max_depth=None, min_samples_split=2, criterion=\"gini\"): ...\n    def fit(self, X, y): ...\n    def predict(self, X): ...\n    def depth(self) -> int: ...\n    def print_rules(self, feature_names): ...   # in dạng \"nếu petal_length \u003C= 2.45 thì setosa\"\n",[992,37002,37003,37008,37013,37018,37023,37028],{"__ignoreMap":1357},[1023,37004,37005],{"class":1362,"line":63},[1023,37006,37007],{},"class DecisionTree:\n",[1023,37009,37010],{"class":1362,"line":68},[1023,37011,37012],{},"    def __init__(self, max_depth=None, min_samples_split=2, criterion=\"gini\"): ...\n",[1023,37014,37015],{"class":1362,"line":73},[1023,37016,37017],{},"    def fit(self, X, y): ...\n",[1023,37019,37020],{"class":1362,"line":78},[1023,37021,37022],{},"    def predict(self, X): ...\n",[1023,37024,37025],{"class":1362,"line":83},[1023,37026,37027],{},"    def depth(self) -> int: ...\n",[1023,37029,37030],{"class":1362,"line":88},[1023,37031,37032],{},"    def print_rules(self, feature_names): ...   # in dạng \"nếu petal_length \u003C= 2.45 thì setosa\"\n",[973,37034,37035,37036,1517],{},"Chạy trên bộ Iris. Chia 70\u002F30. In accuracy train và test với ",[992,37037,37038],{},"max_depth = 1, 2, 3, 5, None",[981,37040,37042],{"id":37041},"bài-3-học-thuộc-và-cắt-tỉa-nâng-cao","Bài 3: Học thuộc và cắt tỉa (nâng cao)",[2273,37044,37045,37048,37054,37057],{},[989,37046,37047],{},"Thêm 20% nhãn nhiễu vào tập train Iris. Cây không giới hạn độ sâu: in accuracy train và test.",[989,37049,6760,37050,37053],{},[1487,37051,37052],{},"reduced-error pruning",": từ dưới lên, thay nút bằng lá nếu accuracy trên tập validation không giảm.",[989,37055,37056],{},"In độ sâu, số lá, accuracy test trước và sau cắt tỉa.",[989,37058,37059,37060,37063],{},"So với ",[992,37061,37062],{},"sklearn.tree.DecisionTreeClassifier"," cùng tham số.",[981,37065,2711],{"id":2710},[986,37067,37069,37074,37084,37090],{"className":37068},[2715],[989,37070,37072,11986],{"className":37071},[2719],[2721,37073],{"disabled":2723,"type":2724},[989,37075,37077,37079,37080,37083],{"className":37076},[2719],[2721,37078],{"disabled":2723,"type":2724}," Bảng accuracy theo ",[992,37081,37082],{},"max_depth"," có số thật.",[989,37085,37087,37089],{"className":37086},[2719],[2721,37088],{"disabled":2723,"type":2724}," Cắt tỉa giảm số lá và không giảm accuracy test đáng kể.",[989,37091,37093,2308,37095,37098],{"className":37092},[2719],[2721,37094],{"disabled":2723,"type":2724},[992,37096,37097],{},"print_rules"," in được luật đọc hiểu được.",[968,37100,2890],{"id":2889},[986,37102,37103,37106,37109,37112],{},[989,37104,37105],{},"Nút, nhánh, lá trong cây là gì?",[989,37107,37108],{},"Độ tạp cao nghĩa là lẫn thế nào?",[989,37110,37111],{},"Cắt tỉa chống overfitting ra sao?",[989,37113,37114],{},"Khi nào nên dùng cây quyết định?",[3014,37116],{},[973,37118,37119],{},"🌕 Bạn đã hoàn thành ngày 53. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,37121,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":37123},[37124,37125,37130,37131,37137],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":37126},[37127,37128,37129],{"id":36507,"depth":73,"text":36508},{"id":36525,"depth":73,"text":36526},{"id":36543,"depth":73,"text":36544},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":37132},[37133,37134,37135,37136],{"id":36634,"depth":73,"text":36635},{"id":36996,"depth":73,"text":36997},{"id":37041,"depth":73,"text":37042},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cây quyết định phân loại: chọn điểm cắt, độ tạp impurity, điểm mạnh yếu, ca sử dụng và cắt tỉa chống overfitting.",{},[3050,8149],{"title":320,"description":37138},[18472,37143,37144],"decision-tree","classification","GpPGBb-ndqg_d0YKgfy6G09fU_XhSc1OrMKJem1r4po",{"id":37147,"title":325,"body":37148,"category":8797,"day":328,"description":37974,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":37975,"navigation":2723,"outcomes":3047,"path":326,"prerequisites":37976,"seo":37977,"stem":327,"tags":37978,"__hash__":37981},"challenges\u002Fchallenges\u002F54.naive-bayes.md",{"type":965,"value":37149,"toc":37958},[37150,37152,37155,37157,37161,37175,37179,37193,37197,37211,37241,37243,37257,37259,37269,37273,37303,37307,37665,37671,37675,37678,37880,37884,37904,37906,37935,37937,37951,37953,37956],[968,37151,971],{"id":970},[973,37153,37154],{},"Bài này học Naive Bayes đoán lớp bằng xác suất.\nBộ này giúp lọc thư rác nhanh mà chuẩn.",[968,37156,979],{"id":978},[981,37158,37160],{"id":37159},"định-lý-bayes","Định lý Bayes",[986,37162,37163,37166,37169,37172],{},[989,37164,37165],{},"Hậu nghiệm = khả năng nhân tiên nghiệm chia bằng chứng.",[989,37167,37168],{},"Tiên nghiệm là tỉ lệ chung, khả năng là dấu hiệu lớp.",[989,37170,37171],{},"So tử số là đủ vì mẫu số chung mọi lớp.",[989,37173,37174],{},"Ví dụ đời thường: thấy từ trúng thưởng thì ngờ thư rác.",[981,37176,37178],{"id":37177},"giả-thiết-ngây-thơ","Giả thiết ngây thơ",[986,37180,37181,37184,37187,37190],{},[989,37182,37183],{},"Coi các từ độc lập khi đã biết lớp.",[989,37185,37186],{},"Khả năng cả mail thành tích khả năng từng từ.",[989,37188,37189],{},"Giả thiết sai nhưng chỉ cần lớp thắng đúng là đủ.",[989,37191,37192],{},"Ví dụ đời thường: trăm bằng chứng yếu cộng lại thành mạnh.",[981,37194,37196],{"id":37195},"làm-mịn-và-3-biến-thể","Làm mịn và 3 biến thể",[986,37198,37199,37202,37205,37208],{},[989,37200,37201],{},"Từ mới chưa thấy phải làm mịn cộng một kẻo tích về 0.",[989,37203,37204],{},"Đa thức cho đếm từ, Bernoulli cho có\u002Fkhông, Gauss cho số.",[989,37206,37207],{},"Chọn sai biến thể thì mô hình méo ngay.",[989,37209,37210],{},"Ví dụ đời thường: từ lạ vẫn cho điểm nhỏ chứ không cho 0.",[1352,37212,37214],{"className":3538,"code":37213,"language":3540,"meta":1357,"style":1357},"# So tử số hậu nghiệm 2 lớp\ndef chon_lop(tien_rac, tien_thuong, kha_rac, kha_thuong):\n    diem_rac = tien_rac * kha_rac  # tử số lớp rác\n    diem_thuong = tien_thuong * kha_thuong  # tử số lớp thường\n    return \"rac\" if diem_rac > diem_thuong else \"thuong\"\n",[992,37215,37216,37221,37226,37231,37236],{"__ignoreMap":1357},[1023,37217,37218],{"class":1362,"line":63},[1023,37219,37220],{},"# So tử số hậu nghiệm 2 lớp\n",[1023,37222,37223],{"class":1362,"line":68},[1023,37224,37225],{},"def chon_lop(tien_rac, tien_thuong, kha_rac, kha_thuong):\n",[1023,37227,37228],{"class":1362,"line":73},[1023,37229,37230],{},"    diem_rac = tien_rac * kha_rac  # tử số lớp rác\n",[1023,37232,37233],{"class":1362,"line":78},[1023,37234,37235],{},"    diem_thuong = tien_thuong * kha_thuong  # tử số lớp thường\n",[1023,37237,37238],{"class":1362,"line":83},[1023,37239,37240],{},"    return \"rac\" if diem_rac > diem_thuong else \"thuong\"\n",[968,37242,1433],{"id":1432},[986,37244,37245,37248,37251,37254],{},[989,37246,37247],{},"Input: mail toàn từ rác mạnh -> Output: phân rác với điểm áp đảo.",[989,37249,37250],{},"Câu này cho thấy từ khóa quyết định rõ ràng.",[989,37252,37253],{},"Input: gặp từ hoàn toàn mới -> Output: xác suất nhỏ dương, không sập tính toán.",[989,37255,37256],{},"Câu này cho thấy làm mịn cứu cả tích.",[968,37258,1482],{"id":1481},[973,37260,1485,37261,2256,37263,33864,37266,1517],{},[1487,37262,13531],{},[992,37264,37265],{},"sklearn.naive_bayes",[992,37267,37268],{},"day-054\u002F",[981,37270,37272],{"id":37271},"bài-1-multinomial-naive-bayes-cho-thư-rác","Bài 1: Multinomial Naive Bayes cho thư rác",[1352,37274,37276],{"className":3538,"code":37275,"language":3540,"meta":1357,"style":1357},"class MultinomialNB:\n    def __init__(self, alpha: float = 1.0): ...          # làm mịn Laplace\n    def fit(self, docs: list[list[str]], labels: list[str]): ...\n    def predict_log_proba(self, doc: list[str]) -> dict[str, float]: ...\n    def predict(self, doc: list[str]) -> str: ...\n",[992,37277,37278,37283,37288,37293,37298],{"__ignoreMap":1357},[1023,37279,37280],{"class":1362,"line":63},[1023,37281,37282],{},"class MultinomialNB:\n",[1023,37284,37285],{"class":1362,"line":68},[1023,37286,37287],{},"    def __init__(self, alpha: float = 1.0): ...          # làm mịn Laplace\n",[1023,37289,37290],{"class":1362,"line":73},[1023,37291,37292],{},"    def fit(self, docs: list[list[str]], labels: list[str]): ...\n",[1023,37294,37295],{"class":1362,"line":78},[1023,37296,37297],{},"    def predict_log_proba(self, doc: list[str]) -> dict[str, float]: ...\n",[1023,37299,37300],{"class":1362,"line":83},[1023,37301,37302],{},"    def predict(self, doc: list[str]) -> str: ...\n",[973,37304,37305],{},[1487,37306,2194],{},[986,37308,37309,37315,37318],{},[989,37310,37311,37312,37314],{},"Tính bằng ",[1487,37313,8397],{}," xác suất để tránh tràn số dưới khi mail dài.",[989,37316,37317],{},"Từ chưa gặp trong tập train thì bỏ qua (không có trong từ vựng).",[989,37319,37320,1517],{},[1023,37321,37323,37417],{"className":37322},[1026],[1023,37324,37326],{"className":37325},[1030],[1032,37327,37328],{"xmlns":1034},[1036,37329,37330,37414],{},[1039,37331,37332,37335,37337,37339,37341,37343,37345,37347],{},[1042,37333,37334],{},"P",[1046,37336,1049],{"stretchy":1048},[1042,37338,27557],{},[1046,37340,17949],{},[1042,37342,1356],{},[1046,37344,1056],{"stretchy":1048},[1046,37346,2325],{},[18110,37348,37349,37376],{},[1039,37350,37351,37353,37355,37357,37359,37361,37363,37365,37367,37369,37371,37373],{},[1042,37352,1356],{},[1042,37354,7687],{},[1042,37356,30390],{},[1042,37358,1262],{},[1042,37360,29580],{},[1046,37362,1049],{"stretchy":1048},[1042,37364,27557],{},[1046,37366,13897],{"separator":1066},[1042,37368,1356],{},[1046,37370,1056],{"stretchy":1048},[1046,37372,21881],{},[1042,37374,37375],{},"α",[1039,37377,37378,37384,37386,37388,37390,37392,37394,37396,37398,37400,37402,37404,37406,37408,37410,37412],{},[17690,37379,37380,37382],{},[1046,37381,17686],{},[1042,37383,27557],{},[1042,37385,1356],{},[1042,37387,7687],{},[1042,37389,30390],{},[1042,37391,1262],{},[1042,37393,29580],{},[1046,37395,1049],{"stretchy":1048},[1042,37397,27557],{},[1046,37399,13897],{"separator":1066},[1042,37401,1356],{},[1046,37403,1056],{"stretchy":1048},[1046,37405,21881],{},[1042,37407,37375],{},[1042,37409,17949],{"mathvariant":2460},[1042,37411,29619],{},[1042,37413,17949],{"mathvariant":2460},[1058,37415,37416],{"encoding":1060},"P(w \\mid c) = \\frac{count(w, c) + \\alpha}{\\sum_w count(w, c) + \\alpha |V|}",[1023,37418,37420,37446,37467],{"className":37419,"ariaHidden":1066},[1065],[1023,37421,37423,37426,37430,37433,37437,37440,37443],{"className":37422},[1070],[1023,37424],{"className":37425,"style":1075},[1074],[1023,37427,37334],{"className":37428,"style":37429},[1079,1080],"margin-right:0.1389em;",[1023,37431,1049],{"className":37432},[1085],[1023,37434,27557],{"className":37435,"style":37436},[1079,1080],"margin-right:0.0269em;",[1023,37438],{"className":37439,"style":2355},[2354],[1023,37441,17949],{"className":37442},[2359],[1023,37444],{"className":37445,"style":2355},[2354],[1023,37447,37449,37452,37455,37458,37461,37464],{"className":37448},[1070],[1023,37450],{"className":37451,"style":1075},[1074],[1023,37453,1356],{"className":37454},[1079,1080],[1023,37456,1056],{"className":37457},[1092],[1023,37459],{"className":37460,"style":2355},[2354],[1023,37462,2325],{"className":37463},[2359],[1023,37465],{"className":37466,"style":2355},[2354],[1023,37468,37470,37474],{"className":37469},[1070],[1023,37471],{"className":37472,"style":37473},[1074],"height:1.58em;vertical-align:-0.57em;",[1023,37475,37477,37480,37662],{"className":37476},[1079],[1023,37478],{"className":37479},[1085,18174],[1023,37481,37483],{"className":37482},[18110],[1023,37484,37486,37653],{"className":37485},[2387,17732],[1023,37487,37489,37650],{"className":37488},[2391],[1023,37490,37493,37597,37605],{"className":37491,"style":37492},[2395],"height:1.01em;",[1023,37494,37495,37498],{"style":18190},[1023,37496],{"className":37497,"style":18194},[2402],[1023,37499,37501],{"className":37500},[2407,2408,2409,2410],[1023,37502,37504,37549,37553,37557,37560,37563,37566,37569,37572,37575,37578,37581,37584,37588,37591,37594],{"className":37503},[1079,2410],[1023,37505,37507,37510],{"className":37506},[8426,2410],[1023,37508,17686],{"className":37509,"style":17758},[8426,17756,17757,2410],[1023,37511,37513],{"className":37512},[2383],[1023,37514,37516,37540],{"className":37515},[2387,17732],[1023,37517,37519,37537],{"className":37518},[2391],[1023,37520,37523],{"className":37521,"style":37522},[2395],"height:-0.0139em;",[1023,37524,37526,37530],{"style":37525},"top:-2.1786em;margin-left:0em;margin-right:0.0714em;",[1023,37527],{"className":37528,"style":37529},[2402],"height:2.5em;",[1023,37531,37534],{"className":37532},[2407,37533,24100,2410],"reset-size3",[1023,37535,27557],{"className":37536,"style":37436},[1079,1080,2410],[1023,37538,17797],{"className":37539},[17796],[1023,37541,37543],{"className":37542},[2391],[1023,37544,37547],{"className":37545,"style":37546},[2395],"height:0.3214em;",[1023,37548],{},[1023,37550],{"className":37551,"style":37552},[2354,2410],"margin-right:0.1952em;",[1023,37554,37556],{"className":37555},[1079,1080,2410],"co",[1023,37558,30390],{"className":37559},[1079,1080,2410],[1023,37561,1262],{"className":37562},[1079,1080,2410],[1023,37564,29580],{"className":37565},[1079,1080,2410],[1023,37567,1049],{"className":37568},[1085,2410],[1023,37570,27557],{"className":37571,"style":37436},[1079,1080,2410],[1023,37573,13897],{"className":37574},[13943,2410],[1023,37576,1356],{"className":37577},[1079,1080,2410],[1023,37579,1056],{"className":37580},[1092,2410],[1023,37582,21881],{"className":37583},[13794,2410],[1023,37585,37375],{"className":37586,"style":37587},[1079,1080,2410],"margin-right:0.0037em;",[1023,37589,17949],{"className":37590},[1079,2410],[1023,37592,29619],{"className":37593,"style":13790},[1079,1080,2410],[1023,37595,17949],{"className":37596},[1079,2410],[1023,37598,37599,37602],{"style":18221},[1023,37600],{"className":37601,"style":18194},[2402],[1023,37603],{"className":37604,"style":18229},[18228],[1023,37606,37608,37611],{"style":37607},"top:-3.485em;",[1023,37609],{"className":37610,"style":18194},[2402],[1023,37612,37614],{"className":37613},[2407,2408,2409,2410],[1023,37615,37617,37620,37623,37626,37629,37632,37635,37638,37641,37644,37647],{"className":37616},[1079,2410],[1023,37618,37556],{"className":37619},[1079,1080,2410],[1023,37621,30390],{"className":37622},[1079,1080,2410],[1023,37624,1262],{"className":37625},[1079,1080,2410],[1023,37627,29580],{"className":37628},[1079,1080,2410],[1023,37630,1049],{"className":37631},[1085,2410],[1023,37633,27557],{"className":37634,"style":37436},[1079,1080,2410],[1023,37636,13897],{"className":37637},[13943,2410],[1023,37639,1356],{"className":37640},[1079,1080,2410],[1023,37642,1056],{"className":37643},[1092,2410],[1023,37645,21881],{"className":37646},[13794,2410],[1023,37648,37375],{"className":37649,"style":37587},[1079,1080,2410],[1023,37651,17797],{"className":37652},[17796],[1023,37654,37656],{"className":37655},[2391],[1023,37657,37660],{"className":37658,"style":37659},[2395],"height:0.57em;",[1023,37661],{},[1023,37663],{"className":37664},[1092,18174],[1352,37666,37669],{"className":37667,"code":37668,"language":2241,"meta":1357},[2239],"train: rác = [\"trúng thưởng tiền\", \"tiền miễn phí\"], thường = [\"họp lúc 3 giờ\", \"gửi báo cáo\"]\npredict(\"nhận tiền miễn phí\")   -> rác\npredict(\"báo cáo cuộc họp\")      -> thường\nmail 5000 từ                      -> không ra -inf hay NaN\n",[992,37670,37668],{"__ignoreMap":1357},[981,37672,37674],{"id":37673},"bài-2-dữ-liệu-thật","Bài 2: Dữ liệu thật",[973,37676,37677],{},"Dùng bộ SMS Spam Collection (5574 tin, công khai).",[2273,37679,37680,37683,37686,37873],{},[989,37681,37682],{},"Tách từ: chữ thường, bỏ dấu câu.",[989,37684,37685],{},"Chia 80\u002F20 có phân tầng. In accuracy, precision, recall của lớp spam.",[989,37687,37688,37689,37872],{},"In 15 từ có ",[1023,37690,37692,37748],{"className":37691},[1026],[1023,37693,37695],{"className":37694},[1030],[1032,37696,37697],{"xmlns":1034},[1036,37698,37699,37745],{},[1039,37700,37701,37703,37705],{},[1042,37702,8397],{},[1046,37704,8400],{},[18110,37706,37707,37727],{},[1039,37708,37709,37711,37713,37715,37717,37719,37721,37723,37725],{},[1042,37710,37334],{},[1046,37712,1049],{"stretchy":1048},[1042,37714,27557],{},[1046,37716,17949],{},[1042,37718,29577],{},[1042,37720,973],{},[1042,37722,6207],{},[1042,37724,15437],{},[1046,37726,1056],{"stretchy":1048},[1039,37728,37729,37731,37733,37735,37737,37739,37741,37743],{},[1042,37730,37334],{},[1046,37732,1049],{"stretchy":1048},[1042,37734,27557],{},[1046,37736,17949],{},[1042,37738,7908],{},[1042,37740,6207],{},[1042,37742,15437],{},[1046,37744,1056],{"stretchy":1048},[1058,37746,37747],{"encoding":1060},"\\log \\frac{P(w \\mid spam)}{P(w \\mid ham)}",[1023,37749,37751],{"className":37750,"ariaHidden":1066},[1065],[1023,37752,37754,37758,37763,37766],{"className":37753},[1070],[1023,37755],{"className":37756,"style":37757},[1074],"height:1.53em;vertical-align:-0.52em;",[1023,37759,8427,37761],{"className":37760},[8426],[1023,37762,7690],{"style":8430},[1023,37764],{"className":37765,"style":8434},[2354],[1023,37767,37769,37772,37869],{"className":37768},[1079],[1023,37770],{"className":37771},[1085,18174],[1023,37773,37775],{"className":37774},[18110],[1023,37776,37778,37861],{"className":37777},[2387,17732],[1023,37779,37781,37858],{"className":37780},[2391],[1023,37782,37784,37814,37822],{"className":37783,"style":37492},[2395],[1023,37785,37786,37789],{"style":18190},[1023,37787],{"className":37788,"style":18194},[2402],[1023,37790,37792],{"className":37791},[2407,2408,2409,2410],[1023,37793,37795,37798,37801,37804,37807,37811],{"className":37794},[1079,2410],[1023,37796,37334],{"className":37797,"style":37429},[1079,1080,2410],[1023,37799,1049],{"className":37800},[1085,2410],[1023,37802,27557],{"className":37803,"style":37436},[1079,1080,2410],[1023,37805,17949],{"className":37806},[2359,2410],[1023,37808,37810],{"className":37809},[1079,1080,2410],"ham",[1023,37812,1056],{"className":37813},[1092,2410],[1023,37815,37816,37819],{"style":18221},[1023,37817],{"className":37818,"style":18194},[2402],[1023,37820],{"className":37821,"style":18229},[18228],[1023,37823,37824,37827],{"style":37607},[1023,37825],{"className":37826,"style":18194},[2402],[1023,37828,37830],{"className":37829},[2407,2408,2409,2410],[1023,37831,37833,37836,37839,37842,37845,37848,37851,37855],{"className":37832},[1079,2410],[1023,37834,37334],{"className":37835,"style":37429},[1079,1080,2410],[1023,37837,1049],{"className":37838},[1085,2410],[1023,37840,27557],{"className":37841,"style":37436},[1079,1080,2410],[1023,37843,17949],{"className":37844},[2359,2410],[1023,37846,29577],{"className":37847},[1079,1080,2410],[1023,37849,973],{"className":37850},[1079,1080,2410],[1023,37852,37854],{"className":37853},[1079,1080,2410],"am",[1023,37856,1056],{"className":37857},[1092,2410],[1023,37859,17797],{"className":37860},[17796],[1023,37862,37864],{"className":37863},[2391],[1023,37865,37867],{"className":37866,"style":18260},[2395],[1023,37868],{},[1023,37870],{"className":37871},[1092,18174]," lớn nhất.",[989,37874,37875,37876,37879],{},"Thử ",[992,37877,37878],{},"alpha = 0.01, 0.1, 1, 10",". Chọn alpha tốt nhất bằng validation.",[981,37881,37883],{"id":37882},"bài-3-gaussian-và-bernoulli-nâng-cao","Bài 3: Gaussian và Bernoulli (nâng cao)",[2273,37885,37886,37895,37901],{},[989,37887,6760,37888,37891,37892,37894],{},[992,37889,37890],{},"GaussianNB",": mỗi lớp mỗi đặc trưng có mean và variance. Cộng ",[992,37893,36436],{}," vào variance. Chạy trên Iris.",[989,37896,6760,37897,37900],{},[992,37898,37899],{},"BernoulliNB",": đặc trưng có\u002Fkhông có từ. Chạy lại SMS Spam. So với Multinomial.",[989,37902,37903],{},"Viết 3 câu: giả thiết độc lập sai ở đâu trong dữ liệu SMS, và vì sao mô hình vẫn tốt.",[981,37905,2711],{"id":2710},[986,37907,37909,37915,37923,37929],{"className":37908},[2715],[989,37910,37912,37914],{"className":37911},[2719],[2721,37913],{"disabled":2723,"type":2724}," Test mẫu pass, mail dài không tràn số.",[989,37916,37918,34128,37920,37922],{"className":37917},[2719],[2721,37919],{"disabled":2723,"type":2724},[992,37921,17633],{}," với cùng alpha.",[989,37924,37926,37928],{"className":37925},[2719],[2721,37927],{"disabled":2723,"type":2724}," Bảng metric Bài 2 và bảng so sánh 3 biến thể có số thật.",[989,37930,37932,37934],{"className":37931},[2719],[2721,37933],{"disabled":2723,"type":2724}," Giải thích được vai trò của làm mịn Laplace bằng ví dụ.",[968,37936,2890],{"id":2889},[986,37938,37939,37942,37945,37948],{},[989,37940,37941],{},"Định lý Bayes gồm 3 thành phần nào?",[989,37943,37944],{},"Giả thiết ngây thơ coi các từ thế nào?",[989,37946,37947],{},"Làm mịn cộng một để làm gì?",[989,37949,37950],{},"Khi nào dùng biến thể Gauss?",[3014,37952],{},[973,37954,37955],{},"🌕 Bạn đã hoàn thành ngày 54. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,37957,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":37959},[37960,37961,37966,37967,37973],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":37962},[37963,37964,37965],{"id":37159,"depth":73,"text":37160},{"id":37177,"depth":73,"text":37178},{"id":37195,"depth":73,"text":37196},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":37968},[37969,37970,37971,37972],{"id":37271,"depth":73,"text":37272},{"id":37673,"depth":73,"text":37674},{"id":37882,"depth":73,"text":37883},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bộ phân loại Bayes ngây thơ: định lý Bayes, luật nhân cộng xác suất, giả thiết độc lập và bài thi văn bản.",{},[18469],{"title":325,"description":37974},[18472,37979,37980],"naive-bayes","nlp","zURFpbuuVb-7UnKZfxrF29ri17kWU2405-CA1cLq41U",{"id":37983,"title":330,"body":37984,"category":8797,"day":333,"description":38535,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":38536,"navigation":2723,"outcomes":3047,"path":331,"prerequisites":38537,"seo":38538,"stem":332,"tags":38539,"__hash__":38542},"challenges\u002Fchallenges\u002F55.hoi-quy.md",{"type":965,"value":37985,"toc":38519},[37986,37988,37991,37993,37997,38011,38015,38029,38033,38047,38097,38099,38113,38115,38125,38129,38158,38164,38168,38171,38406,38410,38440,38449,38464,38466,38496,38498,38512,38514,38517],[968,37987,971],{"id":970},[973,37989,37990],{},"Bài này học hồi quy đoán số liên tục như giá nhà.\nNhánh này giúp dự báo thời tiết từ dữ liệu cũ.",[968,37992,979],{"id":978},[981,37994,37996],{"id":37995},"hồi-quy-đơn","Hồi quy đơn",[986,37998,37999,38002,38005,38008],{},[989,38000,38001],{},"Vẽ đường thẳng sao cho tổng bình phương lỗi nhỏ nhất.",[989,38003,38004],{},"Hệ số góc là mỗi đơn vị đặc trưng đổi bao nhiêu mục tiêu.",[989,38006,38007],{},"Có công thức đóng nên tính ngay không cần lặp.",[989,38009,38010],{},"Ví dụ đời thường: càng học thêm 1 giờ thì điểm tăng 0.5.",[981,38012,38014],{"id":38013},"đánh-giá-và-hồi-quy-bội","Đánh giá và hồi quy bội",[986,38016,38017,38020,38023,38026],{},[989,38018,38019],{},"MSE phạt nặng lỗi lớn, MAE lì hơn với ngoại lệ.",[989,38021,38022],{},"R2 cho biết giải thích được bao nhiêu phần trăm biến thiên.",[989,38024,38025],{},"Hồi quy bội là siêu phẳng nhiều đặc trưng cùng lúc.",[989,38027,38028],{},"Ví dụ đời thường: giá nhà theo cả diện tích và quận.",[981,38030,38032],{"id":38031},"cây-và-boosting-hồi-quy","Cây và boosting hồi quy",[986,38034,38035,38038,38041,38044],{},[989,38036,38037],{},"Cây hồi quy: lá là trung bình vùng, bắt quan hệ cong.",[989,38039,38040],{},"Boosting: nhiều cây nông sửa lỗi cho nhau, điểm cao nhất.",[989,38042,38043],{},"Tuyến tính thắng giải thích, boosting thắng điểm số.",[989,38045,38046],{},"Ví dụ đời thường: đường thẳng kể chuyện, rừng cây vắt kiệt điểm.",[1099,38048,38049,38062],{},[1102,38050,38051],{},[1105,38052,38053,38056,38059],{},[1108,38054,38055],{},"Thước đo",[1108,38057,38058],{},"Ý nghĩa",[1108,38060,38061],{},"Nhạy ngoại lệ",[1118,38063,38064,38075,38086],{},[1105,38065,38066,38069,38072],{},[1123,38067,38068],{},"MSE",[1123,38070,38071],{},"Trung bình bình phương lỗi",[1123,38073,38074],{},"Rất nhạy",[1105,38076,38077,38080,38083],{},[1123,38078,38079],{},"MAE",[1123,38081,38082],{},"Trung bình trị tuyệt đối",[1123,38084,38085],{},"Lì hơn",[1105,38087,38088,38091,38094],{},[1123,38089,38090],{},"R2",[1123,38092,38093],{},"% biến thiên giải thích",[1123,38095,38096],{},"1 là hoàn hảo",[968,38098,1433],{"id":1432},[986,38100,38101,38104,38107,38110],{},[989,38102,38103],{},"Input: điểm nằm đúng trên đường thẳng -> Output: sai số quanh 0.",[989,38105,38106],{},"Câu này cho thấy đường thẳng khôi phục hoàn hảo.",[989,38108,38109],{},"Input: mô hình chỉ đoán trung bình -> Output: R2 bằng 0.",[989,38111,38112],{},"Câu này kiểm tra biên dở nhất của R2.",[968,38114,1482],{"id":1481},[973,38116,1485,38117,17626,38119,33864,38122,1517],{},[1487,38118,13531],{},[992,38120,38121],{},"sklearn.linear_model",[992,38123,38124],{},"day-055\u002F",[981,38126,38128],{"id":38127},"bài-1-hồi-quy-tuyến-tính-công-thức-đóng","Bài 1: Hồi quy tuyến tính công thức đóng",[1352,38130,38132],{"className":3538,"code":38131,"language":3540,"meta":1357,"style":1357},"class LinearRegression:\n    def fit(self, X, y): ...       # thêm cột 1 cho hệ số chặn, giải bằng np.linalg.lstsq\n    def predict(self, X): ...\n    coef_: np.ndarray; intercept_: float\ndef mse(y, yhat); def mae(y, yhat); def r2(y, yhat)\n",[992,38133,38134,38139,38144,38148,38153],{"__ignoreMap":1357},[1023,38135,38136],{"class":1362,"line":63},[1023,38137,38138],{},"class LinearRegression:\n",[1023,38140,38141],{"class":1362,"line":68},[1023,38142,38143],{},"    def fit(self, X, y): ...       # thêm cột 1 cho hệ số chặn, giải bằng np.linalg.lstsq\n",[1023,38145,38146],{"class":1362,"line":73},[1023,38147,37022],{},[1023,38149,38150],{"class":1362,"line":78},[1023,38151,38152],{},"    coef_: np.ndarray; intercept_: float\n",[1023,38154,38155],{"class":1362,"line":83},[1023,38156,38157],{},"def mse(y, yhat); def mae(y, yhat); def r2(y, yhat)\n",[1352,38159,38162],{"className":38160,"code":38161,"language":2241,"meta":1357},[2239],"X = [[1],[2],[3]], y = [2,4,6]       -> coef 2, intercept 0, r2 = 1\nMô hình luôn đoán mean(y)            -> r2 = 0\nThêm 1 ngoại lệ lớn                  -> MSE tăng mạnh hơn MAE (in số)\n",[992,38163,38161],{"__ignoreMap":1357},[981,38165,38167],{"id":38166},"bài-2-hồi-quy-bội-và-diễn-giải","Bài 2: Hồi quy bội và diễn giải",[973,38169,38170],{},"Dùng bộ California Housing.",[2273,38172,38173,38176,38179,38403],{},[989,38174,38175],{},"Chuẩn hóa đặc trưng (scaler ngày 52, fit trên train).",[989,38177,38178],{},"In hệ số từng đặc trưng, sắp theo trị tuyệt đối. Viết 3 câu diễn giải 3 hệ số lớn nhất.",[989,38180,5030,38181,13568,38184,38393,38394,38397,38398,10880,38400,1517],{},[992,38182,38183],{},"Ridge(alpha)",[1023,38185,38187,38240],{"className":38186},[1026],[1023,38188,38190],{"className":38189},[1030],[1032,38191,38192],{"xmlns":1034},[1036,38193,38194,38237],{},[1039,38195,38196,38198,38200,38202,38210,38212,38214,38216,38219,38229,38235],{},[1042,38197,27557],{},[1046,38199,2325],{},[1046,38201,1049],{"stretchy":1048},[2327,38203,38204,38207],{},[1042,38205,38206],{},"X",[1042,38208,38209],{},"T",[1042,38211,38206],{},[1046,38213,21881],{},[1042,38215,37375],{},[1042,38217,38218],{},"I",[2327,38220,38221,38223],{},[1046,38222,1056],{"stretchy":1048},[1039,38224,38225,38227],{},[1046,38226,17698],{},[1051,38228,1053],{},[2327,38230,38231,38233],{},[1042,38232,38206],{},[1042,38234,38209],{},[1042,38236,32887],{},[1058,38238,38239],{"encoding":1060},"w = (X^TX + \\alpha I)^{-1}X^Ty",[1023,38241,38243,38261,38314],{"className":38242,"ariaHidden":1066},[1065],[1023,38244,38246,38249,38252,38255,38258],{"className":38245},[1070],[1023,38247],{"className":38248,"style":2347},[1074],[1023,38250,27557],{"className":38251,"style":37436},[1079,1080],[1023,38253],{"className":38254,"style":2355},[2354],[1023,38256,2325],{"className":38257},[2359],[1023,38259],{"className":38260,"style":2355},[2354],[1023,38262,38264,38268,38271,38302,38305,38308,38311],{"className":38263},[1070],[1023,38265],{"className":38266,"style":38267},[1074],"height:1.0913em;vertical-align:-0.25em;",[1023,38269,1049],{"className":38270},[1085],[1023,38272,38274,38278],{"className":38273},[1079],[1023,38275,38206],{"className":38276,"style":38277},[1079,1080],"margin-right:0.0785em;",[1023,38279,38281],{"className":38280},[2383],[1023,38282,38284],{"className":38283},[2387],[1023,38285,38287],{"className":38286},[2391],[1023,38288,38291],{"className":38289,"style":38290},[2395],"height:0.8413em;",[1023,38292,38293,38296],{"style":2398},[1023,38294],{"className":38295,"style":2403},[2402],[1023,38297,38299],{"className":38298},[2407,2408,2409,2410],[1023,38300,38209],{"className":38301,"style":37429},[1079,1080,2410],[1023,38303,38206],{"className":38304,"style":38277},[1079,1080],[1023,38306],{"className":38307,"style":13790},[2354],[1023,38309,21881],{"className":38310},[13794],[1023,38312],{"className":38313,"style":13790},[2354],[1023,38315,38317,38320,38323,38326,38361,38390],{"className":38316},[1070],[1023,38318],{"className":38319,"style":38267},[1074],[1023,38321,37375],{"className":38322,"style":37587},[1079,1080],[1023,38324,38218],{"className":38325,"style":38277},[1079,1080],[1023,38327,38329,38332],{"className":38328},[1092],[1023,38330,1056],{"className":38331},[1092],[1023,38333,38335],{"className":38334},[2383],[1023,38336,38338],{"className":38337},[2387],[1023,38339,38341],{"className":38340},[2391],[1023,38342,38344],{"className":38343,"style":2369},[2395],[1023,38345,38346,38349],{"style":2398},[1023,38347],{"className":38348,"style":2403},[2402],[1023,38350,38352],{"className":38351},[2407,2408,2409,2410],[1023,38353,38355,38358],{"className":38354},[1079,2410],[1023,38356,17698],{"className":38357},[1079,2410],[1023,38359,1053],{"className":38360},[1079,2410],[1023,38362,38364,38367],{"className":38363},[1079],[1023,38365,38206],{"className":38366,"style":38277},[1079,1080],[1023,38368,38370],{"className":38369},[2383],[1023,38371,38373],{"className":38372},[2387],[1023,38374,38376],{"className":38375},[2391],[1023,38377,38379],{"className":38378,"style":38290},[2395],[1023,38380,38381,38384],{"style":2398},[1023,38382],{"className":38383,"style":2403},[2402],[1023,38385,38387],{"className":38386},[2407,2408,2409,2410],[1023,38388,38209],{"className":38389,"style":37429},[1079,1080,2410],[1023,38391,32887],{"className":38392,"style":7723},[1079,1080],", không phạt hệ số chặn. Vẽ hệ số theo ",[992,38395,38396],{},"alpha"," từ ",[992,38399,18406],{},[992,38401,38402],{},"1e3",[989,38404,38405],{},"In R2 test của Linear và Ridge tốt nhất.",[981,38407,38409],{"id":38408},"bài-3-logistic-regression-nâng-cao","Bài 3: Logistic regression (nâng cao)",[1352,38411,38413],{"className":3538,"code":38412,"language":3540,"meta":1357,"style":1357},"class LogisticRegression:\n    def __init__(self, lr=0.1, epochs=1000, l2=0.0): ...\n    def fit(self, X, y): ...           # gradient descent trên log-loss, vector hóa\n    def predict_proba(self, X): ...\n    def predict(self, X, threshold=0.5): ...\n",[992,38414,38415,38420,38425,38430,38435],{"__ignoreMap":1357},[1023,38416,38417],{"class":1362,"line":63},[1023,38418,38419],{},"class LogisticRegression:\n",[1023,38421,38422],{"class":1362,"line":68},[1023,38423,38424],{},"    def __init__(self, lr=0.1, epochs=1000, l2=0.0): ...\n",[1023,38426,38427],{"class":1362,"line":73},[1023,38428,38429],{},"    def fit(self, X, y): ...           # gradient descent trên log-loss, vector hóa\n",[1023,38431,38432],{"class":1362,"line":78},[1023,38433,38434],{},"    def predict_proba(self, X): ...\n",[1023,38436,38437],{"class":1362,"line":83},[1023,38438,38439],{},"    def predict(self, X, threshold=0.5): ...\n",[973,38441,38442,38443,1509,38446,1517],{},"Dùng sigmoid ổn định số: tách trường hợp ",[992,38444,38445],{},"z >= 0",[992,38447,38448],{},"z \u003C 0",[2273,38450,38451,38454,38457],{},[989,38452,38453],{},"Chạy trên bộ Breast Cancer (sklearn datasets). In accuracy, log-loss train\u002Ftest.",[989,38455,38456],{},"Vẽ log-loss theo epoch: phải giảm dần.",[989,38458,38459,38460,38463],{},"So hệ số với ",[992,38461,38462],{},"sklearn.linear_model.LogisticRegression(penalty=None)"," sau đủ epoch.",[981,38465,2711],{"id":2710},[986,38467,38469,38474,38484,38490],{"className":38468},[2715],[989,38470,38472,11986],{"className":38471},[2719],[2721,38473],{"disabled":2723,"type":2724},[989,38475,38477,38479,38480,35265,38482,1517],{"className":38476},[2719],[2721,38478],{"disabled":2723,"type":2724}," Hệ số Linear khớp ",[992,38481,17633],{},[992,38483,32245],{},[989,38485,38487,38489],{"className":38486},[2719],[2721,38488],{"disabled":2723,"type":2724}," Có hình đường đi hệ số Ridge và hình log-loss theo epoch.",[989,38491,38493,38495],{"className":38492},[2719],[2721,38494],{"disabled":2723,"type":2724}," Giải thích được R2 âm nghĩa là gì.",[968,38497,2890],{"id":2889},[986,38499,38500,38503,38506,38509],{},[989,38501,38502],{},"Hồi quy đơn vẽ đường theo tiêu chí nào?",[989,38504,38505],{},"MSE khác MAE ở điểm nào?",[989,38507,38508],{},"R2 bằng 0 và bằng 1 nghĩa là gì?",[989,38510,38511],{},"Khi nào dùng cây thay vì đường thẳng?",[3014,38513],{},[973,38515,38516],{},"🌕 Bạn đã hoàn thành ngày 55. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,38518,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":38520},[38521,38522,38527,38528,38534],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":38523},[38524,38525,38526],{"id":37995,"depth":73,"text":37996},{"id":38013,"depth":73,"text":38014},{"id":38031,"depth":73,"text":38032},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":38529},[38530,38531,38532,38533],{"id":38127,"depth":73,"text":38128},{"id":38166,"depth":73,"text":38167},{"id":38408,"depth":73,"text":38409},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhánh hồi quy: thử thách regressors, hồi quy đơn và bội, đánh giá regressors, cây hồi quy, boosting hồi quy và dự báo thời tiết.",{},[4669],{"title":330,"description":38535},[18472,38540,38541],"regression","logistic-regression","7jxz-F0IkQvI475qeocT_17xLKkZAulOA8F1hFIeXTc",{"id":38544,"title":335,"body":38545,"category":8797,"day":338,"description":38882,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":38883,"navigation":2723,"outcomes":3047,"path":336,"prerequisites":38884,"seo":38885,"stem":337,"tags":38886,"__hash__":38888},"challenges\u002Fchallenges\u002F56.danh-gia-mo-hinh.md",{"type":965,"value":38546,"toc":38866},[38547,38549,38552,38554,38558,38572,38576,38590,38594,38608,38657,38659,38673,38675,38685,38689,38751,38757,38761,38764,38781,38785,38809,38811,38845,38847,38861,38863],[968,38548,971],{"id":970},[973,38550,38551],{},"Bài này học đọc ma trận nhầm lẫn và precision recall.\nKiến thức này giúp chống overfitting khi triển khai thật.",[968,38553,979],{"id":978},[981,38555,38557],{"id":38556},"ma-trận-4-ô","Ma trận 4 ô",[986,38559,38560,38563,38566,38569],{},[989,38561,38562],{},"Đúng dương: bắt đúng kẻ cần bắt.",[989,38564,38565],{},"Đúng âm: tha đúng người vô tội.",[989,38567,38568],{},"Dương giả: báo oan, âm giả: bỏ sót.",[989,38570,38571],{},"Ví dụ đời thường: hai máy cùng 90% nhưng sai kiểu khác nhau.",[981,38573,38575],{"id":38574},"precision-và-recall","Precision và recall",[986,38577,38578,38581,38584,38587],{},[989,38579,38580],{},"Precision: trong số báo dương, bao nhiêu phần trăm đúng.",[989,38582,38583],{},"Recall: trong số dương thật, tóm được bao nhiêu phần trăm.",[989,38585,38586],{},"Hạ ngưỡng thì recall lên precision xuống, ngược lại cũng vậy.",[989,38588,38589],{},"Ví dụ đời thường: khám bệnh hiểm thì thà báo oan còn hơn bỏ sót.",[981,38591,38593],{"id":38592},"overfitting-và-3-phần-dữ-liệu","Overfitting và 3 phần dữ liệu",[986,38595,38596,38599,38602,38605],{},[989,38597,38598],{},"Overfitting: điểm train cao mà điểm mới thấp.",[989,38600,38601],{},"Nguyên nhân: mô hình khỏe quá, học quá lâu, nhìn trộm đáp án.",[989,38603,38604],{},"Chia train để học, valid để chỉnh, test khóa để báo cáo.",[989,38606,38607],{},"Ví dụ đời thường: học thuộc đề cũ nhưng thi đề mới trượt.",[1099,38609,38610,38622],{},[1102,38611,38612],{},[1105,38613,38614,38617,38620],{},[1108,38615,38616],{},"Chỉ số",[1108,38618,38619],{},"Công thức lời",[1108,38621,23789],{},[1118,38623,38624,38635,38646],{},[1105,38625,38626,38629,38632],{},[1123,38627,38628],{},"Accuracy",[1123,38630,38631],{},"Đường chéo chia tổng",[1123,38633,38634],{},"Lớp cân bằng",[1105,38636,38637,38640,38643],{},[1123,38638,38639],{},"Precision",[1123,38641,38642],{},"Đúng dương chia báo dương",[1123,38644,38645],{},"Sợ báo oan",[1105,38647,38648,38651,38654],{},[1123,38649,38650],{},"Recall",[1123,38652,38653],{},"Đúng dương chia dương thật",[1123,38655,38656],{},"Sợ bỏ sót",[968,38658,1433],{"id":1432},[986,38660,38661,38664,38667,38670],{},[989,38662,38663],{},"Input: mô hình hoàn hảo -> Output: ma trận chỉ có đường chéo, precision recall bằng 1.",[989,38665,38666],{},"Câu này kiểm tra biên giỏi nhất mọi chỉ số.",[989,38668,38669],{},"Input: mô hình lười luôn đoán đa số trên dữ liệu 95-5 -> Output: accuracy 95% nhưng recall thiểu số 0.",[989,38671,38672],{},"Câu này cho thấy accuracy lừa dối khi lệch lớp.",[968,38674,1482],{"id":1481},[973,38676,1485,38677,17626,38679,33864,38682,1517],{},[1487,38678,13531],{},[992,38680,38681],{},"sklearn.metrics",[992,38683,38684],{},"day-056\u002F",[981,38686,38688],{"id":38687},"bài-1-ma-trận-nhầm-lẫn-và-các-chỉ-số","Bài 1: Ma trận nhầm lẫn và các chỉ số",[1099,38690,38691,38699],{},[1102,38692,38693],{},[1105,38694,38695,38697],{},[1108,38696,1566],{},[1108,38698,2547],{},[1118,38700,38701,38715,38731,38741],{},[1105,38702,38703,38708],{},[1123,38704,38705],{},[992,38706,38707],{},"confusion_matrix(y, yhat, labels)",[1123,38709,38710,38711,38714],{},"Ma trận ",[992,38712,38713],{},"k x k",", hàng là nhãn thật, cột là nhãn đoán",[1105,38716,38717,38728],{},[1123,38718,38719,1656,38722,1656,38725],{},[992,38720,38721],{},"precision(y, yhat, pos)",[992,38723,38724],{},"recall(...)",[992,38726,38727],{},"f1(...)",[1123,38729,38730],{},"Mẫu số bằng 0 thì trả 0",[1105,38732,38733,38738],{},[1123,38734,38735],{},[992,38736,38737],{},"macro_f1(y, yhat)",[1123,38739,38740],{},"Trung bình F1 các lớp",[1105,38742,38743,38748],{},[1123,38744,38745],{},[992,38746,38747],{},"report(y, yhat)",[1123,38749,38750],{},"In bảng precision, recall, F1, support từng lớp",[1352,38752,38755],{"className":38753,"code":38754,"language":2241,"meta":1357},[2239],"y    = [1,1,1,0,0,0,0,0]\nyhat = [1,1,0,1,0,0,0,0]\n-> TP=2, FN=1, FP=1, TN=4; precision=0.667, recall=0.667, f1=0.667\n\nDữ liệu 95 âm, 5 dương, luôn đoán âm -> accuracy 0.95, recall(dương) = 0\n",[992,38756,38754],{"__ignoreMap":1357},[981,38758,38760],{"id":38759},"bài-2-ngưỡng-roc-và-pr","Bài 2: Ngưỡng, ROC và PR",[973,38762,38763],{},"Dùng logistic regression ngày 55 trên bộ Breast Cancer.",[2273,38765,38766,38769,38778],{},[989,38767,38768],{},"Quét ngưỡng từ 0 tới 1 bước 0.01. Vẽ precision và recall theo ngưỡng.",[989,38770,35241,38771,1509,38774,38777],{},[992,38772,38773],{},"roc_curve",[992,38775,38776],{},"auc"," (quy tắc hình thang). Vẽ ROC.",[989,38779,38780],{},"Chọn ngưỡng sao cho recall lớp ác tính ≥ 0.98. In precision tại ngưỡng đó. Viết 2 câu vì sao bài toán y tế ưu tiên recall.",[981,38782,38784],{"id":38783},"bài-3-overfitting-và-cross-validation-nâng-cao","Bài 3: Overfitting và cross-validation (nâng cao)",[2273,38786,38787,38794,38803],{},[989,38788,38789,38790,38793],{},"Sinh dữ liệu ",[992,38791,38792],{},"y = sin(x) + nhiễu",", 30 điểm. Khớp đa thức bậc 1, 3, 9, 15. Vẽ đường cong và in MSE train\u002Ftest.",[989,38795,35241,38796,1509,38799,38802],{},[992,38797,38798],{},"k_fold(n, k, seed)",[992,38800,38801],{},"cross_val_score(model, X, y, k)",". Chọn bậc đa thức bằng 5-fold CV.",[989,38804,35212,38805,38808],{},[1487,38806,38807],{},"learning curve",": MSE train và validation theo kích thước tập train cho bậc 3 và bậc 15.",[981,38810,2711],{"id":2710},[986,38812,38814,38824,38833,38839],{"className":38813},[2715],[989,38815,38817,38819,38820,35265,38822,1517],{"className":38816},[2719],[2721,38818],{"disabled":2723,"type":2724}," Chỉ số khớp ",[992,38821,38681],{},[992,38823,36436],{},[989,38825,38827,38829,38830,1517],{"className":38826},[2719],[2721,38828],{"disabled":2723,"type":2724}," Có hình precision-recall theo ngưỡng và ROC, AUC khớp ",[992,38831,38832],{},"roc_auc_score",[989,38834,38836,38838],{"className":38835},[2719],[2721,38837],{"disabled":2723,"type":2724}," Bảng MSE theo bậc đa thức có số thật.",[989,38840,38842,38844],{"className":38841},[2719],[2721,38843],{"disabled":2723,"type":2724}," Giải thích được vì sao tập test phải \"khóa\" tới cuối cùng.",[968,38846,2890],{"id":2889},[986,38848,38849,38852,38855,38858],{},[989,38850,38851],{},"4 ô ma trận nhầm lẫn là gì?",[989,38853,38854],{},"Precision khác recall ở đâu?",[989,38856,38857],{},"Overfitting nhận biết qua 2 đường nào?",[989,38859,38860],{},"Vì sao phải khóa riêng tập test?",[3014,38862],{},[973,38864,38865],{},"🌕 Bạn đã hoàn thành ngày 56. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":38867},[38868,38869,38874,38875,38881],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":38870},[38871,38872,38873],{"id":38556,"depth":73,"text":38557},{"id":38574,"depth":73,"text":38575},{"id":38592,"depth":73,"text":38593},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":38876},[38877,38878,38879,38880],{"id":38687,"depth":73,"text":38688},{"id":38759,"depth":73,"text":38760},{"id":38783,"depth":73,"text":38784},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Chốt nhánh giám sát: ma trận nhầm lẫn, precision recall và đánh đổi, overfitting, ba phần dữ liệu và đọc kết quả classifiers.",{},[18469],{"title":335,"description":38882},[18472,35333,38887],"overfitting","XU6gftqpxo8O7ClqBvIk6hUwwi1BicxiDlDPcQ0XgN8",{"id":38890,"title":340,"body":38891,"category":8797,"day":343,"description":39226,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":39227,"navigation":2723,"outcomes":3047,"path":341,"prerequisites":39228,"seo":39229,"stem":342,"tags":39230,"__hash__":39231},"challenges\u002Fchallenges\u002F57.nlp-co-ban.md",{"type":965,"value":38892,"toc":39210},[38893,38895,38898,38900,38904,38918,38922,38936,38940,38954,38984,38986,39000,39002,39010,39014,39068,39074,39078,39113,39119,39130,39134,39155,39157,39187,39189,39203,39205,39208],[968,38894,971],{"id":970},[973,38896,38897],{},"Bài này học biến văn bản thô thành số.\nViệc này giúp máy phân loại review và tweet được.",[968,38899,979],{"id":978},[981,38901,38903],{"id":38902},"tách-từ-và-làm-sạch","Tách từ và làm sạch",[986,38905,38906,38909,38912,38915],{},[989,38907,38908],{},"Tokenize: cắt câu thành mảnh nhỏ thường là từ.",[989,38910,38911],{},"Làm sạch: thường hóa, gỡ dấu câu, số, thẻ HTML.",[989,38913,38914],{},"Chuẩn hóa: bỏ từ dừng, đưa về gốc từ.",[989,38916,38917],{},"Ví dụ đời thường: tiếng Việt phải tách từ ghép, không cắt bừa.",[981,38919,38921],{"id":38920},"túi-từ-bow","Túi từ BoW",[986,38923,38924,38927,38930,38933],{},[989,38925,38926],{},"Gom từ vựng, mỗi văn bản thành vector đếm từ.",[989,38928,38929],{},"Nhiều văn bản xếp thành ma trận hàng là văn bản.",[989,38931,38932],{},"Ma trận rất thưa vì mỗi văn bản dùng ít từ.",[989,38934,38935],{},"Ví dụ đời thường: hay và không hay cho cùng một vector nên mất thứ tự.",[981,38937,38939],{"id":38938},"tf-idf-cân-bằng","TF-IDF cân bằng",[986,38941,38942,38945,38948,38951],{},[989,38943,38944],{},"TF: từ quan trọng thế nào trong văn bản này.",[989,38946,38947],{},"IDF: từ hiếm thế nào trên toàn tập.",[989,38949,38950],{},"Nhân hai cái ra trọng số cuối, từ hiếm được nâng.",[989,38952,38953],{},"Ví dụ đời thường: ngon ở khắp nơi bị hạ, hải sản tươi hiếm được nâng.",[1352,38955,38957],{"className":3538,"code":38956,"language":3540,"meta":1357,"style":1357},"# Ý tưởng TF-IDF: hay trong bài, hiếm toàn tập\ndef tfidf(tf, df, N):\n    import math  # dùng log\n    idf = math.log(N \u002F df)  # hiếm thì idf cao\n    return tf * idf  # nhân hai cái\n",[992,38958,38959,38964,38969,38974,38979],{"__ignoreMap":1357},[1023,38960,38961],{"class":1362,"line":63},[1023,38962,38963],{},"# Ý tưởng TF-IDF: hay trong bài, hiếm toàn tập\n",[1023,38965,38966],{"class":1362,"line":68},[1023,38967,38968],{},"def tfidf(tf, df, N):\n",[1023,38970,38971],{"class":1362,"line":73},[1023,38972,38973],{},"    import math  # dùng log\n",[1023,38975,38976],{"class":1362,"line":78},[1023,38977,38978],{},"    idf = math.log(N \u002F df)  # hiếm thì idf cao\n",[1023,38980,38981],{"class":1362,"line":83},[1023,38982,38983],{},"    return tf * idf  # nhân hai cái\n",[968,38985,1433],{"id":1432},[986,38987,38988,38991,38994,38997],{},[989,38989,38990],{},"Input: từ the ở 100% tài liệu -> Output: IDF về 0, TF-IDF thấp dù đếm cao.",[989,38992,38993],{},"Câu này cho thấy đếm cao chưa chắc quan trọng.",[989,38995,38996],{},"Input: đảo thứ tự từ giữ nguyên multiset -> Output: vector BoW không đổi.",[989,38998,38999],{},"Câu này chứng minh BoW mất thứ tự.",[968,39001,1482],{"id":1481},[973,39003,1485,39004,39006,39007,1517],{},[1487,39005,13531],{},". Bài 1-2 chỉ dùng thư viện chuẩn và NumPy. Nộp vào ",[992,39008,39009],{},"day-057\u002F",[981,39011,39013],{"id":39012},"bài-1-tokenize-và-làm-sạch","Bài 1: Tokenize và làm sạch",[1099,39015,39016,39024],{},[1102,39017,39018],{},[1105,39019,39020,39022],{},[1108,39021,1566],{},[1108,39023,2547],{},[1118,39025,39026,39036,39046,39055],{},[1105,39027,39028,39033],{},[1123,39029,39030],{},[992,39031,39032],{},"clean(text)",[1123,39034,39035],{},"Chữ thường, gỡ thẻ HTML, gỡ URL, gỡ số, gộp khoảng trắng",[1105,39037,39038,39043],{},[1123,39039,39040],{},[992,39041,39042],{},"tokenize(text)",[1123,39044,39045],{},"Tách theo ký tự không phải chữ, giữ được chữ tiếng Việt có dấu",[1105,39047,39048,39053],{},[1123,39049,39050],{},[992,39051,39052],{},"remove_stopwords(tokens, stopwords)",[1123,39054],{},[1105,39056,39057,39062],{},[1123,39058,39059],{},[992,39060,39061],{},"ngrams(tokens, n)",[1123,39063,39064,39065],{},"Trả list chuỗi nối bằng ",[992,39066,39067],{},"_",[1352,39069,39072],{"className":39070,"code":39071,"language":2241,"meta":1357},[2239],"clean(\"\u003Cb>Giá 100k!\u003C\u002Fb> xem tại https:\u002F\u002Fx.vn\") -> \"giá k xem tại\"\ntokenize(\"Học máy, học sâu.\")                   -> [\"học\", \"máy\", \"học\", \"sâu\"]\nngrams([\"học\",\"máy\",\"học\"], 2)                  -> [\"học_máy\", \"máy_học\"]\n",[992,39073,39071],{"__ignoreMap":1357},[981,39075,39077],{"id":39076},"bài-2-bag-of-words-và-tf-idf","Bài 2: Bag of Words và TF-IDF",[1352,39079,39081],{"className":3538,"code":39080,"language":3540,"meta":1357,"style":1357},"class CountVectorizer:\n    def fit(self, docs): ...              # vocab_: dict[từ, cột], sắp alphabet\n    def transform(self, docs) -> np.ndarray: ...\nclass TfidfVectorizer:\n    def fit(self, docs): ...              # idf = ln((1 + N) \u002F (1 + df)) + 1\n    def transform(self, docs): ...        # tf là số đếm thô, chuẩn hóa L2 mỗi hàng\n",[992,39082,39083,39088,39093,39098,39103,39108],{"__ignoreMap":1357},[1023,39084,39085],{"class":1362,"line":63},[1023,39086,39087],{},"class CountVectorizer:\n",[1023,39089,39090],{"class":1362,"line":68},[1023,39091,39092],{},"    def fit(self, docs): ...              # vocab_: dict[từ, cột], sắp alphabet\n",[1023,39094,39095],{"class":1362,"line":73},[1023,39096,39097],{},"    def transform(self, docs) -> np.ndarray: ...\n",[1023,39099,39100],{"class":1362,"line":78},[1023,39101,39102],{},"class TfidfVectorizer:\n",[1023,39104,39105],{"class":1362,"line":83},[1023,39106,39107],{},"    def fit(self, docs): ...              # idf = ln((1 + N) \u002F (1 + df)) + 1\n",[1023,39109,39110],{"class":1362,"line":88},[1023,39111,39112],{},"    def transform(self, docs): ...        # tf là số đếm thô, chuẩn hóa L2 mỗi hàng\n",[1352,39114,39117],{"className":39115,"code":39116,"language":2241,"meta":1357},[2239],"docs = [\"mèo ăn cá\", \"chó ăn thịt\", \"mèo và chó\"]\nvocab_ có 7 từ; \"ăn\" xuất hiện ở 2\u002F3 văn bản nên idf thấp hơn \"cá\"\nĐảo thứ tự từ trong 1 văn bản -> vector BoW không đổi\n",[992,39118,39116],{"__ignoreMap":1357},[973,39120,39121,39122,39125,39126,39129],{},"Kết quả ",[992,39123,39124],{},"TfidfVectorizer"," phải khớp ",[992,39127,39128],{},"sklearn.feature_extraction.text.TfidfVectorizer"," (tham số mặc định, cùng tokenizer).",[981,39131,39133],{"id":39132},"bài-3-tìm-văn-bản-giống-nhau-nâng-cao","Bài 3: Tìm văn bản giống nhau (nâng cao)",[2273,39135,39136,39139,39142,39152],{},[989,39137,39138],{},"Lấy 200 bài báo ngắn (tự thu thập hoặc bộ dữ liệu công khai).",[989,39140,39141],{},"Biểu diễn TF-IDF. Với một câu truy vấn, trả top 5 bài có cosine cao nhất.",[989,39143,39144,39145,5586,39148,39151],{},"Lưu ma trận dạng thưa (",[992,39146,39147],{},"dict",[992,39149,39150],{},"scipy.sparse","). In tỉ lệ ô khác 0.",[989,39153,39154],{},"So kết quả top 5 khi có và không bỏ từ dừng.",[981,39156,2711],{"id":2710},[986,39158,39160,39165,39175,39181],{"className":39159},[2715],[989,39161,39163,11986],{"className":39162},[2719],[2721,39164],{"disabled":2723,"type":2724},[989,39166,39168,39170,39171,35265,39173,1517],{"className":39167},[2719],[2721,39169],{"disabled":2723,"type":2724}," TF-IDF khớp ",[992,39172,17633],{},[992,39174,36436],{},[989,39176,39178,39180],{"className":39177},[2719],[2721,39179],{"disabled":2723,"type":2724}," Bài 3 trả kết quả hợp lý cho 3 truy vấn, có in độ thưa.",[989,39182,39184,39186],{"className":39183},[2719],[2721,39185],{"disabled":2723,"type":2724}," Giải thích được vì sao \"the\" có IDF thấp.",[968,39188,2890],{"id":2889},[986,39190,39191,39194,39197,39200],{},[989,39192,39193],{},"Tokenize và làm sạch gồm bước nào?",[989,39195,39196],{},"Ma trận thuật ngữ hàng cột là gì?",[989,39198,39199],{},"TF và IDF mỗi cái đo gì?",[989,39201,39202],{},"BoW mất thông tin gì quan trọng?",[3014,39204],{},[973,39206,39207],{},"🌕 Bạn đã hoàn thành ngày 57. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,39209,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":39211},[39212,39213,39218,39219,39225],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":39214},[39215,39216,39217],{"id":38902,"depth":73,"text":38903},{"id":38920,"depth":73,"text":38921},{"id":38938,"depth":73,"text":38939},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":39220},[39221,39222,39223,39224],{"id":39012,"depth":73,"text":39013},{"id":39076,"depth":73,"text":39077},{"id":39132,"depth":73,"text":39133},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tiền xử lý văn bản, tách từ, làm sạch, ma trận thuật ngữ tài liệu, TF-IDF và diễn giải kết quả trên ví dụ minh họa.",{},[14055],{"title":340,"description":39226},[37980],"Yp7UY8nqyWxSa_tIvnIwDOvC0vApYK0VuKQ3A24PA28",{"id":39233,"title":345,"body":39234,"category":8797,"day":348,"description":39577,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":39578,"navigation":2723,"outcomes":3047,"path":346,"prerequisites":39579,"seo":39580,"stem":347,"tags":39581,"__hash__":39583},"challenges\u002Fchallenges\u002F58.recsys-content.md",{"type":965,"value":39235,"toc":39561},[39236,39238,39241,39243,39247,39261,39265,39279,39283,39297,39345,39347,39361,39363,39372,39376,39434,39440,39444,39476,39480,39508,39510,39540,39542,39556,39558],[968,39237,971],{"id":970},[973,39239,39240],{},"Bài này học gợi ý theo nội dung món đã thích.\nCách này giúp gợi phim mới mà không cần cộng đồng.",[968,39242,979],{"id":978},[981,39244,39246],{"id":39245},"content-based-là-gì","Content-based là gì",[986,39248,39249,39252,39255,39258],{},[989,39250,39251],{},"Mỗi món thành vector thể loại, tác giả, từ khóa TF-IDF.",[989,39253,39254],{},"Mỗi người thành trung bình có trọng số món đã thích.",[989,39256,39257],{},"Điểm gợi ý là độ giống giữa người và món chưa xem.",[989,39259,39260],{},"Ví dụ đời thường: hay xem phim không gian thì gợi tiếp phim không gian.",[981,39262,39264],{"id":39263},"đồng-xuất-hiện","Đồng xuất hiện",[986,39266,39267,39270,39273,39276],{},[989,39268,39269],{},"Đếm hai món hay đi chung giỏ bao nhiêu lần.",[989,39271,39272],{},"Cao thì gợi chéo, ai mua máy ảnh gợi thẻ nhớ.",[989,39274,39275],{},"Không cần biết bạn là ai nên gọi là không cá nhân hóa.",[989,39277,39278],{},"Ví dụ đời thường: top phổ biến và mua kèm trên trang chủ.",[981,39280,39282],{"id":39281},"mạnh-yếu","Mạnh yếu",[986,39284,39285,39288,39291,39294],{},[989,39286,39287],{},"Mạnh: giải thích được, gợi được món mới toanh.",[989,39289,39290],{},"Yếu: giam trong bong bóng, khó phát hiện sở thích mới.",[989,39292,39293],{},"Cần metadata tốt, thiếu thể loại thì đói dữ liệu.",[989,39295,39296],{},"Ví dụ đời thường: càng gợi giống quá khứ càng chán.",[1099,39298,39299,39311],{},[1102,39300,39301],{},[1105,39302,39303,39305,39308],{},[1108,39304,14526],{},[1108,39306,39307],{},"Cần gì",[1108,39309,39310],{},"Khi thắng",[1118,39312,39313,39324,39334],{},[1105,39314,39315,39318,39321],{},[1123,39316,39317],{},"Content",[1123,39319,39320],{},"Mô tả món",[1123,39322,39323],{},"Món mới chưa ai xem",[1105,39325,39326,39328,39331],{},[1123,39327,39264],{},[1123,39329,39330],{},"Giỏ chung",[1123,39332,39333],{},"Khách mới, trang chủ",[1105,39335,39336,39339,39342],{},[1123,39337,39338],{},"Phổ biến",[1123,39340,39341],{},"Đếm lượt",[1123,39343,39344],{},"Món ai cũng thích",[968,39346,1433],{"id":1432},[986,39348,39349,39352,39355,39358],{},[989,39350,39351],{},"Input: người chỉ xem hành động, hệ chỉ gợi hành động -> Output: mới mẻ thấp, chẩn đoán kén lọc.",[989,39353,39354],{},"Câu này cho thấy bong bóng lọc giam người dùng.",[989,39356,39357],{},"Input: món mới ra không ai xem -> Output: content vẫn gợi được nhờ mô tả.",[989,39359,39360],{},"Câu này cho thấy lợi thế với món mới toanh.",[968,39362,1482],{"id":1481},[973,39364,1485,39365,39367,39368,39371],{},[1487,39366,13531],{}," với NumPy và pandas. Dùng TF-IDF ngày 57. Nộp vào ",[992,39369,39370],{},"day-058\u002F",". Dữ liệu: MovieLens 100K (công khai).",[981,39373,39375],{"id":39374},"bài-1-gợi-ý-theo-nội-dung","Bài 1: Gợi ý theo nội dung",[1099,39377,39378,39386],{},[1102,39379,39380],{},[1105,39381,39382,39384],{},[1108,39383,1566],{},[1108,39385,2547],{},[1118,39387,39388,39398,39411,39424],{},[1105,39389,39390,39395],{},[1123,39391,39392],{},[992,39393,39394],{},"item_vectors(movies)",[1123,39396,39397],{},"Vector nhị phân thể loại, ghép thêm TF-IDF của tên phim",[1105,39399,39400,39405],{},[1123,39401,39402],{},[992,39403,39404],{},"user_profile(user_id, ratings, item_vecs)",[1123,39406,39407,39408],{},"Trung bình có trọng số các phim đã chấm, trọng số = ",[992,39409,39410],{},"rating - mean_rating_của_user",[1105,39412,39413,39418],{},[1123,39414,39415],{},[992,39416,39417],{},"recommend(user_id, n=10)",[1123,39419,39420,39421,39423],{},"Top ",[992,39422,1262],{}," phim chưa xem có cosine cao nhất với hồ sơ",[1105,39425,39426,39431],{},[1123,39427,39428],{},[992,39429,39430],{},"explain(user_id, movie_id)",[1123,39432,39433],{},"Trả 3 thể loại đóng góp nhiều nhất vào điểm",[1352,39435,39438],{"className":39436,"code":39437,"language":2241,"meta":1357},[2239],"User chỉ chấm cao phim Action -> 10 gợi ý đa số có thể loại Action\nPhim mới chưa ai chấm         -> vẫn xuất hiện được trong gợi ý nếu hợp nội dung\n",[992,39439,39437],{"__ignoreMap":1357},[981,39441,39443],{"id":39442},"bài-2-đồng-xuất-hiện","Bài 2: Đồng xuất hiện",[2273,39445,39446,39458,39470],{},[989,39447,39448,39449,39452,39453,1509,39455,1517],{},"Dựng ma trận đồng xuất hiện: ",[992,39450,39451],{},"C[i][j]"," là số người chấm ≥ 4 cho cả phim ",[992,39454,1837],{},[992,39456,39457],{},"j",[989,39459,39460,39463,39464,39466,39467,1517],{},[992,39461,39462],{},"also_liked(movie_id, n)",": top ",[992,39465,1262],{}," phim theo ",[992,39468,39469],{},"C[i][j] \u002F sqrt(count[i] * count[j])",[989,39471,39472,39473,39475],{},"In kết quả cho 3 phim nổi tiếng. So sánh với khi dùng ",[992,39474,39451],{}," thô: phim phổ biến có lấn át không?",[981,39477,39479],{"id":39478},"bài-3-đánh-giá-và-bong-bóng-lọc-nâng-cao","Bài 3: Đánh giá và bong bóng lọc (nâng cao)",[2273,39481,39482,39485,39495,39505],{},[989,39483,39484],{},"Chia rating theo thời gian: 80% cũ để train, 20% mới để test.",[989,39486,39487,39488,1509,39491,39494],{},"Tính ",[1487,39489,39490],{},"precision@10",[1487,39492,39493],{},"recall@10"," (phim được chấm ≥ 4 trong test coi là liên quan).",[989,39496,39487,39497,39500,39501,39504],{},[1487,39498,39499],{},"độ đa dạng",": trung bình khoảng cách thể loại giữa các cặp phim trong top 10. Tính ",[1487,39502,39503],{},"độ mới lạ",": tỉ lệ thể loại chưa từng xuất hiện trong lịch sử người dùng.",[989,39506,39507],{},"So với baseline \"top phim phổ biến nhất\".",[981,39509,2711],{"id":2710},[986,39511,39513,39519,39528,39534],{"className":39512},[2715],[989,39514,39516,39518],{"className":39515},[2719],[2721,39517],{"disabled":2723,"type":2724}," Test mẫu cho user Action pass.",[989,39520,39522,2308,39524,39527],{"className":39521},[2719],[2721,39523],{"disabled":2723,"type":2724},[992,39525,39526],{},"explain"," trả lý do đọc hiểu được.",[989,39529,39531,39533],{"className":39530},[2719],[2721,39532],{"disabled":2723,"type":2724}," Bảng precision@10, recall@10, đa dạng, mới lạ cho 2 phương pháp.",[989,39535,39537,39539],{"className":39536},[2719],[2721,39538],{"disabled":2723,"type":2724}," Viết 3 câu về bong bóng lọc dựa trên số đo của mình.",[968,39541,2890],{"id":2889},[986,39543,39544,39547,39550,39553],{},[989,39545,39546],{},"Hồ sơ người dùng xây từ đâu?",[989,39548,39549],{},"Đồng xuất hiện đếm cái gì?",[989,39551,39552],{},"Vì sao content giam vào bong bóng?",[989,39554,39555],{},"Món mới toanh thì cách nào thắng?",[3014,39557],{},[973,39559,39560],{},"🌕 Bạn đã hoàn thành ngày 58. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":39562},[39563,39564,39569,39570,39576],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":39565},[39566,39567,39568],{"id":39245,"depth":73,"text":39246},{"id":39263,"depth":73,"text":39264},{"id":39281,"depth":73,"text":39282},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":39571},[39572,39573,39574,39575],{"id":39374,"depth":73,"text":39375},{"id":39442,"depth":73,"text":39443},{"id":39478,"depth":73,"text":39479},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hồ sơ món, vector đặc trưng, tương đồng nội dung, ma trận đồng xuất hiện và gợi ý không cá nhân hóa.",{},[15144],{"title":345,"description":39577},[39582],"recommendation","_mddMBnFwgR6gUwpH-MYJmNjOigTRt6DnAvnqHM2_D4",{"id":39585,"title":350,"body":39586,"category":8797,"day":353,"description":39886,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":39887,"navigation":2723,"outcomes":3047,"path":351,"prerequisites":39888,"seo":39889,"stem":352,"tags":39890,"__hash__":39891},"challenges\u002Fchallenges\u002F59.recsys-collaborative.md",{"type":965,"value":39587,"toc":39870},[39588,39590,39593,39595,39599,39613,39617,39631,39635,39649,39686,39688,39702,39704,39712,39716,39746,39752,39756,39787,39791,39794,39800,39818,39820,39847,39849,39863,39865,39868],[968,39589,971],{"id":970},[973,39591,39592],{},"Bài này học gợi ý theo hành vi cộng đồng giống bạn.\nCách này giúp điền điểm vào ô trống ma trận.",[968,39594,979],{"id":978},[981,39596,39598],{"id":39597},"ma-trận-ô-trống","Ma trận ô trống",[986,39600,39601,39604,39607,39610],{},[989,39602,39603],{},"Hàng là người, cột là món, ô là điểm đã chấm.",[989,39605,39606],{},"Việc cần là đoán điểm ô trống để gợi món cao.",[989,39608,39609],{},"User-based: tìm người giống bạn rồi xin món họ thích.",[989,39611,39612],{},"Ví dụ đời thường: bạn cùng gu khen phim nào thì mình thử phim đó.",[981,39614,39616],{"id":39615},"dự-đoán-có-trừ-trung-bình","Dự đoán có trừ trung bình",[986,39618,39619,39622,39625,39628],{},[989,39620,39621],{},"Trừ mức khó tính của mỗi người trước khi nhân trọng số.",[989,39623,39624],{},"Nhân với độ giống rồi cộng lại, cuối cộng mức của bạn.",[989,39626,39627],{},"Không trừ thì người chấm chặt thiệt thòi mãi.",[989,39629,39630],{},"Ví dụ đời thường: 4 sao của người khó tính bằng 5 sao người dễ tính.",[981,39632,39634],{"id":39633},"user-so-với-item","User so với item",[986,39636,39637,39640,39643,39646],{},[989,39638,39639],{},"User-based trực quan nhưng hồ sơ đổi liên tục, khó mở rộng.",[989,39641,39642],{},"Item-based ổn định vì quan hệ món đổi chậm, tính trước được.",[989,39644,39645],{},"Đo giống bằng cosine hoặc Pearson trừ trung bình.",[989,39647,39648],{},"Ví dụ đời thường: Avatar 2009 gợi phim cùng nhóm người chấm.",[1099,39650,39651,39662],{},[1102,39652,39653],{},[1105,39654,39655,39658,39660],{},[1108,39656,39657],{},"Phái",[1108,39659,28222],{},[1108,39661,28225],{},[1118,39663,39664,39675],{},[1105,39665,39666,39669,39672],{},[1123,39667,39668],{},"User-based",[1123,39670,39671],{},"Bắt gu nhanh",[1123,39673,39674],{},"Nặng khi đông người",[1105,39676,39677,39680,39683],{},[1123,39678,39679],{},"Item-based",[1123,39681,39682],{},"Ổn định, mở rộng",[1123,39684,39685],{},"Cần tính trước offline",[968,39687,1433],{"id":1432},[986,39689,39690,39693,39696,39699],{},[989,39691,39692],{},"Input: 2 người chỉ chung 1 phim mà giống tuyệt đối -> Output: kết luận nhiễu, cần ngưỡng.",[989,39694,39695],{},"Câu này cho thấy mẫu chung ít thì không tin được.",[989,39697,39698],{},"Input: người chấm chặt toàn điểm thấp, hệ không trừ trung bình -> Output: không gợi gì, chẩn đoán lệch.",[989,39700,39701],{},"Câu này cho thấy chuẩn hóa trung bình là bắt buộc.",[968,39703,1482],{"id":1481},[973,39705,1485,39706,39708,39709,1517],{},[1487,39707,13531],{}," với NumPy. Dữ liệu MovieLens 100K. Nộp vào ",[992,39710,39711],{},"day-059\u002F",[981,39713,39715],{"id":39714},"bài-1-user-based-cf","Bài 1: User-based CF",[1352,39717,39719],{"className":3538,"code":39718,"language":3540,"meta":1357,"style":1357},"def similarity(R, u, v, kind=\"pearson\", min_common=3) -> float:\n    \"\"\"R: ma trận user x item, 0 là chưa chấm. Chỉ tính trên phim cả 2 cùng chấm.\n       Ít hơn min_common phim chung thì trả 0.\"\"\"\ndef predict_user_based(R, u, i, k=20) -> float:\n    \"\"\"r_hat = mean_u + sum(sim * (r_vi - mean_v)) \u002F sum(|sim|), lấy k người giống nhất đã chấm i.\"\"\"\n",[992,39720,39721,39726,39731,39736,39741],{"__ignoreMap":1357},[1023,39722,39723],{"class":1362,"line":63},[1023,39724,39725],{},"def similarity(R, u, v, kind=\"pearson\", min_common=3) -> float:\n",[1023,39727,39728],{"class":1362,"line":68},[1023,39729,39730],{},"    \"\"\"R: ma trận user x item, 0 là chưa chấm. Chỉ tính trên phim cả 2 cùng chấm.\n",[1023,39732,39733],{"class":1362,"line":73},[1023,39734,39735],{},"       Ít hơn min_common phim chung thì trả 0.\"\"\"\n",[1023,39737,39738],{"class":1362,"line":78},[1023,39739,39740],{},"def predict_user_based(R, u, i, k=20) -> float:\n",[1023,39742,39743],{"class":1362,"line":83},[1023,39744,39745],{},"    \"\"\"r_hat = mean_u + sum(sim * (r_vi - mean_v)) \u002F sum(|sim|), lấy k người giống nhất đã chấm i.\"\"\"\n",[1352,39747,39750],{"className":39748,"code":39749,"language":2241,"meta":1357},[2239],"Ma trận nhỏ 4 user x 5 phim tự tạo -> tính tay 1 dự đoán và so với code\nUser chấm chặt (toàn 1-2 sao) -> dự đoán vẫn nằm quanh mức của họ, không bị kéo lên 4\n",[992,39751,39749],{"__ignoreMap":1357},[981,39753,39755],{"id":39754},"bài-2-item-based-cf","Bài 2: Item-based CF",[2273,39757,39758,39764,39779],{},[989,39759,39760,39761,16014],{},"Tính trước ma trận độ giống giữa các phim (adjusted cosine: trừ mean của ",[1487,39762,39763],{},"user",[989,39765,39766,39769,39770,39772,39773,39775,39776,39778],{},[992,39767,39768],{},"predict_item_based(R, u, i, k=20)",": dùng ",[992,39771,4022],{}," phim giống ",[992,39774,1837],{}," nhất mà ",[992,39777,30390],{}," đã chấm.",[989,39780,39781,39784,39785,1517],{},[992,39782,39783],{},"recommend(u, n)",": dự đoán mọi phim chưa xem, trả top ",[992,39786,1262],{},[981,39788,39790],{"id":39789},"bài-3-so-sánh-và-đo-nâng-cao","Bài 3: So sánh và đo (nâng cao)",[973,39792,39793],{},"Chia ngẫu nhiên 80\u002F20 rating.",[1352,39795,39798],{"className":39796,"code":39797,"language":2241,"meta":1357},[2239],"phương_pháp          RMSE    MAE    thời_gian_dự_đoán_test\nglobal_mean          ...\nuser_mean            ...\nuser_based k=20      ...\nitem_based k=20      ...\n",[992,39799,39797],{"__ignoreMap":1357},[2273,39801,39802,39810],{},[989,39803,37875,39804,39807,39808,1517],{},[992,39805,39806],{},"k = 5, 10, 20, 50, 100"," cho item-based. Vẽ RMSE theo ",[992,39809,4022],{},[989,39811,37875,39812,1509,39815,39817],{},[992,39813,39814],{},"min_common = 1",[992,39816,2334],{},". Tìm ví dụ cặp user có Pearson = 1 chỉ vì 1-2 phim chung.",[981,39819,2711],{"id":2710},[986,39821,39823,39829,39835,39841],{"className":39822},[2715],[989,39824,39826,39828],{"className":39825},[2719],[2721,39827],{"disabled":2723,"type":2724}," Dự đoán tay trên ma trận nhỏ khớp code.",[989,39830,39832,39834],{"className":39831},[2719],[2721,39833],{"disabled":2723,"type":2724}," Bảng RMSE có 4 phương pháp, CF thắng baseline.",[989,39836,39838,39840],{"className":39837},[2719],[2721,39839],{"disabled":2723,"type":2724}," Có ví dụ độ giống nhiễu khi quá ít phim chung.",[989,39842,39844,39846],{"className":39843},[2719],[2721,39845],{"disabled":2723,"type":2724}," Giải thích được vì sao item-based dễ tính trước hơn user-based.",[968,39848,2890],{"id":2889},[986,39850,39851,39854,39857,39860],{},[989,39852,39853],{},"Ma trận user item hàng cột là gì?",[989,39855,39856],{},"User-based và item-based khác nhau sao?",[989,39858,39859],{},"Vì sao phải trừ điểm trung bình?",[989,39861,39862],{},"Ma trận thưa gây khó gì?",[3014,39864],{},[973,39866,39867],{},"🌕 Bạn đã hoàn thành ngày 59. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,39869,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":39871},[39872,39873,39878,39879,39885],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":39874},[39875,39876,39877],{"id":39597,"depth":73,"text":39598},{"id":39615,"depth":73,"text":39616},{"id":39633,"depth":73,"text":39634},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":39880},[39881,39882,39883,39884],{"id":39714,"depth":73,"text":39715},{"id":39754,"depth":73,"text":39755},{"id":39789,"depth":73,"text":39790},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Ma trận user item, láng giềng gần nhất, tương đồng Pearson cosine, dự đoán xếp hạng và ví dụ phim Avatar trong bài này.",{},[14055],{"title":350,"description":39886},[39582],"Bd7SuS4CyD_1COqu9_yKvmoXnGHnb9yVF7g7pYx7ZkE",{"id":39893,"title":355,"body":39894,"category":8797,"day":358,"description":40268,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":40269,"navigation":2723,"outcomes":3047,"path":356,"prerequisites":40270,"seo":40271,"stem":357,"tags":40272,"__hash__":40274},"challenges\u002Fchallenges\u002F60.cap-va-luu-tru.md",{"type":965,"value":39895,"toc":40252},[39896,39898,39901,39903,39907,39921,39925,39939,39943,39957,40007,40009,40023,40025,40036,40040,40085,40135,40139,40142,40159,40163,40191,40193,40229,40231,40245,40247,40250],[968,39897,971],{"id":970},[973,39899,39900],{},"Bài này học CAP chọn 2 trong 3 khi mạng chia cắt.\nĐịnh lý này giúp chọn kho dữ liệu đúng bài toán.",[968,39902,979],{"id":978},[981,39904,39906],{"id":39905},"cap-là-gì","CAP là gì",[986,39908,39909,39912,39915,39918],{},[989,39910,39911],{},"C là mọi nút đọc cùng giá trị mới nhất.",[989,39913,39914],{},"A là mọi yêu cầu đều có trả lời không treo.",[989,39916,39917],{},"P là mạng chia cắt mà hệ vẫn chạy.",[989,39919,39920],{},"Ví dụ đời thường: cáp đứt 2 miền thì chọn đúng hay chọn nhanh.",[981,39922,39924],{"id":39923},"ba-họ-ca-ap-cp","Ba họ CA AP CP",[986,39926,39927,39930,39933,39936],{},[989,39928,39929],{},"CA: đúng và nhanh nhưng chỉ trong một trung tâm.",[989,39931,39932],{},"AP: nhanh và chịu cắt, chấp nhận cũ tạm thời.",[989,39934,39935],{},"CP: đúng và chịu cắt, thà từ chối còn hơn sai.",[989,39937,39938],{},"Ví dụ đời thường: tiền phải CP, feed mạng xã hội nên AP.",[981,39940,39942],{"id":39941},"quorum-và-nén","Quorum và nén",[986,39944,39945,39948,39951,39954],{},[989,39946,39947],{},"Ghi đa số bản sao thì đọc đa số sẽ thấy mới.",[989,39949,39950],{},"Tăng bản ghi thì đúng hơn nhưng trễ lớn hơn.",[989,39952,39953],{},"Sao 3 bản thì tiền đĩa phình, nén log giảm tiền.",[989,39955,39956],{},"Ví dụ đời thường: hỏi 2 trong 3 thủ kho là biết hàng mới.",[1099,39958,39959,39972],{},[1102,39960,39961],{},[1105,39962,39963,39966,39969],{},[1108,39964,39965],{},"Họ",[1108,39967,39968],{},"Chọn",[1108,39970,39971],{},"Dùng cho",[1118,39973,39974,39985,39996],{},[1105,39975,39976,39979,39982],{},[1123,39977,39978],{},"CA",[1123,39980,39981],{},"Đúng + nhanh",[1123,39983,39984],{},"DB đơn trung tâm",[1105,39986,39987,39990,39993],{},[1123,39988,39989],{},"AP",[1123,39991,39992],{},"Nhanh + chịu cắt",[1123,39994,39995],{},"Giỏ hàng, feed",[1105,39997,39998,40001,40004],{},[1123,39999,40000],{},"CP",[1123,40002,40003],{},"Đúng + chịu cắt",[1123,40005,40006],{},"Tiền, tồn kho",[968,40008,1433],{"id":1432},[986,40010,40011,40014,40017,40020],{},[989,40012,40013],{},"Input: tiền tệ chọn AP, mạng cắt 2 bên cùng trừ -> Output: số dư âm, kết luận chọn sai.",[989,40015,40016],{},"Câu này cho thấy tiền phải CP chấp nhận từ chối.",[989,40018,40019],{},"Input: log phình gấp 10 sau sao 3 bản -> Output: hướng sửa là nén log ít đọc.",[989,40021,40022],{},"Câu này cho thấy nén cứu tiền đĩa và trễ sao chép.",[968,40024,1482],{"id":1481},[973,40026,1485,40027,18407,40029,40032,40033,1517],{},[1487,40028,13531],{},[992,40030,40031],{},"asyncio"," hoặc thread). Đây là mô phỏng, không cần mạng thật. Nộp vào ",[992,40034,40035],{},"day-060\u002F",[981,40037,40039],{"id":40038},"bài-1-kho-key-value-nhân-bản","Bài 1: Kho key-value nhân bản",[1352,40041,40043],{"className":3538,"code":40042,"language":3540,"meta":1357,"style":1357},"class Node:\n    def __init__(self, name): self.data = {}      # key -> (value, version)\nclass Cluster:\n    def __init__(self, n_nodes: int, N: int, W: int, R: int): ...\n    def put(self, key, value) -> bool: ...        # ghi vào W node, trả False nếu không đủ node sống\n    def get(self, key): ...                        # đọc R node, trả value có version lớn nhất\n    def partition(self, group_a: set, group_b: set): ...   # chặn liên lạc giữa 2 nhóm\n    def kill(self, name); def revive(self, name)\n",[992,40044,40045,40050,40055,40060,40065,40070,40075,40080],{"__ignoreMap":1357},[1023,40046,40047],{"class":1362,"line":63},[1023,40048,40049],{},"class Node:\n",[1023,40051,40052],{"class":1362,"line":68},[1023,40053,40054],{},"    def __init__(self, name): self.data = {}      # key -> (value, version)\n",[1023,40056,40057],{"class":1362,"line":73},[1023,40058,40059],{},"class Cluster:\n",[1023,40061,40062],{"class":1362,"line":78},[1023,40063,40064],{},"    def __init__(self, n_nodes: int, N: int, W: int, R: int): ...\n",[1023,40066,40067],{"class":1362,"line":83},[1023,40068,40069],{},"    def put(self, key, value) -> bool: ...        # ghi vào W node, trả False nếu không đủ node sống\n",[1023,40071,40072],{"class":1362,"line":88},[1023,40073,40074],{},"    def get(self, key): ...                        # đọc R node, trả value có version lớn nhất\n",[1023,40076,40077],{"class":1362,"line":93},[1023,40078,40079],{},"    def partition(self, group_a: set, group_b: set): ...   # chặn liên lạc giữa 2 nhóm\n",[1023,40081,40082],{"class":1362,"line":98},[1023,40083,40084],{},"    def kill(self, name); def revive(self, name)\n",[1099,40086,40087,40097],{},[1102,40088,40089],{},[1105,40090,40091,40094],{},[1108,40092,40093],{},"Cấu hình",[1108,40095,40096],{},"Tính chất cần kiểm",[1118,40098,40099,40112,40122],{},[1105,40100,40101,40106],{},[1123,40102,40103],{},[992,40104,40105],{},"N=3, W=2, R=2",[1123,40107,40108,40111],{},[992,40109,40110],{},"W + R > N",": đọc luôn thấy bản mới nhất",[1105,40113,40114,40119],{},[1123,40115,40116],{},[992,40117,40118],{},"N=3, W=1, R=1",[1123,40120,40121],{},"Có thể đọc bản cũ: viết test tái hiện",[1105,40123,40124,40130],{},[1123,40125,40126,40129],{},[992,40127,40128],{},"W=3",", 1 node chết",[1123,40131,40132,40134],{},[992,40133,28504],{}," thất bại (chọn C, bỏ A)",[981,40136,40138],{"id":40137},"bài-2-mô-phỏng-chia-cắt-mạng","Bài 2: Mô phỏng chia cắt mạng",[973,40140,40141],{},"Tài khoản ngân hàng có số dư 100. Cắt mạng thành 2 nhóm. Mỗi nhóm nhận 1 lệnh rút 80.",[2273,40143,40144,40150,40156],{},[989,40145,40146,40149],{},[1487,40147,40148],{},"Chế độ AP:"," mỗi nhóm tự nhận lệnh. Sau khi nối lại, gộp bằng \"version lớn nhất thắng\". In số dư và số tiền đã rút. Chỉ ra sai ở đâu.",[989,40151,40152,40155],{},[1487,40153,40154],{},"Chế độ CP:"," chỉ nhóm có đa số (≥ 2\u002F3 node) nhận ghi. In số lệnh bị từ chối và số dư cuối.",[989,40157,40158],{},"Viết bảng: hệ thống nào (giỏ hàng, số dư ngân hàng, lượt thích, tồn kho vé máy bay) chọn AP hay CP, vì sao.",[981,40160,40162],{"id":40161},"bài-3-chi-phí-nhân-bản-nâng-cao","Bài 3: Chi phí nhân bản (nâng cao)",[2273,40164,40165,40177,40184],{},[989,40166,40167,40168,2461,40170,40172,40173,40176],{},"Mỗi lần gửi tới node có độ trễ ngẫu nhiên 5-50 ms. Đo độ trễ ",[992,40169,28504],{},[992,40171,28507],{}," p50, p99 với ",[992,40174,40175],{},"W, R"," từ 1 tới 3.",[989,40178,40179,40180,40183],{},"Ghi 10.000 bản log. Nén bằng ",[992,40181,40182],{},"zlib"," các bản cũ hơn 1000 lần ghi. In dung lượng trước và sau.",[989,40185,40186,40187,40190],{},"Vẽ biểu đồ: trục x là ",[992,40188,40189],{},"W + R",", trục y là độ trễ p99.",[981,40192,2711],{"id":2710},[986,40194,40196,40209,40215,40221],{"className":40195},[2715],[989,40197,40199,40201,40202,40204,40205,40208],{"className":40198},[2719],[2721,40200],{"disabled":2723,"type":2724}," Test chứng minh ",[992,40203,40110],{}," đọc thấy bản mới, và ",[992,40206,40207],{},"W + R \u003C= N"," có thể đọc cũ.",[989,40210,40212,40214],{"className":40211},[2719],[2721,40213],{"disabled":2723,"type":2724}," Bài 2 in rõ lỗi của chế độ AP với dữ liệu tiền.",[989,40216,40218,40220],{"className":40217},[2719],[2721,40219],{"disabled":2723,"type":2724}," Bảng AP\u002FCP cho 4 hệ thống kèm lý do.",[989,40222,40224,40226,40227,37083],{"className":40223},[2719],[2721,40225],{"disabled":2723,"type":2724}," Biểu đồ độ trễ theo ",[992,40228,40189],{},[968,40230,2890],{"id":2889},[986,40232,40233,40236,40239,40242],{},[989,40234,40235],{},"CAP gồm 3 chữ nào?",[989,40237,40238],{},"Vì sao mạng lớn chỉ chọn 2 trong 3?",[989,40240,40241],{},"Tiền tệ nên AP hay CP?",[989,40243,40244],{},"Quorum đa số giúp gì?",[3014,40246],{},[973,40248,40249],{},"🌕 Bạn đã hoàn thành ngày 60. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,40251,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":40253},[40254,40255,40260,40261,40267],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":40256},[40257,40258,40259],{"id":39905,"depth":73,"text":39906},{"id":39923,"depth":73,"text":39924},{"id":39941,"depth":73,"text":39942},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":40262},[40263,40264,40265,40266],{"id":40038,"depth":73,"text":40039},{"id":40137,"depth":73,"text":40138},{"id":40161,"depth":73,"text":40162},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhất quán sẵn sàng chịu phân vùng, ba họ CA AP CP, lưu trữ phân tán và ví dụ AWS trong bài này.",{},[14055,15144],{"title":355,"description":40268},[40273],"data-engineering","olLhJNnA6qFpik5FXUYYMpZAqPvw--PFNuL2Pu2xyUM",{"id":40276,"title":360,"body":40277,"category":8797,"day":363,"description":40633,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":40634,"navigation":2723,"outcomes":3047,"path":361,"prerequisites":40635,"seo":40636,"stem":362,"tags":40637,"__hash__":40638},"challenges\u002Fchallenges\u002F61.nen-du-lieu.md",{"type":965,"value":40278,"toc":40617},[40279,40281,40284,40286,40290,40307,40311,40328,40366,40370,40387,40412,40414,40438,40440,40448,40452,40472,40476,40494,40500,40514,40518,40521,40527,40530,40534,40558,40560,40594,40596,40610,40612,40615],[968,40280,971],{"id":970},[973,40282,40283],{},"Bài này học nén không mất mát với Huffman và LZ77. Bạn dùng nó để lưu log gọn và tải nhanh hơn.",[968,40285,979],{"id":978},[981,40287,40289],{"id":40288},"nén-mất-mát-và-không-mất-mát","Nén mất mát và không mất mát",[986,40291,40292,40295,40298,40301,40304],{},[989,40293,40294],{},"Nén không mất mát: giải nén ra đúng từng bit gốc.",[989,40296,40297],{},"Nén mất mát: bỏ bớt chi tiết mắt khó nhận thấy.",[989,40299,40300],{},"Ví dụ đời thường: file văn bản như cất giấy tờ gốc, video như ảnh chụp mờ vẫn xem được.",[989,40302,40303],{},"Hợp đồng và code phải dùng không mất mát.",[989,40305,40306],{},"Video 4K nên dùng mất mát cho nhẹ.",[981,40308,40310],{"id":40309},"mã-huffman-biến-dài","Mã Huffman biến dài",[986,40312,40313,40316,40319,40322,40325],{},[989,40314,40315],{},"Định nghĩa: chữ hay gặp cho mã bit ngắn, chữ hiếm cho mã dài.",[989,40317,40318],{},"Không mã nào là tiền tố của mã khác nên giải mã duy nhất.",[989,40320,40321],{},"Ví dụ đời thường: như gán số điện thoại ngắn cho người gọi nhiều.",[989,40323,40324],{},"Mạnh khi tần suất chữ lệch nhau nhiều.",[989,40326,40327],{},"Yếu khi văn bản toàn đoạn lặp dài.",[1099,40329,40330,40340],{},[1102,40331,40332],{},[1105,40333,40334,40337],{},[1108,40335,40336],{},"Trường hợp",[1108,40338,40339],{},"Huffman có tốt?",[1118,40341,40342,40350,40358],{},[1105,40343,40344,40347],{},[1123,40345,40346],{},"Nhiều chữ e, ít chữ z",[1123,40348,40349],{},"Tốt, e mã ngắn",[1105,40351,40352,40355],{},[1123,40353,40354],{},"Log lặp ababab",[1123,40356,40357],{},"Kém, không bắt đoạn lặp",[1105,40359,40360,40363],{},[1123,40361,40362],{},"Văn bản thường",[1123,40364,40365],{},"Khá tốt",[981,40367,40369],{"id":40368},"lz77-cửa-sổ-trượt","LZ77 cửa sổ trượt",[986,40371,40372,40375,40378,40381,40384],{},[989,40373,40374],{},"Định nghĩa: nhìn lại đoạn vừa qua, gặp lặp thì ghi vị trí thay vì ghi chữ.",[989,40376,40377],{},"Mỗi lần lặp ghi 3 số: lùi bao xa, dài bao nhiêu, ký tự tiếp theo.",[989,40379,40380],{},"Ví dụ đời thường: như ghi \"copy 5 chữ ở trên\" thay vì viết lại.",[989,40382,40383],{},"Mạnh với log và HTML nhiều đoạn lặp.",[989,40385,40386],{},"Cửa sổ càng lớn càng bắt lặp xa nhưng tốn nhớ.",[1352,40388,40390],{"className":3538,"code":40389,"language":3540,"meta":1357,"style":1357},"# Ví dụ ý tưởng LZ77\ntext = \"abababab\"\n# gặp \"abab\" lần 2 -> ghi (lùi 4, dài 4)\nprint((\"lùi\", 4, \"dài\", 4))  # thay vì ghi lại chữ\n",[992,40391,40392,40397,40402,40407],{"__ignoreMap":1357},[1023,40393,40394],{"class":1362,"line":63},[1023,40395,40396],{},"# Ví dụ ý tưởng LZ77\n",[1023,40398,40399],{"class":1362,"line":68},[1023,40400,40401],{},"text = \"abababab\"\n",[1023,40403,40404],{"class":1362,"line":73},[1023,40405,40406],{},"# gặp \"abab\" lần 2 -> ghi (lùi 4, dài 4)\n",[1023,40408,40409],{"class":1362,"line":78},[1023,40410,40411],{},"print((\"lùi\", 4, \"dài\", 4))  # thay vì ghi lại chữ\n",[968,40413,1433],{"id":1432},[986,40415,40416,40429,40432,40435],{},[989,40417,9878,40418,40421,40422,40425,40426,1517],{},[992,40419,40420],{},"abababab",". Output: lần đầu ghi ",[992,40423,40424],{},"abab",", lần sau ghi ",[992,40427,40428],{},"(lùi 4, dài 4)",[989,40430,40431],{},"Giải thích: LZ77 không ghi lại chữ lặp mà chỉ ghi vị trí.",[989,40433,40434],{},"Input: log 100 dòng giống nhau. Output: Huffman giảm 20%, LZ77 giảm 80%.",[989,40436,40437],{},"Giải thích: đoạn lặp hợp với từ điển của LZ77 hơn.",[968,40439,1482],{"id":1481},[973,40441,1485,40442,40444,40445,1517],{},[1487,40443,1493],{}," (hoặc Python). Dùng Huffman ngày 27. Nộp vào ",[992,40446,40447],{},"day-061\u002F",[981,40449,40451],{"id":40450},"bài-1-lz77","Bài 1: LZ77",[1352,40453,40455],{"className":1393,"code":40454,"language":1395,"meta":1357,"style":1357},"struct Token { uint16_t offset; uint8_t length; char next; };   \u002F\u002F (lùi, dài, ký tự kế)\nstd::vector\u003CToken> lz77Encode(const std::string &s, int window = 4096, int maxLen = 255);\nstd::string lz77Decode(const std::vector\u003CToken> &tokens);\n",[992,40456,40457,40462,40467],{"__ignoreMap":1357},[1023,40458,40459],{"class":1362,"line":63},[1023,40460,40461],{},"struct Token { uint16_t offset; uint8_t length; char next; };   \u002F\u002F (lùi, dài, ký tự kế)\n",[1023,40463,40464],{"class":1362,"line":68},[1023,40465,40466],{},"std::vector\u003CToken> lz77Encode(const std::string &s, int window = 4096, int maxLen = 255);\n",[1023,40468,40469],{"class":1362,"line":73},[1023,40470,40471],{},"std::string lz77Decode(const std::vector\u003CToken> &tokens);\n",[973,40473,40474],{},[1487,40475,2194],{},[986,40477,40478,40481,40488],{},[989,40479,40480],{},"Tìm đoạn khớp dài nhất trong cửa sổ, hòa thì chọn offset nhỏ nhất.",[989,40482,40483,40484,40487],{},"Đoạn khớp được phép ",[1487,40485,40486],{},"chồng"," lên phần đang mã hóa (offset \u003C length).",[989,40489,40490,40491,1517],{},"Không có khớp thì token là ",[992,40492,40493],{},"(0, 0, c)",[1352,40495,40498],{"className":40496,"code":40497,"language":2241,"meta":1357},[2239],"\"abababab\" -> (0,0,a) (0,0,b) (2,5,b)   (khớp chồng lấn, lùi 2 chép 5 ký tự)\ndecode(encode(s)) == s với mọi s (test 1000 chuỗi ngẫu nhiên, gồm chuỗi rỗng)\n",[992,40499,40497],{"__ignoreMap":1357},[2245,40501,40502],{},[973,40503,40504,40505,38397,40508,31657,40511,40513],{},"Khi giải mã khớp chồng lấn, chép ",[1487,40506,40507],{},"từng ký tự một",[992,40509,40510],{},"out[out.size() - offset]",[992,40512,2259],{}," cả đoạn.",[981,40515,40517],{"id":40516},"bài-2-so-huffman-và-lz77","Bài 2: So Huffman và LZ77",[973,40519,40520],{},"Chạy trên 4 file: văn bản tiếng Việt, log server có nhiều dòng lặp, file HTML, file byte ngẫu nhiên.",[1352,40522,40525],{"className":40523,"code":40524,"language":2241,"meta":1357},[2239],"file        gốc(byte)   huffman   lz77(ước lượng 4 byte\u002Ftoken)   gzip\ntext.txt    ...\nserver.log  ...\n",[992,40526,40524],{"__ignoreMap":1357},[973,40528,40529],{},"Viết 4 câu: loại dữ liệu nào hợp thuật toán nào và vì sao.",[981,40531,40533],{"id":40532},"bài-3-lz77-huffman-kiểu-deflate-nâng-cao","Bài 3: LZ77 + Huffman kiểu DEFLATE (nâng cao)",[2273,40535,40536,40548,40551],{},[989,40537,40538,40539,40542,40543,40542,40546,1517],{},"Mã hóa LZ77 trước, rồi Huffman riêng cho luồng ",[992,40540,40541],{},"offset",", luồng ",[992,40544,40545],{},"length",[992,40547,4228],{},[989,40549,40550],{},"Ghi file nhị phân tự định dạng. Giải nén lại đúng từng byte.",[989,40552,40553,40554,40557],{},"Tăng tốc tìm khớp bằng bảng băm 3 ký tự đầu (",[992,40555,40556],{},"hash chain","). So thời gian với tìm tuyến tính trên file 5 MB.",[981,40559,2711],{"id":2710},[986,40561,40563,40569,40579,40588],{"className":40562},[2715],[989,40564,40566,40568],{"className":40565},[2719],[2721,40567],{"disabled":2723,"type":2724}," Test mẫu và test ngẫu nhiên pass.",[989,40570,40572,40574,40575,40578],{"className":40571},[2719],[2721,40573],{"disabled":2723,"type":2724}," Bảng so sánh 4 file có số thật, có cột ",[992,40576,40577],{},"gzip"," để đối chiếu.",[989,40580,40582,40584,40585,16014],{"className":40581},[2719],[2721,40583],{"disabled":2723,"type":2724}," Bài 3 nén rồi giải nén ra file giống hệt (",[992,40586,40587],{},"cmp",[989,40589,40591,40593],{"className":40590},[2719],[2721,40592],{"disabled":2723,"type":2724}," Phân biệt được nén mất mát và không mất mát bằng ví dụ.",[968,40595,2890],{"id":2889},[986,40597,40598,40601,40604,40607],{},[989,40599,40600],{},"Khi nào dùng nén mất và không mất mát?",[989,40602,40603],{},"Huffman gán mã ngắn dài theo nguyên tắc nào?",[989,40605,40606],{},"LZ77 dùng cửa sổ trượt để làm gì?",[989,40608,40609],{},"Khi nào chọn LZ77 thay vì Huffman?",[3014,40611],{},[973,40613,40614],{},"🌕 Bạn đã hoàn thành ngày 61. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,40616,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":40618},[40619,40620,40625,40626,40632],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":40621},[40622,40623,40624],{"id":40288,"depth":73,"text":40289},{"id":40309,"depth":73,"text":40310},{"id":40368,"depth":73,"text":40369},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":40627},[40628,40629,40630,40631],{"id":40450,"depth":73,"text":40451},{"id":40516,"depth":73,"text":40517},{"id":40532,"depth":73,"text":40533},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nén không mất mát, Huffman biến dài, LZ77 từ điển trượt và định dạng hiện đại kèm bài toán AWS.",{},[3050,4669],{"title":360,"description":40633},[22656],"xb7mG3x1QkKyRbMKlwClSw52ANPWoWC88a4mVWTDwxY",{"id":40640,"title":365,"body":40641,"category":8797,"day":368,"description":41001,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":41002,"navigation":2723,"outcomes":3047,"path":366,"prerequisites":41003,"seo":41004,"stem":367,"tags":41005,"__hash__":41006},"challenges\u002Fchallenges\u002F62.crypto-co-ban.md",{"type":965,"value":40642,"toc":40983},[40643,40645,40648,40650,40654,40668,40672,40686,40711,40715,40732,40736,40750,40754,40765,40767,40787,40789,40800,40806,40810,40865,40871,40875,40889,40893,40928,40930,40960,40962,40976,40978,40981],[968,40644,971],{"id":970},[973,40646,40647],{},"Bài này học mã cổ điển, hàm băm và mã đối xứng. Bạn dùng nó để giữ mật khẩu và file an toàn.",[968,40649,979],{"id":978},[981,40651,40653],{"id":40652},"thuật-ngữ-và-mắt-xích-yếu","Thuật ngữ và mắt xích yếu",[986,40655,40656,40659,40662,40665],{},[989,40657,40658],{},"Bản rõ là tin gốc, bản mã là tin đã khóa.",[989,40660,40661],{},"Khóa là bí mật điều khiển cách khóa và mở.",[989,40663,40664],{},"Hệ mạnh như khâu yếu nhất: mật khẩu yếu là gãy.",[989,40666,40667],{},"Ví dụ đời thường: ổ khóa tốt nhưng để chìa dưới thảm thì vô dụng.",[981,40669,40671],{"id":40670},"mã-thay-thế-và-hoán-vị","Mã thay thế và hoán vị",[986,40673,40674,40677,40680,40683],{},[989,40675,40676],{},"Thay thế: đổi từng chữ theo bảng, ví dụ Caesar dịch 3 nấc.",[989,40678,40679],{},"Hoán vị: giữ nguyên chữ, chỉ xáo vị trí.",[989,40681,40682],{},"Thay thế giữ nguyên tần suất nên dễ bẻ bằng đếm chữ.",[989,40684,40685],{},"Ví dụ đời thường: chữ e nhiều nhất nên ký tự lạ nào nhiều nhất likely là e.",[1352,40687,40689],{"className":3538,"code":40688,"language":3540,"meta":1357,"style":1357},"# Caesar dịch 3\ndef caesar(s):\n    return \"\".join(chr((ord(c)-97+3)%26+97) for c in s)  # dịch mỗi chữ đi 3\nprint(caesar(\"abc\"))  # -> def\n",[992,40690,40691,40696,40701,40706],{"__ignoreMap":1357},[1023,40692,40693],{"class":1362,"line":63},[1023,40694,40695],{},"# Caesar dịch 3\n",[1023,40697,40698],{"class":1362,"line":68},[1023,40699,40700],{},"def caesar(s):\n",[1023,40702,40703],{"class":1362,"line":73},[1023,40704,40705],{},"    return \"\".join(chr((ord(c)-97+3)%26+97) for c in s)  # dịch mỗi chữ đi 3\n",[1023,40707,40708],{"class":1362,"line":78},[1023,40709,40710],{},"print(caesar(\"abc\"))  # -> def\n",[981,40712,40714],{"id":40713},"hàm-băm-md5-và-sha","Hàm băm MD5 và SHA",[986,40716,40717,40720,40723,40726,40729],{},[989,40718,40719],{},"Định nghĩa: nhét dữ liệu dài tùy ý, ra mã ngắn cố định.",[989,40721,40722],{},"Cùng đầu vào cho cùng đầu ra, khác 1 bit là khác hẳn.",[989,40724,40725],{},"Không đảo ngược được để lấy lại gốc.",[989,40727,40728],{},"Ví dụ đời thường: như lấy dấu vân tay, không dựng lại người từ vân tay.",[989,40730,40731],{},"MD5 đã gãy va chạm, chỉ kiểm lỗi thường; SHA-256 dùng cho việc nghiêm túc.",[981,40733,40735],{"id":40734},"mã-đối-xứng","Mã đối xứng",[986,40737,40738,40741,40744,40747],{},[989,40739,40740],{},"Định nghĩa: một khóa chung vừa khóa vừa mở.",[989,40742,40743],{},"Ví dụ đời thường: một chìa vừa khóa vừa mở vali.",[989,40745,40746],{},"Ưu điểm: nhanh, hợp mã lượng lớn như video.",[989,40748,40749],{},"Nhược điểm: khó chia sẻ khóa an toàn cho nhiều người.",[981,40751,40753],{"id":40752},"ba-bước-xác-định-yêu-cầu-bảo-mật","Ba bước xác định yêu cầu bảo mật",[2273,40755,40756,40759,40762],{},[989,40757,40758],{},"Xác định các thực thể: ai gửi, ai nhận, ai có thể tấn công.",[989,40760,40761],{},"Đặt mục tiêu bảo mật: bí mật (chỉ người được phép đọc), toàn vẹn (không bị sửa lén), xác thực (đúng người gửi), chống chối bỏ.",[989,40763,40764],{},"Đánh giá độ nhạy của dữ liệu: dữ liệu càng nhạy, khóa càng dài và kiểm soát càng chặt.",[968,40766,1433],{"id":1432},[986,40768,40769,40778,40781,40784],{},[989,40770,9878,40771,40774,40775,1517],{},[992,40772,40773],{},"abc"," Caesar dịch 3. Output: ",[992,40776,40777],{},"def",[989,40779,40780],{},"Giải thích: mỗi chữ tiến 3 nấc trong bảng chữ cái.",[989,40782,40783],{},"Input: 2 file khác nhau cho cùng MD5. Output: báo va chạm, chuyển sang SHA.",[989,40785,40786],{},"Giải thích: MD5 không còn an toàn cho toàn vẹn nghiêm túc.",[968,40788,1482],{"id":1481},[973,40790,1485,40791,40793,40794,5599,40797,1517],{},[1487,40792,13531],{},". Bài 3 dùng thư viện ",[992,40795,40796],{},"cryptography",[992,40798,40799],{},"day-062\u002F",[40801,40802,40803],"warning",{},[973,40804,40805],{},"Mọi thuật toán tự cài trong bài này chỉ để học. Không dùng chúng để bảo vệ dữ liệu thật.",[981,40807,40809],{"id":40808},"bài-1-mật-mã-cổ-điển","Bài 1: Mật mã cổ điển",[1099,40811,40812,40820],{},[1102,40813,40814],{},[1105,40815,40816,40818],{},[1108,40817,1566],{},[1108,40819,2547],{},[1118,40821,40822,40842,40852],{},[1105,40823,40824,40829],{},[1123,40825,40826],{},[992,40827,40828],{},"caesar(text, shift)",[1123,40830,40831,40832,1656,40834,40837,40838,40841],{},"Dịch chữ cái ",[992,40833,26943],{},[992,40835,40836],{},"A-Z",", giữ nguyên ký tự khác. ",[992,40839,40840],{},"shift"," âm để giải mã",[1105,40843,40844,40849],{},[1123,40845,40846],{},[992,40847,40848],{},"vigenere(text, key, decrypt=False)",[1123,40850,40851],{},"Dịch theo từng chữ của khóa",[1105,40853,40854,40862],{},[1123,40855,40856,1509,40859],{},[992,40857,40858],{},"rail_fence(text, rails)",[992,40860,40861],{},"rail_fence_decrypt",[1123,40863,40864],{},"Hoán vị hàng rào",[1352,40866,40869],{"className":40867,"code":40868,"language":2241,"meta":1357},[2239],"caesar(\"abc\", 3)                       -> \"def\"\ncaesar(\"Xyz!\", 3)                      -> \"Abc!\"\nvigenere(\"ATTACKATDAWN\", \"LEMON\")      -> \"LXFOPVEFRNHR\"\nrail_fence(\"WEAREDISCOVERED\", 3)       -> \"WECRERDSOEEAIVD\"\n",[992,40870,40868],{"__ignoreMap":1357},[981,40872,40874],{"id":40873},"bài-2-bẻ-khóa-bằng-tần-suất","Bài 2: Bẻ khóa bằng tần suất",[2273,40876,40877,40883,40886],{},[989,40878,40879,40882],{},[992,40880,40881],{},"break_caesar(ciphertext)",": thử 26 khóa, chọn khóa có phân bố chữ gần tiếng Anh nhất (chi bình phương).",[989,40884,40885],{},"Mã hóa 1 đoạn văn tiếng Anh 500 chữ bằng Caesar khóa ngẫu nhiên. Bẻ lại đúng khóa.",[989,40887,40888],{},"Viết 3 câu: vì sao thay thế đơn giữ tần suất nên dễ bẻ, và Vigenère khó hơn ở điểm nào.",[981,40890,40892],{"id":40891},"bài-3-băm-và-mã-hóa-đối-xứng-nâng-cao","Bài 3: Băm và mã hóa đối xứng (nâng cao)",[2273,40894,40895,40901,40921],{},[989,40896,2699,40897,40900],{},[992,40898,40899],{},"hashlib.sha256",". Đổi 1 bit đầu vào, đếm số bit khác nhau của 2 mã băm (hiệu ứng thác, kỳ vọng khoảng 128\u002F256).",[989,40902,40903,40904,5586,40907,40910,40911,1509,40914,40917,40918,1517],{},"Lưu mật khẩu đúng cách: ",[992,40905,40906],{},"hashlib.scrypt",[992,40908,40909],{},"pbkdf2_hmac"," với salt ngẫu nhiên 16 byte. Viết ",[992,40912,40913],{},"hash_password",[992,40915,40916],{},"verify_password",". Giải thích vì sao không lưu ",[992,40919,40920],{},"sha256(password)",[989,40922,40923,40924,40927],{},"Mã hóa file bằng AES-GCM (",[992,40925,40926],{},"cryptography.hazmat.primitives.ciphers.aead.AESGCM","). Sửa 1 byte bản mã, chứng minh giải mã báo lỗi xác thực.",[981,40929,2711],{"id":2710},[986,40931,40933,40939,40948,40954],{"className":40932},[2715],[989,40934,40936,40938],{"className":40935},[2719],[2721,40937],{"disabled":2723,"type":2724}," Test mẫu pass, giải mã đúng lại bản rõ.",[989,40940,40942,2308,40944,40947],{"className":40941},[2719],[2721,40943],{"disabled":2723,"type":2724},[992,40945,40946],{},"break_caesar"," tìm đúng khóa trên đoạn 500 chữ.",[989,40949,40951,40953],{"className":40950},[2719],[2721,40952],{"disabled":2723,"type":2724}," Bài 3 cho thấy hiệu ứng thác và phát hiện bản mã bị sửa.",[989,40955,40957,40959],{"className":40956},[2719],[2721,40958],{"disabled":2723,"type":2724}," Không có mật khẩu hay khóa thật nào trong repo.",[968,40961,2890],{"id":2889},[986,40963,40964,40967,40970,40973],{},[989,40965,40966],{},"Bản rõ, bản mã và khóa là gì?",[989,40968,40969],{},"Vì sao mã thay thế dễ bẻ bằng tần suất?",[989,40971,40972],{},"MD5 và SHA khác nhau thế nào?",[989,40974,40975],{},"Bài toán chia sẻ khóa của mã đối xứng là gì?",[3014,40977],{},[973,40979,40980],{},"🌕 Bạn đã hoàn thành ngày 62. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,40982,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":40984},[40985,40986,40993,40994,41000],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":40987},[40988,40989,40990,40991,40992],{"id":40652,"depth":73,"text":40653},{"id":40670,"depth":73,"text":40671},{"id":40713,"depth":73,"text":40714},{"id":40734,"depth":73,"text":40735},{"id":40752,"depth":73,"text":40753},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":40995},[40996,40997,40998,40999],{"id":40808,"depth":73,"text":40809},{"id":40873,"depth":73,"text":40874},{"id":40891,"depth":73,"text":40892},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật ngữ mật mã, mã thay thế hoán vị, thám mã, hàm băm MD5 SHA và mã đối xứng.",{},[3050,15144],{"title":365,"description":41001},[40796],"B2nOZNRYPnAnphoQhhy9R9G66RVTQPgLy4TtNoJXxdU",{"id":41008,"title":370,"body":41009,"category":8797,"day":373,"description":41324,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":41325,"navigation":2723,"outcomes":3047,"path":371,"prerequisites":41326,"seo":41327,"stem":372,"tags":41328,"__hash__":41330},"challenges\u002Fchallenges\u002F63.explainability-dao-duc.md",{"type":965,"value":41010,"toc":41306},[41011,41013,41016,41018,41022,41036,41040,41054,41101,41105,41119,41123,41137,41141,41152,41154,41168,41170,41181,41185,41188,41206,41210,41219,41225,41229,41251,41253,41285,41287,41301,41303],[968,41012,971],{"id":970},[973,41014,41015],{},"Bài này học giải thích mô hình và giảm thiên lệch. Bạn dùng nó để tránh bot học bậy như Tay.",[968,41017,979],{"id":978},[981,41019,41021],{"id":41020},"bài-học-từ-bot-tay-2016","Bài học từ bot Tay 2016",[986,41023,41024,41027,41030,41033],{},[989,41025,41026],{},"Tay là bot học từ mọi câu chat của cộng đồng.",[989,41028,41029],{},"Kẻ xấu mớm lời độc hại, bot phun lại sau 1 ngày.",[989,41031,41032],{},"Lỗi ở thiết kế: học mở không lọc, không phanh.",[989,41034,41035],{},"Ví dụ đời thường: như trẻ nhỏ nghe gì nói nấy, phải có người lớn lọc.",[981,41037,41039],{"id":41038},"hộp-trắng-và-hộp-đen","Hộp trắng và hộp đen",[986,41041,41042,41045,41048,41051],{},[989,41043,41044],{},"Hộp trắng: đọc được luật, ví dụ cây quyết định.",[989,41046,41047],{},"Hộp đen: hàng triệu tham số, ví dụ mạng sâu.",[989,41049,41050],{},"Kỹ sư cần giải thích để debug, người dùng cần để tin.",[989,41052,41053],{},"Ví dụ đời thường: hộp trắng như công thức nấu ăn, hộp đen như món ăn không rõ nguyên liệu.",[1099,41055,41056,41067],{},[1102,41057,41058],{},[1105,41059,41060,41063,41065],{},[1108,41061,41062],{},"Mô hình",[1108,41064,15804],{},[1108,41066,17414],{},[1118,41068,41069,41080,41090],{},[1105,41070,41071,41074,41077],{},[1123,41072,41073],{},"Cây quyết định",[1123,41075,41076],{},"Hộp trắng",[1123,41078,41079],{},"Đọc luật trực tiếp",[1105,41081,41082,41085,41087],{},[1123,41083,41084],{},"Hồi quy tuyến tính",[1123,41086,41076],{},[1123,41088,41089],{},"Đọc trọng số",[1105,41091,41092,41095,41098],{},[1123,41093,41094],{},"Mạng sâu",[1123,41096,41097],{},"Hộp đen",[1123,41099,41100],{},"Cần công cụ thêm",[981,41102,41104],{"id":41103},"ba-bệnh-bằng-chứng","Ba bệnh bằng chứng",[986,41106,41107,41110,41113,41116],{},[989,41108,41109],{},"Bằng chứng mù mờ: tương quan yếu nhưng nói như chắc chắn.",[989,41111,41112],{},"Thiếu truy xuất: không biết dữ liệu nào ra quyết định.",[989,41114,41115],{},"Kết quả bất công: đúng trung bình nhưng sai trên nhóm thiểu số.",[989,41117,41118],{},"Ví dụ đời thường: như chấm cả lớp giỏi mà giấu điểm kém của 1 nhóm.",[981,41120,41122],{"id":41121},"giảm-bias","Giảm bias",[986,41124,41125,41128,41131,41134],{},[989,41126,41127],{},"Làm sạch và cân bằng dữ liệu đầu vào.",[989,41129,41130],{},"Đo riêng độ đúng theo từng nhóm.",[989,41132,41133],{},"Kiểm toán độc lập trước khi tung ra.",[989,41135,41136],{},"Luôn có nút dừng con người cho quyết định nhạy.",[981,41138,41140],{"id":41139},"khi-nào-không-nên-dùng-thuật-toán","Khi nào không nên dùng thuật toán",[986,41142,41143,41146,41149],{},[989,41144,41145],{},"Sự kiện thiên nga đen: hiếm, tác động lớn, không có trong dữ liệu quá khứ (khủng hoảng tài chính, đại dịch).",[989,41147,41148],{},"Mô hình học từ quá khứ nên không dự báo được thiên nga đen, và có thể sai rất tự tin khi nó xảy ra.",[989,41150,41151],{},"Quyết định có hậu quả lớn cần kịch bản dự phòng và người duyệt, không giao trọn cho thuật toán.",[968,41153,1433],{"id":1432},[986,41155,41156,41159,41162,41165],{},[989,41157,41158],{},"Input: bot học trực tiếp mọi câu user không lọc. Output: cảnh báo lặp lại Tay.",[989,41160,41161],{},"Giải thích: phải có lọc và kiểm duyệt trước khi học.",[989,41163,41164],{},"Input: mô hình từ chối vay không giải thích được. Output: rủi ro pháp lý, cần lớp giải thích.",[989,41166,41167],{},"Giải thích: người bị từ chối cần biết lý do cụ thể.",[968,41169,1482],{"id":1481},[973,41171,1485,41172,7386,41174,41176,41177,41180],{},[1487,41173,13531],{},[992,41175,17633],{},", pandas. Nộp vào ",[992,41178,41179],{},"day-063\u002F",". Bài này có code và có báo cáo.",[981,41182,41184],{"id":41183},"bài-1-hộp-trắng-và-hộp-đen","Bài 1: Hộp trắng và hộp đen",[973,41186,41187],{},"Dùng bộ Adult Income (UCI, công khai): đoán thu nhập > 50K.",[2273,41189,41190,41197,41200],{},[989,41191,41192,41193,41196],{},"Huấn luyện cây quyết định ",[992,41194,41195],{},"max_depth=4",". In toàn bộ luật (hộp trắng).",[989,41198,41199],{},"Huấn luyện random forest 200 cây (hộp đen). So accuracy 2 mô hình.",[989,41201,35241,41202,41205],{},[1487,41203,41204],{},"permutation importance",": xáo trộn 1 cột trong tập test, đo accuracy giảm bao nhiêu. Lặp 10 lần mỗi cột. In bảng xếp hạng đặc trưng cho cả 2 mô hình.",[981,41207,41209],{"id":41208},"bài-2-giải-thích-từng-quyết-định","Bài 2: Giải thích từng quyết định",[973,41211,1505,41212,41215,41216,41218],{},[992,41213,41214],{},"explain_one(model, x, X_train)"," theo cách đơn giản: với mỗi đặc trưng, thay giá trị của ",[992,41217,3904],{}," bằng giá trị phổ biến nhất (hoặc trung vị) của tập train, đo xác suất dự đoán đổi bao nhiêu.",[1352,41220,41223],{"className":41221,"code":41222,"language":2241,"meta":1357},[2239],"In cho 3 người bị đoán \u003C= 50K: 3 đặc trưng đẩy kết quả xuống mạnh nhất\n",[992,41224,41222],{"__ignoreMap":1357},[981,41226,41228],{"id":41227},"bài-3-đo-thiên-lệch-nâng-cao","Bài 3: Đo thiên lệch (nâng cao)",[2273,41230,41231,41234,41242,41245],{},[989,41232,41233],{},"Tính theo từng nhóm giới tính: accuracy, tỉ lệ dự đoán dương, TPR, FPR.",[989,41235,39487,41236,1509,41239,1517],{},[1487,41237,41238],{},"demographic parity difference",[1487,41240,41241],{},"equal opportunity difference",[989,41243,41244],{},"Thử một cách giảm lệch: chọn ngưỡng riêng cho từng nhóm để TPR bằng nhau. In lại các chỉ số và accuracy tổng.",[989,41246,1505,41247,41250],{},[992,41248,41249],{},"AUDIT.md"," 1 trang: dữ liệu có lệch gì, mô hình lệch bao nhiêu, cách giảm đã thử, đánh đổi, và khi nào cần con người duyệt quyết định.",[981,41252,2711],{"id":2710},[986,41254,41256,41262,41271,41277],{"className":41255},[2715],[989,41257,41259,41261],{"className":41258},[2719],[2721,41260],{"disabled":2723,"type":2724}," Có bảng permutation importance cho 2 mô hình.",[989,41263,41265,2308,41267,41270],{"className":41264},[2719],[2721,41266],{"disabled":2723,"type":2724},[992,41268,41269],{},"explain_one"," in lý do đọc hiểu được.",[989,41272,41274,41276],{"className":41273},[2719],[2721,41275],{"disabled":2723,"type":2724}," Bảng chỉ số theo nhóm trước và sau giảm lệch có số thật.",[989,41278,41280,2308,41282,41284],{"className":41279},[2719],[2721,41281],{"disabled":2723,"type":2724},[992,41283,41249],{}," đủ 5 mục.",[968,41286,2890],{"id":2889},[986,41288,41289,41292,41295,41298],{},[989,41290,41291],{},"Bài học lớn nhất từ Tay là gì?",[989,41293,41294],{},"Hộp trắng và hộp đen khác nhau thế nào?",[989,41296,41297],{},"Ba bệnh bằng chứng gồm những gì?",[989,41299,41300],{},"Nêu 2 cách giảm bias đơn giản nhất?",[3014,41302],{},[973,41304,41305],{},"🌕 Bạn đã hoàn thành ngày 63. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":41307},[41308,41309,41316,41317,41323],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":41310},[41311,41312,41313,41314,41315],{"id":41020,"depth":73,"text":41021},{"id":41038,"depth":73,"text":41039},{"id":41103,"depth":73,"text":41104},{"id":41121,"depth":73,"text":41122},{"id":41139,"depth":73,"text":41140},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":41318},[41319,41320,41321,41322],{"id":41183,"depth":73,"text":41184},{"id":41208,"depth":73,"text":41209},{"id":41227,"depth":73,"text":41228},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thất bại Tay 2016, giải thích được thuật toán, hộp trắng hộp đen, đạo đức bằng chứng và giảm thiên lệch.",{},[15144],{"title":370,"description":41324},[41329],"responsible-ai","w0HzvSVN3K1LTr2FcYm24tvb5N4HNyAU6LNDr2RHu7E",{"id":41332,"title":375,"body":41333,"category":5189,"day":378,"description":41698,"difficulty":5191,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":41699,"navigation":2723,"outcomes":3047,"path":376,"prerequisites":41700,"seo":41701,"stem":377,"tags":41702,"__hash__":41704},"challenges\u002Fchallenges\u002F64.to-chuc-anti-patterns.md",{"type":965,"value":41334,"toc":41679},[41335,41337,41340,41342,41346,41360,41364,41378,41419,41423,41440,41444,41458,41462,41473,41475,41489,41491,41499,41503,41513,41533,41536,41556,41560,41570,41581,41589,41592,41617,41625,41627,41656,41658,41672,41674,41677],[968,41336,971],{"id":970},[973,41338,41339],{},"Bài này học bản đồ 3 nhóm pattern và 4 anti-pattern. Bạn dùng nó để chọn pattern nhanh và tránh code rối.",[968,41341,979],{"id":978},[981,41343,41345],{"id":41344},"ba-nhóm-pattern","Ba nhóm pattern",[986,41347,41348,41351,41354,41357],{},[989,41349,41350],{},"Tạo sinh: lo cách tạo đối tượng, ví dụ Factory, Singleton.",[989,41352,41353],{},"Cấu trúc: lo cách lắp đối tượng, ví dụ Decorator, Adapter.",[989,41355,41356],{},"Hành vi: lo cách đối tượng nói chuyện, ví dụ Strategy, Observer.",[989,41358,41359],{},"Ví dụ đời thường: như xây nhà có đội làm gạch, đội lắp khung, đội chia việc.",[981,41361,41363],{"id":41362},"bảng-tra-cứu-nhanh","Bảng tra cứu nhanh",[986,41365,41366,41369,41372,41375],{},[989,41367,41368],{},"Muốn đổi thuật toán lúc chạy thì Strategy.",[989,41370,41371],{},"Muốn một đổi nhiều nghe thì Observer.",[989,41373,41374],{},"Muốn bọc thêm việc thì Decorator.",[989,41376,41377],{},"Ví dụ đời thường: như tra từ điển, có nhu cầu là có pattern.",[1099,41379,41380,41389],{},[1102,41381,41382],{},[1105,41383,41384,41386],{},[1108,41385,6561],{},[1108,41387,41388],{},"Pattern",[1118,41390,41391,41398,41405,41412],{},[1105,41392,41393,41396],{},[1123,41394,41395],{},"Đổi thuật toán lúc chạy",[1123,41397,7137],{},[1105,41399,41400,41403],{},[1123,41401,41402],{},"Lan tin một nhiều",[1123,41404,8903],{},[1105,41406,41407,41410],{},[1123,41408,41409],{},"Gom hệ con nhiều bước",[1123,41411,24472],{},[1105,41413,41414,41417],{},[1123,41415,41416],{},"Duyệt mà giấu cách lưu",[1123,41418,27856],{},[981,41420,41422],{"id":41421},"anti-patterns","Anti-patterns",[986,41424,41425,41428,41431,41434,41437],{},[989,41426,41427],{},"Lớp chúa: một lớp ôm mọi việc, sửa một chỗ lan khắp nơi.",[989,41429,41430],{},"Mì Ý: luồng code rối như tô mì, đọc không biết đầu cuối.",[989,41432,41433],{},"Sao chép dán: cùng logic ở chục nơi, sửa sót chỗ này chỗ kia.",[989,41435,41436],{},"Vàng mạ: làm hoành tráng cho yêu cầu chưa tới.",[989,41438,41439],{},"Ví dụ đời thường: lớp chúa như một người vừa nấu vừa thu tiền vừa giữ xe.",[981,41441,41443],{"id":41442},"khi-nào-không-dùng-pattern","Khi nào không dùng pattern",[986,41445,41446,41449,41452,41455],{},[989,41447,41448],{},"Bài toán chỉ cần 1 lớp và 1 vòng lặp là đủ.",[989,41450,41451],{},"Chỉ có 1 biến thể và không đổi suốt lịch sử.",[989,41453,41454],{},"Thêm pattern khiến đọc 1 việc phải nhảy qua 5 lớp.",[989,41456,41457],{},"Ví dụ đời thường: như đi chợ gần nhà thì đi bộ, không cần thuê xe tải.",[981,41459,41461],{"id":41460},"phân-loại-thêm-và-cách-tư-duy-theo-pattern","Phân loại thêm và cách tư duy theo pattern",[986,41463,41464,41467,41470],{},[989,41465,41466],{},"Ngoài 3 nhóm tạo sinh, cấu trúc, hành vi, pattern còn chia theo phạm vi: pattern lớp (quan hệ cố định lúc biên dịch qua kế thừa, ví dụ Factory Method, Template Method, class Adapter) và pattern đối tượng (quan hệ lắp ghép lúc chạy qua hợp thành, phần lớn các pattern còn lại).",[989,41468,41469],{},"Tiến trình tư duy thường gặp: người mới thấy pattern ở khắp nơi; người trung cấp biết khi nào cần và khi nào không; người thành thạo chỉ dùng pattern khi nó là lời giải tự nhiên nhất.",[989,41471,41472],{},"Giữ thiết kế đơn giản trước. Chỉ thêm pattern khi có thay đổi thật đang đòi hỏi, không phải thay đổi tưởng tượng.",[968,41474,1433],{"id":1432},[986,41476,41477,41480,41483,41486],{},[989,41478,41479],{},"Input: nhu cầu đổi thuật toán lúc chạy. Output: chọn Strategy.",[989,41481,41482],{},"Giải thích: Strategy cho phép hoán đổi thuật toán mà không sửa lớp dùng.",[989,41484,41485],{},"Input: cùng logic copy ở 5 nơi. Output: gom về 1 chỗ duy nhất.",[989,41487,41488],{},"Giải thích: hết mùi sao chép dán, sửa 1 lần là xong.",[968,41490,1482],{"id":1481},[973,41492,1485,41493,4801,41495,41498],{},[1487,41494,4800],{},[992,41496,41497],{},"day-064\u002F",". Bài này nặng về đọc và refactor code.",[981,41500,41502],{"id":41501},"bài-1-bảng-tra-pattern","Bài 1: Bảng tra pattern",[973,41504,1505,41505,41508,41509,41512],{},[992,41506,41507],{},"patterns.md"," gồm 1 bảng cho ",[1487,41510,41511],{},"mọi pattern đã học tới ngày 64"," (Strategy, Observer, Decorator, Simple Factory, Singleton, Adapter, Factory Method, Command, Facade, Template Method, Iterator). Mỗi dòng có 5 cột:",[1099,41514,41515],{},[1102,41516,41517],{},[1105,41518,41519,41521,41524,41527,41530],{},[1108,41520,41388],{},[1108,41522,41523],{},"Nhóm (C\u002FS\u002FB)",[1108,41525,41526],{},"Vấn đề giải quyết (1 câu)",[1108,41528,41529],{},"Dấu hiệu nhận biết trong code",[1108,41531,41532],{},"Ngày đã học",[973,41534,41535],{},"Thêm 6 tình huống, mỗi tình huống chọn đúng 1 pattern và viết 1 câu lý do:",[2273,41537,41538,41541,41544,41547,41550,41553],{},[989,41539,41540],{},"Ứng dụng cần xuất báo cáo PDF, Excel, CSV, sau này còn thêm loại khác.",[989,41542,41543],{},"Thư viện thanh toán bên thứ ba có API khác interface của bạn.",[989,41545,41546],{},"Mỗi khi đơn hàng đổi trạng thái, cần báo cho kho, email, thống kê.",[989,41548,41549],{},"Nút \"Hoàn tác\" cho trình soạn thảo.",[989,41551,41552],{},"Cần thêm nén và mã hóa vào luồng ghi file, bật tắt tùy ý.",[989,41554,41555],{},"Khởi động hệ thống cần gọi 8 dịch vụ con theo đúng thứ tự.",[981,41557,41559],{"id":41558},"bài-2-tháo-lớp-chúa","Bài 2: Tháo \"lớp chúa\"",[973,41561,41562,41563,41566,41567,41569],{},"Tự viết (hoặc lấy từ code cũ của bạn) lớp ",[992,41564,41565],{},"OrderManager"," khoảng 200 dòng, có ít nhất: tính giá có giảm giá bằng ",[992,41568,7335],{},", lưu file, gửi email, ghi log, in hóa đơn.",[2273,41571,41572,41575,41578],{},[989,41573,41574],{},"Liệt kê các anti-pattern có trong đó: lớp chúa, sao chép dán, mì Ý.",[989,41576,41577],{},"Refactor bằng pattern phù hợp. Mỗi thay đổi ghi 1 dòng: pattern gì, sửa vấn đề gì.",[989,41579,41580],{},"Viết test giữ nguyên hành vi trước và sau refactor (cùng input, cùng output).",[981,41582,41584,41585,41588],{"id":41583},"bài-3-khi-nào-không-dùng-pattern-nâng-cao","Bài 3: Khi nào ",[1487,41586,41587],{},"không"," dùng pattern (nâng cao)",[973,41590,41591],{},"Cho đoạn code \"vàng mạ\" sau (tự viết lại đầy đủ):",[1352,41593,41595],{"className":1393,"code":41594,"language":1395,"meta":1357,"style":1357},"struct GreeterFactory { virtual std::unique_ptr\u003CGreeter> create() = 0; };\nstruct Greeter { virtual std::string greet(const std::string &name) = 0; };\nstruct DefaultGreeterFactory : GreeterFactory { ... };\nstruct DefaultGreeter : Greeter { ... };   \u002F\u002F chỉ có đúng 1 cài đặt, 3 năm chưa đổi\n",[992,41596,41597,41602,41607,41612],{"__ignoreMap":1357},[1023,41598,41599],{"class":1362,"line":63},[1023,41600,41601],{},"struct GreeterFactory { virtual std::unique_ptr\u003CGreeter> create() = 0; };\n",[1023,41603,41604],{"class":1362,"line":68},[1023,41605,41606],{},"struct Greeter { virtual std::string greet(const std::string &name) = 0; };\n",[1023,41608,41609],{"class":1362,"line":73},[1023,41610,41611],{},"struct DefaultGreeterFactory : GreeterFactory { ... };\n",[1023,41613,41614],{"class":1362,"line":78},[1023,41615,41616],{},"struct DefaultGreeter : Greeter { ... };   \u002F\u002F chỉ có đúng 1 cài đặt, 3 năm chưa đổi\n",[2273,41618,41619,41622],{},[989,41620,41621],{},"Viết lại thành 1 hàm. So số dòng.",[989,41623,41624],{},"Viết 5 câu: khi nào cấu trúc cũ đáng giá, khi nào không.",[981,41626,2711],{"id":2710},[986,41628,41630,41638,41644,41650],{"className":41629},[2715],[989,41631,41633,2308,41635,41637],{"className":41632},[2719],[2721,41634],{"disabled":2723,"type":2724},[992,41636,41507],{}," đủ 11 pattern và 6 tình huống.",[989,41639,41641,41643],{"className":41640},[2719],[2721,41642],{"disabled":2723,"type":2724}," Bài 2 có test trước\u002Fsau refactor pass với cùng dữ liệu.",[989,41645,41647,41649],{"className":41646},[2719],[2721,41648],{"disabled":2723,"type":2724}," Bài 3 có phiên bản rút gọn và lập luận rõ ràng.",[989,41651,41653,41655],{"className":41652},[2719],[2721,41654],{"disabled":2723,"type":2724}," Nêu được 4 anti-pattern bằng lời của mình.",[968,41657,2890],{"id":2889},[986,41659,41660,41663,41666,41669],{},[989,41661,41662],{},"Ba nhóm pattern là gì?",[989,41664,41665],{},"Muốn đổi thuật toán lúc chạy thì dùng gì?",[989,41667,41668],{},"Lớp chúa và mì Ý là bệnh gì?",[989,41670,41671],{},"Khi nào không nên dùng pattern?",[3014,41673],{},[973,41675,41676],{},"🌕 Bạn đã hoàn thành ngày 64. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,41678,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":41680},[41681,41682,41689,41690,41697],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":41683},[41684,41685,41686,41687,41688],{"id":41344,"depth":73,"text":41345},{"id":41362,"depth":73,"text":41363},{"id":41421,"depth":73,"text":41422},{"id":41442,"depth":73,"text":41443},{"id":41460,"depth":73,"text":41461},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":41691},[41692,41693,41694,41696],{"id":41501,"depth":73,"text":41502},{"id":41558,"depth":73,"text":41559},{"id":41583,"depth":73,"text":41695},"Bài 3: Khi nào không dùng pattern (nâng cao)",{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bản đồ ba nhóm tạo sinh cấu trúc hành vi, cách tra cứu pattern theo nhu cầu, và những phản pattern cần tránh.",{},[5195],{"title":375,"description":41698},[41703,41421],"patterns","rH-n1GYNeXv2uSMC9s5Aiekd3d--enH8VpJsRNppNMQ",{"id":41706,"title":380,"body":41707,"category":3041,"day":383,"description":42170,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":42172,"navigation":2723,"outcomes":3047,"path":381,"prerequisites":42173,"seo":42174,"stem":382,"tags":42175,"__hash__":42176},"challenges\u002Fchallenges\u002F65.treap-nang-cao.md",{"type":965,"value":41708,"toc":42153},[41709,41711,41714,41716,41720,41734,41738,41752,41772,41776,41790,41794,41808,41810,41824,41826,41839,41843,41890,41896,41911,41915,41963,41977,41981,41987,42015,42021,42030,42032,42130,42132,42146,42148,42151],[968,41710,971],{"id":970},[973,41712,41713],{},"Bài này học chèn xóa treap bằng xoay. Bạn dùng nó để giữ cây cân bằng khi dữ liệu vào xấu.",[968,41715,979],{"id":978},[981,41717,41719],{"id":41718},"chèn-đặt-lá-rồi-xoay-lên","Chèn: đặt lá rồi xoay lên",[986,41721,41722,41725,41728,41731],{},[989,41723,41724],{},"Bước 1: đặt nút mới như lá theo luật cây tìm kiếm.",[989,41726,41727],{},"Bước 2: nếu ưu tiên vượt cha thì xoay đẩy lên.",[989,41729,41730],{},"Không đổi chỗ trực tiếp vì sẽ phá thứ tự khóa.",[989,41732,41733],{},"Ví dụ đời thường: như nhân viên mới giỏi được thăng chức dần lên trên.",[981,41735,41737],{"id":41736},"xóa-dìm-xuống-lá-rồi-gỡ","Xóa: dìm xuống lá rồi gỡ",[986,41739,41740,41743,41746,41749],{},[989,41741,41742],{},"Muốn xóa nút trong thì xoay dìm nó xuống dần.",[989,41744,41745],{},"Khi thành lá thì gỡ thẳng.",[989,41747,41748],{},"Nút lá gỡ ngay không cần xoay.",[989,41750,41751],{},"Ví dụ đời thường: như đẩy người cần rời xuống cuối hàng rồi mời ra.",[1352,41753,41755],{"className":3538,"code":41754,"language":3540,"meta":1357,"style":1357},"# Ý tưởng chèn \u002F xóa treap\n# chèn: đặt lá theo khóa -> while ưu_tiên_con > ưu_tiên_cha: xoay(cha)\n# xóa: while nút chưa là lá: xoay với con mạnh hơn -> gỡ lá\n",[992,41756,41757,41762,41767],{"__ignoreMap":1357},[1023,41758,41759],{"class":1362,"line":63},[1023,41760,41761],{},"# Ý tưởng chèn \u002F xóa treap\n",[1023,41763,41764],{"class":1362,"line":68},[1023,41765,41766],{},"# chèn: đặt lá theo khóa -> while ưu_tiên_con > ưu_tiên_cha: xoay(cha)\n",[1023,41768,41769],{"class":1362,"line":73},[1023,41770,41771],{},"# xóa: while nút chưa là lá: xoay với con mạnh hơn -> gỡ lá\n",[981,41773,41775],{"id":41774},"treap-ngẫu-nhiên","Treap ngẫu nhiên",[986,41777,41778,41781,41784,41787],{},[989,41779,41780],{},"Định nghĩa: mỗi khóa rút 1 số ngẫu nhiên làm ưu tiên.",[989,41782,41783],{},"Hình dạng cây do số ngẫu nhiên quyết định.",[989,41785,41786],{},"Kẻ tấn công không đoán được dãy nào gây lệch.",[989,41788,41789],{},"Ví dụ đời thường: như bốc thăm chỗ ngồi, không ai xếp được phe cánh.",[981,41791,41793],{"id":41792},"chiều-cao-kỳ-vọng-và-ứng-dụng","Chiều cao kỳ vọng và ứng dụng",[986,41795,41796,41799,41802,41805],{},[989,41797,41798],{},"Chiều cao trung bình là logarit theo số nút.",[989,41800,41801],{},"Chỉ đảm bảo trung bình, không đảm bảo mọi cây cụ thể.",[989,41803,41804],{},"Dùng mọi nơi cần từ điển có thứ tự mà chống tấn công.",[989,41806,41807],{},"Ví dụ đời thường: quản lý gói tin IP, bảng băm dễ bị dồn xô còn treap thì khó.",[968,41809,1433],{"id":1432},[986,41811,41812,41815,41818,41821],{},[989,41813,41814],{},"Input: chèn nút ưu tiên thấp nhất. Output: nằm yên làm lá, không xoay.",[989,41816,41817],{},"Giải thích: ưu tiên thấp thì không vượt cha nào cả.",[989,41819,41820],{},"Input: chèn dãy đã sắp vào BST thuần và treap ngẫu nhiên. Output: BST cao như danh sách, treap thấp hơn hẳn.",[989,41822,41823],{},"Giải thích: số ngẫu nhiên phá được đòn sắp xếp sẵn.",[968,41825,1482],{"id":1481},[973,41827,1485,41828,41830,41831,41834,41835,41838],{},[1487,41829,1493],{},". Dùng tiếp code ngày 29. Nộp vào ",[992,41832,41833],{},"day-065\u002F",". Treap dùng làm từ điển có thứ tự, priority ngẫu nhiên, ",[1487,41836,41837],{},"max-heap"," theo priority.",[981,41840,41842],{"id":41841},"bài-1-chèn-và-xóa-đầy-đủ","Bài 1: Chèn và xóa đầy đủ",[1352,41844,41846],{"className":1393,"code":41845,"language":1395,"meta":1357,"style":1357},"class Treap {\n public:\n  explicit Treap(uint64_t seed);\n  bool insert(int key);             \u002F\u002F trả false nếu đã có\n  bool erase(int key);              \u002F\u002F xoay dìm nút xuống tới lá rồi gỡ\n  bool contains(int key) const;\n  size_t size() const; int height() const;\n  bool check() const;               \u002F\u002F BST + heap\n};\n",[992,41847,41848,41853,41857,41862,41867,41872,41876,41881,41886],{"__ignoreMap":1357},[1023,41849,41850],{"class":1362,"line":63},[1023,41851,41852],{},"class Treap {\n",[1023,41854,41855],{"class":1362,"line":68},[1023,41856,4836],{},[1023,41858,41859],{"class":1362,"line":73},[1023,41860,41861],{},"  explicit Treap(uint64_t seed);\n",[1023,41863,41864],{"class":1362,"line":78},[1023,41865,41866],{},"  bool insert(int key);             \u002F\u002F trả false nếu đã có\n",[1023,41868,41869],{"class":1362,"line":83},[1023,41870,41871],{},"  bool erase(int key);              \u002F\u002F xoay dìm nút xuống tới lá rồi gỡ\n",[1023,41873,41874],{"class":1362,"line":88},[1023,41875,7843],{},[1023,41877,41878],{"class":1362,"line":93},[1023,41879,41880],{},"  size_t size() const; int height() const;\n",[1023,41882,41883],{"class":1362,"line":98},[1023,41884,41885],{},"  bool check() const;               \u002F\u002F BST + heap\n",[1023,41887,41888],{"class":1362,"line":103},[1023,41889,4866],{},[1352,41891,41894],{"className":41892,"code":41893,"language":2241,"meta":1357},[2239],"insert 1..1000 tăng dần  -> check = true, height \u003C 40\nerase mọi số chẵn        -> size 500, check = true\nerase(5000)              -> false\n",[992,41895,41893],{"__ignoreMap":1357},[973,41897,41898,41899,2461,41901,2461,41904,41906,41907,41910],{},"Viết test ngẫu nhiên: 10^5 thao tác ",[992,41900,2251],{},[992,41902,41903],{},"erase",[992,41905,6936],{}," trộn lẫn, so với ",[992,41908,41909],{},"std::set"," sau mỗi thao tác.",[981,41912,41914],{"id":41913},"bài-2-split-và-merge","Bài 2: Split và merge",[1099,41916,41917,41925],{},[1102,41918,41919],{},[1105,41920,41921,41923],{},[1108,41922,1566],{},[1108,41924,2547],{},[1118,41926,41927,41948],{},[1105,41928,41929,41934],{},[1123,41930,41931],{},[992,41932,41933],{},"split(root, key) -> (L, R)",[1123,41935,41936,41938,41939,1656,41942,41938,41945],{},[992,41937,4772],{}," chứa khóa ",[992,41940,41941],{},"\u003C key",[992,41943,41944],{},"R",[992,41946,41947],{},">= key",[1105,41949,41950,41955],{},[1123,41951,41952],{},[992,41953,41954],{},"merge(L, R)",[1123,41956,41957,41958,41960,41961],{},"Mọi khóa của ",[992,41959,4772],{}," nhỏ hơn mọi khóa của ",[992,41962,41944],{},[973,41964,41965,41966,1509,41968,41970,41971,27888,41974,41976],{},"Viết lại ",[992,41967,2251],{},[992,41969,41903],{}," chỉ bằng ",[992,41972,41973],{},"split",[992,41975,17264],{},". Kết quả phải giống Bài 1.",[981,41978,41980],{"id":41979},"bài-3-thống-kê-thứ-tự-nâng-cao","Bài 3: Thống kê thứ tự (nâng cao)",[973,41982,41983,41984,41986],{},"Mỗi nút lưu thêm ",[992,41985,994],{}," của cây con.",[2273,41988,41989,41998,42007],{},[989,41990,41991,41994,41995,41997],{},[992,41992,41993],{},"int kth(int k)",": khóa nhỏ thứ ",[992,41996,4022],{}," (từ 1).",[989,41999,42000,42003,42004,1517],{},[992,42001,42002],{},"int rank(int key)",": số khóa nhỏ hơn ",[992,42005,42006],{},"key",[989,42008,42009,42012,42013,1517],{},[992,42010,42011],{},"int countRange(int lo, int hi)",": số khóa trong ",[992,42014,32970],{},[1352,42016,42019],{"className":42017,"code":42018,"language":2241,"meta":1357},[2239],"khóa {10, 20, 30, 40, 50}: kth(2) = 20, rank(35) = 3, countRange(15, 45) = 3\n",[992,42020,42018],{"__ignoreMap":1357},[973,42022,42023,42024,42026,42027,16014],{},"Đo thời gian 10^6 thao tác trộn lẫn so với ",[992,42025,41909],{}," (không có ",[992,42028,42029],{},"kth",[981,42031,2711],{"id":2710},[986,42033,42035,42043,42054,42124],{"className":42034},[2715],[989,42036,42038,42040,42041,13981],{"className":42037},[2719],[2721,42039],{"disabled":2723,"type":2724}," Test ngẫu nhiên so với ",[992,42042,41909],{},[989,42044,42046,42048,42049,2461,42051,42053],{"className":42045},[2719],[2721,42047],{"disabled":2723,"type":2724}," Bản ",[992,42050,41973],{},[992,42052,17264],{}," cho cùng kết quả bản xoay.",[989,42055,42057,2308,42059,1656,42061,1656,42064,42067,42068,42123],{"className":42056},[2719],[2721,42058],{"disabled":2723,"type":2724},[992,42060,42029],{},[992,42062,42063],{},"rank",[992,42065,42066],{},"countRange"," đúng, ",[1023,42069,42071,42094],{"className":42070},[1026],[1023,42072,42074],{"className":42073},[1030],[1032,42075,42076],{"xmlns":1034},[1036,42077,42078,42092],{},[1039,42079,42080,42082,42084,42086,42088,42090],{},[1042,42081,1044],{},[1046,42083,1049],{"stretchy":1048},[1042,42085,8397],{},[1046,42087,8400],{},[1042,42089,1262],{},[1046,42091,1056],{"stretchy":1048},[1058,42093,8407],{"encoding":1060},[1023,42095,42097],{"className":42096,"ariaHidden":1066},[1065],[1023,42098,42100,42103,42106,42109,42114,42117,42120],{"className":42099},[1070],[1023,42101],{"className":42102,"style":1075},[1074],[1023,42104,1044],{"className":42105,"style":1081},[1079,1080],[1023,42107,1049],{"className":42108},[1085],[1023,42110,8427,42112],{"className":42111},[8426],[1023,42113,7690],{"style":8430},[1023,42115],{"className":42116,"style":8434},[2354],[1023,42118,1262],{"className":42119},[1079,1080],[1023,42121,1056],{"className":42122},[1092]," kỳ vọng.",[989,42125,42127,42129],{"className":42126},[2719],[2721,42128],{"disabled":2723,"type":2724}," Giải thích được vì sao priority ngẫu nhiên chống được dãy chèn xấu.",[968,42131,2890],{"id":2889},[986,42133,42134,42137,42140,42143],{},[989,42135,42136],{},"Chèn treap gồm mấy bước?",[989,42138,42139],{},"Xóa nút trong treap làm thế nào?",[989,42141,42142],{},"Treap ngẫu nhiên gán ưu tiên bằng gì?",[989,42144,42145],{},"Vì sao treap chống được dãy sắp sẵn?",[3014,42147],{},[973,42149,42150],{},"🌕 Bạn đã hoàn thành ngày 65. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,42152,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":42154},[42155,42156,42162,42163,42169],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":42157},[42158,42159,42160,42161],{"id":41718,"depth":73,"text":41719},{"id":41736,"depth":73,"text":41737},{"id":41774,"depth":73,"text":41775},{"id":41792,"depth":73,"text":41793},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":42164},[42165,42166,42167,42168],{"id":41841,"depth":73,"text":41842},{"id":41913,"depth":73,"text":41914},{"id":41979,"depth":73,"text":41980},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hoàn thiện chèn xóa treap bằng xoay, dùng ưu tiên ngẫu nhiên để ép cân bằng kỳ vọng logarit và biết miền ứng dụng.","kho",{},[3050,18469],{"title":380,"description":42170},[23652],"cSuRIU-fyqOAdZGlpbG51_jqX-8jCL7uiRnri67RT9Q",{"id":42178,"title":385,"body":42179,"category":3041,"day":388,"description":42556,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":42557,"navigation":2723,"outcomes":3047,"path":386,"prerequisites":42558,"seo":42559,"stem":387,"tags":42560,"__hash__":42562},"challenges\u002Fchallenges\u002F66.lfu-va-chien-luoc-cache.md",{"type":965,"value":42180,"toc":42538},[42181,42183,42186,42188,42192,42206,42210,42224,42262,42266,42280,42284,42298,42300,42314,42316,42323,42370,42403,42418,42424,42428,42431,42442,42449,42451,42484,42486,42515,42517,42531,42533,42536],[968,42182,971],{"id":970},[973,42184,42185],{},"Bài này học LFU, cách dùng cache và khóa đồng bộ. Bạn dùng nó để web chạy nhanh mà không lỗi race.",[968,42187,979],{"id":978},[981,42189,42191],{"id":42190},"lfu-đuổi-theo-tần-suất","LFU đuổi theo tần suất",[986,42193,42194,42197,42200,42203],{},[989,42195,42196],{},"LRU đuổi kẻ lâu không dùng, LFU đuổi kẻ ít được dùng nhất.",[989,42198,42199],{},"Mỗi lần trúng thì tăng bộ đếm của khóa đó.",[989,42201,42202],{},"Ví dụ đời thường: giữ món bán chạy trăm lần thay vì món vừa hỏi 1 lần.",[989,42204,42205],{},"Thắng khi độ nóng ổn định, ví dụ bảng xếp hạng.",[981,42207,42209],{"id":42208},"hai-bệnh-của-lfu","Hai bệnh của LFU",[986,42211,42212,42215,42218,42221],{},[989,42213,42214],{},"Bám cũ: khóa từng nóng giờ nguội vẫn bám vì đếm cao.",[989,42216,42217],{},"Chào sân: khóa mới đếm bằng 1 nên dễ bị đuổi oan.",[989,42219,42220],{},"Chữa bằng già hóa đếm định kỳ hoặc chỉ đếm trong N phút gần nhất.",[989,42222,42223],{},"Ví dụ đời thường: như cựu vô địch vẫn chiếm suất dù đã giải nghệ.",[1099,42225,42226,42236],{},[1102,42227,42228],{},[1105,42229,42230,42233],{},[1108,42231,42232],{},"Tải",[1108,42234,42235],{},"Nên dùng",[1118,42237,42238,42246,42254],{},[1105,42239,42240,42243],{},[1123,42241,42242],{},"Tin tức đổi nhanh",[1123,42244,42245],{},"LRU",[1105,42247,42248,42251],{},[1123,42249,42250],{},"Bảng xếp hạng ổn định",[1123,42252,42253],{},"LFU",[1105,42255,42256,42259],{},[1123,42257,42258],{},"Hỗn hợp",[1123,42260,42261],{},"Đo cả 2 trên log thật",[981,42263,42265],{"id":42264},"cách-dùng-cache","Cách dùng cache",[986,42267,42268,42271,42274,42277],{},[989,42269,42270],{},"Khóa cache: quá thô thì ít trúng, quá mịn thì tốn nhớ.",[989,42272,42273],{},"Ghi xuyên qua thì đúng ngay mà chậm, ghi lười thì nhanh mà rủi ro mất.",[989,42275,42276],{},"Làm ấm trước khóa nóng để tránh khởi động lạnh.",[989,42278,42279],{},"Ví dụ đời thường: như đặt tên hộp tủ, tên chung quá thì khó tìm, tên chi tiết quá thì nhiều hộp.",[981,42281,42283],{"id":42282},"khóa-đồng-bộ","Khóa đồng bộ",[986,42285,42286,42289,42292,42295],{},[989,42287,42288],{},"Khóa thường: đoạn găng chỉ 1 luồng vào.",[989,42290,42291],{},"Khóa tái nhập: luồng đang giữ được vào tiếp mà không tự khóa mình.",[989,42293,42294],{},"Khóa đọc: nhiều luồng đọc song song, ghi thì độc quyền.",[989,42296,42297],{},"Ví dụ đời thường: như nhà vệ sinh, nhiều người soi gương được nhưng chỉ 1 người dùng buồng.",[968,42299,1433],{"id":1432},[986,42301,42302,42305,42308,42311],{},[989,42303,42304],{},"Input: cache LFU đầy, mọi đếm bằng nhau. Output: đuổi kẻ cũ nhất.",[989,42306,42307],{},"Giải thích: hòa đếm thì lấy cũ nhất cho xác định.",[989,42309,42310],{},"Input: 2 luồng đọc cùng khóa. Output: cả 2 cùng vào.",[989,42312,42313],{},"Giải thích: đọc song song an toàn nhờ khóa đọc.",[968,42315,1482],{"id":1481},[973,42317,1485,42318,5599,42320,1517],{},[1487,42319,4800],{},[992,42321,42322],{},"day-066\u002F",[981,42324,42326,42327],{"id":42325},"bài-1-lfu-cache-o1o1o1","Bài 1: LFU cache ",[1023,42328,42330,42349],{"className":42329},[1026],[1023,42331,42333],{"className":42332},[1030],[1032,42334,42335],{"xmlns":1034},[1036,42336,42337,42347],{},[1039,42338,42339,42341,42343,42345],{},[1042,42340,1044],{},[1046,42342,1049],{"stretchy":1048},[1051,42344,1053],{},[1046,42346,1056],{"stretchy":1048},[1058,42348,1061],{"encoding":1060},[1023,42350,42352],{"className":42351,"ariaHidden":1066},[1065],[1023,42353,42355,42358,42361,42364,42367],{"className":42354},[1070],[1023,42356],{"className":42357,"style":1075},[1074],[1023,42359,1044],{"className":42360,"style":1081},[1079,1080],[1023,42362,1049],{"className":42363},[1085],[1023,42365,1053],{"className":42366},[1079],[1023,42368,1056],{"className":42369},[1092],[1352,42371,42373],{"className":1393,"code":42372,"language":1395,"meta":1357,"style":1357},"class LFUCache {\n public:\n  explicit LFUCache(size_t capacity);\n  std::optional\u003Cint> get(int key);   \u002F\u002F tăng tần suất\n  void put(int key, int value);      \u002F\u002F đầy thì đuổi khóa tần suất thấp nhất; hòa thì đuổi khóa ít dùng gần đây nhất\n};\n",[992,42374,42375,42380,42384,42389,42394,42399],{"__ignoreMap":1357},[1023,42376,42377],{"class":1362,"line":63},[1023,42378,42379],{},"class LFUCache {\n",[1023,42381,42382],{"class":1362,"line":68},[1023,42383,4836],{},[1023,42385,42386],{"class":1362,"line":73},[1023,42387,42388],{},"  explicit LFUCache(size_t capacity);\n",[1023,42390,42391],{"class":1362,"line":78},[1023,42392,42393],{},"  std::optional\u003Cint> get(int key);   \u002F\u002F tăng tần suất\n",[1023,42395,42396],{"class":1362,"line":83},[1023,42397,42398],{},"  void put(int key, int value);      \u002F\u002F đầy thì đuổi khóa tần suất thấp nhất; hòa thì đuổi khóa ít dùng gần đây nhất\n",[1023,42400,42401],{"class":1362,"line":88},[1023,42402,4866],{},[973,42404,42405,2308,42408,1656,42411,42414,42415,1517],{},[1487,42406,42407],{},"Cấu trúc gợi ý:",[992,42409,42410],{},"key -> (value, freq, iterator)",[992,42412,42413],{},"freq -> danh sách khóa theo thứ tự dùng",", biến ",[992,42416,42417],{},"minFreq",[1352,42419,42422],{"className":42420,"code":42421,"language":2241,"meta":1357},[2239],"cap=2: put(1,1), put(2,2), get(1)   -> 1 (freq 1 = 2)\nput(3,3)                             -> đuổi key 2 (freq thấp nhất)\nget(2) -> nullopt; get(3) -> 3\nput(4,4)                             -> key 1 và 3 cùng freq 2, đuổi key 1 (dùng lâu hơn)\n",[992,42423,42421],{"__ignoreMap":1357},[981,42425,42427],{"id":42426},"bài-2-so-lru-và-lfu","Bài 2: So LRU và LFU",[973,42429,42430],{},"Dùng LRU ngày 39. Sinh 3 luồng truy cập 10^6 yêu cầu trên 10^4 khóa, cache 1000:",[2273,42432,42433,42436,42439],{},[989,42434,42435],{},"Zipf ổn định (khóa nóng không đổi).",[989,42437,42438],{},"Zipf đổi khóa nóng mỗi 10^5 yêu cầu.",[989,42440,42441],{},"Quét tuần tự lặp lại (1..2000, 1..2000, ...).",[973,42443,42444,42445,42448],{},"In hit rate của LRU và LFU cho từng luồng. Thêm ",[1487,42446,42447],{},"LFU có già hóa",": mỗi 10^4 yêu cầu chia đôi mọi tần suất. So kết quả ở luồng 2.",[981,42450,29014],{"id":29013},[2273,42452,42453,42466,42475,42478],{},[989,42454,42455,42456,42459,42460,42462,42463,42465],{},"Bọc LRU bằng ",[992,42457,42458],{},"std::shared_mutex",". Giải thích vì sao ",[992,42461,28507],{}," của LRU ",[1487,42464,41587],{}," dùng được khóa đọc chung (nó sửa thứ tự).",[989,42467,6760,42468,42471,42472,1517],{},[1487,42469,42470],{},"sharded cache",": 16 phân mảnh, mỗi mảnh 1 LRU + 1 mutex, chọn mảnh theo ",[992,42473,42474],{},"hash(key) % 16",[989,42476,42477],{},"Đo thông lượng với 1, 2, 4, 8 luồng cho: 1 mutex toàn cục và 16 phân mảnh.",[989,42479,42480,42481,1517],{},"Viết 1 ví dụ deadlock với 2 mutex, rồi sửa bằng ",[992,42482,42483],{},"std::scoped_lock",[981,42485,2711],{"id":2710},[986,42487,42489,42495,42501,42509],{"className":42488},[2715],[989,42490,42492,42494],{"className":42491},[2719],[2721,42493],{"disabled":2723,"type":2724}," LFU pass test mẫu và test ngẫu nhiên so với bản chậm.",[989,42496,42498,42500],{"className":42497},[2719],[2721,42499],{"disabled":2723,"type":2724}," Bảng hit rate 3 luồng x 3 chiến lược có số thật.",[989,42502,42504,2308,42506,42508],{"className":42503},[2719],[2721,42505],{"disabled":2723,"type":2724},[992,42507,16513],{}," sạch.",[989,42510,42512,42514],{"className":42511},[2719],[2721,42513],{"disabled":2723,"type":2724}," Bảng thông lượng theo số luồng có số thật.",[968,42516,2890],{"id":2889},[986,42518,42519,42522,42525,42528],{},[989,42520,42521],{},"LFU và LRU khác nhau thế nào?",[989,42523,42524],{},"Hai bệnh của LFU là gì?",[989,42526,42527],{},"Vì sao cách dùng cache quan trọng như chính sách đuổi?",[989,42529,42530],{},"Khóa đọc khác khóa thường ở điểm nào?",[3014,42532],{},[973,42534,42535],{},"🌕 Bạn đã hoàn thành ngày 66. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,42537,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":42539},[42540,42541,42547,42548,42555],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":42542},[42543,42544,42545,42546],{"id":42190,"depth":73,"text":42191},{"id":42208,"depth":73,"text":42209},{"id":42264,"depth":73,"text":42265},{"id":42282,"depth":73,"text":42283},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":42549},[42550,42552,42553,42554],{"id":42325,"depth":73,"text":42551},"Bài 1: LFU cache O(1)O(1)O(1)",{"id":42426,"depth":73,"text":42427},{"id":29013,"depth":73,"text":29014},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"So sánh LFU với LRU, cách dùng cache hiệu quả, đồng bộ hóa bằng khóa và các ứng dụng cache phân tán.",{},[4669,14055],{"title":385,"description":42556},[29125,42561],"concurrency","xUpM-lnGjp6B1NEOSUfJYdd-831FLrL-9pQ5hDfUTq8",{"id":42564,"title":390,"body":42565,"category":5189,"day":393,"description":42998,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":42999,"navigation":2723,"outcomes":3047,"path":391,"prerequisites":43000,"seo":43001,"stem":392,"tags":43002,"__hash__":43005},"challenges\u002Fchallenges\u002F67.composite-pattern.md",{"type":965,"value":42566,"toc":42982},[42567,42569,42572,42574,42578,42592,42596,42610,42614,42628,42677,42679,42693,42695,42702,42706,42768,42790,42796,42800,42803,42867,42871,42919,42921,42959,42961,42975,42977,42980],[968,42568,971],{"id":970},[973,42570,42571],{},"Bài này học Composite để xử lý cây đồng nhất. Bạn dùng nó cho thực đơn lồng nhau nhiều tầng.",[968,42573,979],{"id":978},[981,42575,42577],{"id":42576},"định-nghĩa-composite","Định nghĩa Composite",[986,42579,42580,42583,42586,42589],{},[989,42581,42582],{},"Gộp đối tượng thành cây để biểu diễn phân cấp phần tử.",[989,42584,42585],{},"Khách hàng đối xử cụm và lá như nhau.",[989,42587,42588],{},"Từ khóa là cây và đồng nhất.",[989,42590,42591],{},"Ví dụ đời thường: như thư mục chứa file và thư mục con, mở đều như nhau.",[981,42593,42595],{"id":42594},"thực-đơn-cây","Thực đơn cây",[986,42597,42598,42601,42604,42607],{},[989,42599,42600],{},"Thực đơn tổng chứa thực đơn con, thực đơn con chứa món lá.",[989,42602,42603],{},"Cụm giữ danh sách con, gọi in thì gọi lan xuống từng con.",[989,42605,42606],{},"Lá chỉ in chính nó, không có con.",[989,42608,42609],{},"Ví dụ đời thường: như gọi cả bàn ăn, bếp tự lo từng món.",[981,42611,42613],{"id":42612},"trong-suốt-vs-an-toàn","Trong suốt vs an toàn",[986,42615,42616,42619,42622,42625],{},[989,42617,42618],{},"Trong suốt: thêm bớt nằm ở giao diện chung, khách không rẽ nhánh.",[989,42620,42621],{},"An toàn: thêm bớt chỉ ở cụm, lá gọn sạch.",[989,42623,42624],{},"Trong suốt lỗi phát hiện lúc chạy, an toàn lỗi phát hiện lúc biên dịch.",[989,42626,42627],{},"Bài này chọn trong suốt vì đơn giản cho khách.",[1099,42629,42630,42642],{},[1102,42631,42632],{},[1105,42633,42634,42636,42639],{},[1108,42635,24466],{},[1108,42637,42638],{},"Trong suốt",[1108,42640,42641],{},"An toàn",[1118,42643,42644,42655,42666],{},[1105,42645,42646,42649,42652],{},[1123,42647,42648],{},"Giao diện chung",[1123,42650,42651],{},"Có thêm bớt",[1123,42653,42654],{},"Chỉ việc chung",[1105,42656,42657,42660,42663],{},[1123,42658,42659],{},"Khách hàng",[1123,42661,42662],{},"Không rẽ nhánh",[1123,42664,42665],{},"Phải kiểm tra cụm",[1105,42667,42668,42671,42674],{},[1123,42669,42670],{},"Lá",[1123,42672,42673],{},"Mang phương thức thừa",[1123,42675,42676],{},"Gọn sạch",[968,42678,1433],{"id":1432},[986,42680,42681,42684,42687,42690],{},[989,42682,42683],{},"Input: gọi in trên thực đơn tổng. Output: mọi món mọi tầng in đúng 1 lần.",[989,42685,42686],{},"Giải thích: yêu cầu lan đệ quy từ cụm cha xuống lá.",[989,42688,42689],{},"Input: thêm con vào món lá ở bản trong suốt. Output: lá từ chối rõ ràng, cây không đổi.",[989,42691,42692],{},"Giải thích: lá không có con nên phải báo lỗi nhẹ nhàng.",[968,42694,1482],{"id":1481},[973,42696,1485,42697,4801,42699,1517],{},[1487,42698,4800],{},[992,42700,42701],{},"day-067\u002F",[981,42703,42705],{"id":42704},"bài-1-thực-đơn-dạng-cây-trong-suốt","Bài 1: Thực đơn dạng cây (trong suốt)",[1352,42707,42709],{"className":1393,"code":42708,"language":1395,"meta":1357,"style":1357},"class MenuComponent {\n public:\n  virtual std::string name() const = 0;\n  virtual void print(std::ostream &os, int indent = 0) const = 0;\n  virtual double price() const { throw std::logic_error(\"không hỗ trợ\"); }\n  virtual bool vegetarian() const { throw std::logic_error(\"không hỗ trợ\"); }\n  virtual void add(std::shared_ptr\u003CMenuComponent>) { throw std::logic_error(\"không hỗ trợ\"); }\n  virtual void remove(const MenuComponent *) { throw std::logic_error(\"không hỗ trợ\"); }\n  virtual ~MenuComponent() = default;\n};\nclass MenuItem : public MenuComponent { ... };   \u002F\u002F lá\nclass Menu : public MenuComponent { ... };       \u002F\u002F cụm, giữ vector con\n",[992,42710,42711,42716,42720,42724,42729,42734,42739,42744,42749,42754,42758,42763],{"__ignoreMap":1357},[1023,42712,42713],{"class":1362,"line":63},[1023,42714,42715],{},"class MenuComponent {\n",[1023,42717,42718],{"class":1362,"line":68},[1023,42719,4836],{},[1023,42721,42722],{"class":1362,"line":73},[1023,42723,15748],{},[1023,42725,42726],{"class":1362,"line":78},[1023,42727,42728],{},"  virtual void print(std::ostream &os, int indent = 0) const = 0;\n",[1023,42730,42731],{"class":1362,"line":83},[1023,42732,42733],{},"  virtual double price() const { throw std::logic_error(\"không hỗ trợ\"); }\n",[1023,42735,42736],{"class":1362,"line":88},[1023,42737,42738],{},"  virtual bool vegetarian() const { throw std::logic_error(\"không hỗ trợ\"); }\n",[1023,42740,42741],{"class":1362,"line":93},[1023,42742,42743],{},"  virtual void add(std::shared_ptr\u003CMenuComponent>) { throw std::logic_error(\"không hỗ trợ\"); }\n",[1023,42745,42746],{"class":1362,"line":98},[1023,42747,42748],{},"  virtual void remove(const MenuComponent *) { throw std::logic_error(\"không hỗ trợ\"); }\n",[1023,42750,42751],{"class":1362,"line":103},[1023,42752,42753],{},"  virtual ~MenuComponent() = default;\n",[1023,42755,42756],{"class":1362,"line":108},[1023,42757,4866],{},[1023,42759,42760],{"class":1362,"line":113},[1023,42761,42762],{},"class MenuItem : public MenuComponent { ... };   \u002F\u002F lá\n",[1023,42764,42765],{"class":1362,"line":118},[1023,42766,42767],{},"class Menu : public MenuComponent { ... };       \u002F\u002F cụm, giữ vector con\n",[973,42769,42770,42771,42774,42775,1656,42778,1656,42781,1838,42784,42786,42787,1517],{},"Dựng cây: ",[992,42772,42773],{},"ALL MENUS"," gồm ",[992,42776,42777],{},"PANCAKE HOUSE",[992,42779,42780],{},"DINER",[992,42782,42783],{},"CAFE",[992,42785,42780],{}," chứa thêm thực đơn con ",[992,42788,42789],{},"DESSERT",[1352,42791,42794],{"className":42792,"code":42793,"language":2241,"meta":1357},[2239],"allMenus.print() -> in mọi món mọi tầng, thụt lề theo độ sâu, mỗi món đúng 1 lần\nitem.add(...)    -> ném logic_error, cây không đổi\n",[992,42795,42793],{"__ignoreMap":1357},[981,42797,42799],{"id":42798},"bài-2-thao-tác-trên-cả-cây","Bài 2: Thao tác trên cả cây",[973,42801,42802],{},"Thêm các hàm đệ quy vào giao diện chung:",[1099,42804,42805,42816],{},[1102,42806,42807],{},[1105,42808,42809,42811,42813],{},[1108,42810,1566],{},[1108,42812,42670],{},[1108,42814,42815],{},"Cụm",[1118,42817,42818,42831,42842,42854],{},[1105,42819,42820,42825,42828],{},[1123,42821,42822],{},[992,42823,42824],{},"double totalPrice()",[1123,42826,42827],{},"giá chính nó",[1123,42829,42830],{},"tổng các con",[1105,42832,42833,42838,42840],{},[1123,42834,42835],{},[992,42836,42837],{},"int countItems()",[1123,42839,1053],{},[1123,42841,42830],{},[1105,42843,42844,42849,42851],{},[1123,42845,42846],{},[992,42847,42848],{},"int depth()",[1123,42850,2379],{},[1123,42852,42853],{},"1 + sâu nhất các con",[1105,42855,42856,42861,42864],{},[1123,42857,42858],{},[992,42859,42860],{},"std::shared_ptr\u003CMenuComponent> find(name)",[1123,42862,42863],{},"so tên",[1123,42865,42866],{},"tìm trong các con",[981,42868,42870],{"id":42869},"bài-3-bản-an-toàn-và-hệ-thống-file-nâng-cao","Bài 3: Bản an toàn và hệ thống file (nâng cao)",[2273,42872,42873,42892],{},[989,42874,42875,42876,13568,42879,2461,42882,42884,42885,42888,42889,42891],{},"Viết lại theo kiểu ",[1487,42877,42878],{},"an toàn",[992,42880,42881],{},"add",[992,42883,24259],{}," chỉ có ở ",[992,42886,42887],{},"Menu",". Viết 1 dòng code gọi ",[992,42890,42881],{}," trên lá: bản an toàn không biên dịch được. Viết bảng so sánh 2 cách.",[989,42893,42894,42895,1509,42898,7423,42901,42904,42905,42907,42908,42911,42912,42914,42915,42918],{},"Mô hình thư mục: ",[992,42896,42897],{},"File(name, size)",[992,42899,42900],{},"Directory",[992,42902,42903],{},"du"," (tổng dung lượng), ",[992,42906,8152],{}," (in cây), ",[992,42909,42910],{},"findLarger(n)"," (các file lớn hơn ",[992,42913,1262],{}," byte). Đọc cây thư mục thật bằng ",[992,42916,42917],{},"std::filesystem"," để dựng Composite.",[981,42920,2711],{"id":2710},[986,42922,42924,42930,42936,42949],{"className":42923},[2715],[989,42925,42927,42929],{"className":42926},[2719],[2721,42928],{"disabled":2723,"type":2724}," Test mẫu pass, in cây đúng thứ tự và thụt lề.",[989,42931,42933,42935],{"className":42932},[2719],[2721,42934],{"disabled":2723,"type":2724}," Các hàm Bài 2 đúng trên cây 4 tầng.",[989,42937,42939,42941,42942,42944,42945,42948],{"className":42938},[2719],[2721,42940],{"disabled":2723,"type":2724}," Bài 3 có bảng trong suốt vs an toàn và ",[992,42943,42903],{}," khớp lệnh ",[992,42946,42947],{},"du -sb"," (sai số do metadata).",[989,42950,42952,42954,42955,42958],{"className":42951},[2719],[2721,42953],{"disabled":2723,"type":2724}," Client in cây mà không có ",[992,42956,42957],{},"dynamic_cast"," hay kiểm tra kiểu.",[968,42960,2890],{"id":2889},[986,42962,42963,42966,42969,42972],{},[989,42964,42965],{},"Định nghĩa Composite trong 1 câu là gì?",[989,42967,42968],{},"Cụm và lá khác nhau thế nào?",[989,42970,42971],{},"Trong suốt và an toàn khác nhau ở đâu?",[989,42973,42974],{},"Lệnh in lan xuống cây ra sao?",[3014,42976],{},[973,42978,42979],{},"🌕 Bạn đã hoàn thành ngày 67. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,42981,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":42983},[42984,42985,42990,42991,42997],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":42986},[42987,42988,42989],{"id":42576,"depth":73,"text":42577},{"id":42594,"depth":73,"text":42595},{"id":42612,"depth":73,"text":42613},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":42992},[42993,42994,42995,42996],{"id":42704,"depth":73,"text":42705},{"id":42798,"depth":73,"text":42799},{"id":42869,"depth":73,"text":42870},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Composite, thực đơn lồng thực đơn con, và đánh đổi giữa trong suốt dễ dùng với an toàn đúng kiểu.",{},[5194,8149],{"title":390,"description":42998},[43003,43004],"composite","menu-tree","zxCjj2FjgA4gtaKoWlKMdBntG7QwLUGwSCe5pwdeEXA",{"id":43007,"title":395,"body":43008,"category":5189,"day":398,"description":43340,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":43341,"navigation":2723,"outcomes":3047,"path":396,"prerequisites":43342,"seo":43343,"stem":397,"tags":43344,"__hash__":43345},"challenges\u002Fchallenges\u002F68.iterator-composite.md",{"type":965,"value":43009,"toc":43324},[43010,43012,43015,43017,43021,43035,43039,43053,43057,43071,43120,43122,43136,43138,43146,43150,43183,43195,43201,43205,43230,43243,43247,43268,43270,43301,43303,43317,43319,43322],[968,43011,971],{"id":970},[973,43013,43014],{},"Bài này học bộ duyệt ngoài cho cây thực đơn. Bạn dùng nó để lọc món chay mà không sửa cây.",[968,43016,979],{"id":978},[981,43018,43020],{"id":43019},"vì-sao-cần-iterator-ngoài","Vì sao cần Iterator ngoài",[986,43022,43023,43026,43029,43032],{},[989,43024,43025],{},"Gọi in đệ quy từ trong thì in hết, không lọc được.",[989,43027,43028],{},"Nhồi lọc vào cụm khiến cụm lo việc không phải của nó.",[989,43030,43031],{},"Cần bộ duyệt ngoài nhả từng món cho phục vụ tự quyết.",[989,43033,43034],{},"Ví dụ đời thường: như cần người dẫn tour chỉ từng phòng thay vì loa phát cả nhà.",[981,43036,43038],{"id":43037},"bộ-duyệt-ngăn-xếp","Bộ duyệt ngăn xếp",[986,43040,43041,43044,43047,43050],{},[989,43042,43043],{},"Giữ 1 ngăn các bộ duyệt con đang dang dở.",[989,43045,43046],{},"Lấy tiếp: lấy món kế trên đỉnh, gặp cụm thì đẩy bộ của nó vào.",[989,43048,43049],{},"Lượt đi sâu dần từng nhánh: hết nhánh này mới sang nhánh khác.",[989,43051,43052],{},"Ví dụ đời thường: như đi hết 1 dãy siêu thị rồi mới sang dãy khác.",[981,43054,43056],{"id":43055},"phục-vụ-dùng-bộ-duyệt","Phục vụ dùng bộ duyệt",[986,43058,43059,43062,43065,43068],{},[989,43060,43061],{},"Xin bộ duyệt từ thực đơn tổng rồi lặp hỏi còn không.",[989,43063,43064],{},"Mỗi món nhận được thì kiểm tra chay rồi in nếu đạt.",[989,43066,43067],{},"Phục vụ không cần biết cụm hay lá, cây sâu mấy tầng.",[989,43069,43070],{},"Mọi hiểu biết về cây nằm gọn trong bộ duyệt.",[1099,43072,43073,43085],{},[1102,43074,43075],{},[1105,43076,43077,43079,43082],{},[1108,43078,24466],{},[1108,43080,43081],{},"Duyệt trong",[1108,43083,43084],{},"Duyệt ngoài",[1118,43086,43087,43098,43109],{},[1105,43088,43089,43092,43095],{},[1123,43090,43091],{},"Ai điều khiển",[1123,43093,43094],{},"Cụm tự gọi con",[1123,43096,43097],{},"Người dùng hỏi từng bước",[1105,43099,43100,43103,43106],{},[1123,43101,43102],{},"Dừng giữa chừng",[1123,43104,43105],{},"Khó, chạy hết",[1123,43107,43108],{},"Dễ, ngừng hỏi là dừng",[1105,43110,43111,43114,43117],{},[1123,43112,43113],{},"Lọc theo ý",[1123,43115,43116],{},"Phải nhồi vào cụm",[1123,43118,43119],{},"Tự lọc khi nhận món",[968,43121,1433],{"id":1432},[986,43123,43124,43127,43130,43133],{},[989,43125,43126],{},"Input: duyệt toàn bộ cây 3 tầng. Output: mọi món ra đúng 1 lần, cha trước con.",[989,43128,43129],{},"Giải thích: ngăn xếp đảm bảo đi sâu dần theo thứ tự.",[989,43131,43132],{},"Input: lọc món chay trên cây. Output: chỉ món chay được in.",[989,43134,43135],{},"Giải thích: phục vụ kiểm tra từng món bộ duyệt nhả ra.",[968,43137,1482],{"id":1481},[973,43139,1485,43140,43142,43143,1517],{},[1487,43141,4800],{}," (hoặc Java). Dùng cây thực đơn ngày 67. Nộp vào ",[992,43144,43145],{},"day-068\u002F",[981,43147,43149],{"id":43148},"bài-1-compositeiterator-bằng-stack","Bài 1: CompositeIterator bằng stack",[1352,43151,43153],{"className":1393,"code":43152,"language":1395,"meta":1357,"style":1357},"class CompositeIterator : public Iterator\u003Cstd::shared_ptr\u003CMenuComponent>> {\n public:\n  explicit CompositeIterator(std::unique_ptr\u003CIterator\u003Cstd::shared_ptr\u003CMenuComponent>>> root);\n  bool hasNext() const override;\n  std::shared_ptr\u003CMenuComponent> next() override;   \u002F\u002F gặp Menu thì đẩy iterator của nó vào stack\n};\n",[992,43154,43155,43160,43164,43169,43174,43179],{"__ignoreMap":1357},[1023,43156,43157],{"class":1362,"line":63},[1023,43158,43159],{},"class CompositeIterator : public Iterator\u003Cstd::shared_ptr\u003CMenuComponent>> {\n",[1023,43161,43162],{"class":1362,"line":68},[1023,43163,4836],{},[1023,43165,43166],{"class":1362,"line":73},[1023,43167,43168],{},"  explicit CompositeIterator(std::unique_ptr\u003CIterator\u003Cstd::shared_ptr\u003CMenuComponent>>> root);\n",[1023,43170,43171],{"class":1362,"line":78},[1023,43172,43173],{},"  bool hasNext() const override;\n",[1023,43175,43176],{"class":1362,"line":83},[1023,43177,43178],{},"  std::shared_ptr\u003CMenuComponent> next() override;   \u002F\u002F gặp Menu thì đẩy iterator của nó vào stack\n",[1023,43180,43181],{"class":1362,"line":88},[1023,43182,4866],{},[973,43184,43185,15881,43188,43191,43192,16014],{},[992,43186,43187],{},"MenuItem::createIterator()",[992,43189,43190],{},"NullIterator"," (luôn ",[992,43193,43194],{},"hasNext() == false",[1352,43196,43199],{"className":43197,"code":43198,"language":2241,"meta":1357},[2239],"Duyệt cây ngày 67 -> mọi thành phần (cả Menu và MenuItem) ra đúng 1 lần, cha trước con\nSố phần tử duyệt được = countItems() + số Menu con\n",[992,43200,43198],{"__ignoreMap":1357},[981,43202,43204],{"id":43203},"bài-2-phục-vụ-lọc-món-chay","Bài 2: Phục vụ lọc món chay",[973,43206,43207,2252,43210,43213,43214,43217,43218,43221,43222,5034,43224,2252,43226,43229],{},[992,43208,43209],{},"Waitress::printVegetarianMenu()",[992,43211,43212],{},"CompositeIterator",". Chỉ gọi ",[992,43215,43216],{},"vegetarian()"," trên ",[992,43219,43220],{},"MenuItem",", bỏ qua ",[992,43223,42887],{},[1487,43225,41587],{},[992,43227,43228],{},"try\u002Fcatch"," làm luồng điều khiển.",[973,43231,43232,43233,1509,43236,43239,43240,1517],{},"Thêm 2 bộ lọc: ",[992,43234,43235],{},"printCheaperThan(double)",[992,43237,43238],{},"printByKeyword(std::string)",". Cả 3 hàm dùng chung 1 hàm duyệt nhận ",[992,43241,43242],{},"std::function\u003Cbool(const MenuItem&)>",[981,43244,43246],{"id":43245},"bài-3-duyệt-theo-chiều-rộng-và-duyệt-lười-nâng-cao","Bài 3: Duyệt theo chiều rộng và duyệt lười (nâng cao)",[2273,43248,43249,43255,43265],{},[989,43250,1505,43251,43254],{},[992,43252,43253],{},"BreadthFirstIterator"," dùng queue. In thứ tự của 2 iterator trên cùng cây, chỉ ra khác biệt.",[989,43256,43257,43258,18407,43261,43264],{},"Viết bản duyệt bằng ",[1487,43259,43260],{},"C++20 coroutine",[992,43262,43263],{},"std::generator"," nếu có, hoặc tự viết generator tối giản), hoặc bằng generator Python nếu làm Python. So số dòng với bản stack.",[989,43266,43267],{},"Sửa cây (thêm món) trong lúc đang duyệt. Quyết định hành vi: ném lỗi hay bỏ qua. Viết test.",[981,43269,2711],{"id":2710},[986,43271,43273,43279,43285,43291],{"className":43272},[2715],[989,43274,43276,43278],{"className":43275},[2719],[2721,43277],{"disabled":2723,"type":2724}," Test số phần tử duyệt được pass.",[989,43280,43282,43284],{"className":43281},[2719],[2721,43283],{"disabled":2723,"type":2724}," 3 bộ lọc dùng chung 1 hàm duyệt.",[989,43286,43288,43290],{"className":43287},[2719],[2721,43289],{"disabled":2723,"type":2724}," In được 2 thứ tự DFS và BFS trên cùng cây.",[989,43292,43294,43296,43297,43300],{"className":43293},[2719],[2721,43295],{"disabled":2723,"type":2724}," Giải thích được vì sao iterator ngoài cho phép lọc còn ",[992,43298,43299],{},"print()"," đệ quy thì không.",[968,43302,2890],{"id":2889},[986,43304,43305,43308,43311,43314],{},[989,43306,43307],{},"Vì sao cây Composite cần Iterator ngoài?",[989,43309,43310],{},"Ngăn xếp giúp đi sâu dần thế nào?",[989,43312,43313],{},"Phục vụ lọc chay mà không biết cây ra sao?",[989,43315,43316],{},"Duyệt trong và ngoài khác nhau ở điểm nào?",[3014,43318],{},[973,43320,43321],{},"🌕 Bạn đã hoàn thành ngày 68. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,43323,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":43325},[43326,43327,43332,43333,43339],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":43328},[43329,43330,43331],{"id":43019,"depth":73,"text":43020},{"id":43037,"depth":73,"text":43038},{"id":43055,"depth":73,"text":43056},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":43334},[43335,43336,43337,43338],{"id":43148,"depth":73,"text":43149},{"id":43203,"depth":73,"text":43204},{"id":43245,"depth":73,"text":43246},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bộ duyệt ngoài cho cây thực đơn, ngăn xếp duyệt sâu dần, và sức mạnh khi hai pattern cộng hưởng.",{},[8149,5194],{"title":395,"description":43340},[28100,43003],"8QVwR2EWTbomfDw-DBWz12KMzImu_cRX2SDPYFkXcRM",{"id":43347,"title":400,"body":43348,"category":8797,"day":403,"description":43941,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":43942,"navigation":2723,"outcomes":3047,"path":401,"prerequisites":43943,"seo":43944,"stem":402,"tags":43945,"__hash__":43948},"challenges\u002Fchallenges\u002F69.kd-tree-nang-cao.md",{"type":965,"value":43349,"toc":43924},[43350,43352,43355,43357,43361,43375,43379,43393,43413,43417,43431,43435,43449,43451,43465,43467,43478,43482,43745,43751,43754,43758,43773,43779,43783,43851,43857,43865,43867,43901,43903,43917,43919,43922],[968,43351,971],{"id":970},[973,43353,43354],{},"Bài này học xóa nút và tìm lân cận trên k-d tree. Bạn dùng nó để tìm điểm gần nhất và điểm trong vùng.",[968,43356,979],{"id":978},[981,43358,43360],{"id":43359},"xóa-nút","Xóa nút",[986,43362,43363,43366,43369,43372],{},[989,43364,43365],{},"Xóa lá thì gỡ thẳng là xong.",[989,43367,43368],{},"Xóa nút trong phải tìm vật thay thế giữ đúng chiều chia.",[989,43370,43371],{},"Vật thay thế có thể nằm sâu ở nhánh bất kỳ.",[989,43373,43374],{},"Ví dụ đời thường: như rút 1 quản lý giữa, phải tìm người hợp đúng chuyên môn thay vào.",[981,43376,43378],{"id":43377},"lân-cận-gần-nhất","Lân cận gần nhất",[986,43380,43381,43384,43387,43390],{},[989,43382,43383],{},"Đi xuống như tìm điểm để có ứng viên tốt ngay.",[989,43385,43386],{},"Khi quay lui, kiểm tra quả cầu quanh điểm hỏi có cắt mặt chia không.",[989,43388,43389],{},"Không cắt thì cắt cả nhánh bên kia cho nhanh.",[989,43391,43392],{},"Ví dụ đời thường: như tìm quán gần nhất, xa hơn quán đã thấy thì bỏ cả khu đó.",[1352,43394,43396],{"className":3538,"code":43395,"language":3540,"meta":1357,"style":1357},"# Ý tưởng cắt tỉa lân cận\n# best = ứng viên tốt nhất hiện tại\n# nếu khoảng_cách(tới mặt chia) > best: bỏ cả nhánh bên kia\n",[992,43397,43398,43403,43408],{"__ignoreMap":1357},[1023,43399,43400],{"class":1362,"line":63},[1023,43401,43402],{},"# Ý tưởng cắt tỉa lân cận\n",[1023,43404,43405],{"class":1362,"line":68},[1023,43406,43407],{},"# best = ứng viên tốt nhất hiện tại\n",[1023,43409,43410],{"class":1362,"line":73},[1023,43411,43412],{},"# nếu khoảng_cách(tới mặt chia) > best: bỏ cả nhánh bên kia\n",[981,43414,43416],{"id":43415},"tìm-kiếm-vùng","Tìm kiếm vùng",[986,43418,43419,43422,43425,43428],{},[989,43420,43421],{},"Cho hình chữ nhật, trả về mọi điểm nằm trong.",[989,43423,43424],{},"Mỗi nút nhớ hộp bao của cây con mình.",[989,43426,43427],{},"Hộp nằm gọn trong truy vấn thì lấy cả cây con.",[989,43429,43430],{},"Hộp rời hẳn truy vấn thì cắt cả cây con.",[981,43432,43434],{"id":43433},"độ-phức-tạp-và-giới-hạn","Độ phức tạp và giới hạn",[986,43436,43437,43440,43443,43446],{},[989,43438,43439],{},"Trung bình logarit nhờ cắt tỉa tốt.",[989,43441,43442],{},"Xấu nhất tuyến tính khi quả cầu nuốt cả cây.",[989,43444,43445],{},"Chiều càng cao càng khó cắt nhánh.",[989,43447,43448],{},"Dữ liệu động ghi nhiều thì nên tái xây định kỳ.",[968,43450,1433],{"id":1432},[986,43452,43453,43456,43459,43462],{},[989,43454,43455],{},"Input: hỏi lân cận của điểm đã có trong cây. Output: chính nó, khoảng cách 0.",[989,43457,43458],{},"Giải thích: không điểm nào gần hơn chính mình.",[989,43460,43461],{},"Input: vùng bao toàn bộ dữ liệu. Output: trả về đúng n điểm.",[989,43463,43464],{},"Giải thích: mọi hộp đều giao nên phải thăm hết.",[968,43466,1482],{"id":1481},[973,43468,1485,43469,19847,43471,43474,43475,1517],{},[1487,43470,1493],{},[992,43472,43473],{},"KDTree\u003CK>"," ngày 45. Nộp vào ",[992,43476,43477],{},"day-069\u002F",[981,43479,43481],{"id":43480},"bài-1-nearest-neighbor-và-k-nn","Bài 1: Nearest neighbor và k-NN",[1099,43483,43484,43492],{},[1102,43485,43486],{},[1105,43487,43488,43490],{},[1108,43489,1566],{},[1108,43491,2547],{},[1118,43493,43494,43722,43735],{},[1105,43495,43496,43501],{},[1123,43497,43498],{},[992,43499,43500],{},"Point nearest(const Point &q) const",[1123,43502,43503,43504],{},"Đi xuống trước, quay lui, cắt nhánh khi ",[1023,43505,43507,43573],{"className":43506},[1026],[1023,43508,43510],{"className":43509},[1030],[1032,43511,43512],{"xmlns":1034},[1036,43513,43514,43570],{},[1039,43515,43516,43518,43521,43523,43525,43527,43529,43531,43533,43535,43537,43539,43541,43543,43545,43547,43549,43555,43558,43560,43562,43564],{},[1046,43517,1049],{"stretchy":1048},[1042,43519,43520],{},"q",[1046,43522,14806],{"stretchy":1048},[1042,43524,6207],{},[1042,43526,3904],{},[1042,43528,1837],{},[1042,43530,29577],{},[1046,43532,14817],{"stretchy":1048},[1046,43534,17698],{},[1042,43536,973],{},[1046,43538,14806],{"stretchy":1048},[1042,43540,6207],{},[1042,43542,3904],{},[1042,43544,1837],{},[1042,43546,29577],{},[1046,43548,14817],{"stretchy":1048},[2327,43550,43551,43553],{},[1046,43552,1056],{"stretchy":1048},[1051,43554,2457],{},[1046,43556,43557],{},"≥",[1042,43559,17703],{},[1042,43561,24035],{},[1042,43563,29577],{},[2327,43565,43566,43568],{},[1042,43567,29580],{},[1051,43569,2457],{},[1058,43571,43572],{"encoding":1060},"(q[axis] - p[axis])^2 \\ge best^2",[1023,43574,43576,43615,43680],{"className":43575,"ariaHidden":1066},[1065],[1023,43577,43579,43582,43585,43588,43591,43594,43597,43600,43603,43606,43609,43612],{"className":43578},[1070],[1023,43580],{"className":43581,"style":1075},[1074],[1023,43583,1049],{"className":43584},[1085],[1023,43586,43520],{"className":43587,"style":7723},[1079,1080],[1023,43589,14806],{"className":43590},[1085],[1023,43592,6207],{"className":43593},[1079,1080],[1023,43595,3904],{"className":43596},[1079,1080],[1023,43598,1837],{"className":43599},[1079,1080],[1023,43601,29577],{"className":43602},[1079,1080],[1023,43604,14817],{"className":43605},[1092],[1023,43607],{"className":43608,"style":13790},[2354],[1023,43610,17698],{"className":43611},[13794],[1023,43613],{"className":43614,"style":13790},[2354],[1023,43616,43618,43621,43624,43627,43630,43633,43636,43639,43642,43671,43674,43677],{"className":43617},[1070],[1023,43619],{"className":43620,"style":2476},[1074],[1023,43622,973],{"className":43623},[1079,1080],[1023,43625,14806],{"className":43626},[1085],[1023,43628,6207],{"className":43629},[1079,1080],[1023,43631,3904],{"className":43632},[1079,1080],[1023,43634,1837],{"className":43635},[1079,1080],[1023,43637,29577],{"className":43638},[1079,1080],[1023,43640,14817],{"className":43641},[1092],[1023,43643,43645,43648],{"className":43644},[1092],[1023,43646,1056],{"className":43647},[1092],[1023,43649,43651],{"className":43650},[2383],[1023,43652,43654],{"className":43653},[2387],[1023,43655,43657],{"className":43656},[2391],[1023,43658,43660],{"className":43659,"style":2369},[2395],[1023,43661,43662,43665],{"style":2398},[1023,43663],{"className":43664,"style":2403},[2402],[1023,43666,43668],{"className":43667},[2407,2408,2409,2410],[1023,43669,2457],{"className":43670},[1079,2410],[1023,43672],{"className":43673,"style":2355},[2354],[1023,43675,43557],{"className":43676},[2359],[1023,43678],{"className":43679,"style":2355},[2354],[1023,43681,43683,43686,43689,43693],{"className":43682},[1070],[1023,43684],{"className":43685,"style":2369},[1074],[1023,43687,17703],{"className":43688},[1079,1080],[1023,43690,43692],{"className":43691},[1079,1080],"es",[1023,43694,43696,43699],{"className":43695},[1079],[1023,43697,29580],{"className":43698},[1079,1080],[1023,43700,43702],{"className":43701},[2383],[1023,43703,43705],{"className":43704},[2387],[1023,43706,43708],{"className":43707},[2391],[1023,43709,43711],{"className":43710,"style":2369},[2395],[1023,43712,43713,43716],{"style":2398},[1023,43714],{"className":43715,"style":2403},[2402],[1023,43717,43719],{"className":43718},[2407,2408,2409,2410],[1023,43720,2457],{"className":43721},[1079,2410],[1105,43723,43724,43729],{},[1123,43725,43726],{},[992,43727,43728],{},"std::vector\u003CPoint> kNearest(const Point &q, int k) const",[1123,43730,43731,43732,43734],{},"Max-heap cỡ ",[992,43733,4022],{},", cắt nhánh theo khoảng cách lớn nhất trong heap",[1105,43736,43737,43742],{},[1123,43738,43739],{},[992,43740,43741],{},"int lastVisited",[1123,43743,43744],{},"Số nút đã thăm ở truy vấn gần nhất",[1352,43746,43749],{"className":43747,"code":43748,"language":2241,"meta":1357},[2239],"7 điểm ngày 45, q=(9,2)       -> nearest (8,1)\nkNearest((5,5), 3)            -> (6,5), (5,4), (4,7)   (sắp theo khoảng cách)\nk > n                         -> trả hết n điểm\n",[992,43750,43748],{"__ignoreMap":1357},[973,43752,43753],{},"Kiểm tra với 10.000 truy vấn ngẫu nhiên: kết quả khớp quét tuyến tính.",[981,43755,43757],{"id":43756},"bài-2-xóa-điểm","Bài 2: Xóa điểm",[973,43759,43760,43763,43764,43766,43767,2308,43769,43772],{},[992,43761,43762],{},"bool remove(const Point &p)",": nút lá gỡ thẳng. Nút trong chia theo trục ",[992,43765,6207],{},": tìm điểm có tọa độ ",[992,43768,6207],{},[1487,43770,43771],{},"nhỏ nhất"," trong cây con phải, chép lên, xóa đệ quy điểm đó. Nếu không có cây con phải, tìm min trong cây con trái rồi chuyển cây con trái thành cây con phải.",[1352,43774,43777],{"className":43775,"code":43776,"language":2241,"meta":1357},[2239],"Xóa gốc của cây 7 điểm -> checkInvariant = true, còn 6 điểm\nXóa 50% trong 10^4 điểm ngẫu nhiên -> checkInvariant = true, nearest vẫn khớp quét tuyến tính\n",[992,43778,43776],{"__ignoreMap":1357},[981,43780,43782],{"id":43781},"bài-3-lời-nguyền-số-chiều-nâng-cao","Bài 3: Lời nguyền số chiều (nâng cao)",[973,43784,23993,43785,43788,43789,43850],{},[992,43786,43787],{},"K = 2, 4, 8, 16, 32",", dựng cây từ ",[1023,43790,43792,43809],{"className":43791},[1026],[1023,43793,43795],{"className":43794},[1030],[1032,43796,43797],{"xmlns":1034},[1036,43798,43799,43807],{},[1039,43800,43801],{},[2327,43802,43803,43805],{},[1051,43804,2331],{},[1051,43806,2334],{},[1058,43808,32773],{"encoding":1060},[1023,43810,43812],{"className":43811,"ariaHidden":1066},[1065],[1023,43813,43815,43818,43821],{"className":43814},[1070],[1023,43816],{"className":43817,"style":2369},[1074],[1023,43819,1053],{"className":43820},[1079],[1023,43822,43824,43827],{"className":43823},[1079],[1023,43825,2379],{"className":43826},[1079],[1023,43828,43830],{"className":43829},[2383],[1023,43831,43833],{"className":43832},[2387],[1023,43834,43836],{"className":43835},[2391],[1023,43837,43839],{"className":43838,"style":2369},[2395],[1023,43840,43841,43844],{"style":2398},[1023,43842],{"className":43843,"style":2403},[2402],[1023,43845,43847],{"className":43846},[2407,2408,2409,2410],[1023,43848,2334],{"className":43849},[1079,2410]," điểm ngẫu nhiên đều. Chạy 1000 truy vấn nearest.",[1352,43852,43855],{"className":43853,"code":43854,"language":2241,"meta":1357},[2239],"K     avg_visited    tỉ_lệ_thăm (\u002Fn)    tốc_độ_so_với_quét\n2     ...\n32    ...\n",[992,43856,43854],{"__ignoreMap":1357},[973,43858,35212,43859,10052,43862,43864],{},[992,43860,43861],{},"avg_visited",[992,43863,20401],{},". Viết 3 câu giải thích vì sao ở chiều cao k-d tree gần như phải thăm hết cây.",[981,43866,2711],{"id":2710},[986,43868,43870,43881,43889,43895],{"className":43869},[2715],[989,43871,43873,2308,43875,1509,43877,43880],{"className":43872},[2719],[2721,43874],{"disabled":2723,"type":2724},[992,43876,33345],{},[992,43878,43879],{},"kNearest"," khớp quét tuyến tính trên 10.000 truy vấn.",[989,43882,43884,2308,43886,43888],{"className":43883},[2719],[2721,43885],{"disabled":2723,"type":2724},[992,43887,24259],{}," giữ bất biến sau 5000 lần xóa.",[989,43890,43892,43894],{"className":43891},[2719],[2721,43893],{"disabled":2723,"type":2724}," Bảng Bài 3 có số thật và hình vẽ.",[989,43896,43898,43900],{"className":43897},[2719],[2721,43899],{"disabled":2723,"type":2724}," Giải thích được điều kiện cắt nhánh bằng hình vẽ tay.",[968,43902,2890],{"id":2889},[986,43904,43905,43908,43911,43914],{},[989,43906,43907],{},"Xóa nút trong k-d tree khó ở đâu?",[989,43909,43910],{},"Cắt tỉa lân cận dựa vào gì?",[989,43912,43913],{},"Tìm kiếm vùng cắt nhánh thế nào?",[989,43915,43916],{},"Khi nào k-d tree suy biến thành duyệt hết?",[3014,43918],{},[973,43920,43921],{},"🌕 Bạn đã hoàn thành ngày 69. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,43923,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":43925},[43926,43927,43933,43934,43940],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":43928},[43929,43930,43931,43932],{"id":43359,"depth":73,"text":43360},{"id":43377,"depth":73,"text":43378},{"id":43415,"depth":73,"text":43416},{"id":43433,"depth":73,"text":43434},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":43935},[43936,43937,43938,43939],{"id":43480,"depth":73,"text":43481},{"id":43756,"depth":73,"text":43757},{"id":43781,"depth":73,"text":43782},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Truy vấn nâng cao trên cây k-d: xóa nút, lân cận gần nhất bằng cắt tỉa siêu cầu, tìm kiếm vùng và bảng tổng kết mọi phương thức.",{},[3050],{"title":400,"description":43941},[33130,43946,43947],"nearest-neighbor","region-search","VThN0HAVWp4KF1bHcEYfIuRns8VhzNDR0358v2urGzI",{"id":43950,"title":405,"body":43951,"category":3041,"day":408,"description":44309,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":44310,"navigation":2723,"outcomes":3047,"path":406,"prerequisites":44311,"seo":44312,"stem":407,"tags":44313,"__hash__":44315},"challenges\u002Fchallenges\u002F70.nn-search-va-rtree.md",{"type":965,"value":43952,"toc":44292},[43953,43955,43958,43960,43964,43978,43982,43996,44000,44014,44018,44032,44034,44048,44050,44061,44065,44128,44134,44138,44181,44199,44205,44209,44230,44232,44269,44271,44285,44287,44290],[968,43954,971],{"id":970},[973,43956,43957],{},"Bài này học R-tree từ ý tưởng cây B. Bạn dùng nó để tìm điểm bản đồ khi dữ liệu đổi liên tục.",[968,43959,979],{"id":978},[981,43961,43963],{"id":43962},"vì-sao-cần-r-tree","Vì sao cần R-tree",[986,43965,43966,43969,43972,43975],{},[989,43967,43968],{},"Duyệt hết mỗi truy vấn là không tưởng với dữ liệu lớn.",[989,43970,43971],{},"K-d tree đuối ở chiều cao và dữ liệu động.",[989,43973,43974],{},"Cần cây luôn cân bằng như cây B nhưng cho nhiều chiều.",[989,43976,43977],{},"Ví dụ đời thường: như cần tủ hồ sơ tự cân, thêm bớt vẫn gọn.",[981,43979,43981],{"id":43980},"ôn-cây-b","Ôn cây B",[986,43983,43984,43987,43990,43993],{},[989,43985,43986],{},"Mọi lá cùng độ sâu nên cây luôn cân bằng.",[989,43988,43989],{},"Nút tràn thì tách và đẩy khóa giữa lên cha.",[989,43991,43992],{},"Tách gộp cục bộ, không cần xoay phức tạp.",[989,43994,43995],{},"R-tree giữ cơ chế này, chỉ thay khóa số bằng hộp không gian.",[981,43997,43999],{"id":43998},"hộp-bao-mbr-và-chèn-điểm","Hộp bao MBR và chèn điểm",[986,44001,44002,44005,44008,44011],{},[989,44003,44004],{},"Mỗi nút lưu hộp chữ nhật bao trọn mọi con của nó.",[989,44006,44007],{},"Các hộp anh em được phép giao nhau.",[989,44009,44010],{},"Chèn: chọn nhánh phải nới ít diện tích nhất rồi đi xuống lá.",[989,44012,44013],{},"Nút tràn thì tách sao cho tổng diện tích 2 hộp mới nhỏ nhất.",[981,44015,44017],{"id":44016},"tìm-kiếm-và-giới-hạn","Tìm kiếm và giới hạn",[986,44019,44020,44023,44026,44029],{},[989,44021,44022],{},"Chỉ lặn vào con có hộp giao với miền hỏi.",[989,44024,44025],{},"Lân cận: thăm hộp gần trước để có ứng viên tốt sớm.",[989,44027,44028],{},"Hộp chồng chéo nặng thì phải lặn nhiều nhánh nên chậm.",[989,44030,44031],{},"Ví dụ đời thường: như tìm nhà trong nhiều khu vực chồng lấn phải gõ nhiều cửa.",[968,44033,1433],{"id":1432},[986,44035,44036,44039,44042,44045],{},[989,44037,44038],{},"Input: chèn điểm mới vào R-tree. Output: các hộp cha nới ra vừa đủ bao điểm.",[989,44040,44041],{},"Giải thích: bất biến hộp cha luôn bao trọn con.",[989,44043,44044],{},"Input: truy vấn vùng chỉ giao 1 nhánh. Output: chỉ thăm nhánh đó, cắt nhánh còn lại.",[989,44046,44047],{},"Giải thích: hộp không giao thì cả cây con không thể chứa đáp án.",[968,44049,1482],{"id":1481},[973,44051,1485,44052,5599,44054,44057,44058,1517],{},[1487,44053,1493],{},[992,44055,44056],{},"day-070\u002F",". Làm việc với hình chữ nhật 2D ",[992,44059,44060],{},"Rect { double x1, y1, x2, y2; }",[981,44062,44064],{"id":44063},"bài-1-hàm-hình-học-cho-r-tree","Bài 1: Hàm hình học cho R-tree",[1099,44066,44067,44075],{},[1102,44068,44069],{},[1105,44070,44071,44073],{},[1108,44072,1566],{},[1108,44074,2547],{},[1118,44076,44077,44086,44096,44108,44118],{},[1105,44078,44079,44084],{},[1123,44080,44081],{},[992,44082,44083],{},"double area(Rect)",[1123,44085],{},[1105,44087,44088,44093],{},[1123,44089,44090],{},[992,44091,44092],{},"Rect combine(Rect a, Rect b)",[1123,44094,44095],{},"Hộp nhỏ nhất bao cả 2",[1105,44097,44098,44103],{},[1123,44099,44100],{},[992,44101,44102],{},"double enlargement(Rect box, Rect add)",[1123,44104,44105],{},[992,44106,44107],{},"area(combine) - area(box)",[1105,44109,44110,44115],{},[1123,44111,44112],{},[992,44113,44114],{},"bool intersects(Rect a, Rect b)",[1123,44116,44117],{},"Chạm cạnh tính là giao",[1105,44119,44120,44125],{},[1123,44121,44122],{},[992,44123,44124],{},"double minDist(Rect r, Point p)",[1123,44126,44127],{},"Khoảng cách nhỏ nhất từ điểm tới hộp, bằng 0 nếu điểm nằm trong",[1352,44129,44132],{"className":44130,"code":44131,"language":2241,"meta":1357},[2239],"combine({0,0,1,1}, {2,2,3,3}) -> {0,0,3,3}\nenlargement({0,0,2,2}, {1,1,3,3}) -> 5\nminDist({0,0,1,1}, (3,1)) -> 2\n",[992,44133,44131],{"__ignoreMap":1357},[981,44135,44137],{"id":44136},"bài-2-r-tree-chèn-và-truy-vấn-vùng","Bài 2: R-tree chèn và truy vấn vùng",[1352,44139,44141],{"className":1393,"code":44140,"language":1395,"meta":1357,"style":1357},"class RTree {\n public:\n  RTree(int M = 8, int m = 3);            \u002F\u002F tối đa M, tối thiểu m mục mỗi nút\n  void insert(const Rect &r, int id);\n  std::vector\u003Cint> search(const Rect &q) const;\n  int height() const;\n  bool check() const;   \u002F\u002F mọi lá cùng độ sâu, hộp cha bao trọn hộp con, số mục trong [m, M] trừ gốc\n};\n",[992,44142,44143,44148,44152,44157,44162,44167,44172,44177],{"__ignoreMap":1357},[1023,44144,44145],{"class":1362,"line":63},[1023,44146,44147],{},"class RTree {\n",[1023,44149,44150],{"class":1362,"line":68},[1023,44151,4836],{},[1023,44153,44154],{"class":1362,"line":73},[1023,44155,44156],{},"  RTree(int M = 8, int m = 3);            \u002F\u002F tối đa M, tối thiểu m mục mỗi nút\n",[1023,44158,44159],{"class":1362,"line":78},[1023,44160,44161],{},"  void insert(const Rect &r, int id);\n",[1023,44163,44164],{"class":1362,"line":83},[1023,44165,44166],{},"  std::vector\u003Cint> search(const Rect &q) const;\n",[1023,44168,44169],{"class":1362,"line":88},[1023,44170,44171],{},"  int height() const;\n",[1023,44173,44174],{"class":1362,"line":93},[1023,44175,44176],{},"  bool check() const;   \u002F\u002F mọi lá cùng độ sâu, hộp cha bao trọn hộp con, số mục trong [m, M] trừ gốc\n",[1023,44178,44179],{"class":1362,"line":98},[1023,44180,4866],{},[986,44182,44183,44189,44196],{},[989,44184,44185,44188],{},[992,44186,44187],{},"chooseLeaf",": chọn con cần nới diện tích ít nhất, hòa thì chọn hộp nhỏ hơn.",[989,44190,44191,44192,44195],{},"Tách nút tràn bằng ",[1487,44193,44194],{},"quadratic split"," (Guttman).",[989,44197,44198],{},"Tách lan lên gốc thì tạo gốc mới.",[1352,44200,44203],{"className":44201,"code":44202,"language":2241,"meta":1357},[2239],"Chèn 10^4 hộp nhỏ ngẫu nhiên -> check = true\nsearch khớp quét tuyến tính trên 1000 truy vấn\n",[992,44204,44202],{"__ignoreMap":1357},[981,44206,44208],{"id":44207},"bài-3-nearest-neighbor-trên-r-tree-nâng-cao","Bài 3: Nearest neighbor trên R-tree (nâng cao)",[2273,44210,44211,44221,44224],{},[989,44212,44213,44216,44217,44220],{},[992,44214,44215],{},"int nearest(Point p)",": best-first search, dùng min-heap theo ",[992,44218,44219],{},"minDist"," của hộp. Dừng khi phần tử đầu heap xa hơn đáp án tốt nhất.",[989,44222,44223],{},"Dữ liệu: 50.000 cửa hàng (điểm = hộp suy biến). So thời gian với k-d tree ngày 69 và quét tuyến tính.",[989,44225,44226,44227,1517],{},"Đếm số nút thăm trung bình. Thử ",[992,44228,44229],{},"M = 4, 8, 16, 32",[981,44231,2711],{"id":2710},[986,44233,44235,44241,44250,44260],{"className":44234},[2715],[989,44236,44238,44240],{"className":44237},[2719],[2721,44239],{"disabled":2723,"type":2724}," Test hàm hình học pass.",[989,44242,44244,2308,44246,44249],{"className":44243},[2719],[2721,44245],{"disabled":2723,"type":2724},[992,44247,44248],{},"check()"," đúng sau 10^4 lần chèn.",[989,44251,44253,2308,44255,1509,44257,44259],{"className":44252},[2719],[2721,44254],{"disabled":2723,"type":2724},[992,44256,27027],{},[992,44258,33345],{}," khớp quét tuyến tính.",[989,44261,44263,44265,44266,37083],{"className":44262},[2719],[2721,44264],{"disabled":2723,"type":2724}," Bảng thời gian theo ",[992,44267,44268],{},"M",[968,44270,2890],{"id":2889},[986,44272,44273,44276,44279,44282],{},[989,44274,44275],{},"R-tree khác k-d tree ở điểm nào?",[989,44277,44278],{},"Hộp bao MBR là gì?",[989,44280,44281],{},"Chèn tràn thì tách nút thế nào?",[989,44283,44284],{},"Khi nào hộp chồng chéo làm truy vấn chậm?",[3014,44286],{},[973,44288,44289],{},"🌕 Bạn đã hoàn thành ngày 70. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,44291,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":44293},[44294,44295,44301,44302,44308],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":44296},[44297,44298,44299,44300],{"id":43962,"depth":73,"text":43963},{"id":43980,"depth":73,"text":43981},{"id":43998,"depth":73,"text":43999},{"id":44016,"depth":73,"text":44017},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":44303},[44304,44305,44306,44307],{"id":44063,"depth":73,"text":44064},{"id":44136,"depth":73,"text":44137},{"id":44207,"depth":73,"text":44208},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Từ cây B tới R-tree lập chỉ mục không gian: chèn điểm, tách nút tràn, tìm kiếm và con đường tới cây tương đồng SS-tree.",{},[3050,14055],{"title":405,"description":44309},[33721,44314,33131],"r-tree","btq1-XDDRMc3HyBB_sbgMxhGLeHTq_cnsbzZWLfHb3w",{"id":44317,"title":410,"body":44318,"category":5189,"day":413,"description":44777,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":44778,"navigation":2723,"outcomes":3047,"path":411,"prerequisites":44779,"seo":44780,"stem":412,"tags":44781,"__hash__":44783},"challenges\u002Fchallenges\u002F71.decorator-io.md",{"type":965,"value":44319,"toc":44760},[44320,44322,44325,44327,44331,44345,44349,44363,44412,44416,44430,44434,44448,44450,44470,44472,44483,44487,44539,44622,44628,44632,44640,44662,44666,44706,44708,44737,44739,44753,44755,44758],[968,44321,971],{"id":970},[973,44323,44324],{},"Bài này học Decorator trong thư viện đọc file. Bạn dùng nó để chồng tầng đệm và đếm dòng.",[968,44326,979],{"id":978},[981,44328,44330],{"id":44329},"luồng-chuẩn-là-decorator","Luồng chuẩn là Decorator",[986,44332,44333,44336,44339,44342],{},[989,44334,44335],{},"Lõi là luồng đọc thô từ file hay bộ nhớ.",[989,44337,44338],{},"Quanh lõi là các tầng: đệm, đếm dòng, đọc kiểu, nén.",[989,44340,44341],{},"Mọi mắt xích đều là luồng nên bọc lẫn nhau được.",[989,44343,44344],{},"Ví dụ đời thường: như ống nước nối thêm đầu lọc, lõi vẫn là ống.",[981,44346,44348],{"id":44347},"đường-đi-yêu-cầu-đọc","Đường đi yêu cầu đọc",[986,44350,44351,44354,44357,44360],{},[989,44352,44353],{},"Tầng ngoài nhận đọc 1 ký tự thì hỏi tầng trong.",[989,44355,44356],{},"Tầng đệm còn hàng thì trả ngay, hết thì hỏi lõi file.",[989,44358,44359],{},"Mỗi tầng chỉ làm đúng việc mình rồi ủy thác phần còn lại.",[989,44361,44362],{},"Ví dụ đời thường: như hỏi kho, kho hết mới hỏi nhà máy.",[1099,44364,44365,44377],{},[1102,44366,44367],{},[1105,44368,44369,44371,44374],{},[1108,44370,24466],{},[1108,44372,44373],{},"Cà phê Starbuzz",[1108,44375,44376],{},"Luồng vào-ra",[1118,44378,44379,44390,44401],{},[1105,44380,44381,44384,44387],{},[1123,44382,44383],{},"Lõi",[1123,44385,44386],{},"Đồ uống nền",[1123,44388,44389],{},"Luồng đọc thô",[1105,44391,44392,44395,44398],{},[1123,44393,44394],{},"Lớp bọc",[1123,44396,44397],{},"Sữa kem",[1123,44399,44400],{},"Đệm đếm dòng nén",[1105,44402,44403,44406,44409],{},[1123,44404,44405],{},"Thêm mới",[1123,44407,44408],{},"Topping mới",[1123,44410,44411],{},"Tầng đọc mới",[981,44413,44415],{"id":44414},"thứ-tự-bọc","Thứ tự bọc",[986,44417,44418,44421,44424,44427],{},[989,44419,44420],{},"Cà phê đổi thứ tự topping giá vẫn vậy.",[989,44422,44423],{},"Luồng đổi thứ tự có thể sai: giải nén phải nằm trong đọc kiểu.",[989,44425,44426],{},"Người chồng tầng phải hiểu ngữ nghĩa từng tầng.",[989,44428,44429],{},"Ghi rõ thứ tự và lý do trong tài liệu.",[981,44431,44433],{"id":44432},"tự-viết-tầng-chữ-thường","Tự viết tầng chữ thường",[986,44435,44436,44439,44442,44445],{},[989,44437,44438],{},"Lớp mới cũng là luồng nên dùng ở mọi nơi cần luồng.",[989,44440,44441],{},"Giữ 1 luồng bên trong, đọc ký tự về rồi đổi hoa thành thường.",[989,44443,44444],{},"Không sửa thư viện cũ, chỉ thêm mắt xích mới.",[989,44446,44447],{},"Chồng nhiều tầng quá thì khó debug và khó đọc.",[968,44449,1433],{"id":1432},[986,44451,44452,44455,44458,44467],{},[989,44453,44454],{},"Input: đọc file qua tầng đệm. Output: đúng từng ký tự, ít lần chạm đĩa hơn.",[989,44456,44457],{},"Giải thích: kho đệm trả ngay khi còn hàng.",[989,44459,9878,44460,44463,44464,1517],{},[992,44461,44462],{},"HeLLo"," qua tầng chữ thường. Output: ",[992,44465,44466],{},"hello",[989,44468,44469],{},"Giải thích: chữ hoa bị đổi, chữ thường và ký tự khác giữ nguyên.",[968,44471,1482],{"id":1481},[973,44473,1485,44474,44476,44477,3568,44480,1517],{},[1487,44475,4800],{}," (hoặc Java với ",[992,44478,44479],{},"FilterInputStream",[992,44481,44482],{},"day-071\u002F",[981,44484,44486],{"id":44485},"bài-1-chuỗi-luồng-đọc","Bài 1: Chuỗi luồng đọc",[1352,44488,44490],{"className":1393,"code":44489,"language":1395,"meta":1357,"style":1357},"class InputStream {\n public:\n  virtual int read() = 0;                   \u002F\u002F trả byte 0..255, hết dữ liệu trả -1\n  virtual ~InputStream() = default;\n};\nclass FilterInputStream : public InputStream {\n protected: std::unique_ptr\u003CInputStream> in;\n public: explicit FilterInputStream(std::unique_ptr\u003CInputStream> in);\n  int read() override { return in->read(); }\n};\n",[992,44491,44492,44497,44501,44506,44511,44515,44520,44525,44530,44535],{"__ignoreMap":1357},[1023,44493,44494],{"class":1362,"line":63},[1023,44495,44496],{},"class InputStream {\n",[1023,44498,44499],{"class":1362,"line":68},[1023,44500,4836],{},[1023,44502,44503],{"class":1362,"line":73},[1023,44504,44505],{},"  virtual int read() = 0;                   \u002F\u002F trả byte 0..255, hết dữ liệu trả -1\n",[1023,44507,44508],{"class":1362,"line":78},[1023,44509,44510],{},"  virtual ~InputStream() = default;\n",[1023,44512,44513],{"class":1362,"line":83},[1023,44514,4866],{},[1023,44516,44517],{"class":1362,"line":88},[1023,44518,44519],{},"class FilterInputStream : public InputStream {\n",[1023,44521,44522],{"class":1362,"line":93},[1023,44523,44524],{}," protected: std::unique_ptr\u003CInputStream> in;\n",[1023,44526,44527],{"class":1362,"line":98},[1023,44528,44529],{}," public: explicit FilterInputStream(std::unique_ptr\u003CInputStream> in);\n",[1023,44531,44532],{"class":1362,"line":103},[1023,44533,44534],{},"  int read() override { return in->read(); }\n",[1023,44536,44537],{"class":1362,"line":108},[1023,44538,4866],{},[1099,44540,44541,44549],{},[1102,44542,44543],{},[1105,44544,44545,44547],{},[1108,44546,4881],{},[1108,44548,1569],{},[1118,44550,44551,44569,44579,44592,44605],{},[1105,44552,44553,44558],{},[1123,44554,44555],{},[992,44556,44557],{},"FileInputStream(path)",[1123,44559,44560,44561,44564,44565,44568],{},"Đọc thô, mỗi ",[992,44562,44563],{},"read()"," là 1 lần ",[992,44566,44567],{},"fread"," 1 byte. Đếm số lần gọi hệ thống",[1105,44570,44571,44576],{},[1123,44572,44573],{},[992,44574,44575],{},"MemoryInputStream(std::string)",[1123,44577,44578],{},"Đọc từ bộ nhớ",[1105,44580,44581,44586],{},[1123,44582,44583],{},[992,44584,44585],{},"BufferedInputStream(in, size)",[1123,44587,44588,44589,44591],{},"Đọc khối ",[992,44590,994],{}," byte vào đệm",[1105,44593,44594,44599],{},[1123,44595,44596],{},[992,44597,44598],{},"LowerCaseInputStream(in)",[1123,44600,15916,44601,35512,44603],{},[992,44602,40836],{},[992,44604,26943],{},[1105,44606,44607,44612],{},[1123,44608,44609],{},[992,44610,44611],{},"LineCountingInputStream(in)",[1123,44613,44614,44615,44618,44619],{},"Đếm ",[992,44616,44617],{},"\\n",", có ",[992,44620,44621],{},"lineCount()",[1352,44623,44626],{"className":44624,"code":44625,"language":2241,"meta":1357},[2239],"LowerCase(Memory(\"HeLLo\")) đọc hết           -> \"hello\"\nLineCounting(Memory(\"a\\nb\\nc\")) đọc hết      -> lineCount = 2\nBuffered(File(1 MB), 4096)                   -> số lần gọi đọc file thô ~ 256 thay vì ~10^6\n",[992,44627,44625],{"__ignoreMap":1357},[981,44629,44631],{"id":44630},"bài-2-thứ-tự-bọc-có-ý-nghĩa","Bài 2: Thứ tự bọc có ý nghĩa",[973,44633,5030,44634,1509,44637,1517],{},[992,44635,44636],{},"Rot13InputStream",[992,44638,44639],{},"Base64DecodeInputStream",[2273,44641,44642,44652,44659],{},[989,44643,44644,44645,44648,44649,1517],{},"Mã hóa chữ ",[992,44646,44647],{},"\"Xin Chao\""," bằng Rot13 rồi Base64, lưu vào ",[992,44650,44651],{},"secret.txt",[989,44653,44654,44655,44658],{},"Chồng tầng đọc đúng thứ tự để ra lại ",[992,44656,44657],{},"\"xin chao\""," (chữ thường). Chồng sai thứ tự và ghi lại kết quả sai.",[989,44660,44661],{},"Viết comment trong code: thứ tự đúng và lý do.",[981,44663,44665],{"id":44664},"bài-3-luồng-ghi-và-nén-nâng-cao","Bài 3: Luồng ghi và nén (nâng cao)",[2273,44667,44668,44688,44701],{},[989,44669,44670,44671,1656,44674,1656,44677,44680,44681,44684,44685,1517],{},"Viết phía ghi tương ứng: ",[992,44672,44673],{},"OutputStream",[992,44675,44676],{},"FileOutputStream",[992,44678,44679],{},"BufferedOutputStream"," (nhớ ",[992,44682,44683],{},"flush"," trong destructor), ",[992,44686,44687],{},"UpperCaseOutputStream",[989,44689,1505,44690,1509,44693,44696,44697,44700],{},[992,44691,44692],{},"RleOutputStream",[992,44694,44695],{},"RleInputStream",": nén chạy dài dạng ",[992,44698,44699],{},"(số lần, byte)",". Kiểm tra ghi rồi đọc lại đúng.",[989,44702,44703,44704,1517],{},"Đo thời gian ghi 10 MB có và không có ",[992,44705,44679],{},[981,44707,2711],{"id":2710},[986,44709,44711,44716,44722,44728],{"className":44710},[2715],[989,44712,44714,11986],{"className":44713},[2719],[2721,44715],{"disabled":2723,"type":2724},[989,44717,44719,44721],{"className":44718},[2719],[2721,44720],{"disabled":2723,"type":2724}," Số lần gọi hệ thống giảm rõ nhờ tầng đệm (có số đo).",[989,44723,44725,44727],{"className":44724},[2719],[2721,44726],{"disabled":2723,"type":2724}," Bài 2 ghi lại được kết quả sai khi đổi thứ tự.",[989,44729,44731,44733,44734,44736],{"className":44730},[2719],[2721,44732],{"disabled":2723,"type":2724}," Không mất dữ liệu cuối file khi quên gọi ",[992,44735,44683],{}," (destructor lo việc này).",[968,44738,2890],{"id":2889},[986,44740,44741,44744,44747,44750],{},[989,44742,44743],{},"Lõi và tầng bọc trong luồng là gì?",[989,44745,44746],{},"Yêu cầu đọc đi qua các tầng thế nào?",[989,44748,44749],{},"Vì sao thứ tự bọc luồng quan trọng?",[989,44751,44752],{},"Tầng chữ thường tự viết hoạt động ra sao?",[3014,44754],{},[973,44756,44757],{},"🌕 Bạn đã hoàn thành ngày 71. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,44759,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":44761},[44762,44763,44769,44770,44776],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":44764},[44765,44766,44767,44768],{"id":44329,"depth":73,"text":44330},{"id":44347,"depth":73,"text":44348},{"id":44414,"depth":73,"text":44415},{"id":44432,"depth":73,"text":44433},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":44771},[44772,44773,44774,44775],{"id":44485,"depth":73,"text":44486},{"id":44630,"depth":73,"text":44631},{"id":44664,"depth":73,"text":44665},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhìn Decorator trong thư viện vào ra chuẩn, cách bọc luồng dữ liệu chồng nhiều tầng, và bài tập tự viết decorator chữ thường.",{},[5194],{"title":410,"description":44777},[12056,44782],"io","CDNJ_DHLrmZKBGdYYmroBGUlsE7o0BcZ0D4sdL3tF4Q",{"id":44785,"title":415,"body":44786,"category":8797,"day":418,"description":45088,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":45089,"navigation":2723,"outcomes":3047,"path":416,"prerequisites":45090,"seo":45091,"stem":417,"tags":45092,"__hash__":45095},"challenges\u002Fchallenges\u002F72.gian-lan-watchtower.md",{"type":965,"value":44787,"toc":45071},[44788,44790,44793,44795,44799,44813,44817,44831,44835,44849,44853,44867,44869,44883,44885,44896,44900,44910,44921,44953,44956,44960,44985,44991,44994,44998,45019,45021,45048,45050,45064,45066,45069],[968,44789,971],{"id":970},[973,44791,44792],{},"Bài này học phát hiện gian lận trên đồ thị giao dịch. Bạn dùng nó để tóm đường dây ẩn sau nhiều trung gian.",[968,44794,979],{"id":978},[981,44796,44798],{"id":44797},"gian-lận-trên-mạng","Gian lận trên mạng",[986,44800,44801,44804,44807,44810],{},[989,44802,44803],{},"Là hành vi trục lợi ẩn trong dòng giao dịch hợp lệ.",[989,44805,44806],{},"Dấu vết là quan hệ bất thường: cụm dày, tài khoản mới nối nhau.",[989,44808,44809],{},"Ví dụ đời thường: như nhóm nick ảo cùng rút khuyến mãi rồi chuyển về 1 mối.",[989,44811,44812],{},"Phân tích mạng xã hội soi đúng quan hệ này.",[981,44814,44816],{"id":44815},"phân-tích-đơn-giản-và-2-hạn-chế","Phân tích đơn giản và 2 hạn chế",[986,44818,44819,44822,44825,44828],{},[989,44820,44821],{},"Dựng đồ thị, tính centrality, khoanh đỉnh vượt ngưỡng rồi điều tra tay.",[989,44823,44824],{},"Dễ giải thích vì mỗi cảnh báo kèm hình và con số.",[989,44826,44827],{},"Hạn chế 1 là nhiễu: tổng đài lương thiện cũng centrality cao.",[989,44829,44830],{},"Hạn chế 2 là thiếu lan truyền: gian lận qua nhiều trung gian thì lọt.",[981,44832,44834],{"id":44833},"phương-pháp-tháp-canh","Phương pháp tháp canh",[986,44836,44837,44840,44843,44846],{},[989,44838,44839],{},"Cắm tháp ở đỉnh đã xác minh gian lận hoặc sạch.",[989,44841,44842],{},"Để độ nghi ngờ lan qua các cạnh cho lân cận.",[989,44844,44845],{},"Càng gần tháp xấu qua đường ngắn thì càng đáng ngờ.",[989,44847,44848],{},"Ví dụ đời thường: như ở gần ổ dịch thì nguy cơ cao hơn.",[981,44850,44852],{"id":44851},"điểm-tiêu-cực-và-bậc-nghi-ngờ","Điểm tiêu cực và bậc nghi ngờ",[986,44854,44855,44858,44861,44864],{},[989,44856,44857],{},"Điểm tiêu cực: từng bị phạt, từng bị khiếu nại đúng thì điểm cao.",[989,44859,44860],{},"Sự kiện cũ giảm trọng số theo thời gian.",[989,44862,44863],{},"Bậc nghi ngờ chuẩn hóa 0 tới 1 để so giữa các nút.",[989,44865,44866],{},"Nút nhiều giao dịch được hiệu chỉnh theo bậc để khỏi oan.",[968,44868,1433],{"id":1432},[986,44870,44871,44874,44877,44880],{},[989,44872,44873],{},"Input: mạng 5 đỉnh thẳng hàng, đầu xác minh gian lận. Output: nghi ngờ giảm dần từ đầu tới cuối.",[989,44875,44876],{},"Giải thích: càng xa tháp xấu thì độ lan truyền càng yếu.",[989,44878,44879],{},"Input: tổng đài nối 20 đỉnh sạch, không sự kiện xấu. Output: hạng thấp hơn đỉnh kề trực tiếp tháp gian lận.",[989,44881,44882],{},"Giải thích: chuẩn hóa theo bậc cứu được tài khoản giao dịch nhiều.",[968,44884,1482],{"id":1481},[973,44886,1485,44887,44889,44890,44892,44893,1517],{},[1487,44888,13531],{}," với NumPy (được dùng ",[992,44891,31660],{}," để đọc và vẽ đồ thị). Nộp vào ",[992,44894,44895],{},"day-072\u002F",[981,44897,44899],{"id":44898},"bài-1-dựng-đồ-thị-giao-dịch","Bài 1: Dựng đồ thị giao dịch",[973,44901,22563,44902,44905,44906,44909],{},[992,44903,44904],{},"transactions.csv"," có cột ",[992,44907,44908],{},"from_account,to_account,amount,timestamp",". Tự sinh dữ liệu giả:",[986,44911,44912,44915,44918],{},[989,44913,44914],{},"500 tài khoản thường, giao dịch ngẫu nhiên.",[989,44916,44917],{},"1 cụm gian lận 12 tài khoản mới mở, chuyển tiền vòng tròn cho nhau với số tiền tròn.",[989,44919,44920],{},"3 tài khoản \"tổng đài\" hợp pháp (ví dụ ví thanh toán) có rất nhiều giao dịch.",[1099,44922,44923,44931],{},[1102,44924,44925],{},[1105,44926,44927,44929],{},[1108,44928,1566],{},[1108,44930,2547],{},[1118,44932,44933,44943],{},[1105,44934,44935,44940],{},[1123,44936,44937],{},[992,44938,44939],{},"build_graph(df)",[1123,44941,44942],{},"Đồ thị vô hướng có trọng số là tổng tiền",[1105,44944,44945,44950],{},[1123,44946,44947],{},[992,44948,44949],{},"flag_by_centrality(G, top=20)",[1123,44951,44952],{},"Trả 20 tài khoản có degree và betweenness cao nhất",[973,44954,44955],{},"Chỉ ra: bao nhiêu tài khoản gian lận nằm trong 20 cảnh báo, bao nhiêu tổng đài bị báo oan.",[981,44957,44959],{"id":44958},"bài-2-watchtower-lan-truyền-nghi-ngờ","Bài 2: Watchtower lan truyền nghi ngờ",[1352,44961,44963],{"className":3538,"code":44962,"language":3540,"meta":1357,"style":1357},"def watchtower(G, bad: set, good: set, alpha: float = 0.5, iters: int = 50) -> dict:\n    \"\"\"Điểm nghi ngờ 0..1. Tháp xấu cố định 1, tháp sạch cố định 0.\n       Mỗi vòng: s(v) = (1 - alpha) * s0(v) + alpha * trung_bình_có_trọng_số(s(u) với u kề v),\n       chia trọng số cạnh cho bậc của u để nút bậc cao không lan quá mạnh.\"\"\"\n",[992,44964,44965,44970,44975,44980],{"__ignoreMap":1357},[1023,44966,44967],{"class":1362,"line":63},[1023,44968,44969],{},"def watchtower(G, bad: set, good: set, alpha: float = 0.5, iters: int = 50) -> dict:\n",[1023,44971,44972],{"class":1362,"line":68},[1023,44973,44974],{},"    \"\"\"Điểm nghi ngờ 0..1. Tháp xấu cố định 1, tháp sạch cố định 0.\n",[1023,44976,44977],{"class":1362,"line":73},[1023,44978,44979],{},"       Mỗi vòng: s(v) = (1 - alpha) * s0(v) + alpha * trung_bình_có_trọng_số(s(u) với u kề v),\n",[1023,44981,44982],{"class":1362,"line":78},[1023,44983,44984],{},"       chia trọng số cạnh cho bậc của u để nút bậc cao không lan quá mạnh.\"\"\"\n",[1352,44986,44989],{"className":44987,"code":44988,"language":2241,"meta":1357},[2239],"Đường thẳng 5 đỉnh, đỉnh 0 xấu -> điểm giảm dần từ 0 tới 4\nTách rời khỏi mọi tháp          -> điểm giữ nguyên giá trị ban đầu (0)\n",[992,44990,44988],{"__ignoreMap":1357},[973,44992,44993],{},"Chạy trên dữ liệu Bài 1 với 2 tài khoản gian lận đã biết làm tháp xấu. In top 20 và so với Bài 1.",[981,44995,44997],{"id":44996},"bài-3-điểm-tiêu-cực-theo-thời-gian-nâng-cao","Bài 3: Điểm tiêu cực theo thời gian (nâng cao)",[2273,44999,45000,45007,45013,45016],{},[989,45001,45002,45003,45006],{},"Mỗi tài khoản có danh sách sự kiện ",[992,45004,45005],{},"(loại, ngày)",": bị phạt (+5), khiếu nại đúng (+2). Điểm mỗi sự kiện giảm nửa sau mỗi 90 ngày.",[989,45008,45009,45010,1517],{},"Kết hợp: ",[992,45011,45012],{},"final = 0.6 * watchtower + 0.4 * negative_normalized",[989,45014,45015],{},"Đánh giá bằng precision@20 và recall@20 so với nhãn gian lận thật. So 3 cách: chỉ centrality, chỉ watchtower, kết hợp.",[989,45017,45018],{},"Vẽ đồ thị con quanh 5 tài khoản điểm cao nhất, tô màu theo điểm.",[981,45020,2711],{"id":2710},[986,45022,45024,45030,45036,45042],{"className":45023},[2715],[989,45025,45027,45029],{"className":45026},[2719],[2721,45028],{"disabled":2723,"type":2724}," Test mẫu đường thẳng 5 đỉnh pass.",[989,45031,45033,45035],{"className":45032},[2719],[2721,45034],{"disabled":2723,"type":2724}," Bảng precision@20 \u002F recall@20 cho 3 cách có số thật.",[989,45037,45039,45041],{"className":45038},[2719],[2721,45040],{"disabled":2723,"type":2724}," Có hình đồ thị con tô màu theo điểm.",[989,45043,45045,45047],{"className":45044},[2719],[2721,45046],{"disabled":2723,"type":2724}," Giải thích được vì sao tổng đài bị báo oan ở Bài 1 và cách Bài 2 giảm điều đó.",[968,45049,2890],{"id":2889},[986,45051,45052,45055,45058,45061],{},[989,45053,45054],{},"Vì sao phân tích mạng hợp để bắt gian lận?",[989,45056,45057],{},"Hai hạn chế của centrality đơn thuần là gì?",[989,45059,45060],{},"Tháp canh lan truyền nghi ngờ thế nào?",[989,45062,45063],{},"Điểm tiêu cực và bậc nghi ngờ là gì?",[3014,45065],{},[973,45067,45068],{},"🌕 Bạn đã hoàn thành ngày 72. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,45070,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":45072},[45073,45074,45080,45081,45087],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":45075},[45076,45077,45078,45079],{"id":44797,"depth":73,"text":44798},{"id":44815,"depth":73,"text":44816},{"id":44833,"depth":73,"text":44834},{"id":44851,"depth":73,"text":44852},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":45082},[45083,45084,45085,45086],{"id":44898,"depth":73,"text":44899},{"id":44958,"depth":73,"text":44959},{"id":44996,"depth":73,"text":44997},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Phân tích gian lận trên mạng xã hội: phân tích đơn giản, hai hạn chế, phương pháp tháp canh với chấm điểm kết quả tiêu cực và bậc nghi ngờ.",{},[15144],{"title":415,"description":45088},[29786,45093,32322,45094],"fraud","case-study","70ts_GNNuxfmrRjwbRw9TkPEmRnZtU1VFmeMUM9q3Aw",{"id":45097,"title":420,"body":45098,"category":8797,"day":423,"description":46176,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":46177,"navigation":2723,"outcomes":3047,"path":421,"prerequisites":46178,"seo":46179,"stem":422,"tags":46180,"__hash__":46183},"challenges\u002Fchallenges\u002F73.pagerank.md",{"type":965,"value":45099,"toc":46159},[45100,45102,45105,45107,45111,45125,45129,45143,45147,45161,45165,45179,45181,45195,45197,45207,45211,45236,45838,45844,45848,46075,46079,46099,46101,46136,46138,46152,46154,46157],[968,45101,971],{"id":970},[973,45103,45104],{},"Bài này học PageRank xếp hạng trang web. Bạn dùng nó để trang hữu ích nhất lên đầu kết quả.",[968,45106,979],{"id":978},[981,45108,45110],{"id":45109},"câu-chuyện-pagerank","Câu chuyện PageRank",[986,45112,45113,45116,45119,45122],{},[989,45114,45115],{},"Hai nghiên cứu sinh Stanford tạo ra cuối thập niên 1990.",[989,45117,45118],{},"Bài toán: nhiều trang cùng khớp truy vấn, cần 1 con số xếp hạng.",[989,45120,45121],{},"Con số phải tính tự động và khó gian lận nội dung.",[989,45123,45124],{},"Ví dụ đời thường: như bầu lớp trưởng bằng phiếu cả trường thay vì tự ứng cử.",[981,45126,45128],{"id":45127},"người-lướt-ngẫu-nhiên","Người lướt ngẫu nhiên",[986,45130,45131,45134,45137,45140],{},[989,45132,45133],{},"Web là đồ thị: trang là nút, liên kết là cạnh có hướng.",[989,45135,45136],{},"Thứ hạng bằng xác suất người click bừa dừng tại trang đó.",[989,45138,45139],{},"Hệ số damping 0.85 là xác suất click tiếp thay vì nhảy ngẫu nhiên.",[989,45141,45142],{},"Alpha càng gần 1 thì cấu trúc liên kết càng quyết định.",[981,45144,45146],{"id":45145},"hai-thành-phần-điểm-số","Hai thành phần điểm số",[986,45148,45149,45152,45155,45158],{},[989,45150,45151],{},"Liên quan truy vấn: nội dung có khớp từ khóa không, dễ làm giả.",[989,45153,45154],{},"Không liên quan truy vấn: uy tín qua liên kết, khó tự phong.",[989,45156,45157],{},"PageRank chính là thành phần thứ 2 này.",[989,45159,45160],{},"Ví dụ đời thường: như điểm thi là nội dung, thư giới thiệu là uy tín.",[981,45162,45164],{"id":45163},"vòng-lặp-lan-truyền","Vòng lặp lan truyền",[986,45166,45167,45170,45173,45176],{},[989,45168,45169],{},"Mỗi vòng mỗi trang chia điểm cho trang nó trỏ tới.",[989,45171,45172],{},"Cộng thêm phần nhảy ngẫu nhiên từ damping.",[989,45174,45175],{},"Lặp tới khi thứ hạng ngừng đổi đáng kể thì dừng.",[989,45177,45178],{},"Trang được nhiều trang quan trọng trỏ tới thì càng quan trọng.",[968,45180,1433],{"id":1432},[986,45182,45183,45186,45189,45192],{},[989,45184,45185],{},"Input: 3 trang nối vòng tròn, mỗi trang trỏ đúng 1 trang tiếp. Output: 3 trang điểm bằng nhau.",[989,45187,45188],{},"Giải thích: đối xứng hoàn toàn nên không ai hơn ai.",[989,45190,45191],{},"Input: trang A được 4 trang trỏ về, trang B được 1 trang. Output: A xếp trên B.",[989,45193,45194],{},"Giải thích: nhiều phiếu uy tín hơn khi điều kiện tương đương.",[968,45196,1482],{"id":1481},[973,45198,1485,45199,17626,45201,33864,45204,1517],{},[1487,45200,13531],{},[992,45202,45203],{},"networkx.pagerank",[992,45205,45206],{},"day-073\u002F",[981,45208,45210],{"id":45209},"bài-1-pagerank-lặp","Bài 1: PageRank lặp",[1352,45212,45214],{"className":3538,"code":45213,"language":3540,"meta":1357,"style":1357},"def pagerank(links: dict[str, list[str]], d: float = 0.85, tol: float = 1e-10,\n             max_iter: int = 1000) -> tuple[dict[str, float], int]:\n    \"\"\"Trả (điểm, số vòng lặp). Tổng điểm luôn bằng 1.\n       Trang không có liên kết ra (dangling) chia đều điểm cho mọi trang.\"\"\"\n",[992,45215,45216,45221,45226,45231],{"__ignoreMap":1357},[1023,45217,45218],{"class":1362,"line":63},[1023,45219,45220],{},"def pagerank(links: dict[str, list[str]], d: float = 0.85, tol: float = 1e-10,\n",[1023,45222,45223],{"class":1362,"line":68},[1023,45224,45225],{},"             max_iter: int = 1000) -> tuple[dict[str, float], int]:\n",[1023,45227,45228],{"class":1362,"line":73},[1023,45229,45230],{},"    \"\"\"Trả (điểm, số vòng lặp). Tổng điểm luôn bằng 1.\n",[1023,45232,45233],{"class":1362,"line":78},[1023,45234,45235],{},"       Trang không có liên kết ra (dangling) chia đều điểm cho mọi trang.\"\"\"\n",[973,45237,34907,45238,1517],{},[1023,45239,45241,45374],{"className":45240},[1026],[1023,45242,45244],{"className":45243},[1030],[1032,45245,45246],{"xmlns":1034},[1036,45247,45248,45371],{},[1039,45249,45250,45252,45254,45256,45258,45260,45262,45274,45276,45278],{},[1042,45251,37334],{},[1042,45253,41944],{},[1046,45255,1049],{"stretchy":1048},[1042,45257,973],{},[1046,45259,1056],{"stretchy":1048},[1046,45261,2325],{},[18110,45263,45264,45272],{},[1039,45265,45266,45268,45270],{},[1051,45267,1053],{},[1046,45269,17698],{},[1042,45271,12999],{},[1042,45273,20421],{},[1046,45275,21881],{},[1042,45277,12999],{},[1039,45279,45280,45282,45295,45323,45325,45353,45369],{},[1046,45281,1049],{"fence":1066},[17690,45283,45284,45286],{},[1046,45285,17686],{},[1039,45287,45288,45290,45293],{},[1042,45289,43520],{},[1046,45291,45292],{},"→",[1042,45294,973],{},[18110,45296,45297,45309],{},[1039,45298,45299,45301,45303,45305,45307],{},[1042,45300,37334],{},[1042,45302,41944],{},[1046,45304,1049],{"stretchy":1048},[1042,45306,43520],{},[1046,45308,1056],{"stretchy":1048},[1039,45310,45311,45313,45315,45317,45319,45321],{},[1042,45312,7687],{},[1042,45314,30390],{},[1042,45316,29580],{},[1046,45318,1049],{"stretchy":1048},[1042,45320,43520],{},[1046,45322,1056],{"stretchy":1048},[1046,45324,21881],{},[17690,45326,45327,45329],{},[1046,45328,17686],{},[1039,45330,45331,45333,45337,45339,45341,45343,45345,45347,45349,45351],{},[1042,45332,43520],{},[45334,45335,45336],"mtext",{}," ",[1042,45338,12999],{},[1042,45340,6207],{},[1042,45342,1262],{},[1042,45344,7690],{},[1042,45346,7684],{},[1042,45348,1837],{},[1042,45350,1262],{},[1042,45352,7690],{},[18110,45354,45355,45367],{},[1039,45356,45357,45359,45361,45363,45365],{},[1042,45358,37334],{},[1042,45360,41944],{},[1046,45362,1049],{"stretchy":1048},[1042,45364,43520],{},[1046,45366,1056],{"stretchy":1048},[1042,45368,20421],{},[1046,45370,1056],{"fence":1066},[1058,45372,45373],{"encoding":1060},"PR(p) = \\frac{1-d}{N} + d \\left( \\sum_{q \\to p} \\frac{PR(q)}{out(q)} + \\sum_{q\\ dangling} \\frac{PR(q)}{N} \\right)",[1023,45375,45377,45408,45499],{"className":45376,"ariaHidden":1066},[1065],[1023,45378,45380,45383,45386,45390,45393,45396,45399,45402,45405],{"className":45379},[1070],[1023,45381],{"className":45382,"style":1075},[1074],[1023,45384,37334],{"className":45385,"style":37429},[1079,1080],[1023,45387,41944],{"className":45388,"style":45389},[1079,1080],"margin-right:0.0077em;",[1023,45391,1049],{"className":45392},[1085],[1023,45394,973],{"className":45395},[1079,1080],[1023,45397,1056],{"className":45398},[1092],[1023,45400],{"className":45401,"style":2355},[2354],[1023,45403,2325],{"className":45404},[2359],[1023,45406],{"className":45407,"style":2355},[2354],[1023,45409,45411,45415,45490,45493,45496],{"className":45410},[1070],[1023,45412],{"className":45413,"style":45414},[1074],"height:1.2251em;vertical-align:-0.345em;",[1023,45416,45418,45421,45487],{"className":45417},[1079],[1023,45419],{"className":45420},[1085,18174],[1023,45422,45424],{"className":45423},[18110],[1023,45425,45427,45478],{"className":45426},[2387,17732],[1023,45428,45430,45475],{"className":45429},[2391],[1023,45431,45433,45447,45455],{"className":45432,"style":18187},[2395],[1023,45434,45435,45438],{"style":18190},[1023,45436],{"className":45437,"style":18194},[2402],[1023,45439,45441],{"className":45440},[2407,2408,2409,2410],[1023,45442,45444],{"className":45443},[1079,2410],[1023,45445,20421],{"className":45446,"style":20451},[1079,1080,2410],[1023,45448,45449,45452],{"style":18221},[1023,45450],{"className":45451,"style":18194},[2402],[1023,45453],{"className":45454,"style":18229},[18228],[1023,45456,45457,45460],{"style":18232},[1023,45458],{"className":45459,"style":18194},[2402],[1023,45461,45463],{"className":45462},[2407,2408,2409,2410],[1023,45464,45466,45469,45472],{"className":45465},[1079,2410],[1023,45467,1053],{"className":45468},[1079,2410],[1023,45470,17698],{"className":45471},[13794,2410],[1023,45473,12999],{"className":45474},[1079,1080,2410],[1023,45476,17797],{"className":45477},[17796],[1023,45479,45481],{"className":45480},[2391],[1023,45482,45485],{"className":45483,"style":45484},[2395],"height:0.345em;",[1023,45486],{},[1023,45488],{"className":45489},[1092,18174],[1023,45491],{"className":45492,"style":13790},[2354],[1023,45494,21881],{"className":45495},[13794],[1023,45497],{"className":45498,"style":13790},[2354],[1023,45500,45502,45506,45509,45512],{"className":45501},[1070],[1023,45503],{"className":45504,"style":45505},[1074],"height:1.8em;vertical-align:-0.65em;",[1023,45507,12999],{"className":45508},[1079,1080],[1023,45510],{"className":45511,"style":8434},[2354],[1023,45513,45515,45522,45572,45575,45670,45673,45676,45679,45749,45752,45832],{"className":45514},[24087],[1023,45516,45518],{"className":45517,"style":24095},[1085,24094],[1023,45519,1049],{"className":45520},[24099,45521],"size2",[1023,45523,45525,45528],{"className":45524},[8426],[1023,45526,17686],{"className":45527,"style":17758},[8426,17756,17757],[1023,45529,45531],{"className":45530},[2383],[1023,45532,45534,45563],{"className":45533},[2387,17732],[1023,45535,45537,45560],{"className":45536},[2391],[1023,45538,45540],{"className":45539,"style":32102},[2395],[1023,45541,45542,45545],{"style":32105},[1023,45543],{"className":45544,"style":2403},[2402],[1023,45546,45548],{"className":45547},[2407,2408,2409,2410],[1023,45549,45551,45554,45557],{"className":45550},[1079,2410],[1023,45552,43520],{"className":45553,"style":7723},[1079,1080,2410],[1023,45555,45292],{"className":45556},[2359,2410],[1023,45558,973],{"className":45559},[1079,1080,2410],[1023,45561,17797],{"className":45562},[17796],[1023,45564,45566],{"className":45565},[2391],[1023,45567,45570],{"className":45568,"style":45569},[2395],"height:0.4358em;",[1023,45571],{},[1023,45573],{"className":45574,"style":8434},[2354],[1023,45576,45578,45581,45667],{"className":45577},[1079],[1023,45579],{"className":45580},[1085,18174],[1023,45582,45584],{"className":45583},[18110],[1023,45585,45587,45659],{"className":45586},[2387,17732],[1023,45588,45590,45656],{"className":45589},[2391],[1023,45591,45593,45622,45630],{"className":45592,"style":37492},[2395],[1023,45594,45595,45598],{"style":18190},[1023,45596],{"className":45597,"style":18194},[2402],[1023,45599,45601],{"className":45600},[2407,2408,2409,2410],[1023,45602,45604,45607,45610,45613,45616,45619],{"className":45603},[1079,2410],[1023,45605,7687],{"className":45606},[1079,1080,2410],[1023,45608,30390],{"className":45609},[1079,1080,2410],[1023,45611,29580],{"className":45612},[1079,1080,2410],[1023,45614,1049],{"className":45615},[1085,2410],[1023,45617,43520],{"className":45618,"style":7723},[1079,1080,2410],[1023,45620,1056],{"className":45621},[1092,2410],[1023,45623,45624,45627],{"style":18221},[1023,45625],{"className":45626,"style":18194},[2402],[1023,45628],{"className":45629,"style":18229},[18228],[1023,45631,45632,45635],{"style":37607},[1023,45633],{"className":45634,"style":18194},[2402],[1023,45636,45638],{"className":45637},[2407,2408,2409,2410],[1023,45639,45641,45644,45647,45650,45653],{"className":45640},[1079,2410],[1023,45642,37334],{"className":45643,"style":37429},[1079,1080,2410],[1023,45645,41944],{"className":45646,"style":45389},[1079,1080,2410],[1023,45648,1049],{"className":45649},[1085,2410],[1023,45651,43520],{"className":45652,"style":7723},[1079,1080,2410],[1023,45654,1056],{"className":45655},[1092,2410],[1023,45657,17797],{"className":45658},[17796],[1023,45660,45662],{"className":45661},[2391],[1023,45663,45665],{"className":45664,"style":18260},[2395],[1023,45666],{},[1023,45668],{"className":45669},[1092,18174],[1023,45671],{"className":45672,"style":13790},[2354],[1023,45674,21881],{"className":45675},[13794],[1023,45677],{"className":45678,"style":13790},[2354],[1023,45680,45682,45685],{"className":45681},[8426],[1023,45683,17686],{"className":45684,"style":17758},[8426,17756,17757],[1023,45686,45688],{"className":45687},[2383],[1023,45689,45691,45741],{"className":45690},[2387,17732],[1023,45692,45694,45738],{"className":45693},[2391],[1023,45695,45698],{"className":45696,"style":45697},[2395],"height:0.1864em;",[1023,45699,45700,45703],{"style":32105},[1023,45701],{"className":45702,"style":2403},[2402],[1023,45704,45706],{"className":45705},[2407,2408,2409,2410],[1023,45707,45709,45712,45718,45721,45725,45728,45731,45735],{"className":45708},[1079,2410],[1023,45710,43520],{"className":45711,"style":7723},[1079,1080,2410],[1023,45713,45715],{"className":45714},[2354,2410],[1023,45716,45336],{"className":45717},[2410],[1023,45719,12999],{"className":45720},[1079,1080,2410],[1023,45722,45724],{"className":45723},[1079,1080,2410],"an",[1023,45726,7690],{"className":45727,"style":7723},[1079,1080,2410],[1023,45729,7684],{"className":45730,"style":7716},[1079,1080,2410],[1023,45732,45734],{"className":45733},[1079,1080,2410],"in",[1023,45736,7690],{"className":45737,"style":7723},[1079,1080,2410],[1023,45739,17797],{"className":45740},[17796],[1023,45742,45744],{"className":45743},[2391],[1023,45745,45747],{"className":45746,"style":45569},[2395],[1023,45748],{},[1023,45750],{"className":45751,"style":8434},[2354],[1023,45753,45755,45758,45829],{"className":45754},[1079],[1023,45756],{"className":45757},[1085,18174],[1023,45759,45761],{"className":45760},[18110],[1023,45762,45764,45821],{"className":45763},[2387,17732],[1023,45765,45767,45818],{"className":45766},[2391],[1023,45768,45770,45784,45792],{"className":45769,"style":37492},[2395],[1023,45771,45772,45775],{"style":18190},[1023,45773],{"className":45774,"style":18194},[2402],[1023,45776,45778],{"className":45777},[2407,2408,2409,2410],[1023,45779,45781],{"className":45780},[1079,2410],[1023,45782,20421],{"className":45783,"style":20451},[1079,1080,2410],[1023,45785,45786,45789],{"style":18221},[1023,45787],{"className":45788,"style":18194},[2402],[1023,45790],{"className":45791,"style":18229},[18228],[1023,45793,45794,45797],{"style":37607},[1023,45795],{"className":45796,"style":18194},[2402],[1023,45798,45800],{"className":45799},[2407,2408,2409,2410],[1023,45801,45803,45806,45809,45812,45815],{"className":45802},[1079,2410],[1023,45804,37334],{"className":45805,"style":37429},[1079,1080,2410],[1023,45807,41944],{"className":45808,"style":45389},[1079,1080,2410],[1023,45810,1049],{"className":45811},[1085,2410],[1023,45813,43520],{"className":45814,"style":7723},[1079,1080,2410],[1023,45816,1056],{"className":45817},[1092,2410],[1023,45819,17797],{"className":45820},[17796],[1023,45822,45824],{"className":45823},[2391],[1023,45825,45827],{"className":45826,"style":45484},[2395],[1023,45828],{},[1023,45830],{"className":45831},[1092,18174],[1023,45833,45835],{"className":45834,"style":24095},[1092,24094],[1023,45836,1056],{"className":45837},[24099,45521],[1352,45839,45842],{"className":45840,"code":45841,"language":2241,"meta":1357},[2239],"Vòng 3 trang A->B->C->A            -> mỗi trang 1\u002F3\nA->B, A->C, B->C, C->A             -> C cao nhất, B thấp nhất\nTrang D không có liên kết ra       -> tổng điểm vẫn bằng 1\n",[992,45843,45841],{"__ignoreMap":1357},[981,45845,45847],{"id":45846},"bài-2-dạng-ma-trận-và-hội-tụ","Bài 2: Dạng ma trận và hội tụ",[2273,45849,45850,46063,46072],{},[989,45851,45852,45853,46054,46055,46058,46059,46062],{},"Dựng ma trận Google ",[1023,45854,45856,45898],{"className":45855},[1026],[1023,45857,45859],{"className":45858},[1030],[1032,45860,45861],{"xmlns":1034},[1036,45862,45863,45895],{},[1039,45864,45865,45868,45870,45872,45874,45876,45888],{},[1042,45866,45867],{},"G",[1046,45869,2325],{},[1042,45871,12999],{},[1042,45873,44268],{},[1046,45875,21881],{},[18110,45877,45878,45886],{},[1039,45879,45880,45882,45884],{},[1051,45881,1053],{},[1046,45883,17698],{},[1042,45885,12999],{},[1042,45887,20421],{},[2327,45889,45890,45893],{},[1051,45891,14659],{"mathvariant":45892},"bold",[1042,45894,38209],{},[1058,45896,45897],{"encoding":1060},"G = dM + \\frac{1-d}{N}\\mathbf{1}\\mathbf{1}^T",[1023,45899,45901,45919,45941],{"className":45900,"ariaHidden":1066},[1065],[1023,45902,45904,45907,45910,45913,45916],{"className":45903},[1070],[1023,45905],{"className":45906,"style":27414},[1074],[1023,45908,45867],{"className":45909},[1079,1080],[1023,45911],{"className":45912,"style":2355},[2354],[1023,45914,2325],{"className":45915},[2359],[1023,45917],{"className":45918,"style":2355},[2354],[1023,45920,45922,45926,45929,45932,45935,45938],{"className":45921},[1070],[1023,45923],{"className":45924,"style":45925},[1074],"height:0.7778em;vertical-align:-0.0833em;",[1023,45927,12999],{"className":45928},[1079,1080],[1023,45930,44268],{"className":45931,"style":20451},[1079,1080],[1023,45933],{"className":45934,"style":13790},[2354],[1023,45936,21881],{"className":45937},[13794],[1023,45939],{"className":45940,"style":13790},[2354],[1023,45942,45944,45947,46021,46025],{"className":45943},[1070],[1023,45945],{"className":45946,"style":45414},[1074],[1023,45948,45950,45953,46018],{"className":45949},[1079],[1023,45951],{"className":45952},[1085,18174],[1023,45954,45956],{"className":45955},[18110],[1023,45957,45959,46010],{"className":45958},[2387,17732],[1023,45960,45962,46007],{"className":45961},[2391],[1023,45963,45965,45979,45987],{"className":45964,"style":18187},[2395],[1023,45966,45967,45970],{"style":18190},[1023,45968],{"className":45969,"style":18194},[2402],[1023,45971,45973],{"className":45972},[2407,2408,2409,2410],[1023,45974,45976],{"className":45975},[1079,2410],[1023,45977,20421],{"className":45978,"style":20451},[1079,1080,2410],[1023,45980,45981,45984],{"style":18221},[1023,45982],{"className":45983,"style":18194},[2402],[1023,45985],{"className":45986,"style":18229},[18228],[1023,45988,45989,45992],{"style":18232},[1023,45990],{"className":45991,"style":18194},[2402],[1023,45993,45995],{"className":45994},[2407,2408,2409,2410],[1023,45996,45998,46001,46004],{"className":45997},[1079,2410],[1023,45999,1053],{"className":46000},[1079,2410],[1023,46002,17698],{"className":46003},[13794,2410],[1023,46005,12999],{"className":46006},[1079,1080,2410],[1023,46008,17797],{"className":46009},[17796],[1023,46011,46013],{"className":46012},[2391],[1023,46014,46016],{"className":46015,"style":45484},[2395],[1023,46017],{},[1023,46019],{"className":46020},[1092,18174],[1023,46022,1053],{"className":46023},[1079,46024],"mathbf",[1023,46026,46028,46031],{"className":46027},[1079],[1023,46029,1053],{"className":46030},[1079,46024],[1023,46032,46034],{"className":46033},[2383],[1023,46035,46037],{"className":46036},[2387],[1023,46038,46040],{"className":46039},[2391],[1023,46041,46043],{"className":46042,"style":38290},[2395],[1023,46044,46045,46048],{"style":2398},[1023,46046],{"className":46047,"style":2403},[2402],[1023,46049,46051],{"className":46050},[2407,2408,2409,2410],[1023,46052,38209],{"className":46053,"style":37429},[1079,1080,2410],". Tính PageRank bằng ",[1487,46056,46057],{},"lặp lũy thừa"," và bằng ",[992,46060,46061],{},"np.linalg.eig"," (vector riêng của trị riêng 1). So 2 kết quả.",[989,46064,23993,46065,46068,46069,46071],{},[992,46066,46067],{},"d = 0.5, 0.85, 0.99",", in số vòng lặp tới hội tụ. Giải thích vì sao ",[992,46070,12999],{}," gần 1 thì chậm.",[989,46073,46074],{},"Vẽ sai số L1 giữa 2 vòng liên tiếp theo số vòng (trục y log).",[981,46076,46078],{"id":46077},"bài-3-mạng-thật-và-gian-lận-liên-kết-nâng-cao","Bài 3: Mạng thật và gian lận liên kết (nâng cao)",[2273,46080,46081,46087,46093],{},[989,46082,46083,46084,46086],{},"Chạy trên một đồ thị web công khai nhỏ (ví dụ đồ thị trích dẫn hoặc Wikipedia vote, vài nghìn nút). Dùng ma trận thưa (",[992,46085,39150],{},"). In top 10.",[989,46088,46089,46092],{},[1487,46090,46091],{},"Link farm:"," thêm 100 trang giả chỉ trỏ vào trang X và trỏ vào nhau. In thứ hạng của X trước và sau.",[989,46094,46095,46098],{},[1487,46096,46097],{},"Personalized PageRank:"," nhảy ngẫu nhiên chỉ về 1 tập trang tin cậy. So thứ hạng của X với PageRank thường khi có link farm.",[981,46100,2711],{"id":2710},[986,46102,46104,46110,46121,46130],{"className":46103},[2715],[989,46105,46107,46109],{"className":46106},[2719],[2721,46108],{"disabled":2723,"type":2724}," Test mẫu pass, tổng điểm luôn bằng 1.",[989,46111,46113,34128,46115,46117,46118,1517],{"className":46112},[2719],[2721,46114],{"disabled":2723,"type":2724},[992,46116,45203],{}," sai số ",[992,46119,46120],{},"1e-8",[989,46122,46124,46126,46127,46129],{"className":46123},[2719],[2721,46125],{"disabled":2723,"type":2724}," Bảng số vòng lặp theo ",[992,46128,12999],{}," và hình hội tụ.",[989,46131,46133,46135],{"className":46132},[2719],[2721,46134],{"disabled":2723,"type":2724}," Bài 3 cho thấy personalized PageRank làm giảm tác dụng link farm.",[968,46137,2890],{"id":2889},[986,46139,46140,46143,46146,46149],{},[989,46141,46142],{},"PageRank mô hình web thành gì?",[989,46144,46145],{},"Hệ số damping 0.85 nghĩa là gì?",[989,46147,46148],{},"Hai thành phần điểm số là gì?",[989,46150,46151],{},"Khi nào vòng lặp được coi là hội tụ?",[3014,46153],{},[973,46155,46156],{},"🌕 Bạn đã hoàn thành ngày 73. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,46158,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":46160},[46161,46162,46168,46169,46175],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":46163},[46164,46165,46166,46167],{"id":45109,"depth":73,"text":45110},{"id":45127,"depth":73,"text":45128},{"id":45145,"depth":73,"text":45146},{"id":45163,"depth":73,"text":45164},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":46170},[46171,46172,46173,46174],{"id":45209,"depth":73,"text":45210},{"id":45846,"depth":73,"text":45847},{"id":46077,"depth":73,"text":46078},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật toán PageRank của Larry Page và Sergey Brin: người lướt ngẫu nhiên, hệ số damping 0.85, hai thành phần liên quan và không liên quan tới truy vấn.",{},[15144,14055],{"title":420,"description":46176},[46181,29786,46182],"pagerank","ranking","9kTg-jOu4qqzrs89HXR4KtwbCyz5OBcF9Sflst-8IZ8",{"id":46185,"title":425,"body":46186,"category":5189,"day":428,"description":46637,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":46638,"navigation":2723,"outcomes":3047,"path":426,"prerequisites":46639,"seo":46640,"stem":427,"tags":46641,"__hash__":46643},"challenges\u002Fchallenges\u002F74.abstract-factory.md",{"type":965,"value":46187,"toc":46621},[46188,46190,46193,46195,46199,46213,46217,46231,46235,46249,46297,46299,46313,46315,46322,46326,46375,46452,46470,46476,46479,46481,46501,46514,46518,46542,46566,46568,46598,46600,46614,46616,46619],[968,46189,971],{"id":970},[973,46191,46192],{},"Bài này học Abstract Factory tạo cả họ đối tượng. Bạn dùng nó để pizza đúng vị từng vùng.",[968,46194,979],{"id":978},[981,46196,46198],{"id":46197},"định-nghĩa","Định nghĩa",[986,46200,46201,46204,46207,46210],{},[989,46202,46203],{},"Cung cấp giao diện tạo họ đối tượng liên quan.",[989,46205,46206],{},"Không cần chỉ rõ lớp cụ thể đằng sau.",[989,46208,46209],{},"Từ khóa là họ liên quan và giấu cụ thể.",[989,46211,46212],{},"Ví dụ đời thường: như bếp chỉ gọi lấy bột, xưởng tự giao đúng loại vùng.",[981,46214,46216],{"id":46215},"xưởng-nguyên-liệu-theo-vùng","Xưởng nguyên liệu theo vùng",[986,46218,46219,46222,46225,46228],{},[989,46220,46221],{},"Pizza New York: bột mỏng, sốt marinara, phô mai tươi.",[989,46223,46224],{},"Pizza Chicago: bột dày, sốt cà chua nghiền, phô mai sợi.",[989,46226,46227],{},"Mỗi pizza chỉ giữ 1 xưởng chung, cần gì hỏi xưởng.",[989,46229,46230],{},"Nếu pizza tự đi chợ sẽ dễ mua nhầm vùng.",[981,46232,46234],{"id":46233},"nhất-quán-trong-họ","Nhất quán trong họ",[986,46236,46237,46240,46243,46246],{},[989,46238,46239],{},"Bột sốt phô mai cùng 1 pizza phải cùng vùng mới chuẩn vị.",[989,46241,46242],{},"Vì cả 3 ra từ cùng 1 xưởng nên nhất quán tự đảm bảo.",[989,46244,46245],{},"Không cần lập trình viên nhớ bằng kỷ luật.",[989,46247,46248],{},"Rẽ nhánh thủ công không bao giờ đảm bảo được điều này.",[1099,46250,46251,46262],{},[1102,46252,46253],{},[1105,46254,46255,46257,46259],{},[1108,46256,24466],{},[1108,46258,20694],{},[1108,46260,46261],{},"Abstract Factory",[1118,46263,46264,46275,46286],{},[1105,46265,46266,46269,46272],{},[1123,46267,46268],{},"Tạo ra",[1123,46270,46271],{},"1 product",[1123,46273,46274],{},"Cả họ product",[1105,46276,46277,46280,46283],{},[1123,46278,46279],{},"Ai quyết định",[1123,46281,46282],{},"Lớp con creator",[1123,46284,46285],{},"Xưởng từng họ",[1105,46287,46288,46291,46294],{},[1123,46289,46290],{},"Nhất quán họ",[1123,46292,46293],{},"Không đặt ra",[1123,46295,46296],{},"Đảm bảo bởi cấu trúc",[968,46298,1433],{"id":1432},[986,46300,46301,46304,46307,46310],{},[989,46302,46303],{},"Input: chuẩn bị pizza phô mai New York. Output: bột sốt phô mai đều bản New York.",[989,46305,46306],{},"Giải thích: cùng 1 xưởng nên không lẫn món Chicago.",[989,46308,46309],{},"Input: thêm xưởng California. Output: pizza mới dùng bộ mới, 2 vùng cũ nguyên vẹn.",[989,46311,46312],{},"Giải thích: thêm họ mới không chạm code cũ.",[968,46314,1482],{"id":1481},[973,46316,1485,46317,4801,46319,1517],{},[1487,46318,4800],{},[992,46320,46321],{},"day-074\u002F",[981,46323,46325],{"id":46324},"bài-1-xưởng-nguyên-liệu-theo-vùng","Bài 1: Xưởng nguyên liệu theo vùng",[1352,46327,46329],{"className":1393,"code":46328,"language":1395,"meta":1357,"style":1357},"struct Dough { virtual std::string name() const = 0; virtual ~Dough() = default; };\nstruct Sauce { ... }; struct Cheese { ... }; struct Clams { ... };\nstruct PizzaIngredientFactory {\n  virtual std::unique_ptr\u003CDough>  createDough()  = 0;\n  virtual std::unique_ptr\u003CSauce>  createSauce()  = 0;\n  virtual std::unique_ptr\u003CCheese> createCheese() = 0;\n  virtual std::unique_ptr\u003CClams>  createClams()  = 0;\n  virtual ~PizzaIngredientFactory() = default;\n};\n",[992,46330,46331,46336,46341,46346,46351,46356,46361,46366,46371],{"__ignoreMap":1357},[1023,46332,46333],{"class":1362,"line":63},[1023,46334,46335],{},"struct Dough { virtual std::string name() const = 0; virtual ~Dough() = default; };\n",[1023,46337,46338],{"class":1362,"line":68},[1023,46339,46340],{},"struct Sauce { ... }; struct Cheese { ... }; struct Clams { ... };\n",[1023,46342,46343],{"class":1362,"line":73},[1023,46344,46345],{},"struct PizzaIngredientFactory {\n",[1023,46347,46348],{"class":1362,"line":78},[1023,46349,46350],{},"  virtual std::unique_ptr\u003CDough>  createDough()  = 0;\n",[1023,46352,46353],{"class":1362,"line":83},[1023,46354,46355],{},"  virtual std::unique_ptr\u003CSauce>  createSauce()  = 0;\n",[1023,46357,46358],{"class":1362,"line":88},[1023,46359,46360],{},"  virtual std::unique_ptr\u003CCheese> createCheese() = 0;\n",[1023,46362,46363],{"class":1362,"line":93},[1023,46364,46365],{},"  virtual std::unique_ptr\u003CClams>  createClams()  = 0;\n",[1023,46367,46368],{"class":1362,"line":98},[1023,46369,46370],{},"  virtual ~PizzaIngredientFactory() = default;\n",[1023,46372,46373],{"class":1362,"line":103},[1023,46374,4866],{},[1099,46376,46377,46396],{},[1102,46378,46379],{},[1105,46380,46381,46384,46387,46390,46393],{},[1108,46382,46383],{},"Xưởng",[1108,46385,46386],{},"Dough",[1108,46388,46389],{},"Sauce",[1108,46391,46392],{},"Cheese",[1108,46394,46395],{},"Clams",[1118,46397,46398,46425],{},[1105,46399,46400,46405,46410,46415,46420],{},[1123,46401,46402],{},[992,46403,46404],{},"NYPizzaIngredientFactory",[1123,46406,46407],{},[992,46408,46409],{},"ThinCrustDough",[1123,46411,46412],{},[992,46413,46414],{},"MarinaraSauce",[1123,46416,46417],{},[992,46418,46419],{},"ReggianoCheese",[1123,46421,46422],{},[992,46423,46424],{},"FreshClams",[1105,46426,46427,46432,46437,46442,46447],{},[1123,46428,46429],{},[992,46430,46431],{},"ChicagoPizzaIngredientFactory",[1123,46433,46434],{},[992,46435,46436],{},"ThickCrustDough",[1123,46438,46439],{},[992,46440,46441],{},"PlumTomatoSauce",[1123,46443,46444],{},[992,46445,46446],{},"MozzarellaCheese",[1123,46448,46449],{},[992,46450,46451],{},"FrozenClams",[973,46453,46454,1509,46457,5016,46460,1838,46463,46466,46467,46469],{},[992,46455,46456],{},"CheesePizza",[992,46458,46459],{},"ClamPizza",[992,46461,46462],{},"PizzaIngredientFactory&",[992,46464,46465],{},"prepare()"," hỏi xưởng lấy nguyên liệu. Hai lớp pizza ",[1487,46468,41587],{}," biết vùng nào.",[1352,46471,46474],{"className":46472,"code":46473,"language":2241,"meta":1357},[2239],"NYPizzaStore.order(\"cheese\")      -> nguyên liệu [Thin Crust, Marinara, Reggiano]\nChicagoPizzaStore.order(\"clam\")   -> [Thick Crust, Plum Tomato, Mozzarella, Frozen Clams]\n",[992,46475,46473],{"__ignoreMap":1357},[973,46477,46478],{},"Viết test kiểm tra mọi nguyên liệu trong 1 pizza cùng vùng.",[981,46480,20891],{"id":20890},[973,46482,5030,46483,18407,46486,1656,46489,1656,46492,1656,46495,46497,46498,46500],{},[992,46484,46485],{},"CaliforniaPizzaIngredientFactory",[992,46487,46488],{},"CauliflowerDough",[992,46490,46491],{},"PestoSauce",[992,46493,46494],{},"GoatCheese",[992,46496,46424],{},") và ",[992,46499,20896],{},". Không file cũ nào đổi.",[973,46502,46503,46504,8530,46507,46510,46511,46513],{},"Sau đó thêm nguyên liệu mới ",[992,46505,46506],{},"Veggies",[1487,46508,46509],{},"mọi"," xưởng. Đếm số file phải sửa. Ghi vào ",[992,46512,2513],{},": đây là điểm yếu của Abstract Factory.",[981,46515,46517],{"id":46516},"bài-3-giao-diện-đa-nền-tảng-nâng-cao","Bài 3: Giao diện đa nền tảng (nâng cao)",[973,46519,46520,46521,1656,46524,1656,46527,46530,46531,1509,46534,46537,46538,46541],{},"Mô phỏng bộ widget: ",[992,46522,46523],{},"Button",[992,46525,46526],{},"Checkbox",[992,46528,46529],{},"TextField",". Hai họ: ",[992,46532,46533],{},"LightTheme",[992,46535,46536],{},"DarkTheme",". Mỗi widget có ",[992,46539,46540],{},"std::string render()"," trả chuỗi mô tả màu nền, màu chữ.",[2273,46543,46544,46550,46559],{},[989,46545,46546,46549],{},[992,46547,46548],{},"WidgetFactory"," với 2 cài đặt.",[989,46551,46552,5016,46555,46558],{},[992,46553,46554],{},"LoginForm",[992,46556,46557],{},"WidgetFactory&",", dựng form 2 ô nhập, 1 checkbox, 1 nút.",[989,46560,46561,46562,46565],{},"Chọn xưởng từ biến môi trường ",[992,46563,46564],{},"THEME",". Viết test chứng minh không có widget sáng nào lọt vào form tối.",[981,46567,2711],{"id":2710},[986,46569,46571,46577,46583,46592],{"className":46570},[2715],[989,46572,46574,46576],{"className":46573},[2719],[2721,46575],{"disabled":2723,"type":2724}," Test nhất quán nguyên liệu theo vùng pass.",[989,46578,46580,46582],{"className":46579},[2719],[2721,46581],{"disabled":2723,"type":2724}," Thêm California không sửa file cũ.",[989,46584,46586,46588,46589,46591],{"className":46585},[2719],[2721,46587],{"disabled":2723,"type":2724}," Có số file phải sửa khi thêm ",[992,46590,46506],{}," kèm nhận xét.",[989,46593,46595,46597],{"className":46594},[2719],[2721,46596],{"disabled":2723,"type":2724}," Vẽ sơ đồ lớp: xưởng trừu tượng, 2 xưởng cụ thể, 2 họ sản phẩm.",[968,46599,2890],{"id":2889},[986,46601,46602,46605,46608,46611],{},[989,46603,46604],{},"Abstract Factory tạo ra cái gì?",[989,46606,46607],{},"Xưởng vùng giúp pizza nhất quán thế nào?",[989,46609,46610],{},"Thêm họ mới và thêm món mới cái nào dễ?",[989,46612,46613],{},"Khác Factory Method ở điểm nào?",[3014,46615],{},[973,46617,46618],{},"🌕 Bạn đã hoàn thành ngày 74. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,46620,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":46622},[46623,46624,46629,46630,46636],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":46625},[46626,46627,46628],{"id":46197,"depth":73,"text":46198},{"id":46215,"depth":73,"text":46216},{"id":46233,"depth":73,"text":46234},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":46631},[46632,46633,46634,46635],{"id":46324,"depth":73,"text":46325},{"id":20890,"depth":73,"text":20891},{"id":46516,"depth":73,"text":46517},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Abstract Factory, xưởng nguyên liệu theo vùng, và cách pizza dùng họ nguyên liệu mà không biết tên cụ thể.",{},[5194],{"title":425,"description":46637},[16071,46642],"abstract-factory","dU7GMUlF1GfKBHR6fNt7wpLe8s8eWLs7MuZVaVe5KQE",{"id":46645,"title":430,"body":46646,"category":5189,"day":433,"description":47036,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":47037,"navigation":2723,"outcomes":3047,"path":431,"prerequisites":47038,"seo":47039,"stem":432,"tags":47040,"__hash__":47042},"challenges\u002Fchallenges\u002F75.factory-so-sanh.md",{"type":965,"value":46647,"toc":47019},[46648,46650,46653,46655,46659,46676,46680,46691,46750,46754,46768,46771,46785,46787,46801,46803,46811,46815,46832,46894,46901,46905,46910,46931,46937,46940,46944,46947,46967,46969,46998,47000,47014,47016],[968,46649,971],{"id":970},[973,46651,46652],{},"Bài này học cách chọn giữa 3 loại factory. Bạn dùng nó để không thiết kế thừa cho bài toán nhỏ.",[968,46654,979],{"id":978},[981,46656,46658],{"id":46657},"hành-trình-pizza-store","Hành trình Pizza Store",[986,46660,46661,46664,46667,46670,46673],{},[989,46662,46663],{},"Nấc 1: rẽ nhánh tạo pizza trong thân cửa hàng.",[989,46665,46666],{},"Nấc 2: gom vào xưởng đơn giản, cửa hàng sạch nhưng xưởng phình.",[989,46668,46669],{},"Nấc 3: mỗi chi nhánh tự tạo pizza vùng mình theo khung chung.",[989,46671,46672],{},"Nấc 4: gom nguyên liệu thành xưởng theo họ cho nhất quán.",[989,46674,46675],{},"Ví dụ đời thường: như quán nhỏ 1 bếp, lớn dần mới cần nhiều bếp chuyên.",[981,46677,46679],{"id":46678},"bảng-so-sánh","Bảng so sánh",[986,46681,46682,46685,46688],{},[989,46683,46684],{},"Xưởng đơn giản: 1 món theo tên gọi, xưởng trung tâm quyết.",[989,46686,46687],{},"Factory Method: 1 product, lớp con quyết định.",[989,46689,46690],{},"Abstract Factory: cả họ product, xưởng từng họ quyết.",[1099,46692,46693,46708],{},[1102,46694,46695],{},[1105,46696,46697,46699,46702,46705],{},[1108,46698,5414],{},[1108,46700,46701],{},"Đơn giản",[1108,46703,46704],{},"Method",[1108,46706,46707],{},"Abstract",[1118,46709,46710,46722,46736],{},[1105,46711,46712,46714,46717,46719],{},[1123,46713,46268],{},[1123,46715,46716],{},"1 món",[1123,46718,46271],{},[1123,46720,46721],{},"Cả họ",[1105,46723,46724,46727,46730,46733],{},[1123,46725,46726],{},"Thêm họ mới",[1123,46728,46729],{},"Sửa xưởng",[1123,46731,46732],{},"Thêm lớp mới",[1123,46734,46735],{},"Thêm xưởng mới",[1105,46737,46738,46741,46744,46747],{},[1123,46739,46740],{},"Thêm món mới",[1123,46742,46743],{},"Sửa 1 chỗ",[1123,46745,46746],{},"Thêm từng vùng",[1123,46748,46749],{},"Sửa mọi xưởng",[981,46751,46753],{"id":46752},"nghịch-lý-mở-rộng","Nghịch lý mở rộng",[986,46755,46756,46759,46762,46765],{},[989,46757,46758],{},"Mọi thiết kế dễ theo 1 chiều và khó theo chiều còn lại.",[989,46760,46761],{},"Thêm họ mới thì Method và Abstract dễ, code cũ nguyên vẹn.",[989,46763,46764],{},"Thêm món mới vào Abstract rất đau vì sửa mọi xưởng.",[989,46766,46767],{},"Phải cược vào chiều nào hay đổi hơn theo lịch sử dự án.",[981,46769,41073],{"id":46770},"cây-quyết-định",[986,46772,46773,46776,46779,46782],{},[989,46774,46775],{},"Không có họ biến thể thì tạo trực tiếp cho gọn.",[989,46777,46778],{},"Logic tạo lặp nhiều nơi thì xưởng đơn giản là đủ.",[989,46780,46781],{},"Có khung chung mà khâu tạo đổi theo biến thể thì Method.",[989,46783,46784],{},"Sản phẩm phải đi cùng họ nhất quán thì Abstract.",[968,46786,1433],{"id":1432},[986,46788,46789,46792,46795,46798],{},[989,46790,46791],{},"Input: thêm vùng mới vào hệ Factory Method. Output: khung cũ nguyên vẹn, vùng mới chạy đúng quy trình.",[989,46793,46794],{},"Giải thích: thêm creator mới không chạm khung.",[989,46796,46797],{},"Input: thêm món mới vào hệ Abstract Factory. Output: phải sửa giao diện và mọi xưởng.",[989,46799,46800],{},"Giải thích: không có cách thêm mà không chạm code cũ.",[968,46802,1482],{"id":1481},[973,46804,1485,46805,4801,46807,46810],{},[1487,46806,4800],{},[992,46808,46809],{},"day-075\u002F",". Bài này là so sánh có code minh họa.",[981,46812,46814],{"id":46813},"bài-1-bốn-nấc-tiến-hóa","Bài 1: Bốn nấc tiến hóa",[973,46816,46817,46818,10880,46821,46824,46825,1509,46828,46831],{},"Viết 4 thư mục ",[992,46819,46820],{},"step1\u002F",[992,46822,46823],{},"step4\u002F",", cùng làm 1 việc: cửa hàng bán pizza ",[992,46826,46827],{},"cheese",[992,46829,46830],{},"clam"," cho 2 vùng NY và Chicago.",[1099,46833,46834,46844],{},[1102,46835,46836],{},[1105,46837,46838,46841],{},[1108,46839,46840],{},"Thư mục",[1108,46842,46843],{},"Cách tạo đối tượng",[1118,46845,46846,46860,46873,46885],{},[1105,46847,46848,46852],{},[1123,46849,46850],{},[992,46851,46820],{},[1123,46853,46854,46857,46858],{},[992,46855,46856],{},"if\u002Felse"," lồng nhau theo vùng và loại, ngay trong ",[992,46859,20864],{},[1105,46861,46862,46867],{},[1123,46863,46864],{},[992,46865,46866],{},"step2\u002F",[1123,46868,46869,46870],{},"Simple Factory nhận ",[992,46871,46872],{},"(vùng, loại)",[1105,46874,46875,46880],{},[1123,46876,46877],{},[992,46878,46879],{},"step3\u002F",[1123,46881,46882,46883],{},"Factory Method: mỗi chi nhánh ghi đè ",[992,46884,20867],{},[1105,46886,46887,46891],{},[1123,46888,46889],{},[992,46890,46823],{},[1123,46892,46893],{},"Factory Method + Abstract Factory nguyên liệu",[973,46895,46896,46897,46900],{},"Mỗi bước có cùng 1 file test ",[992,46898,46899],{},"order_test.cpp"," và cho cùng output.",[981,46902,46904],{"id":46903},"bài-2-đo-chi-phí-thay-đổi","Bài 2: Đo chi phí thay đổi",[973,46906,46907,46908,4437],{},"Áp 3 thay đổi lên cả 4 bước. Mỗi thay đổi đếm số file và số dòng bị sửa bằng ",[992,46909,14320],{},[2273,46911,46912,46918,46924],{},[989,46913,46914,46915,1517],{},"Thêm loại pizza ",[992,46916,46917],{},"veggie",[989,46919,46920,46921,1517],{},"Thêm vùng ",[992,46922,46923],{},"California",[989,46925,46926,46927,46930],{},"Thêm nguyên liệu mới ",[992,46928,46929],{},"Pepperoni"," cho mọi vùng.",[1352,46932,46935],{"className":46933,"code":46934,"language":2241,"meta":1357},[2239],"thay_đổi         step1        step2        step3        step4\nthêm veggie      ... files    ...\nthêm California  ...\nthêm Pepperoni   ...\n",[992,46936,46934],{"__ignoreMap":1357},[973,46938,46939],{},"Viết 5 câu kết luận: mỗi pattern dễ theo chiều nào, khó theo chiều nào.",[981,46941,46943],{"id":46942},"bài-3-chọn-pattern-cho-tình-huống-nâng-cao","Bài 3: Chọn pattern cho tình huống (nâng cao)",[973,46945,46946],{},"Với mỗi tình huống, chọn: tạo trực tiếp, Simple Factory, Factory Method, Abstract Factory. Viết 2 câu lý do và phác thảo interface (5-10 dòng code):",[2273,46948,46949,46952,46955,46958,46964],{},[989,46950,46951],{},"Ứng dụng đọc ảnh PNG, JPEG, WebP theo đuôi file.",[989,46953,46954],{},"Thư viện kiểm thử cho phép người dùng tự định nghĩa cách tạo test fixture.",[989,46956,46957],{},"Game có 3 chủng tộc, mỗi chủng tộc có lính, nhà, vũ khí riêng phải đi cùng nhau.",[989,46959,16860,46960,46963],{},[992,46961,46962],{},"std::vector\u003Cint>"," rỗng.",[989,46965,46966],{},"Driver cơ sở dữ liệu: MySQL, Postgres, SQLite, mỗi loại có Connection, Statement, ResultSet.",[981,46968,2711],{"id":2710},[986,46970,46972,46978,46986,46992],{"className":46971},[2715],[989,46973,46975,46977],{"className":46974},[2719],[2721,46976],{"disabled":2723,"type":2724}," 4 bước cùng pass 1 file test.",[989,46979,46981,46983,46984,1517],{"className":46980},[2719],[2721,46982],{"disabled":2723,"type":2724}," Bảng đo chi phí thay đổi có số thật từ ",[992,46985,14320],{},[989,46987,46989,46991],{"className":46988},[2719],[2721,46990],{"disabled":2723,"type":2724}," Bài 3 có lựa chọn và interface cho cả 5 tình huống.",[989,46993,46995,46997],{"className":46994},[2719],[2721,46996],{"disabled":2723,"type":2724}," Phân biệt được 3 loại factory bằng 1 câu mỗi loại.",[968,46999,2890],{"id":2889},[986,47001,47002,47005,47008,47011],{},[989,47003,47004],{},"Ba factory khác nhau ở đối tượng tạo ra là gì?",[989,47006,47007],{},"Nghịch lý mở rộng nghĩa là gì?",[989,47009,47010],{},"Khi nào xưởng đơn giản là đủ?",[989,47012,47013],{},"Dấu hiệu nào báo cần nâng lên Method hay Abstract?",[3014,47015],{},[973,47017,47018],{},"🌕 Bạn đã hoàn thành ngày 75. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":47020},[47021,47022,47028,47029,47035],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":47023},[47024,47025,47026,47027],{"id":46657,"depth":73,"text":46658},{"id":46678,"depth":73,"text":46679},{"id":46752,"depth":73,"text":46753},{"id":46770,"depth":73,"text":41073},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":47030},[47031,47032,47033,47034],{"id":46813,"depth":73,"text":46814},{"id":46903,"depth":73,"text":46904},{"id":46942,"depth":73,"text":46943},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đặt Simple Factory, Factory Method và Abstract Factory cạnh nhau, chốt nghịch lý thêm họ dễ thêm món khó và cẩm nang chọn.",{},[5194],{"title":430,"description":47036},[16071,47041],"comparison","Dzs_Vlerub0s2B8ad3cs2Dta3BjDRdCbrheGX2xkRcw",{"id":47044,"title":435,"body":47045,"category":8797,"day":438,"description":47526,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":47527,"navigation":2723,"outcomes":3047,"path":436,"prerequisites":47528,"seo":47529,"stem":437,"tags":47530,"__hash__":47534},"challenges\u002Fchallenges\u002F76.quy-hoach-tuyen-tinh.md",{"type":965,"value":47046,"toc":47509},[47047,47049,47052,47054,47058,47072,47076,47090,47110,47114,47128,47131,47145,47147,47161,47163,47177,47181,47362,47376,47382,47385,47389,47392,47398,47418,47422,47425,47431,47452,47454,47486,47488,47502,47504,47507],[968,47048,971],{"id":970},[973,47050,47051],{},"Bài này học mô tả bài toán bằng hàm mục tiêu và ràng buộc. Bạn dùng nó để tính sản lượng lãi nhất cho xưởng.",[968,47053,979],{"id":978},[981,47055,47057],{"id":47056},"ý-tưởng-chính","Ý tưởng chính",[986,47059,47060,47063,47066,47069],{},[989,47061,47062],{},"Không thiết kế bước đi, chỉ mô tả cái gì tốt và cái gì cấm.",[989,47064,47065],{},"Giao cho bộ giải tìm nghiệm tốt nhất.",[989,47067,47068],{},"Ví dụ đời thường: như nói muốn lãi nhất trong giới hạn nguyên liệu, để máy tính chia việc.",[989,47070,47071],{},"Họ hàng: chia để trị, quy hoạch động, tham lam.",[981,47073,47075],{"id":47074},"hàm-mục-tiêu-và-ràng-buộc","Hàm mục tiêu và ràng buộc",[986,47077,47078,47081,47084,47087],{},[989,47079,47080],{},"Biến quyết định: ví dụ sản lượng từng sản phẩm.",[989,47082,47083],{},"Hàm mục tiêu: ví dụ tổng lợi nhuận cần cực đại.",[989,47085,47086],{},"Ràng buộc: giới hạn giờ máy, nguyên liệu, không âm.",[989,47088,47089],{},"Giao các ràng buộc tạo đa diện lồi, nghiệm tốt nhất nằm ở 1 đỉnh.",[1352,47091,47093],{"className":3538,"code":47092,"language":3540,"meta":1357,"style":1357},"# Ví dụ: A lãi 3, B lãi 5; máy 8h, liệu 8kg\n# max 3*A + 5*B với A + 2*B \u003C= 8, 2*A + B \u003C= 8\n# thử từng đỉnh miền khả thi là ra đáp án\n",[992,47094,47095,47100,47105],{"__ignoreMap":1357},[1023,47096,47097],{"class":1362,"line":63},[1023,47098,47099],{},"# Ví dụ: A lãi 3, B lãi 5; máy 8h, liệu 8kg\n",[1023,47101,47102],{"class":1362,"line":68},[1023,47103,47104],{},"# max 3*A + 5*B với A + 2*B \u003C= 8, 2*A + B \u003C= 8\n",[1023,47106,47107],{"class":1362,"line":73},[1023,47108,47109],{},"# thử từng đỉnh miền khả thi là ra đáp án\n",[981,47111,47113],{"id":47112},"ví-dụ-xưởng-sản-xuất","Ví dụ xưởng sản xuất",[986,47115,47116,47119,47122,47125],{},[989,47117,47118],{},"Mỗi sản phẩm tốn định mức máy và liệu khác nhau.",[989,47120,47121],{},"Đọc nghiệm còn đọc giá bóng: nới 1 giờ máy thì lãi thêm bao nhiêu.",[989,47123,47124],{},"Ràng buộc nào đang thắt thì đầu tư vào đó.",[989,47126,47127],{},"Đây là cầu nối giữa toán tối ưu và quyết định kinh doanh.",[981,47129,10673],{"id":47130},"khi-nào-dùng",[986,47132,47133,47136,47139,47142],{},[989,47134,47135],{},"Hợp khi chi phí và tiêu hao xấp xỉ tuyến tính.",[989,47137,47138],{},"Biến nhận giá trị lẻ được như số giờ, số kg.",[989,47140,47141],{},"Không hợp khi biến phải nguyên như số xe, số người.",[989,47143,47144],{},"Viết sai hàm mục tiêu là lỗi nguy hiểm nhất.",[968,47146,1433],{"id":1432},[986,47148,47149,47152,47155,47158],{},[989,47150,47151],{},"Input: xưởng A lãi 3, B lãi 5, máy và liệu đều 8. Output: sản lượng tối ưu ở 1 đỉnh.",[989,47153,47154],{},"Giải thích: nghiệm tuyến tính trên đa diện lồi luôn ở đỉnh.",[989,47156,47157],{},"Input: nới ràng buộc đang thắt thêm 1 đơn vị. Output: lợi nhuận không giảm.",[989,47159,47160],{},"Giải thích: nới chỗ thắt thì miền rộng ra, nghiệm chỉ tốt hơn.",[968,47162,1482],{"id":1481},[973,47164,1485,47165,47167,47168,5586,47171,5599,47174,1517],{},[1487,47166,13531],{},". Bài 2-3 dùng ",[992,47169,47170],{},"scipy.optimize.linprog",[992,47172,47173],{},"PuLP",[992,47175,47176],{},"day-076\u002F",[981,47178,47180],{"id":47179},"bài-1-giải-bằng-đỉnh-2-biến","Bài 1: Giải bằng đỉnh (2 biến)",[973,47182,1505,47183,47186,47187,7386,47251,1656,47307,1656,47359,1517],{},[992,47184,47185],{},"solve_2d(c, A, b)"," cho bài: cực đại ",[1023,47188,47190,47210],{"className":47189},[1026],[1023,47191,47193],{"className":47192},[1030],[1032,47194,47195],{"xmlns":1034},[1036,47196,47197,47207],{},[1039,47198,47199,47205],{},[2327,47200,47201,47203],{},[1042,47202,1356],{},[1042,47204,38209],{},[1042,47206,3904],{},[1058,47208,47209],{"encoding":1060},"c^T x",[1023,47211,47213],{"className":47212,"ariaHidden":1066},[1065],[1023,47214,47216,47219,47248],{"className":47215},[1070],[1023,47217],{"className":47218,"style":38290},[1074],[1023,47220,47222,47225],{"className":47221},[1079],[1023,47223,1356],{"className":47224},[1079,1080],[1023,47226,47228],{"className":47227},[2383],[1023,47229,47231],{"className":47230},[2387],[1023,47232,47234],{"className":47233},[2391],[1023,47235,47237],{"className":47236,"style":38290},[2395],[1023,47238,47239,47242],{"style":2398},[1023,47240],{"className":47241,"style":2403},[2402],[1023,47243,47245],{"className":47244},[2407,2408,2409,2410],[1023,47246,38209],{"className":47247,"style":37429},[1079,1080,2410],[1023,47249,3904],{"className":47250},[1079,1080],[1023,47252,47254,47274],{"className":47253},[1026],[1023,47255,47257],{"className":47256},[1030],[1032,47258,47259],{"xmlns":1034},[1036,47260,47261,47271],{},[1039,47262,47263,47265,47267,47269],{},[1042,47264,22382],{},[1042,47266,3904],{},[1046,47268,21123],{},[1042,47270,17703],{},[1058,47272,47273],{"encoding":1060},"Ax \\le b",[1023,47275,47277,47298],{"className":47276,"ariaHidden":1066},[1065],[1023,47278,47280,47283,47286,47289,47292,47295],{"className":47279},[1070],[1023,47281],{"className":47282,"style":21161},[1074],[1023,47284,22382],{"className":47285},[1079,1080],[1023,47287,3904],{"className":47288},[1079,1080],[1023,47290],{"className":47291,"style":2355},[2354],[1023,47293,21123],{"className":47294},[2359],[1023,47296],{"className":47297,"style":2355},[2354],[1023,47299,47301,47304],{"className":47300},[1070],[1023,47302],{"className":47303,"style":22079},[1074],[1023,47305,17703],{"className":47306},[1079,1080],[1023,47308,47310,47328],{"className":47309},[1026],[1023,47311,47313],{"className":47312},[1030],[1032,47314,47315],{"xmlns":1034},[1036,47316,47317,47325],{},[1039,47318,47319,47321,47323],{},[1042,47320,3904],{},[1046,47322,43557],{},[1051,47324,2379],{},[1058,47326,47327],{"encoding":1060},"x \\ge 0",[1023,47329,47331,47350],{"className":47330,"ariaHidden":1066},[1065],[1023,47332,47334,47338,47341,47344,47347],{"className":47333},[1070],[1023,47335],{"className":47336,"style":47337},[1074],"height:0.7719em;vertical-align:-0.136em;",[1023,47339,3904],{"className":47340},[1079,1080],[1023,47342],{"className":47343,"style":2355},[2354],[1023,47345,43557],{"className":47346},[2359],[1023,47348],{"className":47349,"style":2355},[2354],[1023,47351,47353,47356],{"className":47352},[1070],[1023,47354],{"className":47355,"style":10020},[1074],[1023,47357,2379],{"className":47358},[1079],[1487,47360,47361],{},"đúng 2 biến",[2273,47363,47364,47367,47370],{},[989,47365,47366],{},"Tìm mọi giao điểm của từng cặp đường biên (kể cả trục tọa độ).",[989,47368,47369],{},"Giữ các điểm thỏa mọi ràng buộc.",[989,47371,47372,47373,1517],{},"Trả điểm có giá trị mục tiêu lớn nhất. Miền rỗng thì báo ",[992,47374,47375],{},"infeasible",[1352,47377,47380],{"className":47378,"code":47379,"language":2241,"meta":1357},[2239],"max 3A + 5B, A + 2B \u003C= 8, 2A + B \u003C= 8 -> A = B = 8\u002F3, giá trị 21.33\nĐỉnh khả thi: (0,0), (4,0), (0,4), (8\u002F3, 8\u002F3)\nA + B \u003C= 1, A + B >= 3                -> infeasible\n",[992,47381,47379],{"__ignoreMap":1357},[973,47383,47384],{},"Vẽ miền khả thi và đường mức hàm mục tiêu bằng matplotlib.",[981,47386,47388],{"id":47387},"bài-2-lập-kế-hoạch-sản-xuất","Bài 2: Lập kế hoạch sản xuất",[973,47390,47391],{},"Xưởng làm 3 sản phẩm bàn, ghế, tủ:",[1352,47393,47396],{"className":47394,"code":47395,"language":2241,"meta":1357},[2239],"            gỗ(m3)   giờ_máy   giờ_công   lãi(triệu)\nbàn         0.5      2         3          1.2\nghế         0.2      1         1          0.5\ntủ          1.0      3         4          2.0\nGiới hạn:   40       120       150\nGhế ít nhất 2 lần số bàn (bộ bàn ghế).\n",[992,47397,47395],{"__ignoreMap":1357},[2273,47399,47400,47405,47412],{},[989,47401,47402,47403,16014],{},"Viết mô hình: biến, hàm mục tiêu, ràng buộc (dạng toán trong ",[992,47404,2513],{},[989,47406,47407,47408,47411],{},"Giải bằng ",[992,47409,47410],{},"linprog",". In sản lượng tối ưu và lãi.",[989,47413,9007,47414,47417],{},[1487,47415,47416],{},"giá bóng"," (dual value) của 3 tài nguyên. Nếu được mua thêm 10 giờ máy giá 0.3 triệu\u002Fgiờ thì có nên mua không?",[981,47419,47421],{"id":47420},"bài-3-capacity-planning-và-số-nguyên-nâng-cao","Bài 3: Capacity planning và số nguyên (nâng cao)",[973,47423,47424],{},"Công ty chọn thuê máy chủ 3 loại để phục vụ tải 2000 req\u002Fs, bộ nhớ ít nhất 512 GB:",[1352,47426,47429],{"className":47427,"code":47428,"language":2241,"meta":1357},[2239],"loại    req\u002Fs   RAM(GB)   giá\u002Ftháng\nsmall   150     16        40\nmedium  400     64        110\nlarge   900     128       230\n",[992,47430,47428],{"__ignoreMap":1357},[2273,47432,47433,47436,47449],{},[989,47434,47435],{},"Giải LP thường (cho phép số máy lẻ). In chi phí.",[989,47437,47438,47439,47442,47443,5586,47445,47448],{},"Giải bài ",[1487,47440,47441],{},"số nguyên"," (ILP) bằng ",[992,47444,47173],{},[992,47446,47447],{},"scipy.optimize.milp",". So chi phí.",[989,47450,47451],{},"Làm tròn lên nghiệm LP. So với ILP. Viết 2 câu vì sao làm tròn không luôn tối ưu.",[981,47453,2711],{"id":2710},[986,47455,47457,47468,47474,47480],{"className":47456},[2715],[989,47458,47460,2308,47462,33656,47465,47467],{"className":47459},[2719],[2721,47461],{"disabled":2723,"type":2724},[992,47463,47464],{},"solve_2d",[992,47466,47410],{}," trên 20 bài 2 biến ngẫu nhiên.",[989,47469,47471,47473],{"className":47470},[2719],[2721,47472],{"disabled":2723,"type":2724}," Bài 2 có mô hình toán, nghiệm và quyết định mua giờ máy dựa trên giá bóng.",[989,47475,47477,47479],{"className":47476},[2719],[2721,47478],{"disabled":2723,"type":2724}," Bài 3 có bảng LP, làm tròn, ILP.",[989,47481,47483,47485],{"className":47482},[2719],[2721,47484],{"disabled":2723,"type":2724}," Có hình miền khả thi.",[968,47487,2890],{"id":2889},[986,47489,47490,47493,47496,47499],{},[989,47491,47492],{},"Hàm mục tiêu và ràng buộc là gì?",[989,47494,47495],{},"Vì sao nghiệm tối ưu nằm ở đỉnh?",[989,47497,47498],{},"Giá bóng của ràng buộc nghĩa là gì?",[989,47500,47501],{},"Khi nào không nên ép bài toán thành tuyến tính?",[3014,47503],{},[973,47505,47506],{},"🌕 Bạn đã hoàn thành ngày 76. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,47508,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":47510},[47511,47512,47518,47519,47525],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":47513},[47514,47515,47516,47517],{"id":47056,"depth":73,"text":47057},{"id":47074,"depth":73,"text":47075},{"id":47112,"depth":73,"text":47113},{"id":47130,"depth":73,"text":10673},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":47520},[47521,47522,47523,47524],{"id":47179,"depth":73,"text":47180},{"id":47387,"depth":73,"text":47388},{"id":47420,"depth":73,"text":47421},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thiết kế thuật toán bằng quy hoạch tuyến tính: hàm mục tiêu, ràng buộc, và bài toán hoạch định năng lực với ví dụ xưởng sản xuất.",{},[15144],{"title":435,"description":47526},[47531,47532,47533],"linear-programming","optimization","design","dHEMO9wvHvO07x9p5HSfY-o1CCynh99330RWtXVHHqw",{"id":47536,"title":440,"body":47537,"category":8797,"day":443,"description":48144,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":48145,"navigation":2723,"outcomes":3047,"path":441,"prerequisites":48146,"seo":48147,"stem":442,"tags":48148,"__hash__":48150},"challenges\u002Fchallenges\u002F77.quy-hoach-dong-nang-cao.md",{"type":965,"value":47538,"toc":48127},[47539,47541,47544,47546,47550,47564,47568,47582,47616,47620,47634,47638,47652,47654,47674,47676,47688,47692,47921,47927,47941,47945,47965,47971,48037,48041,48066,48072,48074,48104,48106,48120,48122,48125],[968,47540,971],{"id":970},[973,47542,47543],{},"Bài này học quy hoạch động với ghi nhớ và bảng. Bạn dùng nó để giải ba lô và dãy con chung.",[968,47545,979],{"id":978},[981,47547,47549],{"id":47548},"hai-điều-kiện","Hai điều kiện",[986,47551,47552,47555,47558,47561],{},[989,47553,47554],{},"Bài toán con gối nhau: nhiều nhánh trùng nhau nên lưu lại đỡ tính lại.",[989,47556,47557],{},"Cấu trúc con tối ưu: nghiệm lớn chứa nghiệm nhỏ tối ưu.",[989,47559,47560],{},"Ví dụ đời thường: như lắp Lego, mảnh nhỏ đúng thì khối lớn mới đúng.",[989,47562,47563],{},"Thiếu 1 trong 2 thì quy hoạch động chuẩn bó tay.",[981,47565,47567],{"id":47566},"ghi-nhớ-và-bảng-lặp","Ghi nhớ và bảng lặp",[986,47569,47570,47573,47576,47579],{},[989,47571,47572],{},"Ghi nhớ: giữ đệ quy cũ, thêm từ điển lưu kết quả.",[989,47574,47575],{},"Bảng lặp: điền từ cơ sở lên đích, đỡ tràn ngăn xếp.",[989,47577,47578],{},"Ghi nhớ chỉ tính chỗ chạm tới, bảng lặp chạm cả bảng.",[989,47580,47581],{},"Nén bộ nhớ được khi truy hồi có tính địa phương.",[1352,47583,47585],{"className":3538,"code":47584,"language":3540,"meta":1357,"style":1357},"# Ghi nhớ Fibonacci\nmemo = {}  # lưu kết quả đã tính\ndef fib(n):\n    if n \u003C= 1: return n  # cơ sở\n    if n not in memo: memo[n] = fib(n-1) + fib(n-2)  # nhớ để khỏi tính lại\n    return memo[n]\n",[992,47586,47587,47592,47597,47602,47607,47612],{"__ignoreMap":1357},[1023,47588,47589],{"class":1362,"line":63},[1023,47590,47591],{},"# Ghi nhớ Fibonacci\n",[1023,47593,47594],{"class":1362,"line":68},[1023,47595,47596],{},"memo = {}  # lưu kết quả đã tính\n",[1023,47598,47599],{"class":1362,"line":73},[1023,47600,47601],{},"def fib(n):\n",[1023,47603,47604],{"class":1362,"line":78},[1023,47605,47606],{},"    if n \u003C= 1: return n  # cơ sở\n",[1023,47608,47609],{"class":1362,"line":83},[1023,47610,47611],{},"    if n not in memo: memo[n] = fib(n-1) + fib(n-2)  # nhớ để khỏi tính lại\n",[1023,47613,47614],{"class":1362,"line":88},[1023,47615,8267],{},[981,47617,47619],{"id":47618},"hai-truy-hồi-kinh-điển","Hai truy hồi kinh điển",[986,47621,47622,47625,47628,47631],{},[989,47623,47624],{},"Dãy con chung: cuối khớp thì cộng 1, lệch thì lấy max 2 cách bỏ.",[989,47626,47627],{},"Ba lô 0-1: lấy max giữa bỏ vật và lấy vật cộng phần còn lại.",[989,47629,47630],{},"Cả 2 đều số trạng thái bằng tích 2 chiều.",[989,47632,47633],{},"Mỗi trạng thái chỉ vài phép tính nên nhanh hơn liệt kê mũ nhiều.",[981,47635,47637],{"id":47636},"truy-vết-ngược","Truy vết ngược",[986,47639,47640,47643,47646,47649],{},[989,47641,47642],{},"Biết giá trị tốt nhất mà không biết chọn vật nào thì chưa xong.",[989,47644,47645],{},"Đi từ ô đích lần ngược theo quyết định đã ghi.",[989,47647,47648],{},"Cần bảng quyết định song song bảng giá trị.",[989,47650,47651],{},"Muốn truy vết đầy đủ thì phải giữ cả bảng, khó nén nhớ.",[968,47653,1433],{"id":1432},[986,47655,47656,47665,47668,47671],{},[989,47657,47658,47659,1509,47661,47664],{},"Input: dãy con chung của ",[992,47660,8489],{},[992,47662,47663],{},"\"abc\"",". Output: 0.",[989,47666,47667],{},"Giải thích: chuỗi rỗng thì không có gì chung.",[989,47669,47670],{},"Input: ba lô sức chứa 0. Output: giá trị 0, chọn không vật nào.",[989,47672,47673],{},"Giải thích: không chỗ chứa thì đành tay trắng.",[968,47675,1482],{"id":1481},[973,47677,1485,47678,47680,47681,47684,47685,1517],{},[1487,47679,1493],{},". Mỗi bài viết bản bảng và ",[1487,47682,47683],{},"dựng lại nghiệm",", không chỉ trả giá trị. Nộp vào ",[992,47686,47687],{},"day-077\u002F",[981,47689,47691],{"id":47690},"bài-1-dãy-con-chung-dài-nhất-lcs","Bài 1: Dãy con chung dài nhất (LCS)",[1099,47693,47694,47702],{},[1102,47695,47696],{},[1105,47697,47698,47700],{},[1108,47699,1566],{},[1108,47701,2547],{},[1118,47703,47704,47829,47839],{},[1105,47705,47706,47711],{},[1123,47707,47708],{},[992,47709,47710],{},"int lcsLength(const std::string &a, const std::string &b)",[1123,47712,47713,47714],{},"Bảng ",[1023,47715,47717,47751],{"className":47716},[1026],[1023,47718,47720],{"className":47719},[1030],[1032,47721,47722],{"xmlns":1034},[1036,47723,47724,47748],{},[1039,47725,47726,47728,47730,47732,47734,47736,47738,47740,47742,47744,47746],{},[1046,47727,1049],{"stretchy":1048},[1042,47729,1262],{},[1046,47731,21881],{},[1051,47733,1053],{},[1046,47735,1056],{"stretchy":1048},[1046,47737,13768],{},[1046,47739,1049],{"stretchy":1048},[1042,47741,15437],{},[1046,47743,21881],{},[1051,47745,1053],{},[1046,47747,1056],{"stretchy":1048},[1058,47749,47750],{"encoding":1060},"(n+1) \\times (m+1)",[1023,47752,47754,47775,47796,47817],{"className":47753,"ariaHidden":1066},[1065],[1023,47755,47757,47760,47763,47766,47769,47772],{"className":47756},[1070],[1023,47758],{"className":47759,"style":1075},[1074],[1023,47761,1049],{"className":47762},[1085],[1023,47764,1262],{"className":47765},[1079,1080],[1023,47767],{"className":47768,"style":13790},[2354],[1023,47770,21881],{"className":47771},[13794],[1023,47773],{"className":47774,"style":13790},[2354],[1023,47776,47778,47781,47784,47787,47790,47793],{"className":47777},[1070],[1023,47779],{"className":47780,"style":1075},[1074],[1023,47782,1053],{"className":47783},[1079],[1023,47785,1056],{"className":47786},[1092],[1023,47788],{"className":47789,"style":13790},[2354],[1023,47791,13768],{"className":47792},[13794],[1023,47794],{"className":47795,"style":13790},[2354],[1023,47797,47799,47802,47805,47808,47811,47814],{"className":47798},[1070],[1023,47800],{"className":47801,"style":1075},[1074],[1023,47803,1049],{"className":47804},[1085],[1023,47806,15437],{"className":47807},[1079,1080],[1023,47809],{"className":47810,"style":13790},[2354],[1023,47812,21881],{"className":47813},[13794],[1023,47815],{"className":47816,"style":13790},[2354],[1023,47818,47820,47823,47826],{"className":47819},[1070],[1023,47821],{"className":47822,"style":1075},[1074],[1023,47824,1053],{"className":47825},[1079],[1023,47827,1056],{"className":47828},[1092],[1105,47830,47831,47836],{},[1123,47832,47833],{},[992,47834,47835],{},"std::string lcs(const std::string &a, const std::string &b)",[1123,47837,47838],{},"Truy ngược bảng để lấy chuỗi",[1105,47840,47841,47846],{},[1123,47842,47843],{},[992,47844,47845],{},"int lcsLengthLinear(...)",[1123,47847,47848,47849],{},"Chỉ 2 hàng, bộ nhớ ",[1023,47850,47852,47884],{"className":47851},[1026],[1023,47853,47855],{"className":47854},[1030],[1032,47856,47857],{"xmlns":1034},[1036,47858,47859,47881],{},[1039,47860,47861,47863,47865,47867,47869,47871,47873,47875,47877,47879],{},[1042,47862,1044],{},[1046,47864,1049],{"stretchy":1048},[1042,47866,22184],{},[1046,47868,8400],{},[1046,47870,1049],{"stretchy":1048},[1042,47872,1262],{},[1046,47874,13897],{"separator":1066},[1042,47876,15437],{},[1046,47878,1056],{"stretchy":1048},[1046,47880,1056],{"stretchy":1048},[1058,47882,47883],{"encoding":1060},"O(\\min(n, m))",[1023,47885,47887],{"className":47886,"ariaHidden":1066},[1065],[1023,47888,47890,47893,47896,47899,47902,47905,47908,47911,47914,47917],{"className":47889},[1070],[1023,47891],{"className":47892,"style":1075},[1074],[1023,47894,1044],{"className":47895,"style":1081},[1079,1080],[1023,47897,1049],{"className":47898},[1085],[1023,47900,22184],{"className":47901},[8426],[1023,47903,1049],{"className":47904},[1085],[1023,47906,1262],{"className":47907},[1079,1080],[1023,47909,13897],{"className":47910},[13943],[1023,47912],{"className":47913,"style":8434},[2354],[1023,47915,15437],{"className":47916},[1079,1080],[1023,47918,47920],{"className":47919},[1092],"))",[1352,47922,47925],{"className":47923,"code":47924,"language":2241,"meta":1357},[2239],"\"ABCBDAB\", \"BDCABA\" -> độ dài 4 (ví dụ \"BCBA\")\n\"\", \"abc\"            -> 0, \"\"\n",[992,47926,47924],{"__ignoreMap":1357},[973,47928,47929,47930,47933,47934,47936,47937,47940],{},"Ứng dụng: viết ",[992,47931,47932],{},"diff(fileA, fileB)"," in các dòng thêm ",[992,47935,21881],{},", bớt ",[992,47938,47939],{},"-"," dựa trên LCS theo dòng.",[981,47942,47944],{"id":47943},"bài-2-ba-lô-0-1","Bài 2: Ba lô 0-1",[1352,47946,47948],{"className":1393,"code":47947,"language":1395,"meta":1357,"style":1357},"struct Item { std::string name; int weight; int value; };\nstd::pair\u003Cint, std::vector\u003CItem>> knapsack(const std::vector\u003CItem> &items, int W);\nint knapsack1D(const std::vector\u003CItem> &items, int W);   \u002F\u002F mảng 1 chiều, duyệt w giảm dần\n",[992,47949,47950,47955,47960],{"__ignoreMap":1357},[1023,47951,47952],{"class":1362,"line":63},[1023,47953,47954],{},"struct Item { std::string name; int weight; int value; };\n",[1023,47956,47957],{"class":1362,"line":68},[1023,47958,47959],{},"std::pair\u003Cint, std::vector\u003CItem>> knapsack(const std::vector\u003CItem> &items, int W);\n",[1023,47961,47962],{"class":1362,"line":73},[1023,47963,47964],{},"int knapsack1D(const std::vector\u003CItem> &items, int W);   \u002F\u002F mảng 1 chiều, duyệt w giảm dần\n",[1352,47966,47969],{"className":47967,"code":47968,"language":2241,"meta":1357},[2239],"items (nặng, giá): A(1,1) B(3,4) C(4,5) D(5,7), W=7 -> 9, chọn B + C\nW=0 -> 0, rỗng\n",[992,47970,47968],{"__ignoreMap":1357},[973,47972,47973,47974,48033,48034,1517],{},"Viết thêm bản vét cạn ",[1023,47975,47977,47995],{"className":47976},[1026],[1023,47978,47980],{"className":47979},[1030],[1032,47981,47982],{"xmlns":1034},[1036,47983,47984,47992],{},[1039,47985,47986],{},[2327,47987,47988,47990],{},[1051,47989,2457],{},[1042,47991,1262],{},[1058,47993,47994],{"encoding":1060},"2^n",[1023,47996,47998],{"className":47997,"ariaHidden":1066},[1065],[1023,47999,48001,48004],{"className":48000},[1070],[1023,48002],{"className":48003,"style":8348},[1074],[1023,48005,48007,48010],{"className":48006},[1079],[1023,48008,2457],{"className":48009},[1079],[1023,48011,48013],{"className":48012},[2383],[1023,48014,48016],{"className":48015},[2387],[1023,48017,48019],{"className":48018},[2391],[1023,48020,48022],{"className":48021,"style":8348},[2395],[1023,48023,48024,48027],{"style":2398},[1023,48025],{"className":48026,"style":2403},[2402],[1023,48028,48030],{"className":48029},[2407,2408,2409,2410],[1023,48031,1262],{"className":48032},[1079,1080,2410]," để kiểm tra với ",[992,48035,48036],{},"n \u003C= 20",[981,48038,48040],{"id":48039},"bài-3-edit-distance-và-cắt-thanh-nâng-cao","Bài 3: Edit distance và cắt thanh (nâng cao)",[2273,48042,48043,48053,48063],{},[989,48044,48045,48048,48049,35512,48051,1517],{},[992,48046,48047],{},"editDistance(a, b)"," với thao tác chèn, xóa, thay, chi phí 1. In dãy thao tác biến ",[992,48050,6207],{},[992,48052,17703],{},[989,48054,48055,48056,48058,48059,48062],{},"Cắt thanh dài ",[992,48057,1262],{},", bảng giá ",[992,48060,48061],{},"p[1..n]",". Trả lãi lớn nhất và cách cắt.",[989,48064,48065],{},"Với mỗi bài, viết rõ trong comment: trạng thái, công thức chuyển, base case, thứ tự điền bảng.",[1352,48067,48070],{"className":48068,"code":48069,"language":2241,"meta":1357},[2239],"editDistance(\"kitten\", \"sitting\") -> 3 (thay k->s, thay e->i, chèn g)\np = [1,5,8,9,10,17,17,20], n=8 -> 22 (cắt 2 + 6)\n",[992,48071,48069],{"__ignoreMap":1357},[981,48073,2711],{"id":2710},[986,48075,48077,48083,48089,48098],{"className":48076},[2715],[989,48078,48080,48082],{"className":48079},[2719],[2721,48081],{"disabled":2723,"type":2724}," Test mẫu pass, nghiệm dựng lại đúng giá trị.",[989,48084,48086,48088],{"className":48085},[2719],[2721,48087],{"disabled":2723,"type":2724}," Knapsack khớp vét cạn trên 200 bộ ngẫu nhiên.",[989,48090,48092,2308,48094,48097],{"className":48091},[2719],[2721,48093],{"disabled":2723,"type":2724},[992,48095,48096],{},"diff"," in đúng trên 2 file văn bản nhỏ.",[989,48099,48101,48103],{"className":48100},[2719],[2721,48102],{"disabled":2723,"type":2724}," Mỗi bài có comment 4 mục: trạng thái, chuyển, base, thứ tự.",[968,48105,2890],{"id":2889},[986,48107,48108,48111,48114,48117],{},[989,48109,48110],{},"Hai điều kiện dùng quy hoạch động là gì?",[989,48112,48113],{},"Ghi nhớ và bảng lặp khác nhau thế nào?",[989,48115,48116],{},"Truy hồi ba lô 0-1 viết ra sao?",[989,48118,48119],{},"Truy vết ngược để làm gì?",[3014,48121],{},[973,48123,48124],{},"🌕 Bạn đã hoàn thành ngày 77. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,48126,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":48128},[48129,48130,48136,48137,48143],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":48131},[48132,48133,48134,48135],{"id":47548,"depth":73,"text":47549},{"id":47566,"depth":73,"text":47567},{"id":47618,"depth":73,"text":47619},{"id":47636,"depth":73,"text":47637},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":48138},[48139,48140,48141,48142],{"id":47690,"depth":73,"text":47691},{"id":47943,"depth":73,"text":47944},{"id":48039,"depth":73,"text":48040},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Chiến lược quy hoạch động: bài toán con gối nhau, cấu trúc con tối ưu, ghi nhớ, bảng phương án và tái cấu trúc nghiệm tối ưu.",{},[8149,15143],{"title":440,"description":48144},[15591,48149,47532],"dynamic-programming","wSxvuOnOSZhkqD-sN2glSSkAv99iy2AgGVS57rL4vJY",{"id":48152,"title":445,"body":48153,"category":8797,"day":448,"description":48818,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":48819,"navigation":2723,"outcomes":3047,"path":446,"prerequisites":48820,"seo":48821,"stem":447,"tags":48822,"__hash__":48824},"challenges\u002Fchallenges\u002F78.tsp-ba-chien-luoc.md",{"type":965,"value":48154,"toc":48801},[48155,48157,48160,48162,48166,48180,48183,48197,48201,48215,48219,48233,48279,48281,48295,48297,48305,48309,48329,48457,48463,48467,48474,48480,48489,48493,48524,48526,48778,48780,48794,48796,48799],[968,48156,971],{"id":970},[973,48158,48159],{},"Bài này học bài toán người bán hàng rong TSP. Bạn dùng nó để chọn tour ngắn nhất theo quy mô n.",[968,48161,979],{"id":978},[981,48163,48165],{"id":48164},"bài-toán-tsp","Bài toán TSP",[986,48167,48168,48171,48174,48177],{},[989,48169,48170],{},"Cho n thành phố, tìm vòng qua hết mà ngắn nhất.",[989,48172,48173],{},"Bản tối ưu thuộc lớp NP-khó. Bản quyết định \"có tour dài không quá K không\" là NP-đầy đủ: kiểm một tour cho sẵn thì dễ, tìm thì khó.",[989,48175,48176],{},"Ví dụ đời thường: như shipper tìm vòng giao hết đơn mà ít xăng nhất.",[989,48178,48179],{},"Cần cả nghiệm chuẩn n nhỏ và mẹo nhanh n lớn.",[981,48181,14538],{"id":48182},"vét-cạn",[986,48184,48185,48188,48191,48194],{},[989,48186,48187],{},"Liệt kê mọi hoán vị, tính tổng đường rồi giữ ngắn nhất.",[989,48189,48190],{},"Cố định điểm xuất phát vì tour xoay vòng là 1.",[989,48192,48193],{},"Cỡ n nhân giai thừa nên n bằng 20 là bó tay.",[989,48195,48196],{},"Giá trị duy nhất là đáp án chuẩn để chấm mẹo khác.",[981,48198,48200],{"id":48199},"tham-lam-láng-giềng-gần-nhất","Tham lam láng giềng gần nhất",[986,48202,48203,48206,48209,48212],{},[989,48204,48205],{},"Mỗi bước đi tới thành phố chưa thăm gần nhất.",[989,48207,48208],{},"Chỉ cỡ n bình phương nên chạy tới hàng nghìn thành phố.",[989,48210,48211],{},"Không bảo đảm tốt: vét sạch cụm gần rồi nhảy đắt sang cụm xa.",[989,48213,48214],{},"Ví dụ đời thường: như ăn hết món gần rồi mới chạy xa, tổng đường dài.",[981,48216,48218],{"id":48217},"held-karp-và-so-sánh","Held-Karp và so sánh",[986,48220,48221,48224,48227,48230],{},[989,48222,48223],{},"Trạng thái là tập đã thăm và điểm đang đứng.",[989,48225,48226],{},"Số trạng thái n nhân 2 mũ n, vẫn mũ nhưng hơn hẳn giai thừa.",[989,48228,48229],{},"Cài bằng mặt nạ bit, không sao chép tập mỗi trạng thái.",[989,48231,48232],{},"Quy tắc: n nhỏ vét cạn, n vừa Held-Karp, n lớn tham lam.",[1099,48234,48235,48246],{},[1102,48236,48237],{},[1105,48238,48239,48242,48244],{},[1108,48240,48241],{},"Chiến lược",[1108,48243,11776],{},[1108,48245,10673],{},[1118,48247,48248,48258,48269],{},[1105,48249,48250,48252,48255],{},[1123,48251,14538],{},[1123,48253,48254],{},"Giai thừa",[1123,48256,48257],{},"n dưới 10",[1105,48259,48260,48263,48266],{},[1123,48261,48262],{},"Held-Karp",[1123,48264,48265],{},"n bình phương nhân 2 mũ n",[1123,48267,48268],{},"n tới 20",[1105,48270,48271,48273,48276],{},[1123,48272,14549],{},[1123,48274,48275],{},"n bình phương",[1123,48277,48278],{},"n lớn cần nhanh",[968,48280,1433],{"id":1432},[986,48282,48283,48286,48289,48292],{},[989,48284,48285],{},"Input: mọi thành phố trên 1 đường thẳng. Output: tour tối ưu đi 1 lèo rồi quay về.",[989,48287,48288],{},"Giải thích: tổng bằng 2 lần chiều dài đoạn, cả 3 cách đều ra vậy.",[989,48290,48291],{},"Input: dữ liệu 2 cụm xa nhau. Output: tham lam dài hơn đáp án chuẩn rõ rệt.",[989,48293,48294],{},"Giải thích: tham lam vét 1 cụm trước rồi trả cú nhảy đắt.",[968,48296,1482],{"id":1481},[973,48298,1485,48299,48301,48302,1517],{},[1487,48300,1493],{},". Dùng lại code ngày 16. Nộp vào ",[992,48303,48304],{},"day-078\u002F",[981,48306,48308],{"id":48307},"bài-1-held-karp","Bài 1: Held-Karp",[1352,48310,48312],{"className":1393,"code":48311,"language":1395,"meta":1357,"style":1357},"std::pair\u003Cdouble, std::vector\u003Cint>> heldKarp(const Matrix &d);\n\u002F\u002F dp[mask][j]: đường ngắn nhất bắt đầu ở 0, đi qua đúng tập mask, kết thúc ở j\n\u002F\u002F mask là bit, luôn chứa bit 0\n",[992,48313,48314,48319,48324],{"__ignoreMap":1357},[1023,48315,48316],{"class":1362,"line":63},[1023,48317,48318],{},"std::pair\u003Cdouble, std::vector\u003Cint>> heldKarp(const Matrix &d);\n",[1023,48320,48321],{"class":1362,"line":68},[1023,48322,48323],{},"\u002F\u002F dp[mask][j]: đường ngắn nhất bắt đầu ở 0, đi qua đúng tập mask, kết thúc ở j\n",[1023,48325,48326],{"class":1362,"line":73},[1023,48327,48328],{},"\u002F\u002F mask là bit, luôn chứa bit 0\n",[1099,48330,48331,48339],{},[1102,48332,48333],{},[1105,48334,48335,48337],{},[1108,48336,2547],{},[1108,48338,14241],{},[1118,48340,48341,48432,48443],{},[1105,48342,48343,48346],{},[1123,48344,48345],{},"Bộ nhớ",[1123,48347,48348,48427,48428,48431],{},[1023,48349,48351,48377],{"className":48350},[1026],[1023,48352,48354],{"className":48353},[1030],[1032,48355,48356],{"xmlns":1034},[1036,48357,48358,48374],{},[1039,48359,48360,48362,48364,48366,48372],{},[1042,48361,1044],{},[1046,48363,1049],{"stretchy":1048},[1042,48365,1262],{},[2327,48367,48368,48370],{},[1051,48369,2457],{},[1042,48371,1262],{},[1046,48373,1056],{"stretchy":1048},[1058,48375,48376],{"encoding":1060},"O(n 2^n)",[1023,48378,48380],{"className":48379,"ariaHidden":1066},[1065],[1023,48381,48383,48386,48389,48392,48395,48424],{"className":48382},[1070],[1023,48384],{"className":48385,"style":1075},[1074],[1023,48387,1044],{"className":48388,"style":1081},[1079,1080],[1023,48390,1049],{"className":48391},[1085],[1023,48393,1262],{"className":48394},[1079,1080],[1023,48396,48398,48401],{"className":48397},[1079],[1023,48399,2457],{"className":48400},[1079],[1023,48402,48404],{"className":48403},[2383],[1023,48405,48407],{"className":48406},[2387],[1023,48408,48410],{"className":48409},[2391],[1023,48411,48413],{"className":48412,"style":8348},[2395],[1023,48414,48415,48418],{"style":2398},[1023,48416],{"className":48417,"style":2403},[2402],[1023,48419,48421],{"className":48420},[2407,2408,2409,2410],[1023,48422,1262],{"className":48423},[1079,1080,2410],[1023,48425,1056],{"className":48426},[1092],", dùng ",[992,48429,48430],{},"std::vector\u003Cdouble>"," phẳng",[1105,48433,48434,48437],{},[1123,48435,48436],{},"Dựng lại tour",[1123,48438,48439,48440],{},"Lưu ",[992,48441,48442],{},"parent[mask][j]",[1105,48444,48445,48448],{},[1123,48446,48447],{},"Giới hạn",[1123,48449,48450,48453,48454],{},[992,48451,48452],{},"n > 20"," thì ném ",[992,48455,48456],{},"invalid_argument",[1352,48458,48461],{"className":48459,"code":48460,"language":2241,"meta":1357},[2239],"Ma trận 4 thành phố ngày 16 -> 80, cùng tour với vét cạn\nThành phố trên 1 đường thẳng tại 0, 1, 3, 7 -> 14 (đi tới 7 rồi quay về)\n",[992,48462,48460],{"__ignoreMap":1357},[981,48464,48466],{"id":48465},"bài-2-so-3-chiến-lược","Bài 2: So 3 chiến lược",[973,48468,48469,48470,48473],{},"Sinh điểm ngẫu nhiên trên mặt phẳng với ",[992,48471,48472],{},"n = 8, 10, 12, 16, 20",", 5 bộ mỗi cỡ.",[1352,48475,48478],{"className":48476,"code":48477,"language":2241,"meta":1357},[2239],"n    brute(ms)    held_karp(ms)    greedy(ms)    greedy\u002Fopt\n8    ...\n20   (bỏ qua)     ...\n",[992,48479,48477],{"__ignoreMap":1357},[973,48481,48482,48483,48485,48486,48488],{},"Vẽ thời gian theo ",[992,48484,1262],{}," (trục y log). Ước lượng ",[992,48487,1262],{}," lớn nhất Held-Karp chạy được trong 10 giây và bộ nhớ khi đó.",[981,48490,48492],{"id":48491},"bài-3-cải-thiện-tham-lam-bằng-2-opt-nâng-cao","Bài 3: Cải thiện tham lam bằng 2-opt (nâng cao)",[2273,48494,48495,48508,48517],{},[989,48496,48497,48500,48501,1656,48504,48507],{},[992,48498,48499],{},"twoOpt(tour, d)",": lặp tìm cặp cạnh ",[992,48502,48503],{},"(a,b)",[992,48505,48506],{},"(c,d)"," mà đảo đoạn giữa làm tour ngắn đi. Dừng khi không cải thiện được.",[989,48509,17210,48510,43217,48513,48516],{},[992,48511,48512],{},"greedy + 2-opt",[992,48514,48515],{},"n = 12..20"," và so với Held-Karp. In tỉ lệ trung bình.",[989,48518,17210,48519,43217,48521,48523],{},[992,48520,48512],{},[992,48522,9992],{},". In độ dài và thời gian.",[981,48525,2711],{"id":2710},[986,48527,48529,48539,48545,48554],{"className":48528},[2715],[989,48530,48532,48534,48535,48538],{"className":48531},[2719],[2721,48533],{"disabled":2723,"type":2724}," Held-Karp khớp vét cạn với mọi ",[992,48536,48537],{},"n \u003C= 10"," (50 bộ ngẫu nhiên).",[989,48540,48542,48544],{"className":48541},[2719],[2721,48543],{"disabled":2723,"type":2724}," Bảng so sánh có số thật và hình thời gian.",[989,48546,48548,48550,48551,1517],{"className":48547},[2719],[2721,48549],{"disabled":2723,"type":2724}," 2-opt giảm rõ tỉ lệ ",[992,48552,48553],{},"greedy\u002Fopt",[989,48555,48557,48559,48560,48624,48625,48668,48669,1517],{"className":48556},[2719],[2721,48558],{"disabled":2723,"type":2724}," Viết được số trạng thái ",[1023,48561,48563,48583],{"className":48562},[1026],[1023,48564,48566],{"className":48565},[1030],[1032,48567,48568],{"xmlns":1034},[1036,48569,48570,48580],{},[1039,48571,48572,48574],{},[1042,48573,1262],{},[2327,48575,48576,48578],{},[1051,48577,2457],{},[1042,48579,1262],{},[1058,48581,48582],{"encoding":1060},"n 2^n",[1023,48584,48586],{"className":48585,"ariaHidden":1066},[1065],[1023,48587,48589,48592,48595],{"className":48588},[1070],[1023,48590],{"className":48591,"style":8348},[1074],[1023,48593,1262],{"className":48594},[1079,1080],[1023,48596,48598,48601],{"className":48597},[1079],[1023,48599,2457],{"className":48600},[1079],[1023,48602,48604],{"className":48603},[2383],[1023,48605,48607],{"className":48606},[2387],[1023,48608,48610],{"className":48609},[2391],[1023,48611,48613],{"className":48612,"style":8348},[2395],[1023,48614,48615,48618],{"style":2398},[1023,48616],{"className":48617,"style":2403},[2402],[1023,48619,48621],{"className":48620},[2407,2408,2409,2410],[1023,48622,1262],{"className":48623},[1079,1080,2410]," và chi phí mỗi trạng thái ",[1023,48626,48628,48647],{"className":48627},[1026],[1023,48629,48631],{"className":48630},[1030],[1032,48632,48633],{"xmlns":1034},[1036,48634,48635,48645],{},[1039,48636,48637,48639,48641,48643],{},[1042,48638,1044],{},[1046,48640,1049],{"stretchy":1048},[1042,48642,1262],{},[1046,48644,1056],{"stretchy":1048},[1058,48646,1267],{"encoding":1060},[1023,48648,48650],{"className":48649,"ariaHidden":1066},[1065],[1023,48651,48653,48656,48659,48662,48665],{"className":48652},[1070],[1023,48654],{"className":48655,"style":1075},[1074],[1023,48657,1044],{"className":48658,"style":1081},[1079,1080],[1023,48660,1049],{"className":48661},[1085],[1023,48663,1262],{"className":48664},[1079,1080],[1023,48666,1056],{"className":48667},[1092]," nên tổng ",[1023,48670,48672,48702],{"className":48671},[1026],[1023,48673,48675],{"className":48674},[1030],[1032,48676,48677],{"xmlns":1034},[1036,48678,48679,48699],{},[1039,48680,48681,48683,48685,48691,48697],{},[1042,48682,1044],{},[1046,48684,1049],{"stretchy":1048},[2327,48686,48687,48689],{},[1042,48688,1262],{},[1051,48690,2457],{},[2327,48692,48693,48695],{},[1051,48694,2457],{},[1042,48696,1262],{},[1046,48698,1056],{"stretchy":1048},[1058,48700,48701],{"encoding":1060},"O(n^2 2^n)",[1023,48703,48705],{"className":48704,"ariaHidden":1066},[1065],[1023,48706,48708,48711,48714,48717,48746,48775],{"className":48707},[1070],[1023,48709],{"className":48710,"style":2476},[1074],[1023,48712,1044],{"className":48713,"style":1081},[1079,1080],[1023,48715,1049],{"className":48716},[1085],[1023,48718,48720,48723],{"className":48719},[1079],[1023,48721,1262],{"className":48722},[1079,1080],[1023,48724,48726],{"className":48725},[2383],[1023,48727,48729],{"className":48728},[2387],[1023,48730,48732],{"className":48731},[2391],[1023,48733,48735],{"className":48734,"style":2369},[2395],[1023,48736,48737,48740],{"style":2398},[1023,48738],{"className":48739,"style":2403},[2402],[1023,48741,48743],{"className":48742},[2407,2408,2409,2410],[1023,48744,2457],{"className":48745},[1079,2410],[1023,48747,48749,48752],{"className":48748},[1079],[1023,48750,2457],{"className":48751},[1079],[1023,48753,48755],{"className":48754},[2383],[1023,48756,48758],{"className":48757},[2387],[1023,48759,48761],{"className":48760},[2391],[1023,48762,48764],{"className":48763,"style":8348},[2395],[1023,48765,48766,48769],{"style":2398},[1023,48767],{"className":48768,"style":2403},[2402],[1023,48770,48772],{"className":48771},[2407,2408,2409,2410],[1023,48773,1262],{"className":48774},[1079,1080,2410],[1023,48776,1056],{"className":48777},[1092],[968,48779,2890],{"id":2889},[986,48781,48782,48785,48788,48791],{},[989,48783,48784],{},"TSP phát biểu thế nào và vì sao NP-khó?",[989,48786,48787],{},"Vét cạn tốn cỡ bao nhiêu?",[989,48789,48790],{},"Tham lam thất bại ở dữ liệu nào?",[989,48792,48793],{},"Held-Karp hơn vét cạn ở điểm nào?",[3014,48795],{},[973,48797,48798],{},"🌕 Bạn đã hoàn thành ngày 78. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,48800,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":48802},[48803,48804,48810,48811,48817],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":48805},[48806,48807,48808,48809],{"id":48164,"depth":73,"text":48165},{"id":48182,"depth":73,"text":14538},{"id":48199,"depth":73,"text":48200},{"id":48217,"depth":73,"text":48218},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":48812},[48813,48814,48815,48816],{"id":48307,"depth":73,"text":48308},{"id":48465,"depth":73,"text":48466},{"id":48491,"depth":73,"text":48492},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bài toán người bán hàng rong dưới ba chiến lược vét cạn, tham lam và quy hoạch động Held-Karp, kèm so sánh chất lượng và thời gian.",{},[15143,15144],{"title":445,"description":48818},[48823,15147,15148,15591],"tsp","ABZM5iWwdJ3dWyRssJlmubNEfISSWhlspTqXfwaVufw",{"id":48826,"title":450,"body":48827,"category":8797,"day":453,"description":49322,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":49323,"navigation":2723,"outcomes":3047,"path":451,"prerequisites":49324,"seo":49325,"stem":452,"tags":49326,"__hash__":49328},"challenges\u002Fchallenges\u002F79.do-thi-phang.md",{"type":965,"value":48828,"toc":49305},[48829,48831,48834,48836,48840,48854,48858,48872,48876,48890,48894,48908,48910,48924,48926,48936,48940,48974,48980,48984,49217,49223,49227,49255,49257,49284,49286,49300,49302],[968,48830,971],{"id":970},[973,48832,48833],{},"Bài này học đồ thị phẳng và định lý Kuratowski. Bạn dùng nó để vẽ sơ đồ ít giao cắt nhất.",[968,48835,979],{"id":978},[981,48837,48839],{"id":48838},"nhúng-và-đồ-thị-phẳng","Nhúng và đồ thị phẳng",[986,48841,48842,48845,48848,48851],{},[989,48843,48844],{},"Nhúng là cách đặt đỉnh và vẽ cạnh lên mặt phẳng.",[989,48846,48847],{},"Cùng 1 đồ thị có nhúng rối và nhúng gọn.",[989,48849,48850],{},"Phẳng là tính chất của đồ thị, rối là tính chất của bức vẽ.",[989,48852,48853],{},"Ví dụ đời thường: như cùng 1 mớ dây, xếp khéo thì không rối.",[981,48855,48857],{"id":48856},"hai-chướng-ngại-k5-và-k3-3","Hai chướng ngại K5 và K3-3",[986,48859,48860,48863,48866,48869],{},[989,48861,48862],{},"K5: 5 đỉnh nối đôi một, kiểu gì cũng thừa 1 giao cắt.",[989,48864,48865],{},"K3-3: 2 nhóm 3 đỉnh nối chéo hết, bài toán 3 nhà 3 giếng.",[989,48867,48868],{},"Quá nhiều cạnh dồn vào ít đỉnh thì phải cắt nhau.",[989,48870,48871],{},"Ví dụ đời thường: như vẽ quá nhiều đường bay trên 1 tờ giấy.",[981,48873,48875],{"id":48874},"định-lý-kuratowski","Định lý Kuratowski",[986,48877,48878,48881,48884,48887],{},[989,48879,48880],{},"Đồ thị phẳng khi và chỉ khi không chứa bản phóng K5 hay K3-3.",[989,48882,48883],{},"Bản phóng là chèn thêm đỉnh bậc 2 lên cạnh cũ.",[989,48885,48886],{},"Muốn chứng minh không phẳng thì moi K5 hoặc K3-3 ra.",[989,48888,48889],{},"Muốn thêm cạnh mà giữ phẳng thì kiểm tra chướng ngại trước.",[981,48891,48893],{"id":48892},"kiểu-vẽ-cạnh","Kiểu vẽ cạnh",[986,48895,48896,48899,48902,48905],{},[989,48897,48898],{},"Đoạn thẳng: đơn giản nhưng dễ cắt nhau.",[989,48900,48901],{},"Đa tuyến bẻ góc: vòng tránh được chỗ đông.",[989,48903,48904],{},"Cong Bezier: mềm và dễ bó nhưng tính giao tốn hơn.",[989,48906,48907],{},"Tránh vẽ đỉnh chạm cạnh dù không nối vì gây hiểu nhầm.",[968,48909,1433],{"id":1432},[986,48911,48912,48915,48918,48921],{},[989,48913,48914],{},"Input: đồ thị chứa K3-3 phóng, đòi vẽ phẳng tuyệt đối. Output: báo không thể.",[989,48916,48917],{},"Giải thích: có chướng ngại thì phải chuyển sang tối thiểu giao cắt.",[989,48919,48920],{},"Input: sơ đồ đầy giao cắt nhưng đồ thị nền phẳng. Output: chẩn đoán nhúng xấu.",[989,48922,48923],{},"Giải thích: cần vẽ lại chứ không phải đổi dữ liệu.",[968,48925,1482],{"id":1481},[973,48927,1485,48928,7386,48930,48932,48933,1517],{},[1487,48929,13531],{},[992,48931,31660],{}," và matplotlib. Nộp vào ",[992,48934,48935],{},"day-079\u002F",[981,48937,48939],{"id":48938},"bài-1-đếm-giao-cắt-của-một-bức-vẽ","Bài 1: Đếm giao cắt của một bức vẽ",[1099,48941,48942,48950],{},[1102,48943,48944],{},[1105,48945,48946,48948],{},[1108,48947,1566],{},[1108,48949,2547],{},[1118,48951,48952,48962],{},[1105,48953,48954,48959],{},[1123,48955,48956],{},[992,48957,48958],{},"segments_intersect(p1, p2, p3, p4)",[1123,48960,48961],{},"Dùng tích có hướng. Hai cạnh chung đỉnh không tính là cắt",[1105,48963,48964,48969],{},[1123,48965,48966],{},[992,48967,48968],{},"count_crossings(G, pos)",[1123,48970,48971,48973],{},[992,48972,20509],{},": dict đỉnh -> (x, y). Đếm cặp cạnh cắt nhau",[1352,48975,48978],{"className":48976,"code":48977,"language":2241,"meta":1357},[2239],"K4 vẽ hình vuông có 2 đường chéo -> 1 giao cắt\nK4 vẽ tam giác có 1 đỉnh ở giữa   -> 0 giao cắt\n",[992,48979,48977],{"__ignoreMap":1357},[981,48981,48983],{"id":48982},"bài-2-kiểm-tra-phẳng-bằng-điều-kiện-cần","Bài 2: Kiểm tra phẳng bằng điều kiện cần",[2273,48985,48986,49201,49207],{},[989,48987,1505,48988,48991,48992,49043,49044,49122,49123,1517],{},[992,48989,48990],{},"edge_bound_check(G)",": đồ thị phẳng đơn liên thông có ",[1023,48993,48995,49013],{"className":48994},[1026],[1023,48996,48998],{"className":48997},[1030],[1032,48999,49000],{"xmlns":1034},[1036,49001,49002,49010],{},[1039,49003,49004,49006,49008],{},[1042,49005,1262],{},[1046,49007,43557],{},[1051,49009,13826],{},[1058,49011,49012],{"encoding":1060},"n \\ge 3",[1023,49014,49016,49034],{"className":49015,"ariaHidden":1066},[1065],[1023,49017,49019,49022,49025,49028,49031],{"className":49018},[1070],[1023,49020],{"className":49021,"style":47337},[1074],[1023,49023,1262],{"className":49024},[1079,1080],[1023,49026],{"className":49027,"style":2355},[2354],[1023,49029,43557],{"className":49030},[2359],[1023,49032],{"className":49033,"style":2355},[2354],[1023,49035,49037,49040],{"className":49036},[1070],[1023,49038],{"className":49039,"style":10020},[1074],[1023,49041,13826],{"className":49042},[1079]," thì ",[1023,49045,49047,49071],{"className":49046},[1026],[1023,49048,49050],{"className":49049},[1030],[1032,49051,49052],{"xmlns":1034},[1036,49053,49054,49068],{},[1039,49055,49056,49058,49060,49062,49064,49066],{},[1042,49057,15437],{},[1046,49059,21123],{},[1051,49061,13826],{},[1042,49063,1262],{},[1046,49065,17698],{},[1051,49067,6866],{},[1058,49069,49070],{"encoding":1060},"m \\le 3n - 6",[1023,49072,49074,49092,49113],{"className":49073,"ariaHidden":1066},[1065],[1023,49075,49077,49080,49083,49086,49089],{"className":49076},[1070],[1023,49078],{"className":49079,"style":47337},[1074],[1023,49081,15437],{"className":49082},[1079,1080],[1023,49084],{"className":49085,"style":2355},[2354],[1023,49087,21123],{"className":49088},[2359],[1023,49090],{"className":49091,"style":2355},[2354],[1023,49093,49095,49098,49101,49104,49107,49110],{"className":49094},[1070],[1023,49096],{"className":49097,"style":18148},[1074],[1023,49099,13826],{"className":49100},[1079],[1023,49102,1262],{"className":49103},[1079,1080],[1023,49105],{"className":49106,"style":13790},[2354],[1023,49108,17698],{"className":49109},[13794],[1023,49111],{"className":49112,"style":13790},[2354],[1023,49114,49116,49119],{"className":49115},[1070],[1023,49117],{"className":49118,"style":10020},[1074],[1023,49120,6866],{"className":49121},[1079],". Nếu không có tam giác thì ",[1023,49124,49126,49150],{"className":49125},[1026],[1023,49127,49129],{"className":49128},[1030],[1032,49130,49131],{"xmlns":1034},[1036,49132,49133,49147],{},[1039,49134,49135,49137,49139,49141,49143,49145],{},[1042,49136,15437],{},[1046,49138,21123],{},[1051,49140,2457],{},[1042,49142,1262],{},[1046,49144,17698],{},[1051,49146,25255],{},[1058,49148,49149],{"encoding":1060},"m \\le 2n - 4",[1023,49151,49153,49171,49192],{"className":49152,"ariaHidden":1066},[1065],[1023,49154,49156,49159,49162,49165,49168],{"className":49155},[1070],[1023,49157],{"className":49158,"style":47337},[1074],[1023,49160,15437],{"className":49161},[1079,1080],[1023,49163],{"className":49164,"style":2355},[2354],[1023,49166,21123],{"className":49167},[2359],[1023,49169],{"className":49170,"style":2355},[2354],[1023,49172,49174,49177,49180,49183,49186,49189],{"className":49173},[1070],[1023,49175],{"className":49176,"style":18148},[1074],[1023,49178,2457],{"className":49179},[1079],[1023,49181,1262],{"className":49182},[1079,1080],[1023,49184],{"className":49185,"style":13790},[2354],[1023,49187,17698],{"className":49188},[13794],[1023,49190],{"className":49191,"style":13790},[2354],[1023,49193,49195,49198],{"className":49194},[1070],[1023,49196],{"className":49197,"style":10020},[1074],[1023,49199,25255],{"className":49200},[1079],[989,49202,49203,49204,49206],{},"Áp vào K5, K3,3, cây 10 đỉnh, lưới 4x4. Chỉ ra trường hợp điều kiện cần ",[1487,49205,41587],{}," đủ để kết luận.",[989,49208,37059,49209,49212,49213,49216],{},[992,49210,49211],{},"networkx.check_planarity",". Với đồ thị không phẳng, dùng ",[992,49214,49215],{},"counterexample"," để lấy đồ thị con Kuratowski và vẽ nó ra.",[1352,49218,49221],{"className":49219,"code":49220,"language":2241,"meta":1357},[2239],"K5: m = 10 > 3*5 - 6 = 9  -> chắc chắn không phẳng\nK3,3: m = 9 \u003C= 12 nhưng không có tam giác: 9 > 2*6 - 4 = 8 -> không phẳng\n",[992,49222,49220],{"__ignoreMap":1357},[981,49224,49226],{"id":49225},"bài-3-vẽ-phẳng-nâng-cao","Bài 3: Vẽ phẳng (nâng cao)",[2273,49228,49229,49239,49252],{},[989,49230,49231,49232,49235,49236,1517],{},"Với đồ thị phẳng, dùng ",[992,49233,49234],{},"networkx.planar_layout"," để có bức vẽ 0 giao cắt. Kiểm tra bằng ",[992,49237,49238],{},"count_crossings",[989,49240,49241,49242,1656,49245,1656,49248,49251],{},"So ",[992,49243,49244],{},"spring_layout",[992,49246,49247],{},"circular_layout",[992,49249,49250],{},"planar_layout"," trên 3 đồ thị phẳng (lưới 5x5, đồ thị bánh xe 10 đỉnh, cây nhị phân 31 đỉnh). In bảng số giao cắt.",[989,49253,49254],{},"Thêm từng cạnh ngẫu nhiên vào lưới 5x5 cho tới khi mất tính phẳng. In cạnh làm mất tính phẳng và đồ thị con Kuratowski.",[981,49256,2711],{"id":2710},[986,49258,49260,49266,49272,49278],{"className":49259},[2715],[989,49261,49263,49265],{"className":49262},[2719],[2721,49264],{"disabled":2723,"type":2724}," Test mẫu đếm giao cắt pass.",[989,49267,49269,49271],{"className":49268},[2719],[2721,49270],{"disabled":2723,"type":2724}," Bảng điều kiện cần cho 4 đồ thị kèm nhận xét.",[989,49273,49275,49277],{"className":49274},[2719],[2721,49276],{"disabled":2723,"type":2724}," Có hình đồ thị con Kuratowski.",[989,49279,49281,49283],{"className":49280},[2719],[2721,49282],{"disabled":2723,"type":2724}," Bảng số giao cắt 3 layout có số thật.",[968,49285,2890],{"id":2889},[986,49287,49288,49291,49294,49297],{},[989,49289,49290],{},"Nhúng phẳng nghĩa là gì?",[989,49292,49293],{},"K5 và K3-3 là gì?",[989,49295,49296],{},"Định lý Kuratowski nói gì?",[989,49298,49299],{},"Khi nào nên chấp nhận giao cắt?",[3014,49301],{},[973,49303,49304],{},"🌕 Bạn đã hoàn thành ngày 79. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":49306},[49307,49308,49314,49315,49321],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":49309},[49310,49311,49312,49313],{"id":48838,"depth":73,"text":48839},{"id":48856,"depth":73,"text":48857},{"id":48874,"depth":73,"text":48875},{"id":48892,"depth":73,"text":48893},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":49316},[49317,49318,49319,49320],{"id":48938,"depth":73,"text":48939},{"id":48982,"depth":73,"text":48983},{"id":49225,"depth":73,"text":49226},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhúng đồ thị, đồ thị đầy đủ lưỡng phân, Kuratowski thực hành và trực giác phẳng cho vẽ đồ thị.",{},[3049],{"title":450,"description":49322},[29786,49327],"planarity","fcAzJeWwKe5Ofl_DYWJjg8e5V35bpiYRbNUk0bO7mSA",{"id":49330,"title":455,"body":49331,"category":8797,"day":458,"description":49644,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":49645,"navigation":2723,"outcomes":3047,"path":456,"prerequisites":49646,"seo":49647,"stem":457,"tags":49648,"__hash__":49650},"challenges\u002Fchallenges\u002F80.mini-project-graph.md",{"type":965,"value":49332,"toc":49627},[49333,49335,49338,49340,49344,49358,49362,49376,49380,49394,49440,49444,49458,49460,49474,49476,49485,49489,49494,49500,49515,49521,49525,49532,49538,49545,49548,49552,49572,49574,49606,49608,49622,49624],[968,49334,971],{"id":970},[973,49336,49337],{},"Bài này tổng kết chặng đồ thị bằng mạng giao hàng. Bạn dùng nó để so BFS, DFS, Dijkstra và A*.",[968,49339,979],{"id":978},[981,49341,49343],{"id":49342},"mạng-giao-hàng","Mạng giao hàng",[986,49345,49346,49349,49352,49355],{},[989,49347,49348],{},"Đỉnh là kho, điểm trung chuyển và khách hàng.",[989,49350,49351],{},"Cạnh là đoạn đường có trọng số thời gian.",[989,49353,49354],{},"Cần ít nhất 15 đỉnh và 25 cạnh mẫu.",[989,49356,49357],{},"Mọi trọng số không âm để Dijkstra và A* đúng.",[981,49359,49361],{"id":49360},"bfs-và-dfs","BFS và DFS",[986,49363,49364,49367,49370,49373],{},[989,49365,49366],{},"BFS lan theo lớp bằng hàng đợi, cho đường ít chặng nhất.",[989,49368,49369],{},"DFS đi sâu bằng đệ quy, phát hiện cụm và đỉnh cô lập.",[989,49371,49372],{},"Cả 2 phơi bày cấu trúc mạng trước khi tối ưu.",[989,49374,49375],{},"Ví dụ đời thường: BFS như loang nước, DFS như chui 1 ngõ tới cùng.",[981,49377,49379],{"id":49378},"dijkstra-và-a","Dijkstra và A*",[986,49381,49382,49385,49388,49391],{},[989,49383,49384],{},"Dijkstra dùng heap, rút đỉnh rẻ nhất, nới lỏng cạnh.",[989,49386,49387],{},"A* cộng thêm heuristic đường chim bay từ tọa độ.",[989,49389,49390],{},"Cả 2 cho cùng tổng thời gian tối ưu.",[989,49392,49393],{},"A* thường thăm ít đỉnh hơn nhờ đoán hướng tốt.",[1099,49395,49396,49407],{},[1102,49397,49398],{},[1105,49399,49400,49402,49405],{},[1108,49401,9446],{},[1108,49403,49404],{},"Trả lời",[1108,49406,17655],{},[1118,49408,49409,49419,49429],{},[1105,49410,49411,49413,49416],{},[1123,49412,29899],{},[1123,49414,49415],{},"Tới được không, mấy chặng",[1123,49417,49418],{},"Bản không trọng số",[1105,49420,49421,49423,49426],{},[1123,49422,29902],{},[1123,49424,49425],{},"Cụm nào, ai cô lập",[1123,49427,49428],{},"Quét toàn mạng",[1105,49430,49431,49434,49437],{},[1123,49432,49433],{},"Dijkstra \u002F A*",[1123,49435,49436],{},"Tuyến nhanh nhất",[1123,49438,49439],{},"Bản có trọng số",[981,49441,49443],{"id":49442},"đo-và-báo-cáo","Đo và báo cáo",[986,49445,49446,49449,49452,49455],{},[989,49447,49448],{},"Mỗi lần chạy ghi độ dài tuyến, số đỉnh thăm, thời gian.",[989,49450,49451],{},"Lắp thành ma trận 4 thuật toán nhân 3 truy vấn.",[989,49453,49454],{},"Mọi kết luận phải trỏ về 1 ô cụ thể trong ma trận.",[989,49456,49457],{},"Khuyến nghị theo SLA: cần nhanh thì A*, cần chuẩn thì Dijkstra.",[968,49459,1433],{"id":1432},[986,49461,49462,49465,49468,49471],{},[989,49463,49464],{},"Input: khách nối trực tiếp kho 1 cạnh. Output: mọi thuật toán trả tuyến 1 cạnh.",[989,49466,49467],{},"Giải thích: đường ngắn nhất hiển nhiên, sai là lỗi dựng đồ thị.",[989,49469,49470],{},"Input: Dijkstra và A* cùng cặp kho khách. Output: tổng thời gian bằng nhau tuyệt đối.",[989,49472,49473],{},"Giải thích: cả 2 đều tối ưu nên không thể lệch.",[968,49475,1482],{"id":1481},[973,49477,1485,49478,49480,49481,49484],{},[1487,49479,1493],{}," (hoặc Python). Dùng lại BFS, DFS, Dijkstra, A* các ngày 40-43. Nộp vào ",[992,49482,49483],{},"day-080-mini-project\u002F",". Dành 90 phút.",[981,49486,49488],{"id":49487},"bài-1-dữ-liệu-mạng-giao-hàng","Bài 1: Dữ liệu mạng giao hàng",[973,49490,16860,49491,4437],{},[992,49492,49493],{},"network.txt",[1352,49495,49498],{"className":49496,"code":49497,"language":2241,"meta":1357},[2239],"# nodes: id tên loại x y       (loại: KHO, TRUNG_CHUYEN, KHACH)\n# edges: u v phút              (vô hướng, phút > 0)\n",[992,49499,49497],{"__ignoreMap":1357},[986,49501,49502,49505,49512],{},[989,49503,49504],{},"Ít nhất 15 đỉnh (2 kho, 4 trung chuyển, 9+ khách) và 25 cạnh.",[989,49506,49507,49508,49511],{},"Tọa độ tính bằng km. Tốc độ tối đa 60 km\u002Fh nên ",[992,49509,49510],{},"phút >= khoảng_cách_km",": heuristic A* chấp nhận được.",[989,49513,49514],{},"Có 1 khách bị cô lập để kiểm tra xử lý lỗi.",[973,49516,1505,49517,49520],{},[992,49518,49519],{},"loadNetwork(path)"," và kiểm tra dữ liệu: cạnh trỏ tới đỉnh không có, trọng số âm, trùng id đều báo lỗi rõ dòng nào.",[981,49522,49524],{"id":49523},"bài-2-bốn-thuật-toán-ba-truy-vấn","Bài 2: Bốn thuật toán, ba truy vấn",[973,49526,49527,49528,49531],{},"Với 3 truy vấn ",[992,49529,49530],{},"(kho, khách)",", chạy BFS (ít chặng), DFS (một đường bất kỳ), Dijkstra, A*. Ghi:",[1352,49533,49536],{"className":49534,"code":49535,"language":2241,"meta":1357},[2239],"truy_vấn      thuật_toán   số_chặng   tổng_phút   đỉnh_đã_thăm   thời_gian(µs)\nK1 -> C7      BFS          ...\nK1 -> C7      DFS          ...\nK1 -> C7      Dijkstra     ...\nK1 -> C7      A*           ...\n",[992,49537,49535],{"__ignoreMap":1357},[973,49539,49540,49541,49544],{},"Kiểm tra: Dijkstra và A* luôn cùng ",[992,49542,49543],{},"tổng_phút",". Truy vấn tới khách cô lập trả \"không có đường\".",[973,49546,49547],{},"DFS còn dùng để liệt kê thành phần liên thông và in đỉnh cô lập.",[981,49549,49551],{"id":49550},"bài-3-báo-cáo-và-mở-rộng-nâng-cao","Bài 3: Báo cáo và mở rộng (nâng cao)",[2273,49553,49554,49559,49562],{},[989,49555,49556,49558],{},[992,49557,17400],{},": bảng Bài 2, mỗi kết luận trỏ về 1 ô cụ thể. Khuyến nghị thuật toán cho 2 SLA: \"phản hồi dưới 1 ms\" và \"luôn tối ưu thời gian\".",[989,49560,49561],{},"Sinh mạng 10.000 đỉnh ngẫu nhiên theo tọa độ. Chạy lại 100 truy vấn. So số đỉnh thăm trung bình của Dijkstra và A*.",[989,49563,49564,49565,49568,49569,16014],{},"Tìm kho gần nhất cho mọi khách bằng ",[1487,49566,49567],{},"một"," lần Dijkstra đa nguồn (mọi kho có ",[992,49570,49571],{},"dist = 0",[981,49573,2711],{"id":2710},[986,49575,49577,49586,49592,49598],{"className":49576},[2715],[989,49578,49580,2308,49582,49585],{"className":49579},[2719],[2721,49581],{"disabled":2723,"type":2724},[992,49583,49584],{},"loadNetwork"," bắt được 3 loại lỗi dữ liệu.",[989,49587,49589,49591],{"className":49588},[2719],[2721,49590],{"disabled":2723,"type":2724}," Bảng 12 dòng đủ 3 truy vấn x 4 thuật toán.",[989,49593,49595,49597],{"className":49594},[2719],[2721,49596],{"disabled":2723,"type":2724}," Dijkstra và A* cùng kết quả trên 100 truy vấn ngẫu nhiên.",[989,49599,49601,2308,49603,49605],{"className":49600},[2719],[2721,49602],{"disabled":2723,"type":2724},[992,49604,17400],{}," có khuyến nghị theo SLA gắn với số liệu.",[968,49607,2890],{"id":2889},[986,49609,49610,49613,49616,49619],{},[989,49611,49612],{},"Mạng giao hàng gồm những đỉnh và cạnh nào?",[989,49614,49615],{},"BFS và Dijkstra khác nhau ở điểm nào?",[989,49617,49618],{},"A* hơn Dijkstra ở chỗ nào?",[989,49620,49621],{},"Khi nào dùng BFS thay vì Dijkstra?",[3014,49623],{},[973,49625,49626],{},"🌕 Bạn đã hoàn thành ngày 80. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":49628},[49629,49630,49636,49637,49643],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":49631},[49632,49633,49634,49635],{"id":49342,"depth":73,"text":49343},{"id":49360,"depth":73,"text":49361},{"id":49378,"depth":73,"text":49379},{"id":49442,"depth":73,"text":49443},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":49638},[49639,49640,49641,49642],{"id":49487,"depth":73,"text":49488},{"id":49523,"depth":73,"text":49524},{"id":49550,"depth":73,"text":49551},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Dự án tổng kết chặng đồ thị: xây mạng giao hàng, so sánh BFS, DFS, Dijkstra và A* trên cùng bản đồ, đo đạc và báo cáo.",{},[3050,17499],{"title":455,"description":49644},[17502,29786,29787,30451,49649],"dijkstra","XpPNN-_nRKnUADdeUSumHl0DOPsCxseZwGugzGGB8BE",{"id":49652,"title":460,"body":49653,"category":5189,"day":463,"description":50108,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":50109,"navigation":2723,"outcomes":3047,"path":461,"prerequisites":50110,"seo":50111,"stem":462,"tags":50112,"__hash__":50114},"challenges\u002Fchallenges\u002F81.command-undo-macro.md",{"type":965,"value":49654,"toc":50092},[49655,49657,49660,49662,49666,49680,49684,49698,49718,49722,49736,49785,49787,49801,49803,49811,49815,49831,49887,49901,49907,49911,49924,49996,50002,50006,50018,50040,50042,50069,50071,50085,50087,50090],[968,49656,971],{"id":970},[973,49658,49659],{},"Bài này học hoàn tác và macro nhiều lệnh. Bạn dùng nó cho nút undo quạt và nút mở tiệc 1 chạm.",[968,49661,979],{"id":978},[981,49663,49665],{"id":49664},"nút-hoàn-tác","Nút hoàn tác",[986,49667,49668,49671,49674,49677],{},[989,49669,49670],{},"Quy ước nút undo làm ngược việc của nút vừa bấm.",[989,49672,49673],{},"Đèn bật tắt đối xứng nên dễ, quạt 4 nấc thì khó.",[989,49675,49676],{},"Tắt quạt nấc nhanh phải trả đúng về nhanh, không bật chung chung.",[989,49678,49679],{},"Ví dụ đời thường: như Ctrl+Z phải trả đúng chữ vừa xóa.",[981,49681,49683],{"id":49682},"ghi-nhớ-trạng-thái","Ghi nhớ trạng thái",[986,49685,49686,49689,49692,49695],{},[989,49687,49688],{},"Lệnh ghi lại nấc cũ của quạt trước khi đổi.",[989,49690,49691],{},"Thực thi thì đổi sang nấc mới, hoàn tác thì trả nấc cũ.",[989,49693,49694],{},"Remote chỉ nhớ lệnh gần nhất nên undo 1 bước.",[989,49696,49697],{},"Muốn nhiều bước thì dùng ngăn xếp lịch sử.",[1352,49699,49701],{"className":3538,"code":49700,"language":3540,"meta":1357,"style":1357},"# Ý tưởng lệnh quạt có undo\n# execute: self.cu = quat.nac; quat.doi(self.moi)  # nhớ cũ rồi đổi mới\n# undo: quat.doi(self.cu)  # trả lại nấc cũ\n",[992,49702,49703,49708,49713],{"__ignoreMap":1357},[1023,49704,49705],{"class":1362,"line":63},[1023,49706,49707],{},"# Ý tưởng lệnh quạt có undo\n",[1023,49709,49710],{"class":1362,"line":68},[1023,49711,49712],{},"# execute: self.cu = quat.nac; quat.doi(self.moi)  # nhớ cũ rồi đổi mới\n",[1023,49714,49715],{"class":1362,"line":73},[1023,49716,49717],{},"# undo: quat.doi(self.cu)  # trả lại nấc cũ\n",[981,49719,49721],{"id":49720},"macro-mở-tiệc","Macro mở tiệc",[986,49723,49724,49727,49730,49733],{},[989,49725,49726],{},"Macro cũng là lệnh nên cắm vào khe như lệnh thường.",[989,49728,49729],{},"Bên trong giữ danh sách lệnh nhỏ: đèn, màn, máy chiếu, loa.",[989,49731,49732],{},"Thực thi chạy xuôi từng lệnh, hoàn tác chạy ngược thứ tự.",[989,49734,49735],{},"Ngược thứ tự mới an toàn như xếp bát đĩa.",[1099,49737,49738,49750],{},[1102,49739,49740],{},[1105,49741,49742,49744,49747],{},[1108,49743,24466],{},[1108,49745,49746],{},"Lệnh đơn",[1108,49748,49749],{},"Macro",[1118,49751,49752,49763,49774],{},[1105,49753,49754,49757,49760],{},[1123,49755,49756],{},"Bên trong",[1123,49758,49759],{},"1 thiết bị",[1123,49761,49762],{},"Danh sách lệnh",[1105,49764,49765,49768,49771],{},[1123,49766,49767],{},"Thực thi",[1123,49769,49770],{},"1 hành động",[1123,49772,49773],{},"Chạy xuôi cả danh sách",[1105,49775,49776,49779,49782],{},[1123,49777,49778],{},"Hoàn tác",[1123,49780,49781],{},"Trả trạng thái cũ",[1123,49783,49784],{},"Chạy ngược từng lệnh",[968,49786,1433],{"id":1432},[986,49788,49789,49792,49795,49798],{},[989,49790,49791],{},"Input: quạt nấc vừa, bấm sang nhanh rồi undo. Output: lên nhanh rồi về vừa.",[989,49793,49794],{},"Giải thích: lệnh đã nhớ nấc vừa trước khi đổi.",[989,49796,49797],{},"Input: chạy macro 4 thiết bị rồi undo. Output: bật xuôi, tắt ngược, về đúng trạng thái cũ.",[989,49799,49800],{},"Giải thích: hoàn tác ngược thứ tự mới dọn an toàn.",[968,49802,1482],{"id":1481},[973,49804,1485,49805,49807,49808,1517],{},[1487,49806,4800],{}," (hoặc Java). Dùng remote ngày 28. Nộp vào ",[992,49809,49810],{},"day-081\u002F",[981,49812,49814],{"id":49813},"bài-1-undo-một-bước-và-quạt-4-nấc","Bài 1: Undo một bước và quạt 4 nấc",[973,49816,5030,49817,8530,49820,49823,49824,49827,49828,1517],{},[992,49818,49819],{},"virtual void undo() = 0;",[992,49821,49822],{},"Command",". Remote giữ ",[992,49825,49826],{},"std::shared_ptr\u003CCommand> undoCommand"," và có ",[992,49829,49830],{},"undoButtonPressed()",[1352,49832,49834],{"className":1393,"code":49833,"language":1395,"meta":1357,"style":1357},"class CeilingFan {\n public:\n  enum Speed { OFF, LOW, MEDIUM, HIGH };\n  void setSpeed(Speed s); Speed speed() const;\n};\nclass CeilingFanHighCommand : public Command {\n  CeilingFan &fan; CeilingFan::Speed prev;   \u002F\u002F lưu nấc cũ trước khi đổi\n public:\n  void execute() override;   \u002F\u002F prev = fan.speed(); fan.setSpeed(HIGH);\n  void undo() override;      \u002F\u002F fan.setSpeed(prev);\n};\n",[992,49835,49836,49841,49845,49850,49855,49859,49864,49869,49873,49878,49883],{"__ignoreMap":1357},[1023,49837,49838],{"class":1362,"line":63},[1023,49839,49840],{},"class CeilingFan {\n",[1023,49842,49843],{"class":1362,"line":68},[1023,49844,4836],{},[1023,49846,49847],{"class":1362,"line":73},[1023,49848,49849],{},"  enum Speed { OFF, LOW, MEDIUM, HIGH };\n",[1023,49851,49852],{"class":1362,"line":78},[1023,49853,49854],{},"  void setSpeed(Speed s); Speed speed() const;\n",[1023,49856,49857],{"class":1362,"line":83},[1023,49858,4866],{},[1023,49860,49861],{"class":1362,"line":88},[1023,49862,49863],{},"class CeilingFanHighCommand : public Command {\n",[1023,49865,49866],{"class":1362,"line":93},[1023,49867,49868],{},"  CeilingFan &fan; CeilingFan::Speed prev;   \u002F\u002F lưu nấc cũ trước khi đổi\n",[1023,49870,49871],{"class":1362,"line":98},[1023,49872,4836],{},[1023,49874,49875],{"class":1362,"line":103},[1023,49876,49877],{},"  void execute() override;   \u002F\u002F prev = fan.speed(); fan.setSpeed(HIGH);\n",[1023,49879,49880],{"class":1362,"line":108},[1023,49881,49882],{},"  void undo() override;      \u002F\u002F fan.setSpeed(prev);\n",[1023,49884,49885],{"class":1362,"line":113},[1023,49886,4866],{},[973,49888,1505,49889,1656,49892,1656,49895,1656,49898,1517],{},[992,49890,49891],{},"CeilingFanHighCommand",[992,49893,49894],{},"CeilingFanMediumCommand",[992,49896,49897],{},"CeilingFanLowCommand",[992,49899,49900],{},"CeilingFanOffCommand",[1352,49902,49905],{"className":49903,"code":49904,"language":2241,"meta":1357},[2239],"quạt MEDIUM; bấm HIGH; undo    -> MEDIUM\nquạt LOW; bấm OFF; undo        -> LOW\nLightOn; undo                   -> đèn tắt\nundo khi chưa bấm gì            -> không làm gì (NoCommand)\n",[992,49906,49904],{"__ignoreMap":1357},[981,49908,49910],{"id":49909},"bài-2-undo-nhiều-bước-và-redo","Bài 2: Undo nhiều bước và redo",[973,49912,49913,49914,49917,49918,1509,49921,1517],{},"Thay ",[992,49915,49916],{},"undoCommand"," bằng 2 stack ",[992,49919,49920],{},"history",[992,49922,49923],{},"redoStack",[1099,49925,49926,49936],{},[1102,49927,49928],{},[1105,49929,49930,49933],{},[1108,49931,49932],{},"Hành động",[1108,49934,49935],{},"Hiệu ứng",[1118,49937,49938,49954,49972,49987],{},[1105,49939,49940,49943],{},[1123,49941,49942],{},"Bấm nút bất kỳ",[1123,49944,49945,49948,49949,49951,49952],{},[992,49946,49947],{},"execute",", đẩy vào ",[992,49950,49920],{},", xóa ",[992,49953,49923],{},[1105,49955,49956,49961],{},[1123,49957,49958],{},[992,49959,49960],{},"undo()",[1123,49962,49963,49964,49966,49967,49948,49970],{},"Lấy đỉnh ",[992,49965,49920],{},", gọi ",[992,49968,49969],{},"undo",[992,49971,49923],{},[1105,49973,49974,49979],{},[1123,49975,49976],{},[992,49977,49978],{},"redo()",[1123,49980,49963,49981,49966,49983,49948,49985],{},[992,49982,49923],{},[992,49984,49947],{},[992,49986,49920],{},[1105,49988,49989,49991],{},[1123,49990,48447],{},[1123,49992,49993,49995],{},[992,49994,49920],{}," giữ tối đa 50 lệnh, bỏ lệnh cũ nhất",[1352,49997,50000],{"className":49998,"code":49999,"language":2241,"meta":1357},[2239],"HIGH, LOW, OFF; undo x3 -> quạt về nấc ban đầu\nundo x2; redo           -> quạt ở LOW\nundo; bấm MEDIUM; redo  -> redo không làm gì (redoStack đã bị xóa)\n",[992,50001,49999],{"__ignoreMap":1357},[981,50003,50005],{"id":50004},"bài-3-macro-mở-tiệc-nâng-cao","Bài 3: Macro \"mở tiệc\" (nâng cao)",[973,50007,50008,13568,50011,50013,50014,4233,50016,1517],{},[992,50009,50010],{},"MacroCommand(std::vector\u003Cstd::shared_ptr\u003CCommand>>)",[992,50012,49947],{}," chạy xuôi, ",[992,50015,49969],{},[1487,50017,30171],{},[2273,50019,50020,50031,50037],{},[989,50021,50022,50023,50026,50027,50030],{},"Tạo macro ",[992,50024,50025],{},"partyOn",": đèn dim 30%, stereo bật âm lượng 11, TV bật, hot tub bật và nhiệt 40 độ. Macro ",[992,50028,50029],{},"partyOff"," ngược lại.",[989,50032,50033,50034,50036],{},"Undo ",[992,50035,50025],{}," đưa mọi thiết bị về đúng trạng thái trước đó (không chỉ \"tắt\").",[989,50038,50039],{},"Nếu một lệnh giữa macro ném lỗi, hoàn tác các lệnh đã chạy trước nó rồi ném lại lỗi. Viết test.",[981,50041,2711],{"id":2710},[986,50043,50045,50051,50057,50063],{"className":50044},[2715],[989,50046,50048,50050],{"className":50047},[2719],[2721,50049],{"disabled":2723,"type":2724}," Test mẫu 3 bài pass.",[989,50052,50054,50056],{"className":50053},[2719],[2721,50055],{"disabled":2723,"type":2724}," Undo quạt trả đúng nấc cũ, không phải \"bật mặc định\".",[989,50058,50060,50062],{"className":50059},[2719],[2721,50061],{"disabled":2723,"type":2724}," Macro hoàn tác theo thứ tự ngược, có test lỗi giữa chừng.",[989,50064,50066,50068],{"className":50065},[2719],[2721,50067],{"disabled":2723,"type":2724}," Vẽ trạng thái 2 stack sau mỗi bước của test Bài 2.",[968,50070,2890],{"id":2889},[986,50072,50073,50076,50079,50082],{},[989,50074,50075],{},"Lệnh ghi nhớ gì để undo được?",[989,50077,50078],{},"Vì sao quạt nhiều nấc khó hơn đèn?",[989,50080,50081],{},"Macro thực thi và undo thế nào?",[989,50083,50084],{},"Vì sao undo macro phải ngược thứ tự?",[3014,50086],{},[973,50088,50089],{},"🌕 Bạn đã hoàn thành ngày 81. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,50091,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":50093},[50094,50095,50100,50101,50107],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":50096},[50097,50098,50099],{"id":49664,"depth":73,"text":49665},{"id":49682,"depth":73,"text":49683},{"id":49720,"depth":73,"text":49721},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":50102},[50103,50104,50105,50106],{"id":49813,"depth":73,"text":49814},{"id":49909,"depth":73,"text":49910},{"id":50004,"depth":73,"text":50005},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nút hoàn tác ghi nhớ trạng thái trước khi chạy, và macro một nút mở cả rạp hát cho buổi tiệc.",{},[5194],{"title":460,"description":50108},[23084,49969,50113],"macro","aVsD4l8RH37i92IOLiGceeFGjvidx0_LQvOZt32AWNQ",{"id":50116,"title":465,"body":50117,"category":5189,"day":468,"description":50531,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":50532,"navigation":2723,"outcomes":3047,"path":466,"prerequisites":50533,"seo":50534,"stem":467,"tags":50535,"__hash__":50537},"challenges\u002Fchallenges\u002F82.command-queue-log.md",{"type":965,"value":50118,"toc":50515},[50119,50121,50124,50126,50130,50144,50148,50162,50166,50180,50227,50229,50243,50245,50257,50261,50299,50305,50311,50316,50320,50336,50407,50413,50417,50432,50460,50462,50492,50494,50508,50510,50513],[968,50120,971],{"id":970},[973,50122,50123],{},"Bài này học 3 ứng dụng thực tế của Command. Bạn dùng nó cho hàng đợi in và phục hồi sau sập.",[968,50125,979],{"id":978},[981,50127,50129],{"id":50128},"hàng-đợi-yêu-cầu","Hàng đợi yêu cầu",[986,50131,50132,50135,50138,50141],{},[989,50133,50134],{},"Bên gửi thả lệnh vào hàng đợi rồi làm việc khác.",[989,50136,50137],{},"Bên xử lý lấy dần từng lệnh ra chạy.",[989,50139,50140],{},"Lợi ích là san tải giờ cao điểm, bên gửi không bị chặn.",[989,50142,50143],{},"Ví dụ đời thường: như xếp hàng in, gửi xong đi làm việc khác.",[981,50145,50147],{"id":50146},"ghi-nhật-ký-phục-hồi","Ghi nhật ký phục hồi",[986,50149,50150,50153,50156,50159],{},[989,50151,50152],{},"Mọi lệnh đổi dữ liệu đều ghi vào nhật ký bền vững trước khi chạy.",[989,50154,50155],{},"Sập thì đọc nhật ký và chạy lại từ điểm kiểm tra gần nhất.",[989,50157,50158],{},"Lệnh phải tự chứa đủ thông tin để chạy lại độc lập.",[989,50160,50161],{},"Bốn nhịp: ghi, chạy, đánh dấu xong, chốt điểm kiểm tra.",[981,50163,50165],{"id":50164},"nút-giao-diện","Nút giao diện",[986,50167,50168,50171,50174,50177],{},[989,50169,50170],{},"Nút là bên gọi, lập trình viên gắn lệnh vào nút.",[989,50172,50173],{},"Cùng 1 lệnh gắn được vào nút, menu và phím tắt.",[989,50175,50176],{},"Đổi logic 1 lần thì cả 3 đường cùng đổi.",[989,50178,50179],{},"Đây chính là Command mà dân giao diện dùng hằng ngày.",[1099,50181,50182,50194],{},[1102,50183,50184],{},[1105,50185,50186,50188,50191],{},[1108,50187,27318],{},[1108,50189,50190],{},"Lệnh lưu ở đâu",[1108,50192,50193],{},"Lợi ích chính",[1118,50195,50196,50206,50217],{},[1105,50197,50198,50200,50203],{},[1123,50199,30692],{},[1123,50201,50202],{},"Hàng đợi chung",[1123,50204,50205],{},"San tải, không chặn",[1105,50207,50208,50211,50214],{},[1123,50209,50210],{},"Nhật ký",[1123,50212,50213],{},"Nhật ký bền vững",[1123,50215,50216],{},"Làm lại sau sập",[1105,50218,50219,50221,50224],{},[1123,50220,50165],{},[1123,50222,50223],{},"Gắn vào nút menu",[1123,50225,50226],{},"1 lệnh nhiều đường gọi",[968,50228,1433],{"id":1432},[986,50230,50231,50234,50237,50240],{},[989,50232,50233],{},"Input: 3 máy gửi thả 10 lệnh vào hàng đợi. Output: cả 10 chạy đủ, không mất không lặp.",[989,50235,50236],{},"Giải thích: bên gửi không chờ, bên xử lý lấy dần theo thứ tự.",[989,50238,50239],{},"Input: sập giữa chừng ở lệnh 100, điểm kiểm tra ở 80. Output: chạy lại từ 81 tới 100.",[989,50241,50242],{},"Giải thích: đoạn trước 80 đã chốt nên bỏ qua.",[968,50244,1482],{"id":1481},[973,50246,1485,50247,16234,50249,1656,50251,3568,50254,1517],{},[1487,50248,4800],{},[992,50250,16237],{},[992,50252,50253],{},"std::condition_variable",[992,50255,50256],{},"day-082\u002F",[981,50258,50260],{"id":50259},"bài-1-hàng-đợi-lệnh-nhiều-luồng","Bài 1: Hàng đợi lệnh nhiều luồng",[1352,50262,50264],{"className":1393,"code":50263,"language":1395,"meta":1357,"style":1357},"class CommandQueue {\n public:\n  void push(std::unique_ptr\u003CCommand> c);            \u002F\u002F an toàn luồng\n  std::unique_ptr\u003CCommand> pop();                   \u002F\u002F chờ khi rỗng; trả nullptr khi đã shutdown và rỗng\n  void shutdown();\n};\nclass WorkerPool { public: WorkerPool(CommandQueue &q, int nThreads); void join(); };\n",[992,50265,50266,50271,50275,50280,50285,50290,50294],{"__ignoreMap":1357},[1023,50267,50268],{"class":1362,"line":63},[1023,50269,50270],{},"class CommandQueue {\n",[1023,50272,50273],{"class":1362,"line":68},[1023,50274,4836],{},[1023,50276,50277],{"class":1362,"line":73},[1023,50278,50279],{},"  void push(std::unique_ptr\u003CCommand> c);            \u002F\u002F an toàn luồng\n",[1023,50281,50282],{"class":1362,"line":78},[1023,50283,50284],{},"  std::unique_ptr\u003CCommand> pop();                   \u002F\u002F chờ khi rỗng; trả nullptr khi đã shutdown và rỗng\n",[1023,50286,50287],{"class":1362,"line":83},[1023,50288,50289],{},"  void shutdown();\n",[1023,50291,50292],{"class":1362,"line":88},[1023,50293,4866],{},[1023,50295,50296],{"class":1362,"line":93},[1023,50297,50298],{},"class WorkerPool { public: WorkerPool(CommandQueue &q, int nThreads); void join(); };\n",[973,50300,50301,50304],{},[992,50302,50303],{},"IncrementCommand(std::atomic\u003Cint>&)"," tăng biến đếm 1.",[1352,50306,50309],{"className":50307,"code":50308,"language":2241,"meta":1357},[2239],"3 luồng gửi, mỗi luồng 10.000 lệnh; 4 worker\n-> sau shutdown + join: counter = 30.000 (không mất, không lặp)\n",[992,50310,50308],{"__ignoreMap":1357},[973,50312,50313,50314,1517],{},"Chạy dưới ",[992,50315,16513],{},[981,50317,50319],{"id":50318},"bài-2-nhật-ký-và-khôi-phục-sau-sập","Bài 2: Nhật ký và khôi phục sau sập",[973,50321,50322,50323,50326,50327,1656,50330,1656,50333,1517],{},"Kho số dư tài khoản đơn giản ",[992,50324,50325],{},"std::map\u003Cstd::string, long long>",". Lệnh: ",[992,50328,50329],{},"Deposit(acc, amount)",[992,50331,50332],{},"Withdraw(acc, amount)",[992,50334,50335],{},"Transfer(from, to, amount)",[1099,50337,50338,50346],{},[1102,50339,50340],{},[1105,50341,50342,50344],{},[1108,50343,2547],{},[1108,50345,14241],{},[1118,50347,50348,50361,50379,50394],{},[1105,50349,50350,50355],{},[1123,50351,50352],{},[992,50353,50354],{},"serialize()",[1123,50356,50357,50358],{},"Mỗi lệnh ghi thành 1 dòng text: ",[992,50359,50360],{},"SEQ TYPE args",[1105,50362,50363,50366],{},[1123,50364,50365],{},"Write-ahead log",[1123,50367,50368,50369,1509,50372,2308,50375,50378],{},"Ghi dòng vào ",[992,50370,50371],{},"wal.log",[992,50373,50374],{},"fsync",[1487,50376,50377],{},"trước"," khi chạy lệnh",[1105,50380,50381,50384],{},[1123,50382,50383],{},"Checkpoint",[1123,50385,50386,50387,50390,50391,1184],{},"Mỗi 100 lệnh, ghi toàn bộ số dư vào ",[992,50388,50389],{},"snapshot.txt"," kèm ",[992,50392,50393],{},"SEQ",[1105,50395,50396,50401],{},[1123,50397,50398],{},[992,50399,50400],{},"recover()",[1123,50402,50403,50404,50406],{},"Nạp snapshot, chạy lại các dòng WAL có ",[992,50405,50393],{}," lớn hơn",[1352,50408,50411],{"className":50409,"code":50410,"language":2241,"meta":1357},[2239],"Chạy 250 lệnh, giết tiến trình (hoặc gọi std::abort) ở lệnh 173\nrecover() -> số dư giống hệt khi chạy 173 lệnh không sập\nSnapshot ở 100, chỉ chạy lại 73 lệnh\n",[992,50412,50410],{"__ignoreMap":1357},[981,50414,50416],{"id":50415},"bài-3-một-lệnh-ba-nơi-gọi-nâng-cao","Bài 3: Một lệnh, ba nơi gọi (nâng cao)",[973,50418,50419,50420,7423,50423,1656,50426,1656,50429,1517],{},"Mô phỏng trình soạn thảo có ",[992,50421,50422],{},"Document",[992,50424,50425],{},"SaveCommand",[992,50427,50428],{},"BoldCommand",[992,50430,50431],{},"FindCommand",[2273,50433,50434,50444,50454],{},[989,50435,50436,50437,50440,50441,16014],{},"Gắn cùng một đối tượng lệnh vào: nút toolbar, mục menu, phím tắt (bảng ",[992,50438,50439],{},"std::map\u003Cstd::string, Command*>"," như ",[992,50442,50443],{},"\"Ctrl+S\"",[989,50445,5030,50446,13568,50449,50451,50452,1718],{},[992,50447,50448],{},"canExecute()",[992,50450,50425],{}," chỉ bật khi tài liệu có thay đổi. Cả 3 nơi gọi đều hỏi ",[992,50453,50448],{},[989,50455,50456,50457,50459],{},"Đổi logic ",[992,50458,50425],{}," (thêm ghi file backup). Chứng minh cả 3 nơi đổi theo mà không sửa chúng.",[981,50461,2711],{"id":2710},[986,50463,50465,50471,50477,50483],{"className":50464},[2715],[989,50466,50468,50470],{"className":50467},[2719],[2721,50469],{"disabled":2723,"type":2724}," Bài 1 counter đúng, sanitizer luồng sạch.",[989,50472,50474,50476],{"className":50473},[2719],[2721,50475],{"disabled":2723,"type":2724}," Bài 2 khôi phục đúng sau sập ở vị trí ngẫu nhiên (chạy 20 lần).",[989,50478,50480,50482],{"className":50479},[2719],[2721,50481],{"disabled":2723,"type":2724}," Bài 3 cả 3 nơi dùng chung 1 đối tượng lệnh.",[989,50484,50486,50488,50489,50491],{"className":50485},[2719],[2721,50487],{"disabled":2723,"type":2724}," Giải thích được vì sao phải ghi log ",[1487,50490,50377],{}," khi chạy lệnh.",[968,50493,2890],{"id":2889},[986,50495,50496,50499,50502,50505],{},[989,50497,50498],{},"Hàng đợi tách bên gửi và xử lý thế nào?",[989,50500,50501],{},"Nhật ký giúp phục hồi sau sập ra sao?",[989,50503,50504],{},"Vì sao nút giao diện chính là Command?",[989,50506,50507],{},"Lệnh trong nhật ký cần chứa gì?",[3014,50509],{},[973,50511,50512],{},"🌕 Bạn đã hoàn thành ngày 82. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,50514,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":50516},[50517,50518,50523,50524,50530],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":50519},[50520,50521,50522],{"id":50128,"depth":73,"text":50129},{"id":50146,"depth":73,"text":50147},{"id":50164,"depth":73,"text":50165},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":50525},[50526,50527,50528,50529],{"id":50259,"depth":73,"text":50260},{"id":50318,"depth":73,"text":50319},{"id":50415,"depth":73,"text":50416},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Lệnh bay vào hàng đợi yêu cầu, ghi nhật ký để phục hồi sau sự cố, và nút bấm giao diện với ActionListener.",{},[5194],{"title":465,"description":50531},[23084,6437,50536],"logging","IjEcAMD267IeJB0YDRoFS5LuhjK97EQPoIE6BqgVADs",{"id":50539,"title":470,"body":50540,"category":8797,"day":473,"description":50947,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":50948,"navigation":2723,"outcomes":3047,"path":471,"prerequisites":50949,"seo":50950,"stem":472,"tags":50951,"__hash__":50954},"challenges\u002Fchallenges\u002F83.optics-phan-cap.md",{"type":965,"value":50541,"toc":50930},[50542,50544,50547,50549,50553,50567,50571,50585,50589,50603,50607,50621,50623,50637,50639,50649,50653,50683,50689,50695,50699,50719,50723,50872,50874,50907,50909,50923,50925,50928],[968,50543,971],{"id":970},[973,50545,50546],{},"Bài này học OPTICS cho dữ liệu nhiều mật độ. Bạn dùng nó khi DBSCAN 1 ngưỡng thất bại.",[968,50548,979],{"id":978},[981,50550,50552],{"id":50551},"vì-sao-cần-optics","Vì sao cần OPTICS",[986,50554,50555,50558,50561,50564],{},[989,50556,50557],{},"Epsilon nhỏ giữ cụm dày nhưng xé cụm thưa thành nhiễu.",[989,50559,50560],{},"Epsilon lớn giữ cụm thưa nhưng gộp cụm dày với nhiễu.",[989,50562,50563],{},"Thực tế có cả trung tâm đông và ngoại ô thưa cùng lúc.",[989,50565,50566],{},"OPTICS thay ngưỡng cứng bằng thứ tự sắp xếp.",[981,50568,50570],{"id":50569},"hai-khoảng-cách","Hai khoảng cách",[986,50572,50573,50576,50579,50582],{},[989,50574,50575],{},"Khoảng cách lõi: bán kính nhỏ nhất để điểm thành lõi.",[989,50577,50578],{},"Điểm vùng dày thì lõi nhỏ, vùng thưa thì lõi lớn.",[989,50580,50581],{},"Lan truyền từ p tới q bằng max giữa lõi p và khoảng cách thật.",[989,50583,50584],{},"Ví dụ đời thường: qua cầu hẹp hay rộng thì giá vé theo chỗ hẹp nhất.",[981,50586,50588],{"id":50587},"đồ-thị-lan-truyền","Đồ thị lan truyền",[986,50590,50591,50594,50597,50600],{},[989,50592,50593],{},"Duy trì hàng đợi ưu tiên theo lan truyền nhỏ nhất.",[989,50595,50596],{},"Mỗi bước rút điểm rẻ nhất, ghi thứ tự và khoảng cách của nó.",[989,50598,50599],{},"Vẽ thứ tự ngang và lan truyền đứng được đồ thị thung lũng.",[989,50601,50602],{},"Thung lũng sâu là cụm dày, nông là cụm thưa, đỉnh cao là biên.",[981,50604,50606],{"id":50605},"trích-cụm-và-phân-cấp","Trích cụm và phân cấp",[986,50608,50609,50612,50615,50618],{},[989,50610,50611],{},"Cắt đồ thị ở 1 ngưỡng: đoạn liên tục dưới ngưỡng là 1 cụm.",[989,50613,50614],{},"Hạ ngưỡng được cụm con dày, nâng ngưỡng gộp thành cụm cha.",[989,50616,50617],{},"Agglomerative: mỗi điểm 1 cụm rồi gộp cặp gần nhất dần.",[989,50619,50620],{},"Cắt cây dendrogram cao thấp khác nhau cho số cụm khác nhau.",[968,50622,1433],{"id":1432},[986,50624,50625,50628,50631,50634],{},[989,50626,50627],{},"Input: dữ liệu 1 cụm đều duy nhất. Output: đồ thị 1 thung lũng đơn.",[989,50629,50630],{},"Giải thích: mọi điểm lan truyền rẻ như nhau nên nằm chung 1 hõm.",[989,50632,50633],{},"Input: 2 cụm tách xa. Output: 2 thung lũng cách nhau bởi đỉnh cao.",[989,50635,50636],{},"Giải thích: cầu nối giữa 2 cụm rất đắt nên thành đỉnh ngăn.",[968,50638,1482],{"id":1481},[973,50640,1485,50641,17626,50643,33864,50646,1517],{},[1487,50642,13531],{},[992,50644,50645],{},"sklearn.cluster.OPTICS",[992,50647,50648],{},"day-083\u002F",[981,50650,50652],{"id":50651},"bài-1-optics","Bài 1: OPTICS",[1352,50654,50656],{"className":3538,"code":50655,"language":3540,"meta":1357,"style":1357},"def optics(X, min_pts: int, max_eps: float = np.inf) -> tuple[np.ndarray, np.ndarray, np.ndarray]:\n    \"\"\"Trả (ordering, reachability, core_distance).\n       core_distance(p) = khoảng cách tới hàng xóm thứ min_pts (tính cả p), inf nếu không đủ.\n       reachability(o từ p) = max(core_distance(p), dist(p, o)).\n       Dùng heap theo reachability nhỏ nhất, cập nhật bằng lazy deletion.\"\"\"\n",[992,50657,50658,50663,50668,50673,50678],{"__ignoreMap":1357},[1023,50659,50660],{"class":1362,"line":63},[1023,50661,50662],{},"def optics(X, min_pts: int, max_eps: float = np.inf) -> tuple[np.ndarray, np.ndarray, np.ndarray]:\n",[1023,50664,50665],{"class":1362,"line":68},[1023,50666,50667],{},"    \"\"\"Trả (ordering, reachability, core_distance).\n",[1023,50669,50670],{"class":1362,"line":73},[1023,50671,50672],{},"       core_distance(p) = khoảng cách tới hàng xóm thứ min_pts (tính cả p), inf nếu không đủ.\n",[1023,50674,50675],{"class":1362,"line":78},[1023,50676,50677],{},"       reachability(o từ p) = max(core_distance(p), dist(p, o)).\n",[1023,50679,50680],{"class":1362,"line":83},[1023,50681,50682],{},"       Dùng heap theo reachability nhỏ nhất, cập nhật bằng lazy deletion.\"\"\"\n",[1352,50684,50687],{"className":50685,"code":50686,"language":2241,"meta":1357},[2239],"Dữ liệu 3 cụm Gauss mật độ khác nhau + 20 điểm nhiễu\n-> reachability plot có 3 thung lũng, nhiễu nằm ở các đỉnh\nĐiểm đầu tiên trong ordering có reachability = inf\n",[992,50688,50686],{"__ignoreMap":1357},[973,50690,35212,50691,50694],{},[1487,50692,50693],{},"reachability plot",": trục x là thứ tự, trục y là reachability.",[981,50696,50698],{"id":50697},"bài-2-tách-cụm-từ-reachability-plot","Bài 2: Tách cụm từ reachability plot",[2273,50700,50701,50713],{},[989,50702,50703,50706,50707,50709,50710,50712],{},[992,50704,50705],{},"extract_dbscan(ordering, reachability, core_distance, eps)",": cắt ngang tại ",[992,50708,34552],{},". Kết quả phải khớp DBSCAN ngày 48 với cùng ",[992,50711,34552],{}," (trừ khác biệt ở điểm biên).",[989,50714,50715,50716,50718],{},"Dữ liệu có 1 cụm dày nằm cạnh 1 cụm thưa. Chỉ ra không có ",[992,50717,34552],{}," nào của DBSCAN tách đúng cả hai, nhưng reachability plot thấy rõ cả hai.",[981,50720,50722],{"id":50721},"bài-3-phân-cụm-phân-cấp-nâng-cao","Bài 3: Phân cụm phân cấp (nâng cao)",[2273,50724,50725,50858,50869],{},[989,50726,35241,50727,50730,50731,50805,50806,1517],{},[1487,50728,50729],{},"agglomerative clustering"," với 3 cách nối: single, complete, average. ",[1023,50732,50734,50758],{"className":50733},[1026],[1023,50735,50737],{"className":50736},[1030],[1032,50738,50739],{"xmlns":1034},[1036,50740,50741,50755],{},[1039,50742,50743,50745,50747,50753],{},[1042,50744,1044],{},[1046,50746,1049],{"stretchy":1048},[2327,50748,50749,50751],{},[1042,50750,1262],{},[1051,50752,13826],{},[1046,50754,1056],{"stretchy":1048},[1058,50756,50757],{"encoding":1060},"O(n^3)",[1023,50759,50761],{"className":50760,"ariaHidden":1066},[1065],[1023,50762,50764,50767,50770,50773,50802],{"className":50763},[1070],[1023,50765],{"className":50766,"style":2476},[1074],[1023,50768,1044],{"className":50769,"style":1081},[1079,1080],[1023,50771,1049],{"className":50772},[1085],[1023,50774,50776,50779],{"className":50775},[1079],[1023,50777,1262],{"className":50778},[1079,1080],[1023,50780,50782],{"className":50781},[2383],[1023,50783,50785],{"className":50784},[2387],[1023,50786,50788],{"className":50787},[2391],[1023,50789,50791],{"className":50790,"style":2369},[2395],[1023,50792,50793,50796],{"style":2398},[1023,50794],{"className":50795,"style":2403},[2402],[1023,50797,50799],{"className":50798},[2407,2408,2409,2410],[1023,50800,13826],{"className":50801},[1079,2410],[1023,50803,1056],{"className":50804},[1092]," đơn giản là được với ",[1023,50807,50809,50828],{"className":50808},[1026],[1023,50810,50812],{"className":50811},[1030],[1032,50813,50814],{"xmlns":1034},[1036,50815,50816,50825],{},[1039,50817,50818,50820,50822],{},[1042,50819,1262],{},[1046,50821,21123],{},[1051,50823,50824],{},"300",[1058,50826,50827],{"encoding":1060},"n \\le 300",[1023,50829,50831,50849],{"className":50830,"ariaHidden":1066},[1065],[1023,50832,50834,50837,50840,50843,50846],{"className":50833},[1070],[1023,50835],{"className":50836,"style":47337},[1074],[1023,50838,1262],{"className":50839},[1079,1080],[1023,50841],{"className":50842,"style":2355},[2354],[1023,50844,21123],{"className":50845},[2359],[1023,50847],{"className":50848,"style":2355},[2354],[1023,50850,50852,50855],{"className":50851},[1070],[1023,50853],{"className":50854,"style":10020},[1074],[1023,50856,50824],{"className":50857},[1079],[989,50859,50860,50861,50864,50865,50868],{},"Vẽ dendrogram bằng ",[992,50862,50863],{},"scipy.cluster.hierarchy.dendrogram"," từ ma trận ",[992,50866,50867],{},"linkage"," bạn tự tạo (đúng định dạng scipy).",[989,50870,50871],{},"Chạy 3 cách nối trên dữ liệu trăng lưỡi liềm. Cách nào tách đúng? Giải thích hiện tượng \"chaining\" của single link.",[981,50873,2711],{"id":2710},[986,50875,50877,50889,50895,50901],{"className":50876},[2715],[989,50878,50880,50882,50883,50885,50886,50888],{"className":50879},[2719],[2721,50881],{"disabled":2723,"type":2724}," Reachability khớp ",[992,50884,50645],{}," (sai số ",[992,50887,36436],{},", cùng tham số).",[989,50890,50892,50894],{"className":50891},[2719],[2721,50893],{"disabled":2723,"type":2724}," Có reachability plot và hình tách cụm.",[989,50896,50898,50900],{"className":50897},[2719],[2721,50899],{"disabled":2723,"type":2724}," Có ví dụ DBSCAN thất bại mà OPTICS thấy được.",[989,50902,50904,50906],{"className":50903},[2719],[2721,50905],{"disabled":2723,"type":2724}," Dendrogram 3 cách nối và giải thích chaining.",[968,50908,2890],{"id":2889},[986,50910,50911,50914,50917,50920],{},[989,50912,50913],{},"Khoảng cách lõi là gì?",[989,50915,50916],{},"Khoảng cách lan truyền tính thế nào?",[989,50918,50919],{},"Đồ thị lan truyền đọc ra sao?",[989,50921,50922],{},"Khi nào dùng OPTICS thay vì DBSCAN?",[3014,50924],{},[973,50926,50927],{},"🌕 Bạn đã hoàn thành ngày 83. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,50929,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":50931},[50932,50933,50939,50940,50946],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":50934},[50935,50936,50937,50938],{"id":50551,"depth":73,"text":50552},{"id":50569,"depth":73,"text":50570},{"id":50587,"depth":73,"text":50588},{"id":50605,"depth":73,"text":50606},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":50941},[50942,50943,50944,50945],{"id":50651,"depth":73,"text":50652},{"id":50697,"depth":73,"text":50698},{"id":50721,"depth":73,"text":50722},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật toán OPTICS: khoảng cách lõi, khoảng cách lan truyền, đồ thị lan truyền, trích cụm phân cấp và gom cụm agglomerative.",{},[3050],{"title":470,"description":50947},[34177,50952,50953],"optics","hierarchical","fjale4FAZeDnm1VD4Q9Y960pZnDqXFJpqse41wgEAGo",{"id":50956,"title":475,"body":50957,"category":8797,"day":478,"description":51281,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":51282,"navigation":2723,"outcomes":3047,"path":476,"prerequisites":51283,"seo":51284,"stem":477,"tags":51285,"__hash__":51288},"challenges\u002Fchallenges\u002F84.giam-chieu-pca.md",{"type":965,"value":50958,"toc":51264},[50959,50961,50964,50966,50970,50984,50988,51002,51006,51020,51045,51049,51063,51065,51079,51081,51091,51095,51135,51144,51150,51154,51178,51182,51208,51210,51241,51243,51257,51259,51262],[968,50960,971],{"id":970},[973,50962,50963],{},"Bài này học PCA để nén nhiều chiều thành 2 trục. Bạn dùng nó để vẽ dữ liệu và chạy mô hình nhanh hơn.",[968,50965,979],{"id":978},[981,50967,50969],{"id":50968},"vì-sao-giảm-chiều","Vì sao giảm chiều",[986,50971,50972,50975,50978,50981],{},[989,50973,50974],{},"Chiều cao khiến khoảng cách mất ý nghĩa và tính toán nặng.",[989,50976,50977],{},"Không vẽ được hình cho người xem ở chiều cao.",[989,50979,50980],{},"Giảm xong gom cụm ổn định hơn và chạy nhanh hơn.",[989,50982,50983],{},"Ví dụ đời thường: như tóm tắt bảng điểm dài thành 2 con số tổng kết.",[981,50985,50987],{"id":50986},"ý-tưởng-phương-sai-lớn-nhất","Ý tưởng phương sai lớn nhất",[986,50989,50990,50993,50996,50999],{},[989,50991,50992],{},"Hướng dữ liệu trải rộng nhất chứa nhiều thông tin nhất.",[989,50994,50995],{},"PC1 là hướng phương sai lớn nhất, PC2 vuông góc và lớn tiếp.",[989,50997,50998],{},"Các trục là vector riêng của ma trận hiệp phương sai.",[989,51000,51001],{},"Ví dụ đời thường: đám mây xiên thì trục dọc thân mây là PC1.",[981,51003,51005],{"id":51004},"tỉ-lệ-giữ-lại","Tỉ lệ giữ lại",[986,51007,51008,51011,51014,51017],{},[989,51009,51010],{},"Giá trị riêng cho biết lượng phương sai mỗi trục giữ.",[989,51012,51013],{},"Tỉ lệ bằng tổng đã chọn chia tổng toàn bộ.",[989,51015,51016],{},"Thường giữ ngưỡng 90 tới 95 phần trăm.",[989,51018,51019],{},"Hoa iris giữ PC1 PC2 là gần như toàn bộ 4 đặc trưng.",[1352,51021,51023],{"className":3538,"code":51022,"language":3540,"meta":1357,"style":1357},"# Chọn số chiều theo tỉ lệ\neig = [2.9, 0.9, 0.15, 0.05]  # giá trị riêng đã xếp giảm dần\ntong = sum(eig)  # tổng phương sai\nprint((eig[0]+eig[1])\u002Ftong)  # tỉ lệ giữ 2 trục đầu\n",[992,51024,51025,51030,51035,51040],{"__ignoreMap":1357},[1023,51026,51027],{"class":1362,"line":63},[1023,51028,51029],{},"# Chọn số chiều theo tỉ lệ\n",[1023,51031,51032],{"class":1362,"line":68},[1023,51033,51034],{},"eig = [2.9, 0.9, 0.15, 0.05]  # giá trị riêng đã xếp giảm dần\n",[1023,51036,51037],{"class":1362,"line":73},[1023,51038,51039],{},"tong = sum(eig)  # tổng phương sai\n",[1023,51041,51042],{"class":1362,"line":78},[1023,51043,51044],{},"print((eig[0]+eig[1])\u002Ftong)  # tỉ lệ giữ 2 trục đầu\n",[981,51046,51048],{"id":51047},"pipeline-và-hạn-chế","Pipeline và hạn chế",[986,51050,51051,51054,51057,51060],{},[989,51052,51053],{},"Pipeline: chuẩn hóa, tính hiệp phương sai, trích vector riêng, chọn trục, chiếu xuống.",[989,51055,51056],{},"Chuẩn hóa bắt buộc vì đặc trưng nghìn sẽ nuốt đặc trưng đơn vị.",[989,51058,51059],{},"PCA chỉ xoay tuyến tính nên bó tay với vòng tròn lồng nhau.",[989,51061,51062],{},"Nhạy ngoại lệ và trục mới khó diễn giải nghiệp vụ.",[968,51064,1433],{"id":1432},[986,51066,51067,51070,51073,51076],{},[989,51068,51069],{},"Input: dữ liệu nằm trên 1 đường thẳng. Output: PC1 giữ gần 100%, PC2 gần 0.",[989,51071,51072],{},"Giải thích: mọi biến thiên nằm hết trên 1 hướng.",[989,51074,51075],{},"Input: chiếu rồi dựng ngược với đủ mọi trục. Output: khôi phục đúng dữ liệu gốc.",[989,51077,51078],{},"Giải thích: đủ trục thì phép xoay không mất thông tin.",[968,51080,1482],{"id":1481},[973,51082,1485,51083,17626,51085,33864,51088,1517],{},[1487,51084,13531],{},[992,51086,51087],{},"sklearn.decomposition.PCA",[992,51089,51090],{},"day-084\u002F",[981,51092,51094],{"id":51093},"bài-1-pca-bằng-ma-trận-hiệp-phương-sai","Bài 1: PCA bằng ma trận hiệp phương sai",[1352,51096,51098],{"className":3538,"code":51097,"language":3540,"meta":1357,"style":1357},"class PCA:\n    def __init__(self, n_components: int | float): ...   # float trong (0,1] là tỉ lệ phương sai cần giữ\n    def fit(self, X): ...\n    def transform(self, X): ...\n    def inverse_transform(self, Z): ...\n    components_: np.ndarray            # k x d, mỗi hàng là 1 trục, độ dài 1\n    explained_variance_ratio_: np.ndarray\n",[992,51099,51100,51105,51110,51115,51120,51125,51130],{"__ignoreMap":1357},[1023,51101,51102],{"class":1362,"line":63},[1023,51103,51104],{},"class PCA:\n",[1023,51106,51107],{"class":1362,"line":68},[1023,51108,51109],{},"    def __init__(self, n_components: int | float): ...   # float trong (0,1] là tỉ lệ phương sai cần giữ\n",[1023,51111,51112],{"class":1362,"line":73},[1023,51113,51114],{},"    def fit(self, X): ...\n",[1023,51116,51117],{"class":1362,"line":78},[1023,51118,51119],{},"    def transform(self, X): ...\n",[1023,51121,51122],{"class":1362,"line":83},[1023,51123,51124],{},"    def inverse_transform(self, Z): ...\n",[1023,51126,51127],{"class":1362,"line":88},[1023,51128,51129],{},"    components_: np.ndarray            # k x d, mỗi hàng là 1 trục, độ dài 1\n",[1023,51131,51132],{"class":1362,"line":93},[1023,51133,51134],{},"    explained_variance_ratio_: np.ndarray\n",[973,51136,51137,51139,51140,51143],{},[1487,51138,6076],{}," trừ trung bình trước khi tính hiệp phương sai. Dùng ",[992,51141,51142],{},"np.linalg.eigh"," và sắp giá trị riêng giảm dần. Cố định dấu mỗi trục (phần tử có trị tuyệt đối lớn nhất mang dấu dương) để kết quả tất định.",[1352,51145,51148],{"className":51146,"code":51147,"language":2241,"meta":1357},[2239],"Iris, n_components=2 -> explained_variance_ratio_ ~ [0.92, 0.05]\nn_components=0.95    -> giữ 2 trục\nCác trục vuông góc: components_ @ components_.T ~ I\n",[992,51149,51147],{"__ignoreMap":1357},[981,51151,51153],{"id":51152},"bài-2-pca-bằng-svd-và-trực-quan","Bài 2: PCA bằng SVD và trực quan",[2273,51155,51156,51166,51169,51175],{},[989,51157,51158,51159,2252,51162,51165],{},"Viết bản ",[992,51160,51161],{},"fit_svd",[992,51163,51164],{},"np.linalg.svd",". So với bản eigh.",[989,51167,51168],{},"Vẽ Iris trên PC1-PC2, tô màu theo loài.",[989,51170,35212,51171,51174],{},[1487,51172,51173],{},"scree plot",": tỉ lệ phương sai từng trục và tỉ lệ cộng dồn.",[989,51176,51177],{},"In \"loading\" của PC1: đặc trưng nào đóng góp nhiều nhất.",[981,51179,51181],{"id":51180},"bài-3-nén-ảnh-và-tiền-xử-lý-nâng-cao","Bài 3: Nén ảnh và tiền xử lý (nâng cao)",[2273,51183,51184,51199,51202],{},[989,51185,51186,51187,51190,51191,51194,51195,51198],{},"Bộ chữ số viết tay ",[992,51188,51189],{},"load_digits"," (8x8). Giữ ",[992,51192,51193],{},"k = 5, 10, 20, 40"," trục. Dựng lại ảnh bằng ",[992,51196,51197],{},"inverse_transform",". Vẽ ảnh gốc và ảnh dựng lại, in sai số.",[989,51200,51201],{},"Chạy K-means (ngày 47) trên dữ liệu gốc 64 chiều và trên 10 trục PCA. So silhouette và thời gian.",[989,51203,51204,51205,1517],{},"Chỉ ra 1 trường hợp PCA làm mất thông tin phân lớp: dữ liệu 2 lớp tách nhau theo hướng phương sai ",[1487,51206,51207],{},"nhỏ",[981,51209,2711],{"id":2710},[986,51211,51213,51223,51229,51235],{"className":51212},[2715],[989,51214,51216,34128,51218,50885,51220,51222],{"className":51215},[2719],[2721,51217],{"disabled":2723,"type":2724},[992,51219,51087],{},[992,51221,46120],{},", sau khi cố định dấu).",[989,51224,51226,51228],{"className":51225},[2719],[2721,51227],{"disabled":2723,"type":2724}," Bản eigh và SVD cho cùng kết quả.",[989,51230,51232,51234],{"className":51231},[2719],[2721,51233],{"disabled":2723,"type":2724}," Có scree plot, hình Iris 2D, hình dựng lại chữ số.",[989,51236,51238,51240],{"className":51237},[2719],[2721,51239],{"disabled":2723,"type":2724}," Có ví dụ PCA làm hỏng phân lớp kèm giải thích.",[968,51242,2890],{"id":2889},[986,51244,51245,51248,51251,51254],{},[989,51246,51247],{},"PC1 và PC2 là gì?",[989,51249,51250],{},"Tỉ lệ giữ lại tính thế nào?",[989,51252,51253],{},"Vì sao phải chuẩn hóa trước PCA?",[989,51255,51256],{},"Khi nào PCA thất bại?",[3014,51258],{},[973,51260,51261],{},"🌕 Bạn đã hoàn thành ngày 84. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,51263,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":51265},[51266,51267,51273,51274,51280],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":51268},[51269,51270,51271,51272],{"id":50968,"depth":73,"text":50969},{"id":50986,"depth":73,"text":50987},{"id":51004,"depth":73,"text":51005},{"id":51047,"depth":73,"text":51048},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":51275},[51276,51277,51278,51279],{"id":51093,"depth":73,"text":51094},{"id":51152,"depth":73,"text":51153},{"id":51180,"depth":73,"text":51181},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Giảm chiều bằng phân tích thành phần chính: phương sai lớn nhất, PC1 PC2, tỉ lệ giữ lại và hạn chế tuyến tính của PCA.",{},[4669,14055],{"title":475,"description":51281},[18472,51286,51287],"pca","dimensionality-reduction","y3n_yvNAMjwvgT-Rq_fHCU0gHjZ-WbEqmL98ly89fwA",{"id":51290,"title":480,"body":51291,"category":5189,"day":483,"description":51713,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":51714,"navigation":2723,"outcomes":3047,"path":481,"prerequisites":51715,"seo":51716,"stem":482,"tags":51717,"__hash__":51719},"challenges\u002Fchallenges\u002F85.state-co-ban.md",{"type":965,"value":51292,"toc":51696},[51293,51295,51298,51300,51302,51316,51320,51334,51338,51352,51401,51403,51417,51419,51430,51436,51465,51471,51474,51478,51540,51544,51571,51575,51612,51635,51641,51643,51673,51675,51689,51691,51694],[968,51294,971],{"id":970},[973,51296,51297],{},"Bài này học State để hành vi đổi theo trạng thái. Bạn dùng nó thay cho bảng rẽ nhánh khổng lồ.",[968,51299,979],{"id":978},[981,51301,46198],{"id":46197},[986,51303,51304,51307,51310,51313],{},[989,51305,51306],{},"Cho phép đổi hành vi khi trạng thái nội tại đổi.",[989,51308,51309],{},"Nhìn như thể đối tượng đổi cả lớp của mình.",[989,51311,51312],{},"Từ khóa là hành vi theo trạng thái và ủy thác.",[989,51314,51315],{},"Ví dụ đời thường: như đèn giao thông, cùng nút bấm nhưng mỗi màu phản ứng khác.",[981,51317,51319],{"id":51318},"máy-kẹo-4-trạng-thái","Máy kẹo 4 trạng thái",[986,51321,51322,51325,51328,51331],{},[989,51323,51324],{},"Bốn trạng thái: chờ xu (NoQuarter), đã nhận xu (HasQuarter), đang nhả kẹo (Sold), hết kẹo (SoldOut).",[989,51326,51327],{},"Bốn hành động: bỏ xu, trả xu, quay tay, nhả kẹo.",[989,51329,51330],{},"Cách cũ rẽ nhánh 4 nhân 4 ở mọi nơi, thêm trạng thái là sửa khắp.",[989,51332,51333],{},"Ví dụ mua thành công: chờ nhận xu, quay chuyển sang bán, nhả rồi về chờ.",[981,51335,51337],{"id":51336},"thiết-kế-ủy-thác","Thiết kế ủy thác",[986,51339,51340,51343,51346,51349],{},[989,51341,51342],{},"Mỗi trạng thái là 1 lớp riêng cùng giao diện 4 hành động.",[989,51344,51345],{},"Máy chỉ giữ trạng thái hiện tại và chuyển lời cho nó.",[989,51347,51348],{},"Trạng thái xử lý xong tự chuyển máy sang trạng thái khác.",[989,51350,51351],{},"Mỗi nhịp chỉ đúng 1 lớp làm việc, máy chỉ giữ số kẹo.",[1099,51353,51354,51366],{},[1102,51355,51356],{},[1105,51357,51358,51360,51363],{},[1108,51359,5414],{},[1108,51361,51362],{},"Rẽ nhánh",[1108,51364,51365],{},"Ủy thác State",[1118,51367,51368,51379,51390],{},[1105,51369,51370,51373,51376],{},[1123,51371,51372],{},"Logic 1 trạng thái",[1123,51374,51375],{},"Rải 4 bảng",[1123,51377,51378],{},"Gom 1 lớp",[1105,51380,51381,51384,51387],{},[1123,51382,51383],{},"Thêm trạng thái",[1123,51385,51386],{},"Sửa 4 bảng",[1123,51388,51389],{},"Thêm 1 lớp",[1105,51391,51392,51395,51398],{},[1123,51393,51394],{},"Sót nhánh",[1123,51396,51397],{},"Dễ sót",[1123,51399,51400],{},"Khó sót",[968,51402,1433],{"id":1432},[986,51404,51405,51408,51411,51414],{},[989,51406,51407],{},"Input: quay tay khi chưa bỏ xu. Output: nhắc bỏ xu, không nhả, vẫn chờ xu.",[989,51409,51410],{},"Giải thích: trạng thái chờ chỉ nhắc chứ không chuyển.",[989,51412,51413],{},"Input: mua viên cuối cùng. Output: nhả viên cuối rồi sang hết kẹo.",[989,51415,51416],{},"Giải thích: tồn kho hết thì lượt sau từ chối bỏ xu.",[968,51418,1482],{"id":1481},[973,51420,1485,51421,4801,51423,51426,51427,51429],{},[1487,51422,4800],{},[992,51424,51425],{},"day-085\u002F",". Mọi hành động trả ",[992,51428,23400],{}," thông báo để test.",[981,51431,51433,51434],{"id":51432},"bài-1-máy-bán-kẹo-bằng-switch","Bài 1: Máy bán kẹo bằng ",[992,51435,7335],{},[973,51437,1505,51438,51441,51442,51445,51446,51448,51449,1656,51452,1656,51455,1656,51458,51461,51462,51464],{},[992,51439,51440],{},"GumballMachineV1"," theo cách cũ: 1 biến ",[992,51443,51444],{},"state"," kiểu ",[992,51447,16206],{},", 4 hàm ",[992,51450,51451],{},"insertQuarter",[992,51453,51454],{},"ejectQuarter",[992,51456,51457],{},"turnCrank",[992,51459,51460],{},"dispense",", mỗi hàm là 1 ",[992,51463,7335],{}," 4 nhánh.",[1352,51466,51469],{"className":51467,"code":51468,"language":2241,"meta":1357},[2239],"Máy 2 viên:\nturnCrank()                 -> \"Bạn chưa bỏ xu\"\ninsertQuarter(); turnCrank()-> \"Bạn quay tay... Một viên kẹo lăn ra\", còn 1\ninsertQuarter(); insertQuarter() -> lần 2: \"Đã có xu rồi\"\nejectQuarter()              -> \"Trả xu\"\ninsertQuarter(); turnCrank()-> nhả viên cuối, sang SOLD_OUT\ninsertQuarter()             -> \"Hết kẹo, không nhận xu\"\n",[992,51470,51468],{"__ignoreMap":1357},[973,51472,51473],{},"Viết đủ test cho 16 tổ hợp (4 trạng thái x 4 hành động).",[981,51475,51477],{"id":51476},"bài-2-refactor-sang-state","Bài 2: Refactor sang State",[1352,51479,51481],{"className":1393,"code":51480,"language":1395,"meta":1357,"style":1357},"struct State {\n  virtual std::string insertQuarter() = 0; virtual std::string ejectQuarter() = 0;\n  virtual std::string turnCrank() = 0;     virtual std::string dispense() = 0;\n  virtual ~State() = default;\n};\nclass GumballMachine {\n public:\n  explicit GumballMachine(int count);\n  std::string insertQuarter(); std::string ejectQuarter(); std::string turnCrank();\n  void setState(State *s); int count() const; void releaseBall();\n  State *noQuarterState(); State *hasQuarterState(); State *soldState(); State *soldOutState();\n};\n",[992,51482,51483,51488,51493,51498,51503,51507,51512,51516,51521,51526,51531,51536],{"__ignoreMap":1357},[1023,51484,51485],{"class":1362,"line":63},[1023,51486,51487],{},"struct State {\n",[1023,51489,51490],{"class":1362,"line":68},[1023,51491,51492],{},"  virtual std::string insertQuarter() = 0; virtual std::string ejectQuarter() = 0;\n",[1023,51494,51495],{"class":1362,"line":73},[1023,51496,51497],{},"  virtual std::string turnCrank() = 0;     virtual std::string dispense() = 0;\n",[1023,51499,51500],{"class":1362,"line":78},[1023,51501,51502],{},"  virtual ~State() = default;\n",[1023,51504,51505],{"class":1362,"line":83},[1023,51506,4866],{},[1023,51508,51509],{"class":1362,"line":88},[1023,51510,51511],{},"class GumballMachine {\n",[1023,51513,51514],{"class":1362,"line":93},[1023,51515,4836],{},[1023,51517,51518],{"class":1362,"line":98},[1023,51519,51520],{},"  explicit GumballMachine(int count);\n",[1023,51522,51523],{"class":1362,"line":103},[1023,51524,51525],{},"  std::string insertQuarter(); std::string ejectQuarter(); std::string turnCrank();\n",[1023,51527,51528],{"class":1362,"line":108},[1023,51529,51530],{},"  void setState(State *s); int count() const; void releaseBall();\n",[1023,51532,51533],{"class":1362,"line":113},[1023,51534,51535],{},"  State *noQuarterState(); State *hasQuarterState(); State *soldState(); State *soldOutState();\n",[1023,51537,51538],{"class":1362,"line":118},[1023,51539,4866],{},[973,51541,51542],{},[1487,51543,2194],{},[986,51545,51546,51556,51559],{},[989,51547,51548,7330,51551,2461,51553,51555],{},[992,51549,51550],{},"GumballMachine",[992,51552,7335],{},[992,51554,4951],{}," theo trạng thái.",[989,51557,51558],{},"Cùng 16 test của Bài 1 phải pass với bản mới.",[989,51560,5030,51561,51564,51565,15919,51568,1517],{},[992,51562,51563],{},"refill(int n)",": từ ",[992,51566,51567],{},"SoldOut",[992,51569,51570],{},"NoQuarter",[981,51572,51574],{"id":51573},"bài-3-máy-trạng-thái-cho-đơn-hàng-nâng-cao","Bài 3: Máy trạng thái cho đơn hàng (nâng cao)",[973,51576,51577,51578,1656,51581,1656,51584,1656,51587,1656,51590,1656,51593,51596,51597,1656,51600,1656,51603,1656,51606,1656,51609,1517],{},"Đơn hàng có trạng thái: ",[992,51579,51580],{},"Created",[992,51582,51583],{},"Paid",[992,51585,51586],{},"Shipped",[992,51588,51589],{},"Delivered",[992,51591,51592],{},"Cancelled",[992,51594,51595],{},"Refunded",". Hành động: ",[992,51598,51599],{},"pay",[992,51601,51602],{},"ship",[992,51604,51605],{},"deliver",[992,51607,51608],{},"cancel",[992,51610,51611],{},"refund",[2273,51613,51614,51623,51629],{},[989,51615,51616,51617,51620,51621,1517],{},"Vẽ sơ đồ chuyển trạng thái (Mermaid ",[992,51618,51619],{},"stateDiagram-v2",") trong ",[992,51622,2513],{},[989,51624,51625,51626,51628],{},"Cài bằng State pattern. Hành động không hợp lệ ném ",[992,51627,16336],{}," kèm tên trạng thái.",[989,51630,51631,51632,1517],{},"Ghi lịch sử chuyển trạng thái ",[992,51633,51634],{},"(từ, hành động, tới)",[1352,51636,51639],{"className":51637,"code":51638,"language":2241,"meta":1357},[2239],"Created -pay-> Paid -ship-> Shipped -deliver-> Delivered\nDelivered.cancel() -> logic_error \"Không thể hủy đơn đã giao\"\nPaid -cancel-> Cancelled -refund-> Refunded\n",[992,51640,51638],{"__ignoreMap":1357},[981,51642,2711],{"id":2710},[986,51644,51646,51652,51662,51668],{"className":51645},[2715],[989,51647,51649,51651],{"className":51648},[2719],[2721,51650],{"disabled":2723,"type":2724}," 16 test pass cho cả V1 và bản State.",[989,51653,51655,2308,51657,51659,51660,51555],{"className":51654},[2719],[2721,51656],{"disabled":2723,"type":2724},[992,51658,51550],{}," bản mới không có ",[992,51661,7335],{},[989,51663,51665,51667],{"className":51664},[2719],[2721,51666],{"disabled":2723,"type":2724}," Bài 3 có sơ đồ Mermaid và test mọi chuyển hợp lệ và không hợp lệ.",[989,51669,51671,6299],{"className":51670},[2719],[2721,51672],{"disabled":2723,"type":2724},[968,51674,2890],{"id":2889},[986,51676,51677,51680,51683,51686],{},[989,51678,51679],{},"State định nghĩa trong 1 câu là gì?",[989,51681,51682],{},"Máy kẹo có mấy trạng thái và hành động nào?",[989,51684,51685],{},"Ủy thác trạng thái khác rẽ nhánh ở đâu?",[989,51687,51688],{},"Một lượt mua thành công đi qua những trạng thái nào?",[3014,51690],{},[973,51692,51693],{},"🌕 Bạn đã hoàn thành ngày 85. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,51695,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":51697},[51698,51699,51704,51705,51712],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":51700},[51701,51702,51703],{"id":46197,"depth":73,"text":46198},{"id":51318,"depth":73,"text":51319},{"id":51336,"depth":73,"text":51337},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":51706},[51707,51709,51710,51711],{"id":51432,"depth":73,"text":51708},"Bài 1: Máy bán kẹo bằng switch",{"id":51476,"depth":73,"text":51477},{"id":51573,"depth":73,"text":51574},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa State, máy kẹo bốn trạng thái với rẽ nhánh khổng lồ, và cách mỗi trạng thái tự lo hành vi của mình.",{},[5194,5195],{"title":480,"description":51713},[51444,51718],"gumball","AenB4a6t2C7ZfWEWcqdgfjCJzHkz86JfLK8WMJc8O6M",{"id":51721,"title":485,"body":51722,"category":5189,"day":488,"description":52070,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":52071,"navigation":2723,"outcomes":3047,"path":486,"prerequisites":52072,"seo":52073,"stem":487,"tags":52074,"__hash__":52075},"challenges\u002Fchallenges\u002F86.state-nang-cao.md",{"type":965,"value":51723,"toc":52054},[51724,51726,51729,51731,51735,51749,51753,51770,51774,51788,51835,51837,51851,51853,51864,51868,51884,51931,51937,51950,51954,51976,51980,52004,52006,52033,52035,52049,52051],[968,51725,971],{"id":970},[973,51727,51728],{},"Bài này học thêm trạng thái trúng thưởng và phân biệt State. Bạn dùng nó để mở rộng máy kẹo không vỡ code.",[968,51730,979],{"id":978},[981,51732,51734],{"id":51733},"trạng-thái-trúng-thưởng","Trạng thái trúng thưởng",[986,51736,51737,51740,51743,51746],{},[989,51738,51739],{},"Game 1 phần 10 lượt quay trúng 2 viên thay vì 1.",[989,51741,51742],{},"Thêm 1 lớp trúng thưởng, sửa đúng 1 chỗ ở đã nhận xu.",[989,51744,51745],{},"Quay thì bốc thăm: trúng sang trúng thưởng, trượt sang đã bán.",[989,51747,51748],{},"Trúng thưởng nhả 2 viên rồi về chờ hoặc hết tùy tồn kho.",[981,51750,51752],{"id":51751},"sơ-đồ-5-trạng-thái","Sơ đồ 5 trạng thái",[986,51754,51755,51758,51761,51764,51767],{},[989,51756,51757],{},"Chờ nhận xu thì sang đã nhận.",[989,51759,51760],{},"Đã nhận quay thì bốc thăm, trả xu thì về chờ.",[989,51762,51763],{},"Trúng nhả 2 viên, bán nhả 1 viên rồi về chờ hoặc hết.",[989,51765,51766],{},"Hết kẹo từ chối mọi thứ tới khi nạp lại.",[989,51768,51769],{},"Vẽ sơ đồ ra giấy là có tài liệu sống cho cả nhóm.",[981,51771,51773],{"id":51772},"chia-sẻ-trạng-thái","Chia sẻ trạng thái",[986,51775,51776,51779,51782,51785],{},[989,51777,51778],{},"Đối tượng trạng thái không giữ gì riêng ngoài máy đang phục vụ.",[989,51780,51781],{},"Nhiều máy dùng chung 1 bộ 5 trạng thái cho nhẹ.",[989,51783,51784],{},"Mỗi máy chỉ đổi tham chiếu sang trạng thái chung tương ứng.",[989,51786,51787],{},"Trăm máy cũng chỉ cần 5 đối tượng trạng thái.",[1099,51789,51790,51801],{},[1102,51791,51792],{},[1105,51793,51794,51796,51798],{},[1108,51795,5414],{},[1108,51797,7137],{},[1108,51799,51800],{},"State",[1118,51802,51803,51814,51824],{},[1105,51804,51805,51808,51811],{},[1123,51806,51807],{},"Ai chọn",[1123,51809,51810],{},"Khách ngoài gắn vào",[1123,51812,51813],{},"Nội tại tự chuyển",[1105,51815,51816,51818,51821],{},[1123,51817,24479],{},[1123,51819,51820],{},"Đổi thuật toán theo ý dùng",[1123,51822,51823],{},"Đổi hành vi theo vòng đời",[1105,51825,51826,51829,51832],{},[1123,51827,51828],{},"Quan hệ biến thể",[1123,51830,51831],{},"Độc lập",[1123,51833,51834],{},"Biết nhau qua sơ đồ",[968,51836,1433],{"id":1432},[986,51838,51839,51842,51845,51848],{},[989,51840,51841],{},"Input: quay trúng khi còn nhiều kẹo. Output: nhả 2 viên, tồn giảm 2, về chờ.",[989,51843,51844],{},"Giải thích: trúng thưởng nhả đôi rồi quay về vòng mới.",[989,51846,51847],{},"Input: quay trúng nhưng chỉ còn 1 viên. Output: nhả 1 viên duy nhất, sang hết kẹo.",[989,51849,51850],{},"Giải thích: không nợ viên thứ 2, lượt sau từ chối xu.",[968,51852,1482],{"id":1481},[973,51854,1485,51855,51857,51858,51860,51861,1517],{},[1487,51856,4800],{}," (hoặc Java). Dùng tiếp ",[992,51859,51550],{}," ngày 85. Nộp vào ",[992,51862,51863],{},"day-086\u002F",[981,51865,51867],{"id":51866},"bài-1-game-110-trúng-thưởng","Bài 1: Game 1\u002F10 trúng thưởng",[973,51869,5030,51870,51873,51874,51877,51878,51880,51881,1517],{},[992,51871,51872],{},"WinnerState",". Trong ",[992,51875,51876],{},"HasQuarterState::turnCrank()",", bốc thăm: 10% sang ",[992,51879,51872],{}," (nếu còn ít nhất 2 viên), còn lại sang ",[992,51882,51883],{},"SoldState",[1099,51885,51886,51894],{},[1102,51887,51888],{},[1105,51889,51890,51892],{},[1108,51891,2547],{},[1108,51893,14241],{},[1118,51895,51896,51908,51921],{},[1105,51897,51898,51901],{},[1123,51899,51900],{},"Bốc thăm",[1123,51902,51903,51904,51907],{},"Nhận ",[992,51905,51906],{},"std::function\u003Cint()> rng"," qua constructor máy để test được",[1105,51909,51910,51913],{},[1123,51911,51912],{},"Winner",[1123,51914,51915,51916,51918,51919],{},"Nhả 2 viên. Còn kẹo thì về ",[992,51917,51570],{},", hết thì ",[992,51920,51567],{},[1105,51922,51923,51926],{},[1123,51924,51925],{},"Còn đúng 1 viên",[1123,51927,51928,51929],{},"Không được vào ",[992,51930,51872],{},[1352,51932,51935],{"className":51933,"code":51934,"language":2241,"meta":1357},[2239],"rng luôn trúng, máy 5 viên: mua 1 lần -> còn 3\nrng luôn trúng, máy 1 viên: mua 1 lần -> còn 0, không vào Winner\nrng thật, 10.000 lượt mua, máy nạp lại liên tục -> tỉ lệ trúng ~ 10%\n",[992,51936,51934],{"__ignoreMap":1357},[973,51938,51939,51940,51942,51943,51946,51947,51949],{},"Chứng minh bằng ",[992,51941,14320],{},": chỉ ",[992,51944,51945],{},"HasQuarterState"," và file mới ",[992,51948,51872],{}," thay đổi (cộng dòng đăng ký trong máy).",[981,51951,51953],{"id":51952},"bài-2-dùng-chung-đối-tượng-trạng-thái","Bài 2: Dùng chung đối tượng trạng thái",[2273,51955,51956,51967,51973],{},[989,51957,51958,51959,51962,51963,51966],{},"Biến 5 trạng thái thành ",[1487,51960,51961],{},"không lưu dữ liệu riêng",": mọi hàm nhận ",[992,51964,51965],{},"GumballMachine&"," làm tham số thay vì giữ con trỏ.",[989,51968,51969,51970,51972],{},"Tạo 100 máy dùng chung 5 đối tượng trạng thái ",[992,51971,16213],{},". In số đối tượng trạng thái được tạo (phải là 5).",[989,51974,51975],{},"Viết 3 câu: đánh đổi giữa trạng thái giữ tham chiếu máy và trạng thái dùng chung.",[981,51977,51979],{"id":51978},"bài-3-state-và-strategy-nâng-cao","Bài 3: State và Strategy (nâng cao)",[2273,51981,51982,51985,51998],{},[989,51983,51984],{},"Viết bảng so sánh 2 pattern: ai chọn đối tượng hành vi, ai đổi nó, lúc nào đổi, sơ đồ lớp có giống nhau không.",[989,51986,51987,51988,51990,51991,1656,51994,51997],{},"Viết 1 ví dụ ",[1487,51989,7137],{}," trên chính máy kẹo: chính sách giá (",[992,51992,51993],{},"NormalPrice",[992,51995,51996],{},"HappyHour"," giảm 50%). Người vận hành đặt từ bên ngoài.",[989,51999,1505,52000,52003],{},[992,52001,52002],{},"GumballMonitor"," in báo cáo: vị trí máy, số kẹo, tên trạng thái. Dùng lại ở ngày 98 (Proxy).",[981,52005,2711],{"id":2710},[986,52007,52009,52015,52021,52027],{"className":52008},[2715],[989,52010,52012,52014],{"className":52011},[2719],[2721,52013],{"disabled":2723,"type":2724}," Test trúng thưởng pass với rng giả.",[989,52016,52018,52020],{"className":52017},[2719],[2721,52019],{"disabled":2723,"type":2724}," Thêm Winner chỉ sửa 1 trạng thái cũ.",[989,52022,52024,52026],{"className":52023},[2719],[2721,52025],{"disabled":2723,"type":2724}," 100 máy chỉ dùng 5 đối tượng trạng thái.",[989,52028,52030,52032],{"className":52029},[2719],[2721,52031],{"disabled":2723,"type":2724}," Bảng State vs Strategy có ví dụ code cho cả hai.",[968,52034,2890],{"id":2889},[986,52036,52037,52040,52043,52046],{},[989,52038,52039],{},"Thêm trúng thưởng phải sửa mấy chỗ?",[989,52041,52042],{},"Chia sẻ trạng thái tiết kiệm gì?",[989,52044,52045],{},"Câu hỏi nhanh phân biệt State và Strategy là gì?",[989,52047,52048],{},"Khi nào không nên dùng State?",[3014,52050],{},[973,52052,52053],{},"🌕 Bạn đã hoàn thành ngày 86. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":52055},[52056,52057,52062,52063,52069],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":52058},[52059,52060,52061],{"id":51733,"depth":73,"text":51734},{"id":51751,"depth":73,"text":51752},{"id":51772,"depth":73,"text":51773},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":52064},[52065,52066,52067,52068],{"id":51866,"depth":73,"text":51867},{"id":51952,"depth":73,"text":51953},{"id":51978,"depth":73,"text":51979},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Trạng thái trúng thưởng đổi sơ đồ chuyển, chia sẻ trạng thái giữa nhiều máy, và ranh giới với Strategy.",{},[5194],{"title":485,"description":52070},[51444,7552],"2NnP6n8gWC7vof9v8IIuPwf8Mbb9sug0VaPKzj0X2VI",{"id":52077,"title":490,"body":52078,"category":8797,"day":493,"description":52486,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":52487,"navigation":2723,"outcomes":3047,"path":491,"prerequisites":52488,"seo":52489,"stem":492,"tags":52490,"__hash__":52492},"challenges\u002Fchallenges\u002F87.mapreduce-kmeans-canopy.md",{"type":965,"value":52079,"toc":52469},[52080,52082,52085,52087,52091,52105,52109,52123,52127,52141,52145,52159,52161,52175,52177,52188,52192,52255,52261,52349,52353,52373,52388,52392,52414,52416,52446,52448,52462,52464,52467],[968,52081,971],{"id":970},[973,52083,52084],{},"Bài này học chạy K-means song song và canopy dọn đường. Bạn dùng nó để gom cụm dữ liệu terabyte.",[968,52086,979],{"id":978},[981,52088,52090],{"id":52089},"k-means-song-song","K-means song song",[986,52092,52093,52096,52099,52102],{},[989,52094,52095],{},"Bước gán mỗi điểm độc lập nên chia trăm máy cùng làm.",[989,52097,52098],{},"Map tính tâm gần nhất cho từng điểm rồi nhả cặp tâm điểm.",[989,52100,52101],{},"Shuffle gom cùng tâm về 1 reduce, reduce tính trung bình ra tâm mới.",[989,52103,52104],{},"Lặp tới khi tâm ổn định, mỗi vòng là 1 job.",[981,52106,52108],{"id":52107},"canopy-tiền-xử-lý","Canopy tiền xử lý",[986,52110,52111,52114,52117,52120],{},[989,52112,52113],{},"Phủ nhanh các tán bao điểm bằng 2 ngưỡng lỏng T1 và chặt T2.",[989,52115,52116],{},"Lấy điểm chưa phủ làm tâm, điểm trong T1 vào tán, trong T2 bị xóa chờ.",[989,52118,52119],{},"Điểm vành giữa 2 ngưỡng thuộc tán nhưng vẫn chờ làm tâm khác.",[989,52121,52122],{},"Ví dụ đời thường: như khoanh vùng tìm kiếm trước khi soi kỹ từng nhà.",[981,52124,52126],{"id":52125},"canopy-giúp-k-means","Canopy giúp K-means",[986,52128,52129,52132,52135,52138],{},[989,52130,52131],{},"Chỉ so điểm với tâm có tán chứa nó, đỡ so với mọi tâm.",[989,52133,52134],{},"Số tán sinh ra gợi ý số cụm k khỏi đoán mò.",[989,52136,52137],{},"Lấy tâm tán làm centroid khởi đầu hội tụ nhanh hơn ngẫu nhiên.",[989,52139,52140],{},"Tán lỏng quá thì khổng lồ vô dụng, chặt quá thì vụn như không phủ.",[981,52142,52144],{"id":52143},"giá-của-nhiều-job","Giá của nhiều job",[986,52146,52147,52150,52153,52156],{},[989,52148,52149],{},"Mỗi vòng đọc dữ liệu và tâm cũ từ đĩa rồi ghi tâm mới ra.",[989,52151,52152],{},"Lặp chục vòng thì đọc ghi thành gánh nặng chính.",[989,52154,52155],{},"MapReduce mở rộng tốt nhưng không cứu được độ trễ lặp.",[989,52157,52158],{},"Spark lấp chỗ này bằng giữ dữ liệu trong nhớ qua các vòng.",[968,52160,1433],{"id":1432},[986,52162,52163,52166,52169,52172],{},[989,52164,52165],{},"Input: 1 vòng K-means tay với 8 điểm và 2 tâm. Output: tâm mới bằng trung bình từng nhóm.",[989,52167,52168],{},"Giải thích: reduce chỉ tính trung bình nhóm map đã gán.",[989,52170,52171],{},"Input: canopy với T1 bằng T2. Output: các tán rời nhau không giao.",[989,52173,52174],{},"Giải thích: không có vành giữa nên không có điểm thuộc 2 tán.",[968,52176,1482],{"id":1481},[973,52178,1485,52179,52181,52182,52184,52185,1517],{},[1487,52180,13531],{}," với NumPy và ",[992,52183,35455],{},". Dùng khung MapReduce ngày 50. Nộp vào ",[992,52186,52187],{},"day-087\u002F",[981,52189,52191],{"id":52190},"bài-1-k-means-dạng-mapreduce","Bài 1: K-means dạng MapReduce",[1099,52193,52194,52206],{},[1102,52195,52196],{},[1105,52197,52198,52200,52203],{},[1108,52199,1566],{},[1108,52201,52202],{},"Vào",[1108,52204,52205],{},"Ra",[1118,52207,52208,52225,52241],{},[1105,52209,52210,52215,52218],{},[1123,52211,52212],{},[992,52213,52214],{},"mapper(chunk, centroids)",[1123,52216,52217],{},"1 mảnh điểm",[1123,52219,52220,52221,52224],{},"Với mỗi cụm: ",[992,52222,52223],{},"(cluster_id, (tổng_vector, số_điểm))"," (đã gộp cục bộ như combiner)",[1105,52226,52227,52232,52238],{},[1123,52228,52229],{},[992,52230,52231],{},"reducer(cluster_id, values)",[1123,52233,52234,52235],{},"Danh sách ",[992,52236,52237],{},"(tổng, đếm)",[1123,52239,52240],{},"Tâm mới = tổng \u002F đếm",[1105,52242,52243,52248,52250],{},[1123,52244,52245],{},[992,52246,52247],{},"kmeans_mr(X, k, n_workers, max_iter)",[1123,52249],{},[1123,52251,52252],{},[992,52253,52254],{},"(centroids, số_vòng)",[1352,52256,52259],{"className":52257,"code":52258,"language":2241,"meta":1357},[2239],"Cùng dữ liệu và cùng tâm khởi đầu -> kmeans_mr cho kết quả giống kmeans ngày 47\n",[992,52260,52258],{"__ignoreMap":1357},[973,52262,14627,52263,52346,52347,1517],{},[1023,52264,52266,52287],{"className":52265},[1026],[1023,52267,52269],{"className":52268},[1030],[1032,52270,52271],{"xmlns":1034},[1036,52272,52273,52285],{},[1039,52274,52275,52277,52279],{},[1042,52276,1262],{},[1046,52278,2325],{},[2327,52280,52281,52283],{},[1051,52282,2331],{},[1051,52284,6866],{},[1058,52286,11405],{"encoding":1060},[1023,52288,52290,52308],{"className":52289,"ariaHidden":1066},[1065],[1023,52291,52293,52296,52299,52302,52305],{"className":52292},[1070],[1023,52294],{"className":52295,"style":2347},[1074],[1023,52297,1262],{"className":52298},[1079,1080],[1023,52300],{"className":52301,"style":2355},[2354],[1023,52303,2325],{"className":52304},[2359],[1023,52306],{"className":52307,"style":2355},[2354],[1023,52309,52311,52314,52317],{"className":52310},[1070],[1023,52312],{"className":52313,"style":2369},[1074],[1023,52315,1053],{"className":52316},[1079],[1023,52318,52320,52323],{"className":52319},[1079],[1023,52321,2379],{"className":52322},[1079],[1023,52324,52326],{"className":52325},[2383],[1023,52327,52329],{"className":52328},[2387],[1023,52330,52332],{"className":52331},[2391],[1023,52333,52335],{"className":52334,"style":2369},[2395],[1023,52336,52337,52340],{"style":2398},[1023,52338],{"className":52339,"style":2403},[2402],[1023,52341,52343],{"className":52342},[2407,2408,2409,2410],[1023,52344,6866],{"className":52345},[1079,2410]," điểm 10 chiều, ",[992,52348,35632],{},[981,52350,52352],{"id":52351},"bài-2-canopy-clustering","Bài 2: Canopy clustering",[1352,52354,52356],{"className":3538,"code":52355,"language":3540,"meta":1357,"style":1357},"def canopy(X, T1: float, T2: float, seed=0) -> list[tuple[np.ndarray, list[int]]]:\n    \"\"\"T1 > T2. Chọn ngẫu nhiên 1 điểm còn trong danh sách làm tâm.\n       Điểm cách tâm \u003C T1 vào tán. Điểm cách tâm \u003C T2 bị xóa khỏi danh sách chờ.\"\"\"\n",[992,52357,52358,52363,52368],{"__ignoreMap":1357},[1023,52359,52360],{"class":1362,"line":63},[1023,52361,52362],{},"def canopy(X, T1: float, T2: float, seed=0) -> list[tuple[np.ndarray, list[int]]]:\n",[1023,52364,52365],{"class":1362,"line":68},[1023,52366,52367],{},"    \"\"\"T1 > T2. Chọn ngẫu nhiên 1 điểm còn trong danh sách làm tâm.\n",[1023,52369,52370],{"class":1362,"line":73},[1023,52371,52372],{},"       Điểm cách tâm \u003C T1 vào tán. Điểm cách tâm \u003C T2 bị xóa khỏi danh sách chờ.\"\"\"\n",[2273,52374,52375,52378,52385],{},[989,52376,52377],{},"Dùng khoảng cách rẻ (Manhattan) cho canopy.",[989,52379,52380,52381,52384],{},"In số tán với 3 cặp ",[992,52382,52383],{},"(T1, T2)",". Chọn cặp cho số tán gần số cụm thật.",[989,52386,52387],{},"Dùng tâm tán làm tâm khởi đầu K-means. So số vòng lặp và inertia với khởi tạo ngẫu nhiên và k-means++.",[981,52389,52391],{"id":52390},"bài-3-chi-phí-đọc-ghi-mỗi-vòng-nâng-cao","Bài 3: Chi phí đọc ghi mỗi vòng (nâng cao)",[2273,52393,52394,52401,52411],{},[989,52395,52396,52397,52400],{},"Mô phỏng Hadoop: mỗi vòng đọc dữ liệu từ file ",[992,52398,52399],{},".npy"," trên đĩa và ghi tâm ra file. Đo thời gian đọc ghi so với thời gian tính.",[989,52402,52403,52404,7386,52407,52410],{},"Bản \"Spark\": giữ dữ liệu trong bộ nhớ của worker giữa các vòng (dùng ",[992,52405,52406],{},"Pool",[992,52408,52409],{},"initializer"," nạp dữ liệu 1 lần).",[989,52412,52413],{},"Vẽ biểu đồ thời gian theo số vòng cho 2 bản.",[981,52415,2711],{"id":2710},[986,52417,52419,52428,52434,52440],{"className":52418},[2715],[989,52420,52422,2308,52424,52427],{"className":52421},[2719],[2721,52423],{"disabled":2723,"type":2724},[992,52425,52426],{},"kmeans_mr"," khớp K-means tuần tự.",[989,52429,52431,52433],{"className":52430},[2719],[2721,52432],{"disabled":2723,"type":2724}," Bảng canopy + K-means so với 2 cách khởi tạo khác có số thật.",[989,52435,52437,52439],{"className":52436},[2719],[2721,52438],{"disabled":2723,"type":2724}," Biểu đồ Bài 3 cho thấy chi phí đọc ghi mỗi vòng.",[989,52441,52443,52445],{"className":52442},[2719],[2721,52444],{"disabled":2723,"type":2724}," Giải thích được vì sao combiner trong mapper giảm dữ liệu shuffle.",[968,52447,2890],{"id":2889},[986,52449,52450,52453,52456,52459],{},[989,52451,52452],{},"1 vòng K-means MapReduce gồm những bước nào?",[989,52454,52455],{},"Canopy dùng 2 ngưỡng T1 T2 thế nào?",[989,52457,52458],{},"Vì sao canopy giúp khởi tạo tốt hơn ngẫu nhiên?",[989,52460,52461],{},"Ranh giới lớn nhất của MapReduce lặp là gì?",[3014,52463],{},[973,52465,52466],{},"🌕 Bạn đã hoàn thành ngày 87. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,52468,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":52470},[52471,52472,52478,52479,52485],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":52473},[52474,52475,52476,52477],{"id":52089,"depth":73,"text":52090},{"id":52107,"depth":73,"text":52108},{"id":52125,"depth":73,"text":52126},{"id":52143,"depth":73,"text":52144},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":52480},[52481,52482,52483,52484],{"id":52190,"depth":73,"text":52191},{"id":52351,"depth":73,"text":52352},{"id":52390,"depth":73,"text":52391},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Song song hóa K-means bằng MapReduce, gom cụm canopy tiền xử lý, khởi tạo centroid thông minh và toàn cảnh MapReduce canopy.",{},[14055],{"title":490,"description":52486},[35747,34177,52491,34178],"canopy","7h3YGRPINXpgkMhXA9WhgAB2q35tYn48PjP3MAXrGUo",{"id":52494,"title":495,"body":52495,"category":8797,"day":498,"description":52865,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":52866,"navigation":2723,"outcomes":3047,"path":496,"prerequisites":52867,"seo":52868,"stem":497,"tags":52869,"__hash__":52870},"challenges\u002Fchallenges\u002F88.mapreduce-dbscan.md",{"type":965,"value":52496,"toc":52848},[52497,52499,52502,52504,52508,52522,52526,52540,52544,52558,52562,52576,52578,52592,52594,52604,52608,52628,52634,52638,52659,52665,52669,52796,52798,52825,52827,52841,52843,52846],[968,52498,971],{"id":970},[973,52500,52501],{},"Bài này học chạy DBSCAN song song bằng chia vùng. Bạn dùng nó cho cụm hình lạ ở dữ liệu lớn.",[968,52503,979],{"id":978},[981,52505,52507],{"id":52506},"vì-sao-dbscan-khó-song-song","Vì sao DBSCAN khó song song",[986,52509,52510,52513,52516,52519],{},[989,52511,52512],{},"K-means mỗi điểm quyết định độc lập nên chia mảnh tùy ý.",[989,52514,52515],{},"DBSCAN quyết định theo hàng xóm, hàng xóm có thể sang máy khác.",[989,52517,52518],{},"Chuỗi lan truyền dài có thể bò qua nhiều vùng.",[989,52520,52521],{},"Cắt ẩu là đứt cụm nên cần pha gộp biên riêng.",[981,52523,52525],{"id":52524},"chia-vùng-và-chạy-địa-phương","Chia vùng và chạy địa phương",[986,52527,52528,52531,52534,52537],{},[989,52529,52530],{},"Chia không gian thành vùng có vành đệm rộng ít nhất epsilon.",[989,52532,52533],{},"Mỗi máy chạy DBSCAN trên vùng cộng vành của mình.",[989,52535,52536],{},"Điểm sâu trong vùng chốt ngay, điểm vành chờ gộp.",[989,52538,52539],{},"Vành hẹp hơn epsilon thì sót cầu, rộng quá thì tính trùng nhiều.",[981,52541,52543],{"id":52542},"gộp-biên-và-chốt-nhiễu","Gộp biên và chốt nhiễu",[986,52545,52546,52549,52552,52555],{},[989,52547,52548],{},"Thu cụm chạm vành, xây đồ thị nối qua điểm chung rồi gộp.",[989,52550,52551],{},"Điểm nhiễu địa phương mà kề lõi vùng bên thì cứu thành biên.",[989,52553,52554],{},"Chỉ điểm không ai nhận mới là nhiễu thật.",[989,52556,52557],{},"Gộp cụm trước rồi mới chốt nhiễu sau.",[981,52559,52561],{"id":52560},"khởi-tạo-và-khi-nào-đáng-giá","Khởi tạo và khi nào đáng giá",[986,52563,52564,52567,52570,52573],{},[989,52565,52566],{},"Ngẫu nhiên đơn giản nhưng dễ rơi cực tiểu xấu.",[989,52568,52569],{},"Tâm canopy rải đều theo mật độ nên tốt nhất cho dữ liệu lớn.",[989,52571,52572],{},"DBSCAN không có tâm nhưng canopy giúp chọn epsilon theo vùng.",[989,52574,52575],{},"Dữ liệu vừa 1 máy thì chạy đơn cho xong, vượt nhớ mới MapReduce.",[968,52577,1433],{"id":1432},[986,52579,52580,52583,52586,52589],{},[989,52581,52582],{},"Input: cụm nằm gọn 1 vùng không chạm biên. Output: trùng chạy đơn máy, khỏi gộp.",[989,52584,52585],{},"Giải thích: không chạm vành thì không có gì để nối sang vùng khác.",[989,52587,52588],{},"Input: chuỗi lan truyền vắt qua biên, vành đủ epsilon. Output: nối thành 1 cụm duy nhất.",[989,52590,52591],{},"Giải thích: vành đủ rộng giữ được cầu lan truyền qua biên.",[968,52593,1482],{"id":1481},[973,52595,1485,52596,52181,52598,52600,52601,1517],{},[1487,52597,13531],{},[992,52599,35455],{},". Dùng DBSCAN ngày 48. Nộp vào ",[992,52602,52603],{},"day-088\u002F",[981,52605,52607],{"id":52606},"bài-1-chia-vùng-có-vành-đệm","Bài 1: Chia vùng có vành đệm",[1352,52609,52611],{"className":3538,"code":52610,"language":3540,"meta":1357,"style":1357},"def partition(X, n_x: int, n_y: int, eps: float) -> list[dict]:\n    \"\"\"Chia hộp bao dữ liệu thành lưới n_x * n_y vùng.\n       Mỗi vùng trả {\"core_box\": (x1,y1,x2,y2), \"indices\": chỉ số điểm trong core_box nới thêm eps mỗi phía}.\"\"\"\n",[992,52612,52613,52618,52623],{"__ignoreMap":1357},[1023,52614,52615],{"class":1362,"line":63},[1023,52616,52617],{},"def partition(X, n_x: int, n_y: int, eps: float) -> list[dict]:\n",[1023,52619,52620],{"class":1362,"line":68},[1023,52621,52622],{},"    \"\"\"Chia hộp bao dữ liệu thành lưới n_x * n_y vùng.\n",[1023,52624,52625],{"class":1362,"line":73},[1023,52626,52627],{},"       Mỗi vùng trả {\"core_box\": (x1,y1,x2,y2), \"indices\": chỉ số điểm trong core_box nới thêm eps mỗi phía}.\"\"\"\n",[1352,52629,52632],{"className":52630,"code":52631,"language":2241,"meta":1357},[2239],"Mọi điểm thuộc đúng 1 core_box\nĐiểm cách biên core_box dưới eps xuất hiện ở nhiều vùng (vành)\n",[992,52633,52631],{"__ignoreMap":1357},[981,52635,52637],{"id":52636},"bài-2-dbscan-song-song-và-gộp-biên","Bài 2: DBSCAN song song và gộp biên",[2273,52639,52640,52643,52653,52656],{},[989,52641,52642],{},"Chạy DBSCAN địa phương trên từng vùng song song.",[989,52644,52645,52648,52649,52652],{},[1487,52646,52647],{},"Gộp:"," 2 cụm địa phương có chung ít nhất 1 ",[1487,52650,52651],{},"điểm lõi"," thì là cùng cụm toàn cục. Dùng Union-Find (ngày 33) để gộp.",[989,52654,52655],{},"Điểm là nhiễu ở vùng này nhưng là biên ở vùng khác thì thành biên.",[989,52657,52658],{},"Kết quả cuối phải khớp DBSCAN tuần tự trên toàn bộ dữ liệu (so sánh sau khi đổi tên cụm, chấp nhận khác ở điểm biên nằm giữa 2 cụm).",[1352,52660,52663],{"className":52661,"code":52662,"language":2241,"meta":1357},[2239],"1 cụm dài vắt ngang 4 vùng -> sau gộp còn đúng 1 cụm\n",[992,52664,52662],{"__ignoreMap":1357},[981,52666,52668],{"id":52667},"bài-3-thí-nghiệm-độ-rộng-vành-nâng-cao","Bài 3: Thí nghiệm độ rộng vành (nâng cao)",[2273,52670,52671,52684,52687],{},[989,52672,52673,52674,1656,52677,1656,52680,52683],{},"Chạy với vành rộng ",[992,52675,52676],{},"0.5 * eps",[992,52678,52679],{},"1 * eps",[992,52681,52682],{},"2 * eps",". Với vành hẹp, chỉ ra cụm bị xé đôi.",[989,52685,52686],{},"Đo tổng số điểm được xử lý (cả trùng lặp) và thời gian theo độ rộng vành.",[989,52688,52689,52795],{},[1023,52690,52692,52718],{"className":52691},[1026],[1023,52693,52695],{"className":52694},[1030],[1032,52696,52697],{"xmlns":1034},[1036,52698,52699,52715],{},[1039,52700,52701,52703,52705,52707,52709],{},[1042,52702,1262],{},[1046,52704,2325],{},[1051,52706,2457],{},[1046,52708,18118],{},[2327,52710,52711,52713],{},[1051,52712,2331],{},[1051,52714,2334],{},[1058,52716,52717],{"encoding":1060},"n = 2 \\cdot 10^5",[1023,52719,52721,52739,52757],{"className":52720,"ariaHidden":1066},[1065],[1023,52722,52724,52727,52730,52733,52736],{"className":52723},[1070],[1023,52725],{"className":52726,"style":2347},[1074],[1023,52728,1262],{"className":52729},[1079,1080],[1023,52731],{"className":52732,"style":2355},[2354],[1023,52734,2325],{"className":52735},[2359],[1023,52737],{"className":52738,"style":2355},[2354],[1023,52740,52742,52745,52748,52751,52754],{"className":52741},[1070],[1023,52743],{"className":52744,"style":10020},[1074],[1023,52746,2457],{"className":52747},[1079],[1023,52749],{"className":52750,"style":13790},[2354],[1023,52752,18118],{"className":52753},[13794],[1023,52755],{"className":52756,"style":13790},[2354],[1023,52758,52760,52763,52766],{"className":52759},[1070],[1023,52761],{"className":52762,"style":2369},[1074],[1023,52764,1053],{"className":52765},[1079],[1023,52767,52769,52772],{"className":52768},[1079],[1023,52770,2379],{"className":52771},[1079],[1023,52773,52775],{"className":52774},[2383],[1023,52776,52778],{"className":52777},[2387],[1023,52779,52781],{"className":52780},[2391],[1023,52782,52784],{"className":52783,"style":2369},[2395],[1023,52785,52786,52789],{"style":2398},[1023,52787],{"className":52788,"style":2403},[2402],[1023,52790,52792],{"className":52791},[2407,2408,2409,2410],[1023,52793,2334],{"className":52794},[1079,2410]," điểm. So thời gian song song với 1, 4, 16 vùng và DBSCAN tuần tự có lưới (ngày 48).",[981,52797,2711],{"id":2710},[986,52799,52801,52807,52813,52819],{"className":52800},[2715],[989,52802,52804,52806],{"className":52803},[2719],[2721,52805],{"disabled":2723,"type":2724}," Test phân vùng pass.",[989,52808,52810,52812],{"className":52809},[2719],[2721,52811],{"disabled":2723,"type":2724}," Kết quả gộp khớp DBSCAN tuần tự.",[989,52814,52816,52818],{"className":52815},[2719],[2721,52817],{"disabled":2723,"type":2724}," Có ví dụ vành hẹp làm xé cụm.",[989,52820,52822,52824],{"className":52821},[2719],[2721,52823],{"disabled":2723,"type":2724}," Bảng thời gian và số điểm trùng lặp theo độ rộng vành.",[968,52826,2890],{"id":2889},[986,52828,52829,52832,52835,52838],{},[989,52830,52831],{},"Vì sao DBSCAN khó song song hơn K-means?",[989,52833,52834],{},"Vành đệm rộng bao nhiêu là đủ?",[989,52836,52837],{},"Điểm nhiễu địa phương được cứu thế nào?",[989,52839,52840],{},"Khi nào MapReduce DBSCAN đáng giá?",[3014,52842],{},[973,52844,52845],{},"🌕 Bạn đã hoàn thành ngày 88. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,52847,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":52849},[52850,52851,52857,52858,52864],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":52852},[52853,52854,52855,52856],{"id":52506,"depth":73,"text":52507},{"id":52524,"depth":73,"text":52525},{"id":52542,"depth":73,"text":52543},{"id":52560,"depth":73,"text":52561},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":52859},[52860,52861,52862,52863],{"id":52606,"depth":73,"text":52607},{"id":52636,"depth":73,"text":52637},{"id":52667,"depth":73,"text":52668},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Song song hóa DBSCAN dựa mật độ bằng MapReduce: chia vùng, gộp biên, xử lý nhiễu, và tổng kết khởi tạo centroid cho cả họ gom cụm.",{},[14055],{"title":495,"description":52865},[35747,34739,34177],"DFxT1GKXROizn21T7vBHk5Qdpm1nZt8-HKuT4pOm9yE",{"id":52872,"title":500,"body":52873,"category":8797,"day":503,"description":53223,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":53224,"navigation":2723,"outcomes":3047,"path":501,"prerequisites":53225,"seo":53226,"stem":502,"tags":53227,"__hash__":53230},"challenges\u002Fchallenges\u002F89.rung-va-boosting.md",{"type":965,"value":52874,"toc":53206},[52875,52877,52880,52882,52886,52900,52904,52918,52922,52936,52940,52954,53002,53004,53018,53020,53037,53041,53071,53080,53086,53090,53115,53122,53133,53137,53143,53154,53156,53183,53185,53199,53201,53204],[968,52876,971],{"id":970},[973,52878,52879],{},"Bài này học gộp nhiều cây yếu thành mô hình mạnh. Bạn dùng nó để thắng cây đơn với ít công chỉnh.",[968,52881,979],{"id":978},[981,52883,52885],{"id":52884},"hai-triết-lý-tập-hợp","Hai triết lý tập hợp",[986,52887,52888,52891,52894,52897],{},[989,52889,52890],{},"Bagging: huấn luyện song song nhiều cây rồi bỏ phiếu.",[989,52892,52893],{},"Boosting: huấn luyện nối tiếp, cây sau sửa sai cây trước.",[989,52895,52896],{},"Bagging giảm phương sai nhờ trung bình, boosting giảm chệch dần.",[989,52898,52899],{},"Ví dụ đời thường: bagging như hỏi nhiều bác sĩ rồi lấy ý kiến chung.",[981,52901,52903],{"id":52902},"rừng-ngẫu-nhiên","Rừng ngẫu nhiên",[986,52905,52906,52909,52912,52915],{},[989,52907,52908],{},"Mỗi cây học trên mẫu bootstrap có hoàn lại.",[989,52910,52911],{},"Mỗi điểm cắt chỉ thử 1 tập con ngẫu nhiên đặc trưng.",[989,52913,52914],{},"Phân loại bỏ phiếu đa số, hồi quy lấy trung bình.",[989,52916,52917],{},"Ít siêu tham số, chạy song song tốt, khó hỏng.",[981,52919,52921],{"id":52920},"boosting-gradient-gbm","Boosting gradient GBM",[986,52923,52924,52927,52930,52933],{},[989,52925,52926],{},"Mỗi cây mới học phần dư mà dãy hiện tại còn sai.",[989,52928,52929],{},"Tốc độ học nhỏ để đi chậm mà chắc, cây nông để yếu vừa đủ.",[989,52931,52932],{},"Dừng sớm khi điểm kiểm định ngừng cải thiện.",[989,52934,52935],{},"Nối tiếp nên không song song được và nhiều núm chỉnh hơn.",[981,52937,52939],{"id":52938},"xgboost-và-so-sánh","XGBoost và so sánh",[986,52941,52942,52945,52948,52951],{},[989,52943,52944],{},"Là GBM kỹ nghệ hóa: phạt cây phức tạp, bước đi chính xác hơn.",[989,52946,52947],{},"Xử lý giá trị thiếu tốt, tìm điểm cắt song song, nén dữ liệu.",[989,52949,52950],{},"Rừng lì với nhiễu nhãn hơn, boosting dễ học thuộc nhiễu.",[989,52952,52953],{},"Quy tắc: nhiễu cần ổn định thì rừng trước, sạch cần vắt điểm thì boosting.",[1099,52955,52956,52969],{},[1102,52957,52958],{},[1105,52959,52960,52963,52966],{},[1108,52961,52962],{},"Trục",[1108,52964,52965],{},"Rừng",[1108,52967,52968],{},"Boosting",[1118,52970,52971,52982,52992],{},[1105,52972,52973,52976,52979],{},[1123,52974,52975],{},"Giảm",[1123,52977,52978],{},"Phương sai",[1123,52980,52981],{},"Độ chệch",[1105,52983,52984,52986,52989],{},[1123,52985,34287],{},[1123,52987,52988],{},"Lì đòn",[1123,52990,52991],{},"Dễ thuộc",[1105,52993,52994,52996,52999],{},[1123,52995,12359],{},[1123,52997,52998],{},"Song song",[1123,53000,53001],{},"Nối tiếp",[968,53003,1433],{"id":1432},[986,53005,53006,53009,53012,53015],{},[989,53007,53008],{},"Input: rừng 1 cây với đủ đặc trưng. Output: tương đương cây đơn.",[989,53010,53011],{},"Giải thích: mất cả 2 nguồn ngẫu nhiên thì chỉ còn 1 cây thường.",[989,53013,53014],{},"Input: boosting với tốc độ học bằng 0. Output: đứng yên không học gì.",[989,53016,53017],{},"Giải thích: mỗi bước cộng 0 nên dãy không đổi.",[968,53019,1482],{"id":1481},[973,53021,1485,53022,53024,53025,53028,53029,5586,53032,5599,53034,1517],{},[1487,53023,13531],{}," với NumPy. Dùng ",[992,53026,53027],{},"DecisionTree"," ngày 53. Bài 3 dùng ",[992,53030,53031],{},"xgboost",[992,53033,17633],{},[992,53035,53036],{},"day-089\u002F",[981,53038,53040],{"id":53039},"bài-1-random-forest-tự-cài","Bài 1: Random forest tự cài",[1352,53042,53044],{"className":3538,"code":53043,"language":3540,"meta":1357,"style":1357},"class RandomForest:\n    def __init__(self, n_trees=100, max_depth=None, max_features=\"sqrt\", seed=0, n_jobs=1): ...\n    def fit(self, X, y): ...           # mỗi cây: bootstrap + chỉ thử max_features cột ở mỗi lần cắt\n    def predict(self, X): ...          # bỏ phiếu đa số\n    def oob_score(self) -> float: ...  # accuracy trên các mẫu không được bốc vào cây đó\n",[992,53045,53046,53051,53056,53061,53066],{"__ignoreMap":1357},[1023,53047,53048],{"class":1362,"line":63},[1023,53049,53050],{},"class RandomForest:\n",[1023,53052,53053],{"class":1362,"line":68},[1023,53054,53055],{},"    def __init__(self, n_trees=100, max_depth=None, max_features=\"sqrt\", seed=0, n_jobs=1): ...\n",[1023,53057,53058],{"class":1362,"line":73},[1023,53059,53060],{},"    def fit(self, X, y): ...           # mỗi cây: bootstrap + chỉ thử max_features cột ở mỗi lần cắt\n",[1023,53062,53063],{"class":1362,"line":78},[1023,53064,53065],{},"    def predict(self, X): ...          # bỏ phiếu đa số\n",[1023,53067,53068],{"class":1362,"line":83},[1023,53069,53070],{},"    def oob_score(self) -> float: ...  # accuracy trên các mẫu không được bốc vào cây đó\n",[973,53072,53073,53074,53076,53077,1517],{},"Sửa ",[992,53075,53027],{}," ngày 53 để nhận tham số ",[992,53078,53079],{},"max_features",[1352,53081,53084],{"className":53082,"code":53083,"language":2241,"meta":1357},[2239],"Breast Cancer, 70\u002F30: RandomForest(100) accuracy test > DecisionTree đơn\noob_score xấp xỉ accuracy test (chênh dưới 3%)\n",[992,53085,53083],{"__ignoreMap":1357},[981,53087,53089],{"id":53088},"bài-2-gradient-boosting-cho-hồi-quy","Bài 2: Gradient boosting cho hồi quy",[1352,53091,53093],{"className":3538,"code":53092,"language":3540,"meta":1357,"style":1357},"class GradientBoostingRegressor:\n    def __init__(self, n_estimators=200, learning_rate=0.1, max_depth=3): ...\n    def fit(self, X, y, X_val=None, y_val=None, early_stopping=10): ...\n    # f0 = mean(y); mỗi vòng: r = y - f; khớp cây hồi quy vào r; f += lr * cây(X)\n",[992,53094,53095,53100,53105,53110],{"__ignoreMap":1357},[1023,53096,53097],{"class":1362,"line":63},[1023,53098,53099],{},"class GradientBoostingRegressor:\n",[1023,53101,53102],{"class":1362,"line":68},[1023,53103,53104],{},"    def __init__(self, n_estimators=200, learning_rate=0.1, max_depth=3): ...\n",[1023,53106,53107],{"class":1362,"line":73},[1023,53108,53109],{},"    def fit(self, X, y, X_val=None, y_val=None, early_stopping=10): ...\n",[1023,53111,53112],{"class":1362,"line":78},[1023,53113,53114],{},"    # f0 = mean(y); mỗi vòng: r = y - f; khớp cây hồi quy vào r; f += lr * cây(X)\n",[973,53116,53117,53118,53121],{},"Cần cây ",[1487,53119,53120],{},"hồi quy"," (lá là trung bình, cắt theo giảm MSE). Viết thêm nếu ngày 53 chỉ có phân loại.",[2273,53123,53124,53127],{},[989,53125,53126],{},"Chạy trên California Housing. Vẽ MSE train và validation theo số cây.",[989,53128,37875,53129,53132],{},[992,53130,53131],{},"learning_rate = 1.0, 0.3, 0.1, 0.03",". So số cây tới dừng sớm và MSE test.",[981,53134,53136],{"id":53135},"bài-3-so-sánh-với-thư-viện-nâng-cao","Bài 3: So sánh với thư viện (nâng cao)",[1352,53138,53141],{"className":53139,"code":53140,"language":2241,"meta":1357},[2239],"mô_hình                         accuracy\u002FMSE   thời_gian_train\nDecisionTree (tự cài)           ...\nRandomForest (tự cài)           ...\nGBM (tự cài)                    ...\nsklearn RandomForest            ...\nXGBoost \u002F HistGradientBoosting  ...\n",[992,53142,53140],{"__ignoreMap":1357},[2273,53144,53145,53148],{},[989,53146,53147],{},"Thêm 20% nhãn nhiễu vào Breast Cancer. So độ giảm accuracy của rừng và boosting.",[989,53149,53150,53151,53153],{},"Thêm 10% giá trị thiếu. Chạy XGBoost trực tiếp (xử lý được ",[992,53152,36348],{},") và so với điền trung vị.",[981,53155,2711],{"id":2710},[986,53157,53159,53165,53171,53177],{"className":53158},[2715],[989,53160,53162,53164],{"className":53161},[2719],[2721,53163],{"disabled":2723,"type":2724}," Rừng tự cài thắng cây đơn trên test.",[989,53166,53168,53170],{"className":53167},[2719],[2721,53169],{"disabled":2723,"type":2724}," Có hình MSE theo số cây và bảng learning rate.",[989,53172,53174,53176],{"className":53173},[2719],[2721,53175],{"disabled":2723,"type":2724}," Bảng so sánh 5 mô hình có số thật.",[989,53178,53180,53182],{"className":53179},[2719],[2721,53181],{"disabled":2723,"type":2724}," Giải thích được bagging giảm phương sai, boosting giảm chệch.",[968,53184,2890],{"id":2889},[986,53186,53187,53190,53193,53196],{},[989,53188,53189],{},"Bagging và boosting khác nhau thế nào?",[989,53191,53192],{},"Hai nguồn ngẫu nhiên của rừng là gì?",[989,53194,53195],{},"Mỗi cây GBM học cái gì?",[989,53197,53198],{},"Khi nào chọn rừng thay vì boosting?",[3014,53200],{},[973,53202,53203],{},"🌕 Bạn đã hoàn thành ngày 89. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,53205,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":53207},[53208,53209,53215,53216,53222],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":53210},[53211,53212,53213,53214],{"id":52884,"depth":73,"text":52885},{"id":52902,"depth":73,"text":52903},{"id":52920,"depth":73,"text":52921},{"id":52938,"depth":73,"text":52939},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":53217},[53218,53219,53220,53221],{"id":53039,"depth":73,"text":53040},{"id":53088,"depth":73,"text":53089},{"id":53135,"depth":73,"text":53136},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Học tập hợp từ cây đơn: rừng ngẫu nhiên bagging, boosting gradient, XGBoost và so sánh rừng với boosting trên thử thách classifiers.",{},[18469],{"title":500,"description":53223},[18472,53228,53229,53031],"random-forest","boosting","IoxOED7qtCOpFjHw6vyHbr85Efn9T9Sl8Q7uYVSie34",{"id":53232,"title":505,"body":53233,"category":8797,"day":508,"description":54262,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":54263,"navigation":2723,"outcomes":3047,"path":506,"prerequisites":54264,"seo":54265,"stem":507,"tags":54266,"__hash__":54269},"challenges\u002Fchallenges\u002F90.svm.md",{"type":965,"value":53234,"toc":54245},[53235,53237,53240,53242,53246,53260,53264,53278,53282,53296,53333,53337,53351,53353,53367,53369,53380,53384,53418,53907,53913,53916,53920,53926,53932,53938,53942,54193,54195,54222,54224,54238,54240,54243],[968,53236,971],{"id":970},[973,53238,53239],{},"Bài này học SVM tìm biên lề rộng nhất. Bạn dùng nó cho dữ liệu phi tuyến như vòng tròn lồng nhau.",[968,53241,979],{"id":978},[981,53243,53245],{"id":53244},"lề-và-vector-hỗ-trợ","Lề và vector hỗ trợ",[986,53247,53248,53251,53254,53257],{},[989,53249,53250],{},"Lề là khoảng cách từ biên tới điểm gần nhất mỗi lớp.",[989,53252,53253],{},"SVM cực đại hóa lề vì lề rộng khó bị nhiễu đẩy qua.",[989,53255,53256],{},"Điểm nằm đúng biên lề gọi là vector hỗ trợ.",[989,53258,53259],{},"Xóa điểm thường biên không đổi, xóa hỗ trợ biên xoay ngay.",[981,53261,53263],{"id":53262},"lề-mềm-và-c","Lề mềm và C",[986,53265,53266,53269,53272,53275],{},[989,53267,53268],{},"Dữ liệu thật hiếm khi tách sạch nên cho phép vài điểm vi phạm.",[989,53270,53271],{},"C lớn phạt nặng nên lề hẹp mà ít sai huấn luyện.",[989,53273,53274],{},"C nhỏ chấp nhận sai để lề rộng tổng quát tốt.",[989,53276,53277],{},"C là núm chỉnh chính, phải dò bằng kiểm định chéo.",[981,53279,53281],{"id":53280},"ánh-xạ-và-kernel","Ánh xạ và kernel",[986,53283,53284,53287,53290,53293],{},[989,53285,53286],{},"Vòng tròn lồng nhau không đường thẳng nào tách được.",[989,53288,53289],{},"Thêm chiều bình phương bán kính thì tách phẳng đẹp.",[989,53291,53292],{},"Kernel tính tích vô hướng ở không gian mới mà không dựng nó.",[989,53294,53295],{},"Tuyến tính cho dữ liệu thẳng, đa thức cho cong vừa, RBF cho cong tùy ý.",[1099,53297,53298,53307],{},[1102,53299,53300],{},[1105,53301,53302,53305],{},[1108,53303,53304],{},"Kernel",[1108,53306,10673],{},[1118,53308,53309,53317,53325],{},[1105,53310,53311,53314],{},[1123,53312,53313],{},"Tuyến tính",[1123,53315,53316],{},"Dữ liệu đã tách thẳng",[1105,53318,53319,53322],{},[1123,53320,53321],{},"Đa thức",[1123,53323,53324],{},"Biên cong vừa",[1105,53326,53327,53330],{},[1123,53328,53329],{},"RBF",[1123,53331,53332],{},"Vòng tròn lồng nhau",[981,53334,53336],{"id":53335},"gamma-và-khi-nào-thắng","Gamma và khi nào thắng",[986,53338,53339,53342,53345,53348],{},[989,53340,53341],{},"Gamma lớn biên uốn sát dữ liệu dễ thuộc lòng.",[989,53343,53344],{},"Gamma nhỏ biên mượt có thể học thiếu.",[989,53346,53347],{},"Phải dò lưới C và gamma vì chúng tương tác nhau.",[989,53349,53350],{},"SVM thắng ở chiều cao mẫu vừa, thua ở dữ liệu khổng lồ vì huấn luyện nặng.",[968,53352,1433],{"id":1432},[986,53354,53355,53358,53361,53364],{},[989,53356,53357],{},"Input: 6 điểm tách được, vẽ biên lề cực đại. Output: vài điểm biên là hỗ trợ.",[989,53359,53360],{},"Giải thích: chỉ điểm sát biên mới quyết định vị trí biên.",[989,53362,53363],{},"Input: RBF với gamma tiến về 0. Output: biên gần phẳng như tuyến tính.",[989,53365,53366],{},"Giải thích: mỗi điểm ảnh hưởng rộng nên biên mượt ra.",[968,53368,1482],{"id":1481},[973,53370,1485,53371,53373,53374,5599,53377,1517],{},[1487,53372,13531],{}," với NumPy. Bài 3 dùng ",[992,53375,53376],{},"sklearn.svm",[992,53378,53379],{},"day-090\u002F",[981,53381,53383],{"id":53382},"bài-1-linear-svm-bằng-subgradient","Bài 1: Linear SVM bằng subgradient",[1352,53385,53387],{"className":3538,"code":53386,"language":3540,"meta":1357,"style":1357},"class LinearSVM:\n    def __init__(self, C: float = 1.0, lr: float = 1e-3, epochs: int = 1000, seed: int = 0): ...\n    def fit(self, X, y): ...           # y trong {-1, +1}\n    def decision_function(self, X): ...\n    def predict(self, X): ...\n    def support_vectors(self, X, y, tol=1e-3): ...   # điểm có y * f(x) \u003C= 1 + tol\n",[992,53388,53389,53394,53399,53404,53409,53413],{"__ignoreMap":1357},[1023,53390,53391],{"class":1362,"line":63},[1023,53392,53393],{},"class LinearSVM:\n",[1023,53395,53396],{"class":1362,"line":68},[1023,53397,53398],{},"    def __init__(self, C: float = 1.0, lr: float = 1e-3, epochs: int = 1000, seed: int = 0): ...\n",[1023,53400,53401],{"class":1362,"line":73},[1023,53402,53403],{},"    def fit(self, X, y): ...           # y trong {-1, +1}\n",[1023,53405,53406],{"class":1362,"line":78},[1023,53407,53408],{},"    def decision_function(self, X): ...\n",[1023,53410,53411],{"class":1362,"line":83},[1023,53412,37022],{},[1023,53414,53415],{"class":1362,"line":88},[1023,53416,53417],{},"    def support_vectors(self, X, y, tol=1e-3): ...   # điểm có y * f(x) \u003C= 1 + tol\n",[973,53419,53420,53421,1517],{},"Mục tiêu (hinge loss): ",[1023,53422,53424,53518],{"className":53423},[1026],[1023,53425,53427],{"className":53426},[1030],[1032,53428,53429],{"xmlns":1034},[1036,53430,53431,53515],{},[1039,53432,53433,53449,53455,53457,53459,53465,53467,53469,53475,53477,53479,53481,53483,53485,53487,53489,53495,53497,53499,53501,53507,53509,53511,53513],{},[17690,53434,53435,53441],{},[1039,53436,53437,53439],{},[1042,53438,22184],{},[1046,53440,8400],{},[1039,53442,53443,53445,53447],{},[1042,53444,27557],{},[1046,53446,13897],{"separator":1066},[1042,53448,17703],{},[18110,53450,53451,53453],{},[1051,53452,1053],{},[1051,53454,2457],{},[1046,53456,18125],{"stretchy":1048},[1042,53458,27557],{},[2327,53460,53461,53463],{},[1046,53462,18125],{"stretchy":1048},[1051,53464,2457],{},[1046,53466,21881],{},[1042,53468,1489],{},[17690,53470,53471,53473],{},[1046,53472,17686],{},[1042,53474,1837],{},[1042,53476,35034],{},[1046,53478,8400],{},[1046,53480,1049],{"stretchy":1048},[1051,53482,2379],{},[1046,53484,13897],{"separator":1066},[1051,53486,1053],{},[1046,53488,17698],{},[17690,53490,53491,53493],{},[1042,53492,32887],{},[1042,53494,1837],{},[1046,53496,1049],{"stretchy":1048},[1042,53498,27557],{},[1046,53500,18118],{},[17690,53502,53503,53505],{},[1042,53504,3904],{},[1042,53506,1837],{},[1046,53508,21881],{},[1042,53510,17703],{},[1046,53512,1056],{"stretchy":1048},[1046,53514,1056],{"stretchy":1048},[1058,53516,53517],{"encoding":1060},"\\min_{w,b} \\frac{1}{2}\\lVert w \\rVert^2 + C \\sum_i \\max(0, 1 - y_i(w \\cdot x_i + b))",[1023,53519,53521,53694,53777,53839,53895],{"className":53520,"ariaHidden":1066},[1065],[1023,53522,53524,53528,53579,53582,53650,53653,53656,53685,53688,53691],{"className":53523},[1070],[1023,53525],{"className":53526,"style":53527},[1074],"height:1.1901em;vertical-align:-0.345em;",[1023,53529,53531,53534],{"className":53530},[8426],[1023,53532,22184],{"className":53533},[8426],[1023,53535,53537],{"className":53536},[2383],[1023,53538,53540,53570],{"className":53539},[2387,17732],[1023,53541,53543,53567],{"className":53542},[2391],[1023,53544,53546],{"className":53545,"style":36863},[2395],[1023,53547,53549,53552],{"style":53548},"top:-2.55em;margin-right:0.05em;",[1023,53550],{"className":53551,"style":2403},[2402],[1023,53553,53555],{"className":53554},[2407,2408,2409,2410],[1023,53556,53558,53561,53564],{"className":53557},[1079,2410],[1023,53559,27557],{"className":53560,"style":37436},[1079,1080,2410],[1023,53562,13897],{"className":53563},[13943,2410],[1023,53565,17703],{"className":53566},[1079,1080,2410],[1023,53568,17797],{"className":53569},[17796],[1023,53571,53573],{"className":53572},[2391],[1023,53574,53577],{"className":53575,"style":53576},[2395],"height:0.2861em;",[1023,53578],{},[1023,53580],{"className":53581,"style":8434},[2354],[1023,53583,53585,53588,53647],{"className":53584},[1079],[1023,53586],{"className":53587},[1085,18174],[1023,53589,53591],{"className":53590},[18110],[1023,53592,53594,53639],{"className":53593},[2387,17732],[1023,53595,53597,53636],{"className":53596},[2391],[1023,53598,53600,53614,53622],{"className":53599,"style":31783},[2395],[1023,53601,53602,53605],{"style":18190},[1023,53603],{"className":53604,"style":18194},[2402],[1023,53606,53608],{"className":53607},[2407,2408,2409,2410],[1023,53609,53611],{"className":53610},[1079,2410],[1023,53612,2457],{"className":53613},[1079,2410],[1023,53615,53616,53619],{"style":18221},[1023,53617],{"className":53618,"style":18194},[2402],[1023,53620],{"className":53621,"style":18229},[18228],[1023,53623,53624,53627],{"style":18232},[1023,53625],{"className":53626,"style":18194},[2402],[1023,53628,53630],{"className":53629},[2407,2408,2409,2410],[1023,53631,53633],{"className":53632},[1079,2410],[1023,53634,1053],{"className":53635},[1079,2410],[1023,53637,17797],{"className":53638},[17796],[1023,53640,53642],{"className":53641},[2391],[1023,53643,53645],{"className":53644,"style":45484},[2395],[1023,53646],{},[1023,53648],{"className":53649},[1092,18174],[1023,53651,18125],{"className":53652},[1085],[1023,53654,27557],{"className":53655,"style":37436},[1079,1080],[1023,53657,53659,53662],{"className":53658},[1092],[1023,53660,18125],{"className":53661},[1092],[1023,53663,53665],{"className":53664},[2383],[1023,53666,53668],{"className":53667},[2387],[1023,53669,53671],{"className":53670},[2391],[1023,53672,53674],{"className":53673,"style":2369},[2395],[1023,53675,53676,53679],{"style":2398},[1023,53677],{"className":53678,"style":2403},[2402],[1023,53680,53682],{"className":53681},[2407,2408,2409,2410],[1023,53683,2457],{"className":53684},[1079,2410],[1023,53686],{"className":53687,"style":13790},[2354],[1023,53689,21881],{"className":53690},[13794],[1023,53692],{"className":53693,"style":13790},[2354],[1023,53695,53697,53700,53703,53706,53747,53750,53753,53756,53759,53762,53765,53768,53771,53774],{"className":53696},[1070],[1023,53698],{"className":53699,"style":32071},[1074],[1023,53701,1489],{"className":53702,"style":20466},[1079,1080],[1023,53704],{"className":53705,"style":8434},[2354],[1023,53707,53709,53712],{"className":53708},[8426],[1023,53710,17686],{"className":53711,"style":17758},[8426,17756,17757],[1023,53713,53715],{"className":53714},[2383],[1023,53716,53718,53739],{"className":53717},[2387,17732],[1023,53719,53721,53736],{"className":53720},[2391],[1023,53722,53725],{"className":53723,"style":53724},[2395],"height:0.162em;",[1023,53726,53727,53730],{"style":32105},[1023,53728],{"className":53729,"style":2403},[2402],[1023,53731,53733],{"className":53732},[2407,2408,2409,2410],[1023,53734,1837],{"className":53735},[1079,1080,2410],[1023,53737,17797],{"className":53738},[17796],[1023,53740,53742],{"className":53741},[2391],[1023,53743,53745],{"className":53744,"style":32124},[2395],[1023,53746],{},[1023,53748],{"className":53749,"style":8434},[2354],[1023,53751,35034],{"className":53752},[8426],[1023,53754,1049],{"className":53755},[1085],[1023,53757,2379],{"className":53758},[1079],[1023,53760,13897],{"className":53761},[13943],[1023,53763],{"className":53764,"style":8434},[2354],[1023,53766,1053],{"className":53767},[1079],[1023,53769],{"className":53770,"style":13790},[2354],[1023,53772,17698],{"className":53773},[13794],[1023,53775],{"className":53776,"style":13790},[2354],[1023,53778,53780,53783,53824,53827,53830,53833,53836],{"className":53779},[1070],[1023,53781],{"className":53782,"style":1075},[1074],[1023,53784,53786,53789],{"className":53785},[1079],[1023,53787,32887],{"className":53788,"style":7723},[1079,1080],[1023,53790,53792],{"className":53791},[2383],[1023,53793,53795,53816],{"className":53794},[2387,17732],[1023,53796,53798,53813],{"className":53797},[2391],[1023,53799,53801],{"className":53800,"style":17780},[2395],[1023,53802,53804,53807],{"style":53803},"top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;",[1023,53805],{"className":53806,"style":2403},[2402],[1023,53808,53810],{"className":53809},[2407,2408,2409,2410],[1023,53811,1837],{"className":53812},[1079,1080,2410],[1023,53814,17797],{"className":53815},[17796],[1023,53817,53819],{"className":53818},[2391],[1023,53820,53822],{"className":53821,"style":17804},[2395],[1023,53823],{},[1023,53825,1049],{"className":53826},[1085],[1023,53828,27557],{"className":53829,"style":37436},[1079,1080],[1023,53831],{"className":53832,"style":13790},[2354],[1023,53834,18118],{"className":53835},[13794],[1023,53837],{"className":53838,"style":13790},[2354],[1023,53840,53842,53846,53886,53889,53892],{"className":53841},[1070],[1023,53843],{"className":53844,"style":53845},[1074],"height:0.7333em;vertical-align:-0.15em;",[1023,53847,53849,53852],{"className":53848},[1079],[1023,53850,3904],{"className":53851},[1079,1080],[1023,53853,53855],{"className":53854},[2383],[1023,53856,53858,53878],{"className":53857},[2387,17732],[1023,53859,53861,53875],{"className":53860},[2391],[1023,53862,53864],{"className":53863,"style":17780},[2395],[1023,53865,53866,53869],{"style":17783},[1023,53867],{"className":53868,"style":2403},[2402],[1023,53870,53872],{"className":53871},[2407,2408,2409,2410],[1023,53873,1837],{"className":53874},[1079,1080,2410],[1023,53876,17797],{"className":53877},[17796],[1023,53879,53881],{"className":53880},[2391],[1023,53882,53884],{"className":53883,"style":17804},[2395],[1023,53885],{},[1023,53887],{"className":53888,"style":13790},[2354],[1023,53890,21881],{"className":53891},[13794],[1023,53893],{"className":53894,"style":13790},[2354],[1023,53896,53898,53901,53904],{"className":53897},[1070],[1023,53899],{"className":53900,"style":1075},[1074],[1023,53902,17703],{"className":53903},[1079,1080],[1023,53905,47920],{"className":53906},[1092],[1352,53908,53911],{"className":53909,"code":53910,"language":2241,"meta":1357},[2239],"2 cụm tách được, C lớn  -> accuracy train 100%, lề = 2 \u002F ||w||\nXóa 1 điểm không phải vector hỗ trợ rồi huấn luyện lại -> biên gần như không đổi\nXóa 1 vector hỗ trợ     -> biên dịch chuyển (in w, b trước và sau)\n",[992,53912,53910],{"__ignoreMap":1357},[973,53914,53915],{},"Vẽ biên, 2 đường lề, và khoanh các vector hỗ trợ.",[981,53917,53919],{"id":53918},"bài-2-ảnh-hưởng-của-c","Bài 2: Ảnh hưởng của C",[973,53921,53922,53923,1517],{},"Dữ liệu 2 lớp có chồng lấn. Chạy ",[992,53924,53925],{},"C = 0.01, 0.1, 1, 10, 100",[1352,53927,53930],{"className":53928,"code":53929,"language":2241,"meta":1357},[2239],"C       độ_rộng_lề    số_vector_hỗ_trợ    acc_train    acc_test\n0.01    ...\n100     ...\n",[992,53931,53929],{"__ignoreMap":1357},[973,53933,53934,53935,53937],{},"Chọn ",[992,53936,1489],{}," bằng 5-fold cross-validation (dùng hàm ngày 56).",[981,53939,53941],{"id":53940},"bài-3-kernel-nâng-cao","Bài 3: Kernel (nâng cao)",[2273,53943,53944,53947,54178,54187],{},[989,53945,53946],{},"Dữ liệu 2 vòng tròn đồng tâm. Linear SVM thất bại.",[989,53948,53949,53950,54177],{},"Thêm đặc trưng thủ công ",[1023,53951,53953,53991],{"className":53952},[1026],[1023,53954,53956],{"className":53955},[1030],[1032,53957,53958],{"xmlns":1034},[1036,53959,53960,53988],{},[1039,53961,53962,53968,53970,53978,53980],{},[17690,53963,53964,53966],{},[1042,53965,3904],{},[1051,53967,13826],{},[1046,53969,2325],{},[36676,53971,53972,53974,53976],{},[1042,53973,3904],{},[1051,53975,1053],{},[1051,53977,2457],{},[1046,53979,21881],{},[36676,53981,53982,53984,53986],{},[1042,53983,3904],{},[1051,53985,2457],{},[1051,53987,2457],{},[1058,53989,53990],{"encoding":1060},"x_3 = x_1^2 + x_2^2",[1023,53992,53994,54051,54120],{"className":53993,"ariaHidden":1066},[1065],[1023,53995,53997,54001,54042,54045,54048],{"className":53996},[1070],[1023,53998],{"className":53999,"style":54000},[1074],"height:0.5806em;vertical-align:-0.15em;",[1023,54002,54004,54007],{"className":54003},[1079],[1023,54005,3904],{"className":54006},[1079,1080],[1023,54008,54010],{"className":54009},[2383],[1023,54011,54013,54034],{"className":54012},[2387,17732],[1023,54014,54016,54031],{"className":54015},[2391],[1023,54017,54020],{"className":54018,"style":54019},[2395],"height:0.3011em;",[1023,54021,54022,54025],{"style":17783},[1023,54023],{"className":54024,"style":2403},[2402],[1023,54026,54028],{"className":54027},[2407,2408,2409,2410],[1023,54029,13826],{"className":54030},[1079,2410],[1023,54032,17797],{"className":54033},[17796],[1023,54035,54037],{"className":54036},[2391],[1023,54038,54040],{"className":54039,"style":17804},[2395],[1023,54041],{},[1023,54043],{"className":54044,"style":2355},[2354],[1023,54046,2325],{"className":54047},[2359],[1023,54049],{"className":54050,"style":2355},[2354],[1023,54052,54054,54058,54111,54114,54117],{"className":54053},[1070],[1023,54055],{"className":54056,"style":54057},[1074],"height:1.0622em;vertical-align:-0.2481em;",[1023,54059,54061,54064],{"className":54060},[1079],[1023,54062,3904],{"className":54063},[1079,1080],[1023,54065,54067],{"className":54066},[2383],[1023,54068,54070,54102],{"className":54069},[2387,17732],[1023,54071,54073,54099],{"className":54072},[2391],[1023,54074,54076,54088],{"className":54075,"style":2369},[2395],[1023,54077,54079,54082],{"style":54078},"top:-2.4519em;margin-left:0em;margin-right:0.05em;",[1023,54080],{"className":54081,"style":2403},[2402],[1023,54083,54085],{"className":54084},[2407,2408,2409,2410],[1023,54086,1053],{"className":54087},[1079,2410],[1023,54089,54090,54093],{"style":2398},[1023,54091],{"className":54092,"style":2403},[2402],[1023,54094,54096],{"className":54095},[2407,2408,2409,2410],[1023,54097,2457],{"className":54098},[1079,2410],[1023,54100,17797],{"className":54101},[17796],[1023,54103,54105],{"className":54104},[2391],[1023,54106,54109],{"className":54107,"style":54108},[2395],"height:0.2481em;",[1023,54110],{},[1023,54112],{"className":54113,"style":13790},[2354],[1023,54115,21881],{"className":54116},[13794],[1023,54118],{"className":54119,"style":13790},[2354],[1023,54121,54123,54126],{"className":54122},[1070],[1023,54124],{"className":54125,"style":54057},[1074],[1023,54127,54129,54132],{"className":54128},[1079],[1023,54130,3904],{"className":54131},[1079,1080],[1023,54133,54135],{"className":54134},[2383],[1023,54136,54138,54169],{"className":54137},[2387,17732],[1023,54139,54141,54166],{"className":54140},[2391],[1023,54142,54144,54155],{"className":54143,"style":2369},[2395],[1023,54145,54146,54149],{"style":54078},[1023,54147],{"className":54148,"style":2403},[2402],[1023,54150,54152],{"className":54151},[2407,2408,2409,2410],[1023,54153,2457],{"className":54154},[1079,2410],[1023,54156,54157,54160],{"style":2398},[1023,54158],{"className":54159,"style":2403},[2402],[1023,54161,54163],{"className":54162},[2407,2408,2409,2410],[1023,54164,2457],{"className":54165},[1079,2410],[1023,54167,17797],{"className":54168},[17796],[1023,54170,54172],{"className":54171},[2391],[1023,54173,54175],{"className":54174,"style":54108},[2395],[1023,54176],{},". Linear SVM trên 3 chiều tách được. Vẽ minh họa 3D.",[989,54179,2699,54180,7386,54183,54186],{},[992,54181,54182],{},"sklearn.svm.SVC(kernel=\"rbf\")",[992,54184,54185],{},"gamma = 0.1, 1, 10, 100",". Vẽ 4 biên quyết định. Chỉ ra gamma nào học thuộc.",[989,54188,54189,54190,1517],{},"Tự cài hàm kernel RBF và kiểm tra ma trận Gram bằng với ",[992,54191,54192],{},"sklearn.metrics.pairwise.rbf_kernel",[981,54194,2711],{"id":2710},[986,54196,54198,54204,54210,54216],{"className":54197},[2715],[989,54199,54201,54203],{"className":54200},[2719],[2721,54202],{"disabled":2723,"type":2724}," Hình biên, lề, vector hỗ trợ cho Bài 1.",[989,54205,54207,54209],{"className":54206},[2719],[2721,54208],{"disabled":2723,"type":2724}," Bảng C có số thật và C được chọn bằng CV.",[989,54211,54213,54215],{"className":54212},[2719],[2721,54214],{"disabled":2723,"type":2724}," Có 4 hình biên RBF theo gamma.",[989,54217,54219,54221],{"className":54218},[2719],[2721,54220],{"disabled":2723,"type":2724}," Giải thích được \"kernel trick\" bằng ví dụ bình phương bán kính.",[968,54223,2890],{"id":2889},[986,54225,54226,54229,54232,54235],{},[989,54227,54228],{},"Lề margin là gì?",[989,54230,54231],{},"Tham số C điều khiển điều gì?",[989,54233,54234],{},"Kernel giúp gì cho dữ liệu phi tuyến?",[989,54236,54237],{},"Gamma lớn và nhỏ khác nhau ra sao?",[3014,54239],{},[973,54241,54242],{},"🌕 Bạn đã hoàn thành ngày 90. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,54244,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":54246},[54247,54248,54254,54255,54261],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":54249},[54250,54251,54252,54253],{"id":53244,"depth":73,"text":53245},{"id":53262,"depth":73,"text":53263},{"id":53280,"depth":73,"text":53281},{"id":53335,"depth":73,"text":53336},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":54256},[54257,54258,54259,54260],{"id":53382,"depth":73,"text":53383},{"id":53918,"depth":73,"text":53919},{"id":53940,"depth":73,"text":53941},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Máy vector hỗ trợ: lề cực đại, vector hỗ trợ, kernel cho dữ liệu phi tuyến và bài thi classifiers.",{},[15144],{"title":505,"description":54262},[18472,54267,54268],"svm","kernel","GsgNbV_VhnbQemOfVW-25c-YeQ4NKZs6z2_Ysjn5268",{"id":54271,"title":510,"body":54272,"category":8797,"day":513,"description":54627,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":54628,"navigation":2723,"outcomes":3047,"path":511,"prerequisites":54629,"seo":54630,"stem":512,"tags":54631,"__hash__":54632},"challenges\u002Fchallenges\u002F91.recsys-nang-cao.md",{"type":965,"value":54273,"toc":54610},[54274,54276,54279,54281,54285,54302,54306,54320,54370,54374,54388,54392,54403,54405,54413,54433,54435,54443,54447,54472,54495,54501,54504,54508,54522,54526,54552,54558,54560,54587,54589,54603,54605,54608],[968,54275,971],{"id":970},[973,54277,54278],{},"Bài này học gợi ý bằng nhân tử ẩn và mô hình lai.\nDùng để gợi ý phim, món ăn khi dữ liệu thưa.",[968,54280,979],{"id":978},[981,54282,54284],{"id":54283},"phân-rã-ma-trận","Phân rã ma trận",[986,54286,54287,54290,54293,54296,54299],{},[989,54288,54289],{},"Định nghĩa: nén mỗi người và mỗi món thành vector ngắn.",[989,54291,54292],{},"Điểm dự đoán = độ khớp hai vector + thiên lệch.",[989,54294,54295],{},"Ví dụ đời thường: như đoán khẩu vị từ vài món tủ.",[989,54297,54298],{},"Học bằng cách chỉnh vector cho khớp điểm đã biết.",[989,54300,54301],{},"Chịu thưa tốt hơn tìm láng giềng trực tiếp.",[981,54303,54305],{"id":54304},"cold-start-và-dữ-liệu-thưa","Cold start và dữ liệu thưa",[986,54307,54308,54311,54314,54317],{},[989,54309,54310],{},"Cold start: người mới hoặc món mới chưa có dữ liệu.",[989,54312,54313],{},"Sửa bằng gợi phổ biến và hỏi sở thích lúc đầu.",[989,54315,54316],{},"Dữ liệu thưa: mỗi người chỉ chấm vài món.",[989,54318,54319],{},"Sửa bằng tín hiệu ngầm như lượt xem, lượt click.",[1099,54321,54322,54335],{},[1102,54323,54324],{},[1105,54325,54326,54329,54332],{},[1108,54327,54328],{},"Vấn đề",[1108,54330,54331],{},"Dấu hiệu",[1108,54333,54334],{},"Cách sửa",[1118,54336,54337,54348,54359],{},[1105,54338,54339,54342,54345],{},[1123,54340,54341],{},"Cold user",[1123,54343,54344],{},"Người mới, chưa chấm gì",[1123,54346,54347],{},"Hỏi sở thích, gợi hot",[1105,54349,54350,54353,54356],{},[1123,54351,54352],{},"Cold item",[1123,54354,54355],{},"Món mới, chưa ai chấm",[1123,54357,54358],{},"Dùng mô tả nội dung",[1105,54360,54361,54364,54367],{},[1123,54362,54363],{},"Thưa",[1123,54365,54366],{},"Ma trận rỗng > 99%",[1123,54368,54369],{},"Phân rã, tín hiệu ngầm",[981,54371,54373],{"id":54372},"mô-hình-lai","Mô hình lai",[986,54375,54376,54379,54382,54385],{},[989,54377,54378],{},"Định nghĩa: kết hợp nhiều mô hình gợi ý với nhau.",[989,54380,54381],{},"Lai song song: trộn điểm các mô hình lại.",[989,54383,54384],{},"Lai nối tiếp: mô hình trước lọc, mô hình sau xếp hạng.",[989,54386,54387],{},"Ví dụ đời thường: như hỏi nhiều bạn rồi chốt lại.",[981,54389,54391],{"id":54390},"giới-hạn-khác-của-hệ-gợi-ý","Giới hạn khác của hệ gợi ý",[986,54393,54394,54397,54400],{},[989,54395,54396],{},"Cần metadata tốt: thiếu mô tả món thì content-based không có gì để so.",[989,54398,54399],{},"Ảnh hưởng xã hội là con dao hai lưỡi: gợi theo đám đông làm món nổi càng nổi, món ngách khó được thấy.",[989,54401,54402],{},"Gu người dùng trôi theo thời gian, cần huấn luyện lại định kỳ.",[968,54404,1433],{"id":1432},[986,54406,54407,54410],{},[989,54408,54409],{},"Input: người mới chưa chấm gì -> Output: gợi top phim hot.",[989,54411,54412],{},"Giải thích: collaborative câm nên dùng phổ biến và nội dung.",[1352,54414,54416],{"className":3538,"code":54415,"language":3540,"meta":1357,"style":1357},"# Dự đoán điểm bằng vector ẩn\npred = sum(u * v for u, v in zip(user, item)) + bias\nprint(pred)  # điểm gợi ý\n",[992,54417,54418,54423,54428],{"__ignoreMap":1357},[1023,54419,54420],{"class":1362,"line":63},[1023,54421,54422],{},"# Dự đoán điểm bằng vector ẩn\n",[1023,54424,54425],{"class":1362,"line":68},[1023,54426,54427],{},"pred = sum(u * v for u, v in zip(user, item)) + bias\n",[1023,54429,54430],{"class":1362,"line":73},[1023,54431,54432],{},"print(pred)  # điểm gợi ý\n",[968,54434,1482],{"id":1481},[973,54436,1485,54437,54439,54440,1517],{},[1487,54438,13531],{}," với NumPy. Dữ liệu MovieLens 100K. Dùng lại baseline ngày 59. Nộp vào ",[992,54441,54442],{},"day-091\u002F",[981,54444,54446],{"id":54445},"bài-1-matrix-factorization-bằng-sgd","Bài 1: Matrix factorization bằng SGD",[1352,54448,54450],{"className":3538,"code":54449,"language":3540,"meta":1357,"style":1357},"class MF:\n    def __init__(self, k=20, lr=0.01, reg=0.05, epochs=30, seed=0): ...\n    def fit(self, ratings: list[tuple[int, int, float]], val=None): ...\n    def predict(self, u, i) -> float: ...     # mu + b_u + b_i + P[u] . Q[i], kẹp vào [1, 5]\n",[992,54451,54452,54457,54462,54467],{"__ignoreMap":1357},[1023,54453,54454],{"class":1362,"line":63},[1023,54455,54456],{},"class MF:\n",[1023,54458,54459],{"class":1362,"line":68},[1023,54460,54461],{},"    def __init__(self, k=20, lr=0.01, reg=0.05, epochs=30, seed=0): ...\n",[1023,54463,54464],{"class":1362,"line":73},[1023,54465,54466],{},"    def fit(self, ratings: list[tuple[int, int, float]], val=None): ...\n",[1023,54468,54469],{"class":1362,"line":78},[1023,54470,54471],{},"    def predict(self, u, i) -> float: ...     # mu + b_u + b_i + P[u] . Q[i], kẹp vào [1, 5]\n",[973,54473,54474,54475,13568,54478,54481,54482,1656,54485,1656,54488,1656,54491,54494],{},"Mỗi rating ",[992,54476,54477],{},"(u, i, r)",[992,54479,54480],{},"e = r - predict",", cập nhật ",[992,54483,54484],{},"b_u",[992,54486,54487],{},"b_i",[992,54489,54490],{},"P[u]",[992,54492,54493],{},"Q[i]"," với regularization. Xáo trộn thứ tự rating mỗi epoch.",[1352,54496,54499],{"className":54497,"code":54498,"language":2241,"meta":1357},[2239],"Sau 30 epoch: RMSE train giảm đều mỗi epoch\nRMSE test \u003C item-based CF ngày 59\nk = 0 (chỉ bias) -> vẫn thắng global mean\n",[992,54500,54498],{"__ignoreMap":1357},[973,54502,54503],{},"Vẽ RMSE train và validation theo epoch.",[981,54505,54507],{"id":54506},"bài-2-cold-start-và-sparsity","Bài 2: Cold start và sparsity",[2273,54509,54510,54513,54519],{},[989,54511,54512],{},"Tách 50 user có ít nhất 50 rating. Giả làm user mới: chỉ giữ 0, 1, 3, 5, 10 rating của họ trong train. Đo RMSE trên phần còn lại cho từng mức.",[989,54514,54515,54516,54518],{},"Chiến lược cho user 0 rating: gợi top phim theo ",[992,54517,54487],{}," (phổ biến và được chấm cao). Đo precision@10.",[989,54520,54521],{},"Chiến lược \"hỏi sở thích\": user chọn 3 thể loại, gợi top phim các thể loại đó. So precision@10.",[981,54523,54525],{"id":54524},"bài-3-mô-hình-lai-nâng-cao","Bài 3: Mô hình lai (nâng cao)",[2273,54527,54528,54540,54546],{},[989,54529,54530,2308,54533,54536,54537,54539],{},[1487,54531,54532],{},"Lai song song:",[992,54534,54535],{},"score = a * MF + (1 - a) * content (ngày 58)",". Quét ",[992,54538,6207],{}," từ 0 tới 1, chọn theo precision@10 trên validation.",[989,54541,54542,54545],{},[1487,54543,54544],{},"Lai nối tiếp:"," content-based lọc 200 ứng viên, MF xếp hạng lấy top 10.",[989,54547,54548,54551],{},[1487,54549,54550],{},"Lai chuyển đổi:"," user có dưới 5 rating dùng content, còn lại dùng MF.",[1352,54553,54556],{"className":54554,"code":54555,"language":2241,"meta":1357},[2239],"chiến_lược        RMSE    precision@10    recall@10\nMF                ...\ncontent           ...\nlai song song     ...\nlai nối tiếp      ...\nlai chuyển đổi    ...\n",[992,54557,54555],{"__ignoreMap":1357},[981,54559,2711],{"id":2710},[986,54561,54563,54569,54575,54581],{"className":54562},[2715],[989,54564,54566,54568],{"className":54565},[2719],[2721,54567],{"disabled":2723,"type":2724}," MF thắng baseline và CF, có hình RMSE theo epoch.",[989,54570,54572,54574],{"className":54571},[2719],[2721,54573],{"disabled":2723,"type":2724}," Bảng RMSE theo số rating của user mới.",[989,54576,54578,54580],{"className":54577},[2719],[2721,54579],{"disabled":2723,"type":2724}," Bảng 5 chiến lược có số thật.",[989,54582,54584,54586],{"className":54583},[2719],[2721,54585],{"disabled":2723,"type":2724}," Giải thích được vì sao MF chịu thưa tốt hơn tìm láng giềng.",[968,54588,2890],{"id":2889},[986,54590,54591,54594,54597,54600],{},[989,54592,54593],{},"Phân rã ma trận là gì?",[989,54595,54596],{},"Cold start user khác cold item thế nào?",[989,54598,54599],{},"Vì sao ma trận điểm luôn thưa?",[989,54601,54602],{},"Lai song song khác lai nối tiếp ra sao?",[3014,54604],{},[973,54606,54607],{},"🌕 Bạn đã hoàn thành ngày 91. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,54609,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":54611},[54612,54613,54619,54620,54626],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":54614},[54615,54616,54617,54618],{"id":54283,"depth":73,"text":54284},{"id":54304,"depth":73,"text":54305},{"id":54372,"depth":73,"text":54373},{"id":54390,"depth":73,"text":54391},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":54621},[54622,54623,54624,54625],{"id":54445,"depth":73,"text":54446},{"id":54506,"depth":73,"text":54507},{"id":54524,"depth":73,"text":54525},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhân tử ẩn, Netflix Prize, cold start, sparsity, ảnh hưởng xã hội hai mặt và mô hình lai tiến hóa.",{},[18469],{"title":510,"description":54627},[39582],"0qWjBxU2kH2mhOL7t14A7rQEChvZ5A-W1D7qIATUCxo",{"id":54634,"title":515,"body":54635,"category":5189,"day":518,"description":55126,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":55127,"navigation":2723,"outcomes":3047,"path":516,"prerequisites":55128,"seo":55129,"stem":517,"tags":55130,"__hash__":55131},"challenges\u002Fchallenges\u002F92.bridge-builder.md",{"type":965,"value":54636,"toc":55110},[54637,54639,54642,54644,54648,54665,54702,54706,54723,54758,54760,54774,54776,54790,54792,54799,54803,54874,54887,54893,54898,54902,54965,55025,55031,55035,55058,55060,55087,55089,55103,55105,55108],[968,54638,971],{"id":970},[973,54640,54641],{},"Bài này học Bridge tách điều khiển khỏi thiết bị và Builder dựng từng bước.\nDùng để thêm hãng TV hay món ăn không vỡ code.",[968,54643,979],{"id":978},[981,54645,54647],{"id":54646},"bridge","Bridge",[986,54649,54650,54653,54656,54659,54662],{},[989,54651,54652],{},"Định nghĩa: tách trừu tượng khỏi cài đặt qua một cầu.",[989,54654,54655],{},"Remote giữ một cầu tới TV, bấm nút là chuyển lời.",[989,54657,54658],{},"Ví dụ đời thường: như remote đa năng bấm là TV chạy.",[989,54660,54661],{},"Thêm hãng TV mới chỉ thêm 1 lớp.",[989,54663,54664],{},"Không nhân số lớp theo tích hai chiều.",[1099,54666,54667,54679],{},[1102,54668,54669],{},[1105,54670,54671,54673,54676],{},[1108,54672,7111],{},[1108,54674,54675],{},"Thêm hãng mới",[1108,54677,54678],{},"Thêm remote mới",[1118,54680,54681,54691],{},[1105,54682,54683,54686,54689],{},[1123,54684,54685],{},"Kế thừa liệt kê",[1123,54687,54688],{},"Nhân thêm nhiều lớp",[1123,54690,54688],{},[1105,54692,54693,54696,54699],{},[1123,54694,54695],{},"Bridge qua cầu",[1123,54697,54698],{},"Chỉ 1 lớp TV",[1123,54700,54701],{},"Chỉ 1 lớp remote",[981,54703,54705],{"id":54704},"builder","Builder",[986,54707,54708,54711,54714,54717,54720],{},[989,54709,54710],{},"Định nghĩa: dựng đối tượng phức tạp qua từng bước nhỏ.",[989,54712,54713],{},"Thay constructor khổng lồ nhiều tham số rối rắm.",[989,54715,54716],{},"Ví dụ đời thường: như gọi cơm chọn từng món một.",[989,54718,54719],{},"Mỗi bước trả về chính builder để nối chuỗi.",[989,54721,54722],{},"Bước cuối gọi build để ra thành phẩm.",[1352,54724,54726],{"className":3538,"code":54725,"language":3540,"meta":1357,"style":1357},"# Builder dựng bữa ăn từng bước\nmeal = (MealBuilder()\n    .them_mon_chinh(\"cơm gà\")  # chọn món chính\n    .them_nuoc(\"trà đá\")  # chọn nước\n    .build())  # chốt đơn\nprint(meal)\n",[992,54727,54728,54733,54738,54743,54748,54753],{"__ignoreMap":1357},[1023,54729,54730],{"class":1362,"line":63},[1023,54731,54732],{},"# Builder dựng bữa ăn từng bước\n",[1023,54734,54735],{"class":1362,"line":68},[1023,54736,54737],{},"meal = (MealBuilder()\n",[1023,54739,54740],{"class":1362,"line":73},[1023,54741,54742],{},"    .them_mon_chinh(\"cơm gà\")  # chọn món chính\n",[1023,54744,54745],{"class":1362,"line":78},[1023,54746,54747],{},"    .them_nuoc(\"trà đá\")  # chọn nước\n",[1023,54749,54750],{"class":1362,"line":83},[1023,54751,54752],{},"    .build())  # chốt đơn\n",[1023,54754,54755],{"class":1362,"line":88},[1023,54756,54757],{},"print(meal)\n",[981,54759,10673],{"id":47130},[986,54761,54762,54765,54768,54771],{},[989,54763,54764],{},"Dùng Bridge khi hai chiều cùng thay đổi độc lập.",[989,54766,54767],{},"Dùng Builder khi đối tượng có quá nhiều tùy chọn.",[989,54769,54770],{},"Không dùng Bridge cho quan hệ một chiều đơn giản.",[989,54772,54773],{},"Không dùng Builder cho object chỉ 1-2 field.",[968,54775,1433],{"id":1432},[986,54777,54778,54781,54784,54787],{},[989,54779,54780],{},"Input: thêm hãng TV thứ 4 -> Output: chỉ thêm 1 lớp TV mới.",[989,54782,54783],{},"Giải thích: remote cũ giữ nguyên vì chỉ nói qua cầu.",[989,54785,54786],{},"Input: bữa ăn thiếu nước -> Output: builder báo thiếu trước khi build.",[989,54788,54789],{},"Giải thích: từng bước kiểm tra rõ hơn constructor dài.",[968,54791,1482],{"id":1481},[973,54793,1485,54794,4801,54796,1517],{},[1487,54795,4800],{},[992,54797,54798],{},"day-092\u002F",[981,54800,54802],{"id":54801},"bài-1-bridge-cho-remote-và-tv","Bài 1: Bridge cho remote và TV",[1352,54804,54806],{"className":1393,"code":54805,"language":1395,"meta":1357,"style":1357},"struct TV {   \u002F\u002F implementor\n  virtual void on() = 0; virtual void off() = 0; virtual void tuneChannel(int ch) = 0;\n  virtual int channel() const = 0; virtual ~TV() = default;\n};\nclass RemoteControl {   \u002F\u002F abstraction\n protected: TV &tv;\n public:\n  explicit RemoteControl(TV &t);\n  virtual void on(); virtual void off(); virtual void setChannel(int ch);\n  virtual ~RemoteControl() = default;\n};\nclass ConcreteRemote : public RemoteControl {\n public: void nextChannel(); void previousChannel(); void favorite(int slot); void setFavorite(int slot, int ch);\n};\n",[992,54807,54808,54813,54818,54823,54827,54832,54837,54841,54846,54851,54856,54860,54865,54870],{"__ignoreMap":1357},[1023,54809,54810],{"class":1362,"line":63},[1023,54811,54812],{},"struct TV {   \u002F\u002F implementor\n",[1023,54814,54815],{"class":1362,"line":68},[1023,54816,54817],{},"  virtual void on() = 0; virtual void off() = 0; virtual void tuneChannel(int ch) = 0;\n",[1023,54819,54820],{"class":1362,"line":73},[1023,54821,54822],{},"  virtual int channel() const = 0; virtual ~TV() = default;\n",[1023,54824,54825],{"class":1362,"line":78},[1023,54826,4866],{},[1023,54828,54829],{"class":1362,"line":83},[1023,54830,54831],{},"class RemoteControl {   \u002F\u002F abstraction\n",[1023,54833,54834],{"class":1362,"line":88},[1023,54835,54836],{}," protected: TV &tv;\n",[1023,54838,54839],{"class":1362,"line":93},[1023,54840,4836],{},[1023,54842,54843],{"class":1362,"line":98},[1023,54844,54845],{},"  explicit RemoteControl(TV &t);\n",[1023,54847,54848],{"class":1362,"line":103},[1023,54849,54850],{},"  virtual void on(); virtual void off(); virtual void setChannel(int ch);\n",[1023,54852,54853],{"class":1362,"line":108},[1023,54854,54855],{},"  virtual ~RemoteControl() = default;\n",[1023,54857,54858],{"class":1362,"line":113},[1023,54859,4866],{},[1023,54861,54862],{"class":1362,"line":118},[1023,54863,54864],{},"class ConcreteRemote : public RemoteControl {\n",[1023,54866,54867],{"class":1362,"line":123},[1023,54868,54869],{}," public: void nextChannel(); void previousChannel(); void favorite(int slot); void setFavorite(int slot, int ch);\n",[1023,54871,54872],{"class":1362,"line":128},[1023,54873,4866],{},[973,54875,54876,54877,1656,54880,1656,54883,54886],{},"TV cụ thể: ",[992,54878,54879],{},"SonyTV",[992,54881,54882],{},"SamsungTV",[992,54884,54885],{},"LgTV"," (kênh hợp lệ khác nhau: Sony 1-99, Samsung 1-999, LG 1-500; kênh sai thì ném lỗi).",[1352,54888,54891],{"className":54889,"code":54890,"language":2241,"meta":1357},[2239],"ConcreteRemote(SonyTV).setChannel(5); nextChannel() -> Sony kênh 6\nConcreteRemote(SonyTV).setChannel(99); nextChannel() -> quay vòng về 1\n",[992,54892,54890],{"__ignoreMap":1357},[973,54894,54895,54896,1517],{},"Đếm số lớp cần viết với kế thừa thuần (mỗi loại remote x mỗi hãng) và với Bridge, khi có 3 loại remote và 3 hãng TV. Ghi vào ",[992,54897,2513],{},[981,54899,54901],{"id":54900},"bài-2-builder-cho-đối-tượng-nhiều-tùy-chọn","Bài 2: Builder cho đối tượng nhiều tùy chọn",[1352,54903,54905],{"className":1393,"code":54904,"language":1395,"meta":1357,"style":1357},"class HttpRequest { \u002F* method, url, headers, query, body, timeoutMs, retries *\u002F };\nclass HttpRequestBuilder {\n public:\n  explicit HttpRequestBuilder(std::string url);\n  HttpRequestBuilder &method(std::string m);\n  HttpRequestBuilder &header(std::string k, std::string v);\n  HttpRequestBuilder &query(std::string k, std::string v);\n  HttpRequestBuilder &body(std::string b);\n  HttpRequestBuilder &timeout(int ms);\n  HttpRequestBuilder &retries(int n);\n  HttpRequest build() const;   \u002F\u002F kiểm tra hợp lệ\n};\n",[992,54906,54907,54912,54917,54921,54926,54931,54936,54941,54946,54951,54956,54961],{"__ignoreMap":1357},[1023,54908,54909],{"class":1362,"line":63},[1023,54910,54911],{},"class HttpRequest { \u002F* method, url, headers, query, body, timeoutMs, retries *\u002F };\n",[1023,54913,54914],{"class":1362,"line":68},[1023,54915,54916],{},"class HttpRequestBuilder {\n",[1023,54918,54919],{"class":1362,"line":73},[1023,54920,4836],{},[1023,54922,54923],{"class":1362,"line":78},[1023,54924,54925],{},"  explicit HttpRequestBuilder(std::string url);\n",[1023,54927,54928],{"class":1362,"line":83},[1023,54929,54930],{},"  HttpRequestBuilder &method(std::string m);\n",[1023,54932,54933],{"class":1362,"line":88},[1023,54934,54935],{},"  HttpRequestBuilder &header(std::string k, std::string v);\n",[1023,54937,54938],{"class":1362,"line":93},[1023,54939,54940],{},"  HttpRequestBuilder &query(std::string k, std::string v);\n",[1023,54942,54943],{"class":1362,"line":98},[1023,54944,54945],{},"  HttpRequestBuilder &body(std::string b);\n",[1023,54947,54948],{"class":1362,"line":103},[1023,54949,54950],{},"  HttpRequestBuilder &timeout(int ms);\n",[1023,54952,54953],{"class":1362,"line":108},[1023,54954,54955],{},"  HttpRequestBuilder &retries(int n);\n",[1023,54957,54958],{"class":1362,"line":113},[1023,54959,54960],{},"  HttpRequest build() const;   \u002F\u002F kiểm tra hợp lệ\n",[1023,54962,54963],{"class":1362,"line":118},[1023,54964,4866],{},[1099,54966,54967,54980],{},[1102,54968,54969],{},[1105,54970,54971,54977],{},[1108,54972,54973,54974],{},"Luật kiểm tra trong ",[992,54975,54976],{},"build()",[1108,54978,54979],{},"Lỗi",[1118,54981,54982,54996,55010],{},[1105,54983,54984,54992],{},[1123,54985,54986,5059,54989],{},[992,54987,54988],{},"GET",[992,54990,54991],{},"body",[1123,54993,54994],{},[992,54995,48456],{},[1105,54997,54998,55006],{},[1123,54999,55000,5586,55003],{},[992,55001,55002],{},"timeout \u003C= 0",[992,55004,55005],{},"retries \u003C 0",[1123,55007,55008],{},[992,55009,48456],{},[1105,55011,55012,55021],{},[1123,55013,55014,55015,5586,55018],{},"URL không bắt đầu bằng ",[992,55016,55017],{},"http:\u002F\u002F",[992,55019,55020],{},"https:\u002F\u002F",[1123,55022,55023],{},[992,55024,48456],{},[973,55026,1505,55027,55030],{},[992,55028,55029],{},"HttpRequest::toString()"," in dạng request HTTP thô. Test 5 request hợp lệ và 3 request lỗi.",[981,55032,55034],{"id":55033},"bài-3-kết-hợp-và-phản-biện-nâng-cao","Bài 3: Kết hợp và phản biện (nâng cao)",[2273,55036,55037,55052],{},[989,55038,1505,55039,55042,55043,18407,55046,1656,55049,16014],{},[992,55040,55041],{},"ReportBuilder"," dựng báo cáo gồm tiêu đề, các mục, bảng. Kết hợp Bridge: báo cáo xuất qua ",[992,55044,55045],{},"Renderer",[992,55047,55048],{},"MarkdownRenderer",[992,55050,55051],{},"HtmlRenderer",[989,55053,49241,55054,55057],{},[992,55055,55056],{},"HttpRequestBuilder"," với constructor 7 tham số và với struct có designated initializers C++20. Viết 3 câu: khi nào Builder đáng giá, khi nào không.",[981,55059,2711],{"id":2710},[986,55061,55063,55069,55075,55081],{"className":55062},[2715],[989,55064,55066,55068],{"className":55065},[2719],[2721,55067],{"disabled":2723,"type":2724}," Test Bridge pass với 3 hãng TV.",[989,55070,55072,55074],{"className":55071},[2719],[2721,55073],{"disabled":2723,"type":2724}," Bảng số lớp kế thừa thuần vs Bridge.",[989,55076,55078,55080],{"className":55077},[2719],[2721,55079],{"disabled":2723,"type":2724}," Builder kiểm tra đủ 3 luật, có test lỗi.",[989,55082,55084,55086],{"className":55083},[2719],[2721,55085],{"disabled":2723,"type":2724}," Bài 3 có phản biện Builder bằng code thật.",[968,55088,2890],{"id":2889},[986,55090,55091,55094,55097,55100],{},[989,55092,55093],{},"Bridge tách cái gì khỏi cái gì?",[989,55095,55096],{},"Vì sao kế thừa liệt kê gây bùng nổ lớp?",[989,55098,55099],{},"Builder thay thế nỗi đau nào?",[989,55101,55102],{},"Khi nào không nên dùng Builder?",[3014,55104],{},[973,55106,55107],{},"🌕 Bạn đã hoàn thành ngày 92. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,55109,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":55111},[55112,55113,55118,55119,55125],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":55114},[55115,55116,55117],{"id":54646,"depth":73,"text":54647},{"id":54704,"depth":73,"text":54705},{"id":47130,"depth":73,"text":10673},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":55120},[55121,55122,55123,55124],{"id":54801,"depth":73,"text":54802},{"id":54900,"depth":73,"text":54901},{"id":55033,"depth":73,"text":55034},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Bridge tách trừu tượng khỏi cài đặt cho remote TV, Builder dựng bữa ăn từng bước thay vì constructor khổng lồ.",{},[5194],{"title":515,"description":55126},[41703,54646,54704],"7ZO31ePwIeI_6xRJmntp-Ggcr4tZYR-hQPDYQzYSOwY",{"id":55133,"title":520,"body":55134,"category":8797,"day":523,"description":55452,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":55453,"navigation":2723,"outcomes":3047,"path":521,"prerequisites":55454,"seo":55455,"stem":522,"tags":55456,"__hash__":55458},"challenges\u002Fchallenges\u002F93.perceptron-mang-noron.md",{"type":965,"value":55135,"toc":55436},[55136,55138,55141,55143,55147,55164,55168,55185,55223,55227,55244,55246,55254,55274,55276,55284,55288,55318,55324,55327,55331,55334,55337,55343,55350,55354,55384,55386,55413,55415,55429,55431,55434],[968,55137,971],{"id":970},[973,55139,55140],{},"Bài này học perceptron và vì sao cần tầng ẩn.\nDùng để hiểu gốc của mọi mạng noron ngày nay.",[968,55142,979],{"id":978},[981,55144,55146],{"id":55145},"perceptron","Perceptron",[986,55148,55149,55152,55155,55158,55161],{},[989,55150,55151],{},"Định nghĩa: noron cộng dồn bằng chứng có trọng số rồi bật tắt.",[989,55153,55154],{},"Tổng vượt ngưỡng thì bắn tín hiệu, không thì im.",[989,55156,55157],{},"Ví dụ đời thường: như cân phiếu bầu có trọng số.",[989,55159,55160],{},"Học bằng cách dịch trọng số khi đoán sai.",[989,55162,55163],{},"Chỉ tách được dữ liệu chia được bằng 1 đường thẳng.",[981,55165,55167],{"id":55166},"giới-hạn-xor","Giới hạn XOR",[986,55169,55170,55173,55176,55179,55182],{},[989,55171,55172],{},"Định nghĩa: XOR cần 4 miền xen kẽ kiểu bàn cờ.",[989,55174,55175],{},"Một đường thẳng không tách được 2 cặp chéo nhau.",[989,55177,55178],{},"Ví dụ đời thường: như 1 nhát kéo không cắt chéo 2 lần.",[989,55180,55181],{},"Đây là giới hạn biểu diễn, không phải thiếu dữ liệu.",[989,55183,55184],{},"Muốn giải phải thêm tầng ẩn.",[1099,55186,55187,55199],{},[1102,55188,55189],{},[1105,55190,55191,55193,55196],{},[1108,55192,41062],{},[1108,55194,55195],{},"XOR 4 điểm",[1108,55197,55198],{},"Vì sao",[1118,55200,55201,55212],{},[1105,55202,55203,55206,55209],{},[1123,55204,55205],{},"Perceptron đơn",[1123,55207,55208],{},"Tối đa ~75%",[1123,55210,55211],{},"Chỉ 1 đường thẳng",[1105,55213,55214,55217,55220],{},[1123,55215,55216],{},"MLP 2 noron ẩn",[1123,55218,55219],{},"100%",[1123,55221,55222],{},"Ghép 2 đường ranh",[981,55224,55226],{"id":55225},"mạng-nhiều-lớp","Mạng nhiều lớp",[986,55228,55229,55232,55235,55238,55241],{},[989,55230,55231],{},"Định nghĩa: xếp noron thành lớp vào, ẩn, ra.",[989,55233,55234],{},"Tầng ẩn biến đổi không gian cho tách được tuyến tính.",[989,55236,55237],{},"Ví dụ đời thường: như gấp giấy rồi cắt 1 nhát thẳng.",[989,55239,55240],{},"Sâu vừa phải thường lợi tham số hơn nông quá rộng.",[989,55242,55243],{},"Mạng tuyến tính thuần dù sâu vẫn gộp thành 1 phép.",[968,55245,1433],{"id":1432},[986,55247,55248,55251],{},[989,55249,55250],{},"Input: 4 điểm XOR -> Output: perceptron đơn sai ít nhất 1 điểm.",[989,55252,55253],{},"Giải thích: không có đường thẳng nào tách được cặp chéo.",[1352,55255,55257],{"className":3538,"code":55256,"language":3540,"meta":1357,"style":1357},"# Đếm tham số mạng 2 vào, 2 ẩn, 1 ra\ntham_so = 2*2 + 2 + 2*1 + 1  # trọng số + ngưỡng\nprint(tham_so)  # 9\n",[992,55258,55259,55264,55269],{"__ignoreMap":1357},[1023,55260,55261],{"class":1362,"line":63},[1023,55262,55263],{},"# Đếm tham số mạng 2 vào, 2 ẩn, 1 ra\n",[1023,55265,55266],{"class":1362,"line":68},[1023,55267,55268],{},"tham_so = 2*2 + 2 + 2*1 + 1  # trọng số + ngưỡng\n",[1023,55270,55271],{"class":1362,"line":73},[1023,55272,55273],{},"print(tham_so)  # 9\n",[968,55275,1482],{"id":1481},[973,55277,1485,55278,55280,55281,1517],{},[1487,55279,13531],{}," với NumPy. Không dùng thư viện học sâu. Nộp vào ",[992,55282,55283],{},"day-093\u002F",[981,55285,55287],{"id":55286},"bài-1-perceptron","Bài 1: Perceptron",[1352,55289,55291],{"className":3538,"code":55290,"language":3540,"meta":1357,"style":1357},"class Perceptron:\n    def __init__(self, lr: float = 1.0, epochs: int = 100): ...\n    def fit(self, X, y): ...        # y trong {0, 1}, cập nhật w += lr * (y - yhat) * x\n    def predict(self, X): ...       # bậc thang: 1 nếu w.x + b > 0\n    errors_: list[int]              # số lỗi mỗi epoch\n",[992,55292,55293,55298,55303,55308,55313],{"__ignoreMap":1357},[1023,55294,55295],{"class":1362,"line":63},[1023,55296,55297],{},"class Perceptron:\n",[1023,55299,55300],{"class":1362,"line":68},[1023,55301,55302],{},"    def __init__(self, lr: float = 1.0, epochs: int = 100): ...\n",[1023,55304,55305],{"class":1362,"line":73},[1023,55306,55307],{},"    def fit(self, X, y): ...        # y trong {0, 1}, cập nhật w += lr * (y - yhat) * x\n",[1023,55309,55310],{"class":1362,"line":78},[1023,55311,55312],{},"    def predict(self, X): ...       # bậc thang: 1 nếu w.x + b > 0\n",[1023,55314,55315],{"class":1362,"line":83},[1023,55316,55317],{},"    errors_: list[int]              # số lỗi mỗi epoch\n",[1352,55319,55322],{"className":55320,"code":55321,"language":2241,"meta":1357},[2239],"AND -> hội tụ, 0 lỗi, in w và b\nOR  -> hội tụ, 0 lỗi\nXOR -> sau 100 epoch vẫn sai ít nhất 1 trên 4 điểm\n",[992,55323,55321],{"__ignoreMap":1357},[973,55325,55326],{},"Vẽ đường biên của AND và OR. Vẽ 4 điểm XOR và giải thích bằng hình vì sao không có đường thẳng nào tách được.",[981,55328,55330],{"id":55329},"bài-2-mạng-2-lớp-giải-xor-bằng-tay","Bài 2: Mạng 2 lớp giải XOR bằng tay",[973,55332,55333],{},"Không huấn luyện. Chọn tay trọng số cho mạng 2 đầu vào, 2 nơ-ron ẩn (bậc thang), 1 đầu ra để tính XOR.",[973,55335,55336],{},"Gợi ý: nơ-ron ẩn 1 tính OR, nơ-ron ẩn 2 tính NAND, đầu ra tính AND của 2 nơ-ron ẩn.",[1352,55338,55341],{"className":55339,"code":55340,"language":2241,"meta":1357},[2239],"forward([0,0]) = 0; forward([0,1]) = 1; forward([1,0]) = 1; forward([1,1]) = 0\n",[992,55342,55340],{"__ignoreMap":1357},[973,55344,55345,55346,55349],{},"In giá trị tầng ẩn cho 4 điểm. Vẽ 4 điểm trong ",[1487,55347,55348],{},"không gian ẩn",": chúng tách được bằng 1 đường thẳng.",[981,55351,55353],{"id":55352},"bài-3-mlp-forward-và-giới-hạn-tuyến-tính-nâng-cao","Bài 3: MLP forward và giới hạn tuyến tính (nâng cao)",[2273,55355,55356,55366,55377],{},[989,55357,1505,55358,55361,55362,55365],{},[992,55359,55360],{},"MLP(layer_sizes, activation)"," chỉ có ",[992,55363,55364],{},"forward"," với trọng số khởi tạo ngẫu nhiên (He\u002FXavier).",[989,55367,55368,55369,55372,55373,55376],{},"Chứng minh bằng số: mạng 3 tầng ",[1487,55370,55371],{},"không có hàm kích hoạt"," tương đương 1 ma trận duy nhất. Tính ",[992,55374,55375],{},"W = W3 @ W2 @ W1"," và so output với mạng gốc trên 100 input ngẫu nhiên.",[989,55378,55379,55380,55383],{},"Đếm số tham số của MLP ",[992,55381,55382],{},"[784, 256, 128, 10]",". Viết công thức tổng quát.",[981,55385,2711],{"id":2710},[986,55387,55389,55395,55401,55407],{"className":55388},[2715],[989,55390,55392,55394],{"className":55391},[2719],[2721,55393],{"disabled":2723,"type":2724}," Perceptron hội tụ trên AND, OR và thất bại trên XOR.",[989,55396,55398,55400],{"className":55397},[2719],[2721,55399],{"disabled":2723,"type":2724}," Mạng tay giải đúng XOR, có hình không gian ẩn.",[989,55402,55404,55406],{"className":55403},[2719],[2721,55405],{"disabled":2723,"type":2724}," Bài 3 chứng minh bằng số mạng tuyến tính sâu gộp thành 1 phép.",[989,55408,55410,55412],{"className":55409},[2719],[2721,55411],{"disabled":2723,"type":2724}," Giải thích được vì sao XOR cần tầng ẩn.",[968,55414,2890],{"id":2889},[986,55416,55417,55420,55423,55426],{},[989,55418,55419],{},"Perceptron tính output thế nào?",[989,55421,55422],{},"Vì sao 1 đường thẳng không giải được XOR?",[989,55424,55425],{},"Tầng ẩn giúp gì cho XOR?",[989,55427,55428],{},"Mạng sâu khác mạng rộng ra sao?",[3014,55430],{},[973,55432,55433],{},"🌕 Bạn đã hoàn thành ngày 93. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,55435,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":55437},[55438,55439,55444,55445,55451],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":55440},[55441,55442,55443],{"id":55145,"depth":73,"text":55146},{"id":55166,"depth":73,"text":55167},{"id":55225,"depth":73,"text":55226},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":55446},[55447,55448,55449,55450],{"id":55286,"depth":73,"text":55287},{"id":55329,"depth":73,"text":55330},{"id":55352,"depth":73,"text":55353},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Perceptron Rosenblatt, giới hạn XOR của Minsky-Papert, kiến trúc nhiều lớp, hidden layer và trực giác hình học của mạng noron sâu.",{},[15144],{"title":520,"description":55452},[55457],"neural-network","qN_ljw0A0NE4-qRRg-8EJty_QAneu20t-33BK8SFKds",{"id":55460,"title":525,"body":55461,"category":8797,"day":528,"description":56126,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":56127,"navigation":2723,"outcomes":3047,"path":526,"prerequisites":56128,"seo":56129,"stem":527,"tags":56130,"__hash__":56131},"challenges\u002Fchallenges\u002F94.huan-luyen-mang.md",{"type":965,"value":55462,"toc":56109},[55463,55465,55468,55470,55474,55491,55495,55512,55572,55576,55593,55597,55633,55635,55643,55663,55665,55673,55677,55712,55991,55997,56001,56007,56031,56035,56055,56057,56086,56088,56102,56104,56107],[968,55464,971],{"id":970},[973,55466,55467],{},"Bài này học loss, lan truyền ngược và hàm kích hoạt.\nDùng để huấn luyện mạng noron chạy được thật.",[968,55469,979],{"id":978},[981,55471,55473],{"id":55472},"loss-và-gradient-descent","Loss và gradient descent",[986,55475,55476,55479,55482,55485,55488],{},[989,55477,55478],{},"Định nghĩa: loss đo khoảng cách giữa đoán và nhãn đúng.",[989,55480,55481],{},"Mục tiêu học là tìm trọng số làm loss nhỏ nhất.",[989,55483,55484],{},"Ví dụ đời thường: như đo độ lệch bia bắn khỏi hồng tâm.",[989,55486,55487],{},"Gradient descent: bước ngược hướng dốc để xuống đáy.",[989,55489,55490],{},"Tốc độ học lớn thì vọt qua đáy, bé thì bò chậm.",[981,55492,55494],{"id":55493},"lan-truyền-ngược","Lan truyền ngược",[986,55496,55497,55500,55503,55506,55509],{},[989,55498,55499],{},"Định nghĩa: chia lỗi đầu ra ngược về từng noron.",[989,55501,55502],{},"Noron góp lỗi nhiều thì chỉnh nhiều hơn.",[989,55504,55505],{},"Ví dụ đời thường: như truy trách nhiệm từ cuối dây chuyền.",[989,55507,55508],{},"Gồm 2 pha: lan xuôi tính đoán, lan ngược chỉnh.",[989,55510,55511],{},"Dùng quy tắc dây chuyền để tính đạo hàm từng lớp.",[1099,55513,55514,55526],{},[1102,55515,55516],{},[1105,55517,55518,55521,55524],{},[1108,55519,55520],{},"Hàm kích hoạt",[1108,55522,55523],{},"Dạng",[1108,55525,10673],{},[1118,55527,55528,55539,55550,55561],{},[1105,55529,55530,55533,55536],{},[1123,55531,55532],{},"Sigmoid",[1123,55534,55535],{},"Cong 0 tới 1",[1123,55537,55538],{},"Đầu ra nhị phân",[1105,55540,55541,55544,55547],{},[1123,55542,55543],{},"ReLU",[1123,55545,55546],{},"Giữ dương, cắt âm",[1123,55548,55549],{},"Tầng ẩn mặc định",[1105,55551,55552,55555,55558],{},[1123,55553,55554],{},"Softmax",[1123,55556,55557],{},"Thành xác suất",[1123,55559,55560],{},"Phân loại nhiều lớp",[1105,55562,55563,55566,55569],{},[1123,55564,55565],{},"Tanh",[1123,55567,55568],{},"Từ -1 tới 1",[1123,55570,55571],{},"Dữ liệu quanh 0",[981,55573,55575],{"id":55574},"siêu-tham-số","Siêu tham số",[986,55577,55578,55581,55584,55587,55590],{},[989,55579,55580],{},"Định nghĩa: số do người chọn, mạng không tự học.",[989,55582,55583],{},"Gồm tốc độ học, số epoch, cỡ batch.",[989,55585,55586],{},"Ví dụ đời thường: như núm vặn bếp do đầu bếp chỉnh.",[989,55588,55589],{},"Sai siêu tham số thì mạng giỏi cũng học hỏng.",[989,55591,55592],{},"Nên thử vài giá trị rồi đo trên tập kiểm tra.",[981,55594,55596],{"id":55595},"thêm-hàm-kích-hoạt","Thêm hàm kích hoạt",[1099,55598,55599,55609],{},[1102,55600,55601],{},[1105,55602,55603,55605,55607],{},[1108,55604,1566],{},[1108,55606,55523],{},[1108,55608,17655],{},[1118,55610,55611,55622],{},[1105,55612,55613,55616,55619],{},[1123,55614,55615],{},"Bậc thang (step)",[1123,55617,55618],{},"0 hoặc 1",[1123,55620,55621],{},"Dùng trong perceptron gốc, không có đạo hàm để lan ngược",[1105,55623,55624,55627,55630],{},[1123,55625,55626],{},"Leaky ReLU",[1123,55628,55629],{},"Giữ dương, âm nhân hệ số nhỏ như 0.01",[1123,55631,55632],{},"Tránh nơ-ron \"chết\" khi luôn nhận đầu vào âm",[968,55634,1433],{"id":1432},[986,55636,55637,55640],{},[989,55638,55639],{},"Input: loss dao động vọt lên xuống -> Output: giảm tốc độ học.",[989,55641,55642],{},"Giải thích: bước quá lớn nên nhảy qua đáy liên tục.",[1352,55644,55646],{"className":3538,"code":55645,"language":3540,"meta":1357,"style":1357},"# Cập nhật 1 trọng số theo gradient\nw = w - toc_do_hoc * dao_ham  # bước ngược dốc\nprint(w)  # trọng số mới\n",[992,55647,55648,55653,55658],{"__ignoreMap":1357},[1023,55649,55650],{"class":1362,"line":63},[1023,55651,55652],{},"# Cập nhật 1 trọng số theo gradient\n",[1023,55654,55655],{"class":1362,"line":68},[1023,55656,55657],{},"w = w - toc_do_hoc * dao_ham  # bước ngược dốc\n",[1023,55659,55660],{"class":1362,"line":73},[1023,55661,55662],{},"print(w)  # trọng số mới\n",[968,55664,1482],{"id":1481},[973,55666,1485,55667,55669,55670,1517],{},[1487,55668,13531],{}," với NumPy. Không dùng thư viện học sâu cho Bài 1-2. Nộp vào ",[992,55671,55672],{},"day-094\u002F",[981,55674,55676],{"id":55675},"bài-1-backprop-cho-mlp","Bài 1: Backprop cho MLP",[1352,55678,55680],{"className":3538,"code":55679,"language":3540,"meta":1357,"style":1357},"class MLP:\n    def __init__(self, sizes: list[int], activation=\"relu\", seed=0): ...\n    def forward(self, X) -> np.ndarray: ...            # đầu ra softmax, lưu cache cho backward\n    def backward(self, y_onehot) -> list[tuple]: ...   # trả (dW, db) mỗi tầng\n    def step(self, grads, lr): ...\ndef cross_entropy(probs, y_onehot) -> float: ...\n",[992,55681,55682,55687,55692,55697,55702,55707],{"__ignoreMap":1357},[1023,55683,55684],{"class":1362,"line":63},[1023,55685,55686],{},"class MLP:\n",[1023,55688,55689],{"class":1362,"line":68},[1023,55690,55691],{},"    def __init__(self, sizes: list[int], activation=\"relu\", seed=0): ...\n",[1023,55693,55694],{"class":1362,"line":73},[1023,55695,55696],{},"    def forward(self, X) -> np.ndarray: ...            # đầu ra softmax, lưu cache cho backward\n",[1023,55698,55699],{"class":1362,"line":78},[1023,55700,55701],{},"    def backward(self, y_onehot) -> list[tuple]: ...   # trả (dW, db) mỗi tầng\n",[1023,55703,55704],{"class":1362,"line":83},[1023,55705,55706],{},"    def step(self, grads, lr): ...\n",[1023,55708,55709],{"class":1362,"line":88},[1023,55710,55711],{},"def cross_entropy(probs, y_onehot) -> float: ...\n",[973,55713,55714,55717,55718,55721,55722,55725,55726,1656,55894,55988,55989,1517],{},[1487,55715,55716],{},"Kiểm tra gradient"," bắt buộc: với mạng nhỏ ",[992,55719,55720],{},"[4, 5, 3]",", so ",[992,55723,55724],{},"dW"," từ backprop với sai phân trung tâm ",[1023,55727,55729,55777],{"className":55728},[1026],[1023,55730,55732],{"className":55731},[1030],[1032,55733,55734],{"xmlns":1034},[1036,55735,55736,55774],{},[1039,55737,55738],{},[18110,55739,55740,55768],{},[1039,55741,55742,55744,55746,55748,55750,55752,55754,55756,55758,55760,55762,55764,55766],{},[1042,55743,4772],{},[1046,55745,1049],{"stretchy":1048},[1042,55747,27557],{},[1046,55749,21881],{},[1042,55751,7908],{},[1046,55753,1056],{"stretchy":1048},[1046,55755,17698],{},[1042,55757,4772],{},[1046,55759,1049],{"stretchy":1048},[1042,55761,27557],{},[1046,55763,17698],{},[1042,55765,7908],{},[1046,55767,1056],{"stretchy":1048},[1039,55769,55770,55772],{},[1051,55771,2457],{},[1042,55773,7908],{},[1058,55775,55776],{"encoding":1060},"\\frac{L(w+h) - L(w-h)}{2h}",[1023,55778,55780],{"className":55779,"ariaHidden":1066},[1065],[1023,55781,55783,55787],{"className":55782},[1070],[1023,55784],{"className":55785,"style":55786},[1074],"height:1.355em;vertical-align:-0.345em;",[1023,55788,55790,55793,55891],{"className":55789},[1079],[1023,55791],{"className":55792},[1085,18174],[1023,55794,55796],{"className":55795},[18110],[1023,55797,55799,55883],{"className":55798},[2387,17732],[1023,55800,55802,55880],{"className":55801},[2391],[1023,55803,55805,55822,55830],{"className":55804,"style":37492},[2395],[1023,55806,55807,55810],{"style":18190},[1023,55808],{"className":55809,"style":18194},[2402],[1023,55811,55813],{"className":55812},[2407,2408,2409,2410],[1023,55814,55816,55819],{"className":55815},[1079,2410],[1023,55817,2457],{"className":55818},[1079,2410],[1023,55820,7908],{"className":55821},[1079,1080,2410],[1023,55823,55824,55827],{"style":18221},[1023,55825],{"className":55826,"style":18194},[2402],[1023,55828],{"className":55829,"style":18229},[18228],[1023,55831,55832,55835],{"style":37607},[1023,55833],{"className":55834,"style":18194},[2402],[1023,55836,55838],{"className":55837},[2407,2408,2409,2410],[1023,55839,55841,55844,55847,55850,55853,55856,55859,55862,55865,55868,55871,55874,55877],{"className":55840},[1079,2410],[1023,55842,4772],{"className":55843},[1079,1080,2410],[1023,55845,1049],{"className":55846},[1085,2410],[1023,55848,27557],{"className":55849,"style":37436},[1079,1080,2410],[1023,55851,21881],{"className":55852},[13794,2410],[1023,55854,7908],{"className":55855},[1079,1080,2410],[1023,55857,1056],{"className":55858},[1092,2410],[1023,55860,17698],{"className":55861},[13794,2410],[1023,55863,4772],{"className":55864},[1079,1080,2410],[1023,55866,1049],{"className":55867},[1085,2410],[1023,55869,27557],{"className":55870,"style":37436},[1079,1080,2410],[1023,55872,17698],{"className":55873},[13794,2410],[1023,55875,7908],{"className":55876},[1079,1080,2410],[1023,55878,1056],{"className":55879},[1092,2410],[1023,55881,17797],{"className":55882},[17796],[1023,55884,55886],{"className":55885},[2391],[1023,55887,55889],{"className":55888,"style":45484},[2395],[1023,55890],{},[1023,55892],{"className":55893},[1092,18174],[1023,55895,55897,55923],{"className":55896},[1026],[1023,55898,55900],{"className":55899},[1030],[1032,55901,55902],{"xmlns":1034},[1036,55903,55904,55920],{},[1039,55905,55906,55908,55910],{},[1042,55907,7908],{},[1046,55909,2325],{},[2327,55911,55912,55914],{},[1051,55913,2331],{},[1039,55915,55916,55918],{},[1046,55917,17698],{},[1051,55919,2334],{},[1058,55921,55922],{"encoding":1060},"h = 10^{-5}",[1023,55924,55926,55944],{"className":55925,"ariaHidden":1066},[1065],[1023,55927,55929,55932,55935,55938,55941],{"className":55928},[1070],[1023,55930],{"className":55931,"style":22079},[1074],[1023,55933,7908],{"className":55934},[1079,1080],[1023,55936],{"className":55937,"style":2355},[2354],[1023,55939,2325],{"className":55940},[2359],[1023,55942],{"className":55943,"style":2355},[2354],[1023,55945,55947,55950,55953],{"className":55946},[1070],[1023,55948],{"className":55949,"style":2369},[1074],[1023,55951,1053],{"className":55952},[1079],[1023,55954,55956,55959],{"className":55955},[1079],[1023,55957,2379],{"className":55958},[1079],[1023,55960,55962],{"className":55961},[2383],[1023,55963,55965],{"className":55964},[2387],[1023,55966,55968],{"className":55967},[2391],[1023,55969,55971],{"className":55970,"style":2369},[2395],[1023,55972,55973,55976],{"style":2398},[1023,55974],{"className":55975,"style":2403},[2402],[1023,55977,55979],{"className":55978},[2407,2408,2409,2410],[1023,55980,55982,55985],{"className":55981},[1079,2410],[1023,55983,17698],{"className":55984},[1079,2410],[1023,55986,2334],{"className":55987},[1079,2410],". Sai số tương đối dưới ",[992,55990,32245],{},[1352,55992,55995],{"className":55993,"code":55994,"language":2241,"meta":1357},[2239],"Học XOR với [2, 4, 2], 2000 bước -> accuracy 100%\ngradient check -> relative error \u003C 1e-6 cho mọi tầng\n",[992,55996,55994],{"__ignoreMap":1357},[981,55998,56000],{"id":55999},"bài-2-huấn-luyện-trên-chữ-số-viết-tay","Bài 2: Huấn luyện trên chữ số viết tay",[973,56002,56003,56004,56006],{},"Bộ ",[992,56005,51189],{}," (8x8, 10 lớp) hoặc MNIST.",[2273,56008,56009,56012,56019],{},[989,56010,56011],{},"Mini-batch SGD, batch 32, 30 epoch. Vẽ loss và accuracy train\u002Fvalidation theo epoch.",[989,56013,56014,56015,56018],{},"Quét ",[992,56016,56017],{},"lr = 1.0, 0.1, 0.01, 0.001",". Vẽ 4 đường loss. Chỉ ra lr nào dao động, lr nào bò chậm.",[989,56020,49241,56021,1656,56024,1656,56027,56030],{},[992,56022,56023],{},"sigmoid",[992,56025,56026],{},"tanh",[992,56028,56029],{},"relu"," ở tầng ẩn: accuracy sau 30 epoch.",[981,56032,56034],{"id":56033},"bài-3-so-với-pytorch-nâng-cao","Bài 3: So với PyTorch (nâng cao)",[2273,56036,56037,56040,56049],{},[989,56038,56039],{},"Dựng cùng kiến trúc bằng PyTorch. Khởi tạo cùng trọng số với mạng tự cài (copy từ NumPy sang). Chạy 1 bước. So gradient: phải khớp.",[989,56041,5030,56042,1509,56045,56048],{},[1487,56043,56044],{},"momentum",[1487,56046,56047],{},"Adam"," vào mạng tự cài. So tốc độ hội tụ với SGD thuần.",[989,56050,5030,56051,56054],{},[1487,56052,56053],{},"dừng sớm"," theo validation loss (patience 5).",[981,56056,2711],{"id":2710},[986,56058,56060,56066,56072,56078],{"className":56059},[2715],[989,56061,56063,56065],{"className":56062},[2719],[2721,56064],{"disabled":2723,"type":2724}," Gradient check pass.",[989,56067,56069,56071],{"className":56068},[2719],[2721,56070],{"disabled":2723,"type":2724}," Accuracy test chữ số trên 95% (load_digits).",[989,56073,56075,56077],{"className":56074},[2719],[2721,56076],{"disabled":2723,"type":2724}," Có hình loss theo lr và bảng so sánh hàm kích hoạt.",[989,56079,56081,56083,56084,1517],{"className":56080},[2719],[2721,56082],{"disabled":2723,"type":2724}," Gradient khớp PyTorch sai số ",[992,56085,32245],{},[968,56087,2890],{"id":2889},[986,56089,56090,56093,56096,56099],{},[989,56091,56092],{},"Loss dùng để làm gì?",[989,56094,56095],{},"Lan truyền ngược chia lỗi thế nào?",[989,56097,56098],{},"ReLU khác sigmoid ở đâu?",[989,56100,56101],{},"Siêu tham số khác tham số thế nào?",[3014,56103],{},[973,56105,56106],{},"🌕 Bạn đã hoàn thành ngày 94. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,56108,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":56110},[56111,56112,56118,56119,56125],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":56113},[56114,56115,56116,56117],{"id":55472,"depth":73,"text":55473},{"id":55493,"depth":73,"text":55494},{"id":55574,"depth":73,"text":55575},{"id":55595,"depth":73,"text":55596},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":56120},[56121,56122,56123,56124],{"id":55675,"depth":73,"text":55676},{"id":55999,"depth":73,"text":56000},{"id":56033,"depth":73,"text":56034},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hàm mất mát, lan truyền ngược, gradient descent, sáu hàm kích hoạt step sigmoid ReLU leaky ReLU tanh softmax và siêu tham số Keras.",{},[17499],{"title":525,"description":56126},[55457],"J2yxOIoCGrd1czv9LZhZxv_A6FuApYm-f2DVvqt6PL0",{"id":56133,"title":530,"body":56134,"category":5189,"day":533,"description":56581,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":56582,"navigation":2723,"outcomes":3047,"path":531,"prerequisites":56583,"seo":56584,"stem":532,"tags":56585,"__hash__":56586},"challenges\u002Fchallenges\u002F95.mediator-memento-prototype.md",{"type":965,"value":56135,"toc":56565},[56136,56138,56141,56143,56147,56164,56168,56185,56232,56235,56252,56254,56262,56287,56289,56296,56300,56343,56380,56386,56397,56401,56439,56450,56456,56460,56508,56510,56542,56544,56558,56560,56563],[968,56137,971],{"id":970},[973,56139,56140],{},"Bài này học trạm điều phối, vé lưu game và nhân bản mẫu.\nDùng để giảm dây nối chằng chịt giữa các object.",[968,56142,979],{"id":978},[981,56144,56146],{"id":56145},"mediator","Mediator",[986,56148,56149,56152,56155,56158,56161],{},[989,56150,56151],{},"Định nghĩa: một trạm gom mọi giao tiếp giữa các object.",[989,56153,56154],{},"Các object chỉ biết trạm, không biết nhau.",[989,56156,56157],{},"Ví dụ đời thường: như tháp không lưu điều phối máy bay.",[989,56159,56160],{},"Thêm máy mới chỉ cần đăng ký vào trạm.",[989,56162,56163],{},"Tránh số đường nối tăng theo bình phương.",[981,56165,56167],{"id":56166},"memento","Memento",[986,56169,56170,56173,56176,56179,56182],{},[989,56171,56172],{},"Định nghĩa: chụp trạng thái để khôi phục sau mà không lộ ruột.",[989,56174,56175],{},"Gồm 3 vai: nhân vật tự chụp, vé nhớ kín, menu giữ vé.",[989,56177,56178],{},"Ví dụ đời thường: như vé save game cất két không cần đọc.",[989,56180,56181],{},"Menu chỉ cất vé, không được mở xem bên trong.",[989,56183,56184],{},"Muốn quay lại thì lấy vé đưa nhân vật tự hồi.",[1099,56186,56187,56199],{},[1102,56188,56189],{},[1105,56190,56191,56193,56196],{},[1108,56192,41388],{},[1108,56194,56195],{},"Nỗi đau",[1108,56197,56198],{},"Cách giải",[1118,56200,56201,56211,56221],{},[1105,56202,56203,56205,56208],{},[1123,56204,56146],{},[1123,56206,56207],{},"Object nối nhau chằng chịt",[1123,56209,56210],{},"Nói qua 1 trạm",[1105,56212,56213,56215,56218],{},[1123,56214,56167],{},[1123,56216,56217],{},"Muốn undo mà lộ nội tạng",[1123,56219,56220],{},"Chụp vé kín",[1105,56222,56223,56226,56229],{},[1123,56224,56225],{},"Prototype",[1123,56227,56228],{},"Tạo mới tốn kém",[1123,56230,56231],{},"Clone từ mẫu",[981,56233,56225],{"id":56234},"prototype",[986,56236,56237,56240,56243,56246,56249],{},[989,56238,56239],{},"Định nghĩa: tạo object mới bằng cách clone mẫu có sẵn.",[989,56241,56242],{},"Nhanh hơn dựng từ đầu khi khởi tạo nặng.",[989,56244,56245],{},"Ví dụ đời thường: như photo đơn mẫu thay vì viết lại.",[989,56247,56248],{},"Clone sâu thì độc lập, clone nông thì chia sẻ ruột.",[989,56250,56251],{},"Cần chú ý sao chép đúng phần thay đổi được.",[968,56253,1433],{"id":1432},[986,56255,56256,56259],{},[989,56257,56258],{},"Input: 10 máy bay cần phối hợp -> Output: mỗi máy chỉ nối 1 trạm.",[989,56260,56261],{},"Giải thích: không còn đường nối tay đôi bình phương nữa.",[1352,56263,56265],{"className":3538,"code":56264,"language":3540,"meta":1357,"style":1357},"# Clone mẫu thay vì dựng mới\nimport copy\nquai_moi = copy.deepcopy(quai_mau)  # sao chép độc lập\nprint(quai_moi)  # dùng ngay\n",[992,56266,56267,56272,56277,56282],{"__ignoreMap":1357},[1023,56268,56269],{"class":1362,"line":63},[1023,56270,56271],{},"# Clone mẫu thay vì dựng mới\n",[1023,56273,56274],{"class":1362,"line":68},[1023,56275,56276],{},"import copy\n",[1023,56278,56279],{"class":1362,"line":73},[1023,56280,56281],{},"quai_moi = copy.deepcopy(quai_mau)  # sao chép độc lập\n",[1023,56283,56284],{"class":1362,"line":78},[1023,56285,56286],{},"print(quai_moi)  # dùng ngay\n",[968,56288,1482],{"id":1481},[973,56290,1485,56291,4801,56293,1517],{},[1487,56292,4800],{},[992,56294,56295],{},"day-095\u002F",[981,56297,56299],{"id":56298},"bài-1-mediator-cho-tháp-điều-khiển","Bài 1: Mediator cho tháp điều khiển",[1352,56301,56303],{"className":1393,"code":56302,"language":1395,"meta":1357,"style":1357},"struct Mediator { virtual void notify(Aircraft &sender, const std::string &event) = 0; virtual ~Mediator() = default; };\nclass ControlTower : public Mediator { \u002F* giữ danh sách máy bay và trạng thái đường băng *\u002F };\nclass Aircraft {\n public:\n  Aircraft(std::string callsign, Mediator &m);\n  void requestLanding(); void landed(); void requestTakeoff(); void tookOff();\n  void receive(const std::string &msg);   \u002F\u002F lưu tin nhắn nhận được để test\n};\n",[992,56304,56305,56310,56315,56320,56324,56329,56334,56339],{"__ignoreMap":1357},[1023,56306,56307],{"class":1362,"line":63},[1023,56308,56309],{},"struct Mediator { virtual void notify(Aircraft &sender, const std::string &event) = 0; virtual ~Mediator() = default; };\n",[1023,56311,56312],{"class":1362,"line":68},[1023,56313,56314],{},"class ControlTower : public Mediator { \u002F* giữ danh sách máy bay và trạng thái đường băng *\u002F };\n",[1023,56316,56317],{"class":1362,"line":73},[1023,56318,56319],{},"class Aircraft {\n",[1023,56321,56322],{"class":1362,"line":78},[1023,56323,4836],{},[1023,56325,56326],{"class":1362,"line":83},[1023,56327,56328],{},"  Aircraft(std::string callsign, Mediator &m);\n",[1023,56330,56331],{"class":1362,"line":88},[1023,56332,56333],{},"  void requestLanding(); void landed(); void requestTakeoff(); void tookOff();\n",[1023,56335,56336],{"class":1362,"line":93},[1023,56337,56338],{},"  void receive(const std::string &msg);   \u002F\u002F lưu tin nhắn nhận được để test\n",[1023,56340,56341],{"class":1362,"line":98},[1023,56342,4866],{},[1099,56344,56345,56354],{},[1102,56346,56347],{},[1105,56348,56349,56352],{},[1108,56350,56351],{},"Luật của tháp",[1108,56353,14241],{},[1118,56355,56356,56364,56372],{},[1105,56357,56358,56361],{},[1123,56359,56360],{},"1 đường băng",[1123,56362,56363],{},"Chỉ 1 máy dùng tại một thời điểm",[1105,56365,56366,56369],{},[1123,56367,56368],{},"Hạ cánh ưu tiên hơn cất cánh",[1123,56370,56371],{},"Hàng chờ riêng",[1105,56373,56374,56377],{},[1123,56375,56376],{},"Đường băng trống",[1123,56378,56379],{},"Tháp báo máy kế tiếp trong hàng",[1352,56381,56384],{"className":56382,"code":56383,"language":2241,"meta":1357},[2239],"A xin hạ cánh -> A nhận \"được hạ cánh\"\nB xin cất cánh -> B nhận \"chờ\"\nC xin hạ cánh -> C nhận \"chờ\"\nA báo đã hạ cánh -> C (ưu tiên hạ cánh) nhận \"được hạ cánh\", B vẫn chờ\n",[992,56385,56383],{"__ignoreMap":1357},[973,56387,56388,2308,56390,56393,56394,56396],{},[1487,56389,6076],{},[992,56391,56392],{},"Aircraft"," không giữ tham chiếu tới ",[992,56395,56392],{}," khác.",[981,56398,56400],{"id":56399},"bài-2-memento-cho-trình-soạn-thảo","Bài 2: Memento cho trình soạn thảo",[1352,56402,56404],{"className":1393,"code":56403,"language":1395,"meta":1357,"style":1357},"class Editor {\n public:\n  void type(const std::string &s); void moveCursor(int pos); void select(int from, int to);\n  class Memento { friend class Editor; \u002F* private: text, cursor, selection *\u002F };\n  Memento save() const; void restore(const Memento &m);\n};\nclass History { public: void push(Editor::Memento m); std::optional\u003CEditor::Memento> pop(); };\n",[992,56405,56406,56411,56415,56420,56425,56430,56434],{"__ignoreMap":1357},[1023,56407,56408],{"class":1362,"line":63},[1023,56409,56410],{},"class Editor {\n",[1023,56412,56413],{"class":1362,"line":68},[1023,56414,4836],{},[1023,56416,56417],{"class":1362,"line":73},[1023,56418,56419],{},"  void type(const std::string &s); void moveCursor(int pos); void select(int from, int to);\n",[1023,56421,56422],{"class":1362,"line":78},[1023,56423,56424],{},"  class Memento { friend class Editor; \u002F* private: text, cursor, selection *\u002F };\n",[1023,56426,56427],{"class":1362,"line":83},[1023,56428,56429],{},"  Memento save() const; void restore(const Memento &m);\n",[1023,56431,56432],{"class":1362,"line":88},[1023,56433,4866],{},[1023,56435,56436],{"class":1362,"line":93},[1023,56437,56438],{},"class History { public: void push(Editor::Memento m); std::optional\u003CEditor::Memento> pop(); };\n",[973,56440,56441,2308,56443,56446,56447,56449],{},[1487,56442,6076],{},[992,56444,56445],{},"History"," không đọc được nội dung ",[992,56448,56167],{}," (không có getter public).",[1352,56451,56454],{"className":56452,"code":56453,"language":2241,"meta":1357},[2239],"type \"Hello\"; save; type \" World\"; save; type \"!\"\nrestore 2 lần -> \"Hello\", con trỏ đúng vị trí lúc lưu\n",[992,56455,56453],{"__ignoreMap":1357},[981,56457,56459],{"id":56458},"bài-3-prototype-và-clone-sâu-nâng-cao","Bài 3: Prototype và clone sâu (nâng cao)",[2273,56461,56462,56482,56488,56498],{},[989,56463,56464,5059,56467,7423,56470,1656,56473,1656,56475,56478,56479,16014],{},[992,56465,56466],{},"Shape",[992,56468,56469],{},"virtual std::unique_ptr\u003CShape> clone() const = 0",[992,56471,56472],{},"Circle",[992,56474,5058],{},[992,56476,56477],{},"Group"," (chứa ",[992,56480,56481],{},"vector\u003Cunique_ptr\u003CShape>>",[989,56483,56484,56487],{},[992,56485,56486],{},"Group::clone()"," phải clone sâu. Viết test: sửa bản clone không đổi bản gốc.",[989,56489,1505,56490,56493,56494,56497],{},[992,56491,56492],{},"ShapeRegistry",": đăng ký mẫu theo tên, ",[992,56495,56496],{},"create(name)"," trả bản clone.",[989,56499,56500,56501,56503,56504,56507],{},"Cố tình viết bản clone nông cho ",[992,56502,56477],{}," (dùng ",[992,56505,56506],{},"shared_ptr"," chia sẻ con). Viết test cho thấy lỗi.",[981,56509,2711],{"id":2710},[986,56511,56513,56519,56530,56536],{"className":56512},[2715],[989,56514,56516,56518],{"className":56515},[2719],[2721,56517],{"disabled":2723,"type":2724}," Test tháp điều khiển pass đúng thứ tự ưu tiên.",[989,56520,56522,2308,56524,56526,56527,56529],{"className":56521},[2719],[2721,56523],{"disabled":2723,"type":2724},[992,56525,56445],{}," không truy cập được ruột ",[992,56528,56167],{}," (kiểm bằng biên dịch).",[989,56531,56533,56535],{"className":56532},[2719],[2721,56534],{"disabled":2723,"type":2724}," Clone sâu độc lập, có test chứng minh clone nông sai.",[989,56537,56539,56541],{"className":56538},[2719],[2721,56540],{"disabled":2723,"type":2724}," Viết 1 câu cho mỗi pattern: vấn đề nó giải quyết.",[968,56543,2890],{"id":2889},[986,56545,56546,56549,56552,56555],{},[989,56547,56548],{},"Mediator giảm dây nối thế nào?",[989,56550,56551],{},"3 vai trong Memento là gì?",[989,56553,56554],{},"Khi nào nên clone thay vì new?",[989,56556,56557],{},"Clone nông khác clone sâu ra sao?",[3014,56559],{},[973,56561,56562],{},"🌕 Bạn đã hoàn thành ngày 95. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,56564,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":56566},[56567,56568,56573,56574,56580],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":56569},[56570,56571,56572],{"id":56145,"depth":73,"text":56146},{"id":56166,"depth":73,"text":56167},{"id":56234,"depth":73,"text":56225},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":56575},[56576,56577,56578,56579],{"id":56298,"depth":73,"text":56299},{"id":56399,"depth":73,"text":56400},{"id":56458,"depth":73,"text":56459},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Trạm điều phối máy bay, vé lưu trạng thái game, và bản sao mẫu thay vì tạo mới trong ba pattern bổ sung.",{},[5194],{"title":530,"description":56581},[41703,56145,56166,56234],"xIRkiTEVw6q7lDwRiGZEVb_ZqVHaesb6eJGZy85DpEE",{"id":56588,"title":535,"body":56589,"category":8797,"day":538,"description":57311,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":57312,"navigation":2723,"outcomes":3047,"path":536,"prerequisites":57313,"seo":57314,"stem":537,"tags":57315,"__hash__":57317},"challenges\u002Fchallenges\u002F96.cnn.md",{"type":965,"value":56590,"toc":57295},[56591,56593,56596,56598,56602,56619,56623,56640,56689,56693,56710,56712,56720,56740,56742,56754,56758,56967,56973,56980,56984,57210,57214,57235,57237,57272,57274,57288,57290,57293],[968,56592,971],{"id":970},[973,56594,56595],{},"Bài này học kernel quét ảnh và tầng gộp thu nhỏ.\nDùng để nhận diện ảnh nhanh hơn MLP rất nhiều.",[968,56597,979],{"id":978},[981,56599,56601],{"id":56600},"tích-chập","Tích chập",[986,56603,56604,56607,56610,56613,56616],{},[989,56605,56606],{},"Định nghĩa: kernel nhỏ trượt khắp ảnh để đo độ khớp mẫu.",[989,56608,56609],{},"Cùng kernel dùng chung trọng số trên toàn ảnh.",[989,56611,56612],{},"Ví dụ đời thường: như con tem dò khắp bản đồ tìm hình.",[989,56614,56615],{},"Mẫu học ở góc trái vẫn nhận ra ở góc phải.",[989,56617,56618],{},"Số tham số giảm mạnh so với nối đầy đủ.",[981,56620,56622],{"id":56621},"stride-và-padding","Stride và padding",[986,56624,56625,56628,56631,56634,56637],{},[989,56626,56627],{},"Kernel: cửa sổ nhìn rộng bao nhiêu mỗi lần.",[989,56629,56630],{},"Stride: mỗi bước nhảy mấy điểm ảnh.",[989,56632,56633],{},"Padding: có bọc viền để giữ kích thước biên không.",[989,56635,56636],{},"Ví dụ đời thường: như bước chân dài thì mau hết sân.",[989,56638,56639],{},"Stride lớn thì bản đồ đặc trưng co nhanh.",[1099,56641,56642,56655],{},[1102,56643,56644],{},[1105,56645,56646,56649,56652],{},[1108,56647,56648],{},"Tham số",[1108,56650,56651],{},"Tăng lên thì",[1108,56653,56654],{},"Giảm xuống thì",[1118,56656,56657,56667,56678],{},[1105,56658,56659,56661,56664],{},[1123,56660,53304],{},[1123,56662,56663],{},"Nhìn rộng hơn",[1123,56665,56666],{},"Nhìn chi tiết hơn",[1105,56668,56669,56672,56675],{},[1123,56670,56671],{},"Stride",[1123,56673,56674],{},"Ảnh ra nhỏ hơn",[1123,56676,56677],{},"Ảnh ra lớn hơn",[1105,56679,56680,56683,56686],{},[1123,56681,56682],{},"Padding",[1123,56684,56685],{},"Giữ biên tốt hơn",[1123,56687,56688],{},"Mất viền nhiều hơn",[981,56690,56692],{"id":56691},"pooling-và-phân-cấp","Pooling và phân cấp",[986,56694,56695,56698,56701,56704,56707],{},[989,56696,56697],{},"Định nghĩa: tóm tắt mỗi ô nhỏ thành 1 con số.",[989,56699,56700],{},"Gộp cực đại giữ chi tiết nổi bật nhất mỗi ô.",[989,56702,56703],{},"Tầng thấp bắt cạnh, tầng cao bắt mặt và vật.",[989,56705,56706],{},"Ví dụ đời thường: như nhìn xa chỉ thấy hình lớn.",[989,56708,56709],{},"Nhờ đó CNN vượt MLP trên ảnh thật.",[968,56711,1433],{"id":1432},[986,56713,56714,56717],{},[989,56715,56716],{},"Input: ảnh 32x32, kernel 3x3, stride 1 -> Output: bản đồ ~30x30.",[989,56718,56719],{},"Giải thích: trừ viền kernel nên nhỏ hơn ảnh gốc một chút.",[1352,56721,56723],{"className":3538,"code":56722,"language":3540,"meta":1357,"style":1357},"# Gộp cực đại trên ô 2x2\no = max([1, 5, 3, 2])  # giữ số nổi bật nhất\nprint(o)  # 5\n",[992,56724,56725,56730,56735],{"__ignoreMap":1357},[1023,56726,56727],{"class":1362,"line":63},[1023,56728,56729],{},"# Gộp cực đại trên ô 2x2\n",[1023,56731,56732],{"class":1362,"line":68},[1023,56733,56734],{},"o = max([1, 5, 3, 2])  # giữ số nổi bật nhất\n",[1023,56736,56737],{"class":1362,"line":73},[1023,56738,56739],{},"print(o)  # 5\n",[968,56741,1482],{"id":1481},[973,56743,1485,56744,56746,56747,56750,56751,1517],{},[1487,56745,13531],{}," với NumPy cho Bài 1-2, ",[1487,56748,56749],{},"PyTorch"," cho Bài 3. Nộp vào ",[992,56752,56753],{},"day-096\u002F",[981,56755,56757],{"id":56756},"bài-1-tích-chập-và-gộp-tự-cài","Bài 1: Tích chập và gộp tự cài",[1099,56759,56760,56768],{},[1102,56761,56762],{},[1105,56763,56764,56766],{},[1108,56765,1566],{},[1108,56767,2547],{},[1118,56769,56770,56927,56947,56956],{},[1105,56771,56772,56777],{},[1123,56773,56774],{},[992,56775,56776],{},"conv2d(x, k, stride=1, padding=0)",[1123,56778,56779,13568,56781,1656,56784,13568,56786,56789,56790],{},[992,56780,3904],{},[992,56782,56783],{},"(H, W)",[992,56785,4022],{},[992,56787,56788],{},"(kh, kw)",". Kích thước ra ",[1023,56791,56793,56838],{"className":56792},[1026],[1023,56794,56796],{"className":56795},[1030],[1032,56797,56798],{"xmlns":1034},[1036,56799,56800,56835],{},[1039,56801,56802,56805,56807,56810,56812,56814,56816,56818,56820,56822,56824,56826,56828,56831,56833],{},[1046,56803,56804],{"stretchy":1048},"⌊",[1046,56806,1049],{"stretchy":1048},[1042,56808,56809],{},"H",[1046,56811,21881],{},[1051,56813,2457],{},[1042,56815,973],{},[1046,56817,17698],{},[1042,56819,4022],{},[1042,56821,7908],{},[1046,56823,1056],{"stretchy":1048},[1042,56825,2461],{"mathvariant":2460},[1042,56827,29577],{},[1046,56829,56830],{"stretchy":1048},"⌋",[1046,56832,21881],{},[1051,56834,1053],{},[1058,56836,56837],{"encoding":1060},"\\lfloor (H + 2p - kh) \u002F s \\rfloor + 1",[1023,56839,56841,56864,56885,56918],{"className":56840,"ariaHidden":1066},[1065],[1023,56842,56844,56847,56851,56855,56858,56861],{"className":56843},[1070],[1023,56845],{"className":56846,"style":1075},[1074],[1023,56848,56850],{"className":56849},[1085],"⌊(",[1023,56852,56809],{"className":56853,"style":56854},[1079,1080],"margin-right:0.0813em;",[1023,56856],{"className":56857,"style":13790},[2354],[1023,56859,21881],{"className":56860},[13794],[1023,56862],{"className":56863,"style":13790},[2354],[1023,56865,56867,56870,56873,56876,56879,56882],{"className":56866},[1070],[1023,56868],{"className":56869,"style":13936},[1074],[1023,56871,2457],{"className":56872},[1079],[1023,56874,973],{"className":56875},[1079,1080],[1023,56877],{"className":56878,"style":13790},[2354],[1023,56880,17698],{"className":56881},[13794],[1023,56883],{"className":56884,"style":13790},[2354],[1023,56886,56888,56891,56894,56897,56900,56903,56906,56909,56912,56915],{"className":56887},[1070],[1023,56889],{"className":56890,"style":1075},[1074],[1023,56892,4022],{"className":56893,"style":4066},[1079,1080],[1023,56895,7908],{"className":56896},[1079,1080],[1023,56898,1056],{"className":56899},[1092],[1023,56901,2461],{"className":56902},[1079],[1023,56904,29577],{"className":56905},[1079,1080],[1023,56907,56830],{"className":56908},[1092],[1023,56910],{"className":56911,"style":13790},[2354],[1023,56913,21881],{"className":56914},[13794],[1023,56916],{"className":56917,"style":13790},[2354],[1023,56919,56921,56924],{"className":56920},[1070],[1023,56922],{"className":56923,"style":10020},[1074],[1023,56925,1053],{"className":56926},[1079],[1105,56928,56929,56934],{},[1123,56930,56931],{},[992,56932,56933],{},"conv2d_multi(x, W, b, stride, padding)",[1123,56935,56936,13568,56938,1656,56941,13568,56944],{},[992,56937,3904],{},[992,56939,56940],{},"(C_in, H, W)",[992,56942,56943],{},"W",[992,56945,56946],{},"(C_out, C_in, kh, kw)",[1105,56948,56949,56954],{},[1123,56950,56951],{},[992,56952,56953],{},"maxpool2d(x, size=2, stride=2)",[1123,56955],{},[1105,56957,56958,56964],{},[1123,56959,56960,56963],{},[992,56961,56962],{},"im2col"," (tùy chọn)",[1123,56965,56966],{},"Tăng tốc bằng phép nhân ma trận",[1352,56968,56971],{"className":56969,"code":56970,"language":2241,"meta":1357},[2239],"Ảnh 32x32, kernel 3x3, stride 1, padding 0 -> 30x30\nẢnh 32x32, kernel 3x3, stride 1, padding 1 -> 32x32\nẢnh 32x32, kernel 5x5, stride 2, padding 0 -> 14x14\nmaxpool 4x4 -> 2x2\n",[992,56972,56970],{"__ignoreMap":1357},[973,56974,56975,56976,56979],{},"Kết quả khớp ",[992,56977,56978],{},"torch.nn.functional.conv2d"," (lưu ý PyTorch tính cross-correlation, không lật kernel).",[981,56981,56983],{"id":56982},"bài-2-kernel-phát-hiện-cạnh","Bài 2: Kernel phát hiện cạnh",[2273,56985,56986,56989,57207],{},[989,56987,56988],{},"Đọc ảnh xám. Áp kernel Sobel ngang, Sobel dọc, và làm mờ Gauss 5x5. Lưu 3 ảnh kết quả.",[989,56990,56991,56992,57206],{},"Tính độ lớn gradient ",[1023,56993,56995,57029],{"className":56994},[1026],[1023,56996,56998],{"className":56997},[1030],[1032,56999,57000],{"xmlns":1034},[1036,57001,57002,57026],{},[1039,57003,57004],{},[17680,57005,57006],{},[1039,57007,57008,57016,57018],{},[36676,57009,57010,57012,57014],{},[1042,57011,45867],{},[1042,57013,3904],{},[1051,57015,2457],{},[1046,57017,21881],{},[36676,57019,57020,57022,57024],{},[1042,57021,45867],{},[1042,57023,32887],{},[1051,57025,2457],{},[1058,57027,57028],{"encoding":1060},"\\sqrt{G_x^2 + G_y^2}",[1023,57030,57032],{"className":57031,"ariaHidden":1066},[1065],[1023,57033,57035,57039],{"className":57034},[1070],[1023,57036],{"className":57037,"style":57038},[1074],"height:1.84em;vertical-align:-0.6765em;",[1023,57040,57042],{"className":57041},[1079,17728],[1023,57043,57045,57197],{"className":57044},[2387,17732],[1023,57046,57048,57194],{"className":57047},[2391],[1023,57049,57052,57177],{"className":57050,"style":57051},[2395],"height:1.1635em;",[1023,57053,57056,57060],{"className":57054,"style":57055},[17743],"top:-3.8em;",[1023,57057],{"className":57058,"style":57059},[2402],"height:3.8em;",[1023,57061,57063,57116,57119,57122,57125],{"className":57062,"style":17752},[1079],[1023,57064,57066,57069],{"className":57065},[1079],[1023,57067,45867],{"className":57068},[1079,1080],[1023,57070,57072],{"className":57071},[2383],[1023,57073,57075,57107],{"className":57074},[2387,17732],[1023,57076,57078,57104],{"className":57077},[2391],[1023,57079,57081,57093],{"className":57080,"style":17874},[2395],[1023,57082,57084,57087],{"style":57083},"top:-2.453em;margin-left:0em;margin-right:0.05em;",[1023,57085],{"className":57086,"style":2403},[2402],[1023,57088,57090],{"className":57089},[2407,2408,2409,2410],[1023,57091,3904],{"className":57092},[1079,1080,2410],[1023,57094,57095,57098],{"style":17877},[1023,57096],{"className":57097,"style":2403},[2402],[1023,57099,57101],{"className":57100},[2407,2408,2409,2410],[1023,57102,2457],{"className":57103},[1079,2410],[1023,57105,17797],{"className":57106},[17796],[1023,57108,57110],{"className":57109},[2391],[1023,57111,57114],{"className":57112,"style":57113},[2395],"height:0.247em;",[1023,57115],{},[1023,57117],{"className":57118,"style":13790},[2354],[1023,57120,21881],{"className":57121},[13794],[1023,57123],{"className":57124,"style":13790},[2354],[1023,57126,57128,57131],{"className":57127},[1079],[1023,57129,45867],{"className":57130},[1079,1080],[1023,57132,57134],{"className":57133},[2383],[1023,57135,57137,57168],{"className":57136},[2387,17732],[1023,57138,57140,57165],{"className":57139},[2391],[1023,57141,57143,57154],{"className":57142,"style":17874},[2395],[1023,57144,57145,57148],{"style":57083},[1023,57146],{"className":57147,"style":2403},[2402],[1023,57149,57151],{"className":57150},[2407,2408,2409,2410],[1023,57152,32887],{"className":57153,"style":7723},[1079,1080,2410],[1023,57155,57156,57159],{"style":17877},[1023,57157],{"className":57158,"style":2403},[2402],[1023,57160,57162],{"className":57161},[2407,2408,2409,2410],[1023,57163,2457],{"className":57164},[1079,2410],[1023,57166,17797],{"className":57167},[17796],[1023,57169,57171],{"className":57170},[2391],[1023,57172,57175],{"className":57173,"style":57174},[2395],"height:0.3831em;",[1023,57176],{},[1023,57178,57180,57183],{"style":57179},"top:-3.1235em;",[1023,57181],{"className":57182,"style":57059},[2402],[1023,57184,57187],{"className":57185,"style":57186},[17896],"min-width:1.02em;height:1.88em;",[17899,57188,57191],{"xmlns":17901,"width":17902,"height":57189,"viewBox":57190,"preserveAspectRatio":17905},"1.88em","0 0 400000 1944",[17907,57192],{"d":57193},"M983 90\nl0 -0\nc4,-6.7,10,-10,18,-10 H400000v40\nH1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7\ns-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744\nc-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30\nc26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722\nc56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5\nc53.7,-170.3,84.5,-266.8,92.5,-289.5z\nM1001 80h400000v40h-400000z",[1023,57195,17797],{"className":57196},[17796],[1023,57198,57200],{"className":57199},[2391],[1023,57201,57204],{"className":57202,"style":57203},[2395],"height:0.6765em;",[1023,57205],{}," và lưu ảnh cạnh.",[989,57208,57209],{},"Dịch ảnh sang phải 5 pixel. Chứng minh bản đồ đặc trưng cũng dịch 5 pixel (tính tương biến tịnh tiến).",[981,57211,57213],{"id":57212},"bài-3-cnn-nhỏ-cho-chữ-số-nâng-cao","Bài 3: CNN nhỏ cho chữ số (nâng cao)",[2273,57215,57216,57223,57226,57232],{},[989,57217,57218,57219,57222],{},"Dựng CNN bằng PyTorch: ",[992,57220,57221],{},"Conv(1,16,3) - ReLU - MaxPool - Conv(16,32,3) - ReLU - MaxPool - Linear - 10",". Huấn luyện trên MNIST 3 epoch.",[989,57224,57225],{},"Dựng MLP có số tham số tương đương. So accuracy test.",[989,57227,57228,57229,1517],{},"Đếm tham số từng tầng bằng tay và so với ",[992,57230,57231],{},"sum(p.numel())",[989,57233,57234],{},"Vẽ 16 kernel của tầng conv đầu tiên sau huấn luyện.",[981,57236,2711],{"id":2710},[986,57238,57240,57254,57260,57266],{"className":57239},[2715],[989,57241,57243,2308,57245,1509,57248,57251,57252,1517],{"className":57242},[2719],[2721,57244],{"disabled":2723,"type":2724},[992,57246,57247],{},"conv2d",[992,57249,57250],{},"maxpool2d"," khớp PyTorch sai số ",[992,57253,32245],{},[989,57255,57257,57259],{"className":57256},[2719],[2721,57258],{"disabled":2723,"type":2724}," Có ảnh Sobel, Gauss, ảnh cạnh và minh chứng tính tương biến.",[989,57261,57263,57265],{"className":57262},[2719],[2721,57264],{"disabled":2723,"type":2724}," Bảng CNN vs MLP có số thật.",[989,57267,57269,57271],{"className":57268},[2719],[2721,57270],{"disabled":2723,"type":2724}," Đếm tham số tay khớp PyTorch.",[968,57273,2890],{"id":2889},[986,57275,57276,57279,57282,57285],{},[989,57277,57278],{},"Kernel làm gì trên ảnh?",[989,57280,57281],{},"Stride và padding khác nhau sao?",[989,57283,57284],{},"Pooling để làm gì?",[989,57286,57287],{},"Vì sao tầng sâu thấy vật lớn?",[3014,57289],{},[973,57291,57292],{},"🌕 Bạn đã hoàn thành ngày 96. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,57294,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":57296},[57297,57298,57303,57304,57310],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":57299},[57300,57301,57302],{"id":56600,"depth":73,"text":56601},{"id":56621,"depth":73,"text":56622},{"id":56691,"depth":73,"text":56692},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":57305},[57306,57307,57308,57309],{"id":56756,"depth":73,"text":56757},{"id":56982,"depth":73,"text":56983},{"id":57212,"depth":73,"text":57213},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Phép tích chập, kernel, stride padding, pooling, trực giác phân cấp đặc trưng và vì sao CNN vượt MLP trên ảnh.",{},[14055],{"title":535,"description":57311},[57316],"cnn","o99LtuF0i2PkXTEKJhu7b2MdJAb8u7BCtFIkF4Uxxjg",{"id":57319,"title":540,"body":57320,"category":8797,"day":543,"description":57664,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":57665,"navigation":2723,"outcomes":3047,"path":541,"prerequisites":57666,"seo":57667,"stem":542,"tags":57668,"__hash__":57669},"challenges\u002Fchallenges\u002F97.gan-va-transfer.md",{"type":965,"value":57321,"toc":57648},[57322,57324,57327,57329,57333,57350,57354,57371,57418,57422,57439,57441,57449,57474,57476,57489,57493,57496,57539,57550,57554,57565,57569,57572,57590,57596,57598,57625,57627,57641,57643,57646],[968,57323,971],{"id":970},[973,57325,57326],{},"Bài này học vẽ ảnh giả bằng đấu tay đôi và tái dùng mô hình.\nDùng để sinh ảnh đẹp khi dữ liệu mới rất ít.",[968,57328,979],{"id":978},[981,57330,57332],{"id":57331},"gan","GAN",[986,57334,57335,57338,57341,57344,57347],{},[989,57336,57337],{},"Định nghĩa: bộ sinh vẽ giả, bộ phân biệt soi thật giả.",[989,57339,57340],{},"Sinh càng giỏi thì phân biệt càng khó đoán.",[989,57342,57343],{},"Ví dụ đời thường: như thợ vẽ giả đấu với giám định.",[989,57345,57346],{},"Điểm chuẩn là phân biệt chỉ đoán mò 50%.",[989,57348,57349],{},"Loss dao động là bình thường vì 2 bên cùng học.",[981,57351,57353],{"id":57352},"mode-collapse","Mode collapse",[986,57355,57356,57359,57362,57365,57368],{},[989,57357,57358],{},"Định nghĩa: bộ sinh vẽ mãi 1 kiểu dễ lừa.",[989,57360,57361],{},"Ảnh sắc nét nhưng quanh quẩn vài mẫu lặp lại.",[989,57363,57364],{},"Ví dụ đời thường: như học sinh chỉ học tủ 1 đề.",[989,57366,57367],{},"Do phân biệt quá mạnh sớm hoặc tín hiệu nghèo.",[989,57369,57370],{},"Sửa bằng đa dạng batch và cân tốc độ học.",[1099,57372,57373,57383],{},[1102,57374,57375],{},[1105,57376,57377,57379,57381],{},[1108,57378,54979],{},[1108,57380,54331],{},[1108,57382,54334],{},[1118,57384,57385,57396,57407],{},[1105,57386,57387,57390,57393],{},[1123,57388,57389],{},"Sinh yếu",[1123,57391,57392],{},"Ảnh mờ, đa dạng",[1123,57394,57395],{},"Tăng sức bộ sinh",[1105,57397,57398,57401,57404],{},[1123,57399,57400],{},"Sập mode",[1123,57402,57403],{},"Nét nhưng lặp 1 kiểu",[1123,57405,57406],{},"Đa dạng batch",[1105,57408,57409,57412,57415],{},[1123,57410,57411],{},"Phân biệt yếu",[1123,57413,57414],{},"Khen cả ảnh xấu",[1123,57416,57417],{},"Tăng sức phân biệt",[981,57419,57421],{"id":57420},"transfer-learning","Transfer learning",[986,57423,57424,57427,57430,57433,57436],{},[989,57425,57426],{},"Định nghĩa: tái dùng mô hình lớn cho bài mới ít dữ liệu.",[989,57428,57429],{},"Đóng băng tầng thấp, chỉ tinh chỉnh tầng cuối.",[989,57431,57432],{},"Ví dụ đời thường: như thợ giỏi đổi nghề vẫn giữ tay nghề.",[989,57434,57435],{},"Tầng thấp giữ cạnh và vân chung mọi ảnh.",[989,57437,57438],{},"Dữ liệu càng ít càng nên đóng băng nhiều.",[968,57440,1433],{"id":1432},[986,57442,57443,57446],{},[989,57444,57445],{},"Input: ảnh sinh ra toàn 1 kiểu mặt -> Output: kết luận sập mode.",[989,57447,57448],{},"Giải thích: nét nhưng thiếu đa dạng là dấu hiệu điển hình.",[1352,57450,57452],{"className":3538,"code":57451,"language":3540,"meta":1357,"style":1357},"# Đóng băng tầng thấp, mở tầng cuối\nfor layer in model.layers[:-2]:\n    layer.trainable = False  # giữ kiến thức cũ\nprint(\"san sang tinh chinh\")\n",[992,57453,57454,57459,57464,57469],{"__ignoreMap":1357},[1023,57455,57456],{"class":1362,"line":63},[1023,57457,57458],{},"# Đóng băng tầng thấp, mở tầng cuối\n",[1023,57460,57461],{"class":1362,"line":68},[1023,57462,57463],{},"for layer in model.layers[:-2]:\n",[1023,57465,57466],{"class":1362,"line":73},[1023,57467,57468],{},"    layer.trainable = False  # giữ kiến thức cũ\n",[1023,57470,57471],{"class":1362,"line":78},[1023,57472,57473],{},"print(\"san sang tinh chinh\")\n",[968,57475,1482],{"id":1481},[973,57477,1485,57478,7386,57480,1509,57482,57485,57486,1517],{},[1487,57479,13531],{},[1487,57481,56749],{},[992,57483,57484],{},"torchvision",". Có GPU thì tốt, CPU vẫn chạy được với dữ liệu nhỏ. Nộp vào ",[992,57487,57488],{},"day-097\u002F",[981,57490,57492],{"id":57491},"bài-1-gan-trên-dữ-liệu-2d","Bài 1: GAN trên dữ liệu 2D",[973,57494,57495],{},"Dữ liệu thật: 8 cụm Gauss xếp thành vòng tròn.",[1099,57497,57498,57507],{},[1102,57499,57500],{},[1105,57501,57502,57504],{},[1108,57503,2544],{},[1108,57505,57506],{},"Kiến trúc",[1118,57508,57509,57520,57531],{},[1105,57510,57511,57514],{},[1123,57512,57513],{},"Generator",[1123,57515,57516,57519],{},[992,57517,57518],{},"z (2) -> 128 -> 128 -> 2",", ReLU",[1105,57521,57522,57525],{},[1123,57523,57524],{},"Discriminator",[1123,57526,57527,57530],{},[992,57528,57529],{},"2 -> 128 -> 128 -> 1",", LeakyReLU, sigmoid ở cuối",[1105,57532,57533,57536],{},[1123,57534,57535],{},"Loss",[1123,57537,57538],{},"BCE, generator dùng non-saturating loss",[2273,57540,57541,57544,57547],{},[989,57542,57543],{},"Huấn luyện 5000 bước. Mỗi 500 bước vẽ điểm sinh ra chồng lên điểm thật.",[989,57545,57546],{},"Vẽ loss của D và G theo bước.",[989,57548,57549],{},"In output trung bình của D trên dữ liệu thật và giả ở cuối. Giải thích vì sao gần 0.5 là tốt.",[981,57551,57553],{"id":57552},"bài-2-tái-hiện-và-sửa-mode-collapse","Bài 2: Tái hiện và sửa mode collapse",[2273,57555,57556,57559,57562],{},[989,57557,57558],{},"Cố tình gây mode collapse: learning rate của D gấp 10 lần G, hoặc cho D học 5 bước mỗi bước G. Vẽ kết quả: G chỉ sinh vài cụm.",[989,57560,57561],{},"Đếm số cụm được phủ (cụm có ít nhất 5% điểm sinh ra rơi vào bán kính 0.5).",[989,57563,57564],{},"Thử 1 cách sửa: cân lại learning rate, thêm nhiễu vào input của D, hoặc minibatch discrimination. So số cụm được phủ.",[981,57566,57568],{"id":57567},"bài-3-transfer-learning-nâng-cao","Bài 3: Transfer learning (nâng cao)",[973,57570,57571],{},"Dữ liệu: 2 lớp ảnh, mỗi lớp 100 ảnh (ví dụ tập con của Oxford Pets hoặc tự chụp).",[2273,57573,57574,57584,57587],{},[989,57575,57576,57577,57580,57581,1517],{},"Tải ",[992,57578,57579],{},"resnet18"," pretrained. Thay tầng cuối bằng ",[992,57582,57583],{},"Linear(512, 2)",[989,57585,57586],{},"Ba chế độ: (a) huấn luyện từ đầu không pretrained, (b) đóng băng mọi tầng trừ tầng cuối, (c) mở băng block cuối cùng với lr nhỏ.",[989,57588,57589],{},"Mỗi chế độ 10 epoch. In accuracy validation và thời gian.",[1352,57591,57594],{"className":57592,"code":57593,"language":2241,"meta":1357},[2239],"chế_độ                 acc_val    thời_gian\ntừ đầu                 ...\nđóng băng hết trừ cuối ...\nfine-tune block cuối   ...\n",[992,57595,57593],{"__ignoreMap":1357},[981,57597,2711],{"id":2710},[986,57599,57601,57607,57613,57619],{"className":57600},[2715],[989,57602,57604,57606],{"className":57603},[2719],[2721,57605],{"disabled":2723,"type":2724}," Có chuỗi hình GAN học qua các mốc bước.",[989,57608,57610,57612],{"className":57609},[2719],[2721,57611],{"disabled":2723,"type":2724}," Tái hiện được mode collapse và có số cụm được phủ trước và sau khi sửa.",[989,57614,57616,57618],{"className":57615},[2719],[2721,57617],{"disabled":2723,"type":2724}," Bảng 3 chế độ transfer có số thật.",[989,57620,57622,57624],{"className":57621},[2719],[2721,57623],{"disabled":2723,"type":2724}," Giải thích được vì sao ít dữ liệu thì nên đóng băng nhiều.",[968,57626,2890],{"id":2889},[986,57628,57629,57632,57635,57638],{},[989,57630,57631],{},"2 mạng trong GAN làm gì?",[989,57633,57634],{},"Mode collapse là gì?",[989,57636,57637],{},"Transfer learning tiết kiệm gì?",[989,57639,57640],{},"Khi nào nên đóng băng nhiều tầng?",[3014,57642],{},[973,57644,57645],{},"🌕 Bạn đã hoàn thành ngày 97. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,57647,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":57649},[57650,57651,57656,57657,57663],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":57652},[57653,57654,57655],{"id":57331,"depth":73,"text":57332},{"id":57352,"depth":73,"text":57353},{"id":57420,"depth":73,"text":57421},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":57658},[57659,57660,57661,57662],{"id":57491,"depth":73,"text":57492},{"id":57552,"depth":73,"text":57553},{"id":57567,"depth":73,"text":57568},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đối đầu sinh phân biệt, mode collapse, tái sử dụng mô hình tiền huấn luyện, đóng băng tầng và tinh chỉnh cho dữ liệu ít.",{},[18469],{"title":540,"description":57664},[55457],"csJM8IEm0fVfR5spcSEzVQbZeSaK7lxsPTthcmpcZjY",{"id":57671,"title":545,"body":57672,"category":5189,"day":548,"description":58097,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":58098,"navigation":2723,"outcomes":3047,"path":546,"prerequisites":58099,"seo":58100,"stem":547,"tags":58101,"__hash__":58103},"challenges\u002Fchallenges\u002F98.proxy-remote-virtual.md",{"type":965,"value":57673,"toc":58081},[57674,57676,57679,57681,57685,57702,57706,57723,57771,57775,57792,57794,57802,57837,57839,57852,57856,57880,57940,57946,57949,57953,57992,57998,58002,58008,58029,58031,58058,58060,58074,58076,58079],[968,57675,971],{"id":970},[973,57677,57678],{},"Bài này học người đại diện đứng giữa khách và hàng thật.\nDùng để gọi máy xa và tải ảnh nặng không chờ.",[968,57680,979],{"id":978},[981,57682,57684],{"id":57683},"định-nghĩa-proxy","Định nghĩa Proxy",[986,57686,57687,57690,57693,57696,57699],{},[989,57688,57689],{},"Định nghĩa: đại diện cho object khác để kiểm soát truy cập.",[989,57691,57692],{},"Đại diện và hàng thật tuân cùng một giao diện.",[989,57694,57695],{},"Ví dụ đời thường: như lễ tân nhận yêu cầu thay giám đốc.",[989,57697,57698],{},"Khách không biết mình đang nói với đại diện.",[989,57700,57701],{},"Từ khóa là đại diện và kiểm soát truy cập.",[981,57703,57705],{"id":57704},"remote-proxy","Remote proxy",[986,57707,57708,57711,57714,57717,57720],{},[989,57709,57710],{},"Định nghĩa: đại diện địa phương cho máy ở xa qua mạng.",[989,57712,57713],{},"Ông chủ gọi đại diện như gọi máy thật tại chỗ.",[989,57715,57716],{},"Ví dụ đời thường: như gọi shipper thay vì tới quán xa.",[989,57718,57719],{},"Đại diện lo đóng gói yêu cầu gửi qua mạng.",[989,57721,57722],{},"Bên kia mở gói rồi hỏi máy thật.",[1099,57724,57725,57736],{},[1102,57726,57727],{},[1105,57728,57729,57732,57734],{},[1108,57730,57731],{},"Loại proxy",[1108,57733,56195],{},[1108,57735,56198],{},[1118,57737,57738,57749,57760],{},[1105,57739,57740,57743,57746],{},[1123,57741,57742],{},"Remote",[1123,57744,57745],{},"Máy ở xa, gọi khó",[1123,57747,57748],{},"Đại diện tại chỗ",[1105,57750,57751,57754,57757],{},[1123,57752,57753],{},"Virtual",[1123,57755,57756],{},"Ảnh nặng, tải chậm",[1123,57758,57759],{},"Hiện tạm rồi tải sau",[1105,57761,57762,57765,57768],{},[1123,57763,57764],{},"Bảo vệ",[1123,57766,57767],{},"Cần kiểm quyền",[1123,57769,57770],{},"Chặn trước khi vào",[981,57772,57774],{"id":57773},"virtual-proxy","Virtual proxy",[986,57776,57777,57780,57783,57786,57789],{},[989,57778,57779],{},"Định nghĩa: giữ chỗ trước, tải hàng nặng sau.",[989,57781,57782],{},"Danh sách hiện ngay, ảnh bìa tải dần từng cái.",[989,57784,57785],{},"Ví dụ đời thường: như khung xám chờ ảnh tải xong.",[989,57787,57788],{},"Tải hết trước khi hiện thì người dùng chờ dài.",[989,57790,57791],{},"Click món nào mới tải nặng món đó.",[968,57793,1433],{"id":1432},[986,57795,57796,57799],{},[989,57797,57798],{},"Input: hỏi tồn kho máy kẹo ở xa -> Output: gọi đại diện tại văn phòng.",[989,57800,57801],{},"Giải thích: đại diện chuyển lời qua mạng tới máy thật.",[1352,57803,57805],{"className":3538,"code":57804,"language":3540,"meta":1357,"style":1357},"# Đại diện kiểm soát trước khi gọi hàng thật\nclass Proxy:\n    def lay_kho(self):\n        if not self.quyen:  # kiểm tra trước\n            return \"từ chối\"\n        return self.may_that.lay_kho()  # chuyển lời\n",[992,57806,57807,57812,57817,57822,57827,57832],{"__ignoreMap":1357},[1023,57808,57809],{"class":1362,"line":63},[1023,57810,57811],{},"# Đại diện kiểm soát trước khi gọi hàng thật\n",[1023,57813,57814],{"class":1362,"line":68},[1023,57815,57816],{},"class Proxy:\n",[1023,57818,57819],{"class":1362,"line":73},[1023,57820,57821],{},"    def lay_kho(self):\n",[1023,57823,57824],{"class":1362,"line":78},[1023,57825,57826],{},"        if not self.quyen:  # kiểm tra trước\n",[1023,57828,57829],{"class":1362,"line":83},[1023,57830,57831],{},"            return \"từ chối\"\n",[1023,57833,57834],{"class":1362,"line":88},[1023,57835,57836],{},"        return self.may_that.lay_kho()  # chuyển lời\n",[968,57838,1482],{"id":1481},[973,57840,1485,57841,57843,57844,1509,57846,57848,57849,1517],{},[1487,57842,4800],{}," (hoặc Java). Dùng ",[992,57845,51550],{},[992,57847,52002],{}," ngày 86. Nộp vào ",[992,57850,57851],{},"day-098\u002F",[981,57853,57855],{"id":57854},"bài-1-remote-proxy-qua-socket","Bài 1: Remote proxy qua socket",[1352,57857,57859],{"className":1393,"code":57858,"language":1395,"meta":1357,"style":1357},"struct GumballMachineRemote {\n  virtual int count() = 0; virtual std::string location() = 0; virtual std::string state() = 0;\n  virtual ~GumballMachineRemote() = default;\n};\n",[992,57860,57861,57866,57871,57876],{"__ignoreMap":1357},[1023,57862,57863],{"class":1362,"line":63},[1023,57864,57865],{},"struct GumballMachineRemote {\n",[1023,57867,57868],{"class":1362,"line":68},[1023,57869,57870],{},"  virtual int count() = 0; virtual std::string location() = 0; virtual std::string state() = 0;\n",[1023,57872,57873],{"class":1362,"line":73},[1023,57874,57875],{},"  virtual ~GumballMachineRemote() = default;\n",[1023,57877,57878],{"class":1362,"line":78},[1023,57879,4866],{},[1099,57881,57882,57890],{},[1102,57883,57884],{},[1105,57885,57886,57888],{},[1108,57887,2544],{},[1108,57889,1569],{},[1118,57891,57892,57914,57927],{},[1105,57893,57894,57899],{},[1123,57895,57896],{},[992,57897,57898],{},"GumballServer",[1123,57900,17210,57901,57903,57904,1656,57907,1656,57910,57913],{},[992,57902,51550],{}," thật, nghe TCP cổng 5000. Nhận dòng ",[992,57905,57906],{},"COUNT",[992,57908,57909],{},"LOCATION",[992,57911,57912],{},"STATE",", trả 1 dòng kết quả",[1105,57915,57916,57921],{},[1123,57917,57918],{},[992,57919,57920],{},"GumballStub : GumballMachineRemote",[1123,57922,57923,57924],{},"Mở socket, gửi lệnh, đọc kết quả. Lỗi mạng ném ",[992,57925,57926],{},"RemoteException",[1105,57928,57929,57933],{},[1123,57930,57931],{},[992,57932,52002],{},[1123,57934,57935,57936,57939],{},"Chỉ biết ",[992,57937,57938],{},"GumballMachineRemote&",", không biết là máy thật hay stub",[1352,57941,57944],{"className":57942,"code":57943,"language":2241,"meta":1357},[2239],"Monitor(máy thật) và Monitor(stub tới server) in cùng báo cáo\nTắt server rồi gọi stub -> RemoteException, monitor in \"không liên lạc được\"\n",[992,57945,57943],{"__ignoreMap":1357},[973,57947,57948],{},"Chạy 3 server ở 3 cổng (3 máy ở 3 thành phố). Monitor in báo cáo cả 3.",[981,57950,57952],{"id":57951},"bài-2-virtual-proxy-cho-ảnh-bìa","Bài 2: Virtual proxy cho ảnh bìa",[1352,57954,57956],{"className":1393,"code":57955,"language":1395,"meta":1357,"style":1357},"struct Icon { virtual int width() = 0; virtual int height() = 0; virtual std::string paint() = 0; virtual ~Icon() = default; };\nclass ImageIcon : public Icon { \u002F* constructor tải ảnh: giả lập sleep 2 giây *\u002F };\nclass ImageProxy : public Icon {\n  \u002F\u002F chưa tải xong: width\u002Fheight trả 800x600, paint trả \"Đang tải ảnh bìa...\"\n  \u002F\u002F lần gọi paint đầu tiên: khởi động tải ở luồng nền\n  \u002F\u002F tải xong: ủy thác mọi lời gọi cho ImageIcon\n};\n",[992,57957,57958,57963,57968,57973,57978,57983,57988],{"__ignoreMap":1357},[1023,57959,57960],{"class":1362,"line":63},[1023,57961,57962],{},"struct Icon { virtual int width() = 0; virtual int height() = 0; virtual std::string paint() = 0; virtual ~Icon() = default; };\n",[1023,57964,57965],{"class":1362,"line":68},[1023,57966,57967],{},"class ImageIcon : public Icon { \u002F* constructor tải ảnh: giả lập sleep 2 giây *\u002F };\n",[1023,57969,57970],{"class":1362,"line":73},[1023,57971,57972],{},"class ImageProxy : public Icon {\n",[1023,57974,57975],{"class":1362,"line":78},[1023,57976,57977],{},"  \u002F\u002F chưa tải xong: width\u002Fheight trả 800x600, paint trả \"Đang tải ảnh bìa...\"\n",[1023,57979,57980],{"class":1362,"line":83},[1023,57981,57982],{},"  \u002F\u002F lần gọi paint đầu tiên: khởi động tải ở luồng nền\n",[1023,57984,57985],{"class":1362,"line":88},[1023,57986,57987],{},"  \u002F\u002F tải xong: ủy thác mọi lời gọi cho ImageIcon\n",[1023,57989,57990],{"class":1362,"line":93},[1023,57991,4866],{},[1352,57993,57996],{"className":57994,"code":57995,"language":2241,"meta":1357},[2239],"Tạo 20 ImageProxy -> tức thì (dưới 10 ms)\npaint() ngay lập tức -> \"Đang tải ảnh bìa...\"\npaint() sau 3 giây   -> nội dung ảnh thật\nChỉ ảnh nào được paint mới tải (đếm số lần tải)\n",[992,57997,57995],{"__ignoreMap":1357},[981,57999,58001],{"id":58000},"bài-3-caching-proxy-nâng-cao","Bài 3: Caching proxy (nâng cao)",[973,58003,58004,58007],{},[992,58005,58006],{},"WeatherService::forecast(city)"," giả lập gọi API mất 500 ms.",[2273,58009,58010,58020,58026],{},[989,58011,1505,58012,58015,58016,58019],{},[992,58013,58014],{},"CachingWeatherProxy"," cùng interface: cache kết quả 10 phút theo ",[992,58017,58018],{},"city"," (dùng đồng hồ giả để test).",[989,58021,1505,58022,58025],{},[992,58023,58024],{},"LoggingWeatherProxy"," ghi thời gian mỗi lần gọi. Chồng 2 proxy lên nhau.",[989,58027,58028],{},"Viết 3 câu: Proxy khác Decorator ở điểm nào khi cả hai đều bọc cùng interface.",[981,58030,2711],{"id":2710},[986,58032,58034,58040,58046,58052],{"className":58033},[2715],[989,58035,58037,58039],{"className":58036},[2719],[2721,58038],{"disabled":2723,"type":2724}," Monitor chạy với cả máy thật và stub, xử lý lỗi mạng.",[989,58041,58043,58045],{"className":58042},[2719],[2721,58044],{"disabled":2723,"type":2724}," Virtual proxy chỉ tải ảnh khi cần, không chặn luồng chính.",[989,58047,58049,58051],{"className":58048},[2719],[2721,58050],{"disabled":2723,"type":2724}," Caching proxy test bằng đồng hồ giả.",[989,58053,58055,58057],{"className":58054},[2719],[2721,58056],{"disabled":2723,"type":2724}," Phân biệt được Proxy, Decorator, Adapter bằng mục đích.",[968,58059,2890],{"id":2889},[986,58061,58062,58065,58068,58071],{},[989,58063,58064],{},"Proxy khác hàng thật ở đâu?",[989,58066,58067],{},"Remote proxy giấu cái gì?",[989,58069,58070],{},"Virtual proxy tải khi nào?",[989,58072,58073],{},"Từ khóa của Proxy là gì?",[3014,58075],{},[973,58077,58078],{},"🌕 Bạn đã hoàn thành ngày 98. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,58080,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":58082},[58083,58084,58089,58090,58096],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":58085},[58086,58087,58088],{"id":57683,"depth":73,"text":57684},{"id":57704,"depth":73,"text":57705},{"id":57773,"depth":73,"text":57774},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":58091},[58092,58093,58094,58095],{"id":57854,"depth":73,"text":57855},{"id":57951,"depth":73,"text":57952},{"id":58000,"depth":73,"text":58001},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Định nghĩa Proxy, người đại diện cho tài nguyên ở xa qua mạng, và ảnh bìa đĩa than tải chậm với virtual proxy.",{},[5194,14055],{"title":545,"description":58097},[58102,23085,20909],"proxy","4-ZdDRlgHw7SzVnu57NF3aP9Bg-K2yNh1_LzC_aGbOg",{"id":58105,"title":550,"body":58106,"category":8797,"day":553,"description":58660,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":58661,"navigation":2723,"outcomes":3047,"path":551,"prerequisites":58662,"seo":58663,"stem":552,"tags":58664,"__hash__":58665},"challenges\u002Fchallenges\u002F99.embedding-sentiment.md",{"type":965,"value":58107,"toc":58644},[58108,58110,58113,58115,58119,58136,58140,58157,58193,58197,58214,58216,58224,58249,58251,58262,58266,58486,58527,58533,58537,58540,58555,58561,58565,58588,58590,58621,58623,58637,58639,58642],[968,58109,971],{"id":970},[973,58111,58112],{},"Bài này học biến từ thành vector và đoán khen chê.\nDùng để hiểu nghĩa từ và chấm review nhà hàng.",[968,58114,979],{"id":978},[981,58116,58118],{"id":58117},"word-embedding","Word embedding",[986,58120,58121,58124,58127,58130,58133],{},[989,58122,58123],{},"Định nghĩa: nhúng mỗi từ thành vector ngắn dày đặc.",[989,58125,58126],{},"Từ đồng nghĩa nằm gần nhau trong không gian.",[989,58128,58129],{},"Ví dụ đời thường: như xếp bạn cùng sở thích ngồi gần.",[989,58131,58132],{},"Học bằng cách đoán từ xung quanh trong văn bản lớn.",[989,58134,58135],{},"Hay đi chung thì kéo gần, hiếm chung thì đẩy xa.",[981,58137,58139],{"id":58138},"cosine-và-so-sánh-bow","Cosine và so sánh BoW",[986,58141,58142,58145,58148,58151,58154],{},[989,58143,58144],{},"Cosine đo góc giữa 2 vector, góc nhỏ là gần nghĩa.",[989,58146,58147],{},"BoW thưa theo cỡ từ vựng, không biết từ gần nghĩa.",[989,58149,58150],{},"Embedding chỉ vài trăm chiều, bắt được nghĩa tốt.",[989,58152,58153],{},"Ví dụ đời thường: như đo độ hợp gu bằng góc nhìn.",[989,58155,58156],{},"Nhược điểm: mỗi từ 1 vector nên từ đa nghĩa bị trộn.",[1099,58158,58159,58170],{},[1102,58160,58161],{},[1105,58162,58163,58166,58168],{},[1108,58164,58165],{},"Cách biểu diễn",[1108,58167,16149],{},[1108,58169,16152],{},[1118,58171,58172,58182],{},[1105,58173,58174,58176,58179],{},[1123,58175,38921],{},[1123,58177,58178],{},"Dễ hiểu từng chiều",[1123,58180,58181],{},"Thưa, không biết gần nghĩa",[1105,58183,58184,58187,58190],{},[1123,58185,58186],{},"Embedding",[1123,58188,58189],{},"Gọn, bắt được nghĩa",[1123,58191,58192],{},"Khó giải thích, cần nhiều data",[981,58194,58196],{"id":58195},"sentiment-bằng-naive-bayes","Sentiment bằng Naive Bayes",[986,58198,58199,58202,58205,58208,58211],{},[989,58200,58201],{},"Định nghĩa: đếm từ khen chê để đoán nhãn review.",[989,58203,58204],{},"Từ nào hay đi với khen thì đẩy về phía khen.",[989,58206,58207],{},"Ví dụ đời thường: như thấy \"ngon\" nhiều thì đoán khen.",[989,58209,58210],{},"Cần làm sạch chữ, tách từ trước khi đếm.",[989,58212,58213],{},"Đo bằng độ chính xác trên review chưa thấy.",[968,58215,1433],{"id":1432},[986,58217,58218,58221],{},[989,58219,58220],{},"Input: \"món ngon, phục vụ tệ\" -> Output: 1 khen + 1 chê.",[989,58222,58223],{},"Giải thích: mỗi từ góp phiếu theo tần suất đã học.",[1352,58225,58227],{"className":3538,"code":58226,"language":3540,"meta":1357,"style":1357},"# So sánh gần nghĩa bằng cosine\nimport math\ncos = (a @ b) \u002F (len_a * len_b)  # góc nhỏ là gần nghĩa\nprint(cos)  # gần 1 là rất giống\n",[992,58228,58229,58234,58239,58244],{"__ignoreMap":1357},[1023,58230,58231],{"class":1362,"line":63},[1023,58232,58233],{},"# So sánh gần nghĩa bằng cosine\n",[1023,58235,58236],{"class":1362,"line":68},[1023,58237,58238],{},"import math\n",[1023,58240,58241],{"class":1362,"line":73},[1023,58242,58243],{},"cos = (a @ b) \u002F (len_a * len_b)  # góc nhỏ là gần nghĩa\n",[1023,58245,58246],{"class":1362,"line":78},[1023,58247,58248],{},"print(cos)  # gần 1 là rất giống\n",[968,58250,1482],{"id":1481},[973,58252,1485,58253,53373,58255,58258,58259,1517],{},[1487,58254,13531],{},[992,58256,58257],{},"gensim"," (hoặc PyTorch). Nộp vào ",[992,58260,58261],{},"day-099\u002F",[981,58263,58265],{"id":58264},"bài-1-embedding-từ-ma-trận-đồng-xuất-hiện","Bài 1: Embedding từ ma trận đồng xuất hiện",[2273,58267,58268,58271,58274,58483],{},[989,58269,58270],{},"Lấy một kho văn bản khoảng 1 triệu từ (ví dụ text8 hoặc bài báo tiếng Việt đã tách từ).",[989,58272,58273],{},"Dựng ma trận đồng xuất hiện với cửa sổ ±2, giữ 5000 từ phổ biến nhất.",[989,58275,39487,58276,13568,58279,1517],{},[1487,58277,58278],{},"PPMI",[1023,58280,58282,58344],{"className":58281},[1026],[1023,58283,58285],{"className":58284},[1030],[1032,58286,58287],{"xmlns":1034},[1036,58288,58289,58341],{},[1039,58290,58291,58293,58295,58297,58299,58301,58303,58305,58339],{},[1042,58292,35034],{},[1046,58294,8400],{},[1046,58296,1049],{"stretchy":1048},[1051,58298,2379],{},[1046,58300,13897],{"separator":1066},[1042,58302,8397],{},[1046,58304,8400],{},[18110,58306,58307,58321],{},[1039,58308,58309,58311,58313,58315,58317,58319],{},[1042,58310,37334],{},[1046,58312,1049],{"stretchy":1048},[1042,58314,27557],{},[1046,58316,13897],{"separator":1066},[1042,58318,1356],{},[1046,58320,1056],{"stretchy":1048},[1039,58322,58323,58325,58327,58329,58331,58333,58335,58337],{},[1042,58324,37334],{},[1046,58326,1049],{"stretchy":1048},[1042,58328,27557],{},[1046,58330,1056],{"stretchy":1048},[1042,58332,37334],{},[1046,58334,1049],{"stretchy":1048},[1042,58336,1356],{},[1046,58338,1056],{"stretchy":1048},[1046,58340,1056],{"stretchy":1048},[1058,58342,58343],{"encoding":1060},"\\max(0, \\log \\frac{P(w,c)}{P(w)P(c)})",[1023,58345,58347],{"className":58346,"ariaHidden":1066},[1065],[1023,58348,58350,58353,58356,58359,58362,58365,58368,58373,58376,58480],{"className":58349},[1070],[1023,58351],{"className":58352,"style":37757},[1074],[1023,58354,35034],{"className":58355},[8426],[1023,58357,1049],{"className":58358},[1085],[1023,58360,2379],{"className":58361},[1079],[1023,58363,13897],{"className":58364},[13943],[1023,58366],{"className":58367,"style":8434},[2354],[1023,58369,8427,58371],{"className":58370},[8426],[1023,58372,7690],{"style":8430},[1023,58374],{"className":58375,"style":8434},[2354],[1023,58377,58379,58382,58477],{"className":58378},[1079],[1023,58380],{"className":58381},[1085,18174],[1023,58383,58385],{"className":58384},[18110],[1023,58386,58388,58469],{"className":58387},[2387,17732],[1023,58389,58391,58466],{"className":58390},[2391],[1023,58392,58394,58429,58437],{"className":58393,"style":37492},[2395],[1023,58395,58396,58399],{"style":18190},[1023,58397],{"className":58398,"style":18194},[2402],[1023,58400,58402],{"className":58401},[2407,2408,2409,2410],[1023,58403,58405,58408,58411,58414,58417,58420,58423,58426],{"className":58404},[1079,2410],[1023,58406,37334],{"className":58407,"style":37429},[1079,1080,2410],[1023,58409,1049],{"className":58410},[1085,2410],[1023,58412,27557],{"className":58413,"style":37436},[1079,1080,2410],[1023,58415,1056],{"className":58416},[1092,2410],[1023,58418,37334],{"className":58419,"style":37429},[1079,1080,2410],[1023,58421,1049],{"className":58422},[1085,2410],[1023,58424,1356],{"className":58425},[1079,1080,2410],[1023,58427,1056],{"className":58428},[1092,2410],[1023,58430,58431,58434],{"style":18221},[1023,58432],{"className":58433,"style":18194},[2402],[1023,58435],{"className":58436,"style":18229},[18228],[1023,58438,58439,58442],{"style":37607},[1023,58440],{"className":58441,"style":18194},[2402],[1023,58443,58445],{"className":58444},[2407,2408,2409,2410],[1023,58446,58448,58451,58454,58457,58460,58463],{"className":58447},[1079,2410],[1023,58449,37334],{"className":58450,"style":37429},[1079,1080,2410],[1023,58452,1049],{"className":58453},[1085,2410],[1023,58455,27557],{"className":58456,"style":37436},[1079,1080,2410],[1023,58458,13897],{"className":58459},[13943,2410],[1023,58461,1356],{"className":58462},[1079,1080,2410],[1023,58464,1056],{"className":58465},[1092,2410],[1023,58467,17797],{"className":58468},[17796],[1023,58470,58472],{"className":58471},[2391],[1023,58473,58475],{"className":58474,"style":18260},[2395],[1023,58476],{},[1023,58478],{"className":58479},[1092,18174],[1023,58481,1056],{"className":58482},[1092],[989,58484,58485],{},"Giảm chiều bằng SVD cắt còn 100 chiều. Mỗi hàng là vector của 1 từ.",[1099,58487,58488,58496],{},[1102,58489,58490],{},[1105,58491,58492,58494],{},[1108,58493,1566],{},[1108,58495,2547],{},[1118,58497,58498,58510],{},[1105,58499,58500,58505],{},[1123,58501,58502],{},[992,58503,58504],{},"most_similar(word, n=10)",[1123,58506,39420,58507,58509],{},[992,58508,1262],{}," từ cosine cao nhất, không tính chính nó",[1105,58511,58512,58517],{},[1123,58513,58514],{},[992,58515,58516],{},"analogy(a, b, c)",[1123,58518,58519,58520,58523,58524],{},"Từ gần ",[992,58521,58522],{},"b - a + c"," nhất, ví dụ ",[992,58525,58526],{},"king - man + woman",[973,58528,9007,58529,58532],{},[992,58530,58531],{},"most_similar"," cho 5 từ. Nhận xét kết quả nào hợp lý, kết quả nào lạ.",[981,58534,58536],{"id":58535},"bài-2-sentiment-bằng-naive-bayes-và-bằng-embedding","Bài 2: Sentiment bằng Naive Bayes và bằng embedding",[973,58538,58539],{},"Dữ liệu: review phim IMDB (tập con 10.000 review) hoặc review tiếng Việt công khai.",[2273,58541,58542,58545,58552],{},[989,58543,58544],{},"Naive Bayes ngày 54 trên BoW. In accuracy test.",[989,58546,58547,58548,58551],{},"Biểu diễn mỗi review bằng ",[1487,58549,58550],{},"trung bình vector embedding"," các từ, rồi logistic regression ngày 55. In accuracy test.",[989,58553,58554],{},"Tìm 5 review mà 2 mô hình bất đồng. Đọc và giải thích vì sao.",[1352,58556,58559],{"className":58557,"code":58558,"language":2241,"meta":1357},[2239],"\"món ngon, phục vụ tệ\" -> in từng từ và điểm log-ratio khen\u002Fchê của nó\n",[992,58560,58558],{"__ignoreMap":1357},[981,58562,58564],{"id":58563},"bài-3-word2vec-nâng-cao","Bài 3: Word2vec (nâng cao)",[2273,58566,58567,58574,58582,58585],{},[989,58568,58569,58570,58573],{},"Huấn luyện ",[992,58571,58572],{},"gensim.models.Word2Vec"," (skip-gram, 100 chiều) trên cùng kho văn bản.",[989,58575,49241,58576,1509,58578,58581],{},[992,58577,58531],{},[992,58579,58580],{},"analogy"," với PPMI-SVD của Bài 1.",[989,58583,58584],{},"Chọn 1 từ đa nghĩa (ví dụ \"bank\" hoặc \"đường\"). In 10 từ gần nhất. Chỉ ra 2 nghĩa bị trộn vào 1 vector.",[989,58586,58587],{},"Vẽ 50 từ bằng PCA 2D, tô màu theo nhóm chủ đề.",[981,58589,2711],{"id":2710},[986,58591,58593,58603,58609,58615],{"className":58592},[2715],[989,58594,58596,2308,58598,1509,58600,58602],{"className":58595},[2719],[2721,58597],{"disabled":2723,"type":2724},[992,58599,58531],{},[992,58601,58580],{}," chạy được, có bảng kết quả.",[989,58604,58606,58608],{"className":58605},[2719],[2721,58607],{"disabled":2723,"type":2724}," Bảng accuracy 2 cách sentiment có số thật.",[989,58610,58612,58614],{"className":58611},[2719],[2721,58613],{"disabled":2723,"type":2724}," Có ví dụ từ đa nghĩa bị trộn.",[989,58616,58618,58620],{"className":58617},[2719],[2721,58619],{"disabled":2723,"type":2724}," Giải thích được vì sao embedding \"biết\" từ gần nghĩa còn BoW thì không.",[968,58622,2890],{"id":2889},[986,58624,58625,58628,58631,58634],{},[989,58626,58627],{},"Embedding khác túi từ ở đâu?",[989,58629,58630],{},"Cosine gần 1 nghĩa là gì?",[989,58632,58633],{},"Naive Bayes đoán cảm xúc thế nào?",[989,58635,58636],{},"Vì sao từ đa nghĩa gây khó?",[3014,58638],{},[973,58640,58641],{},"🌕 Bạn đã hoàn thành ngày 99. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,58643,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":58645},[58646,58647,58652,58653,58659],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":58648},[58649,58650,58651],{"id":58117,"depth":73,"text":58118},{"id":58138,"depth":73,"text":58139},{"id":58195,"depth":73,"text":58196},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":58654},[58655,58656,58657,58658],{"id":58264,"depth":73,"text":58265},{"id":58535,"depth":73,"text":58536},{"id":58563,"depth":73,"text":58564},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Word2Vec, điểm tương đồng, ưu nhược điểm embedding dày đặc và case sentiment review nhà hàng bằng Naive Bayes.",{},[18469],{"title":550,"description":58660},[37980],"qD-HsUho8LTNwxn67pimi23gFzBur4eQJiZuGX0U5VA",{"id":58667,"title":555,"body":58668,"category":8797,"day":558,"description":59282,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":59283,"navigation":2723,"outcomes":3047,"path":556,"prerequisites":59284,"seo":59285,"stem":557,"tags":59286,"__hash__":59288},"challenges\u002Fchallenges\u002F100.rnn-chuoi.md",{"type":965,"value":58669,"toc":59266},[58670,58672,58675,58677,58681,58698,58757,58761,58778,58782,58799,58801,58809,58829,58831,58840,58844,58874,58888,58894,58898,59170,59174,59179,59212,59214,59243,59245,59259,59261,59264],[968,58671,971],{"id":970},[973,58673,58674],{},"Bài này học xử lý chuỗi có thứ tự và cell nhớ RNN.\nDùng để dịch câu, chấm cảm xúc và gán nhãn từ.",[968,58676,979],{"id":978},[981,58678,58680],{"id":58679},"bốn-kiểu-chuỗi","Bốn kiểu chuỗi",[986,58682,58683,58686,58689,58692,58695],{},[989,58684,58685],{},"One-to-many: 1 ảnh sinh ra 1 câu mô tả.",[989,58687,58688],{},"Many-to-one: 1 câu cho ra 1 nhãn cảm xúc.",[989,58690,58691],{},"Many-to-many đồng bộ: gán nhãn từng từ một.",[989,58693,58694],{},"Many-to-many lệch: dịch máy, vào dài khác ra.",[989,58696,58697],{},"Ví dụ đời thường: như nghe cả câu mới hiểu ý.",[1099,58699,58700,58713],{},[1102,58701,58702],{},[1105,58703,58704,58707,58710],{},[1108,58705,58706],{},"Kiểu",[1108,58708,58709],{},"Input",[1108,58711,58712],{},"Output",[1118,58714,58715,58726,58736,58747],{},[1105,58716,58717,58720,58723],{},[1123,58718,58719],{},"One-to-many",[1123,58721,58722],{},"1 ảnh",[1123,58724,58725],{},"1 câu",[1105,58727,58728,58731,58733],{},[1123,58729,58730],{},"Many-to-one",[1123,58732,58725],{},[1123,58734,58735],{},"1 nhãn",[1105,58737,58738,58741,58744],{},[1123,58739,58740],{},"Đồng bộ",[1123,58742,58743],{},"N từ",[1123,58745,58746],{},"N nhãn",[1105,58748,58749,58752,58754],{},[1123,58750,58751],{},"Lệch",[1123,58753,58743],{},[1123,58755,58756],{},"M từ khác",[981,58758,58760],{"id":58759},"cell-rnn","Cell RNN",[986,58762,58763,58766,58769,58772,58775],{},[989,58764,58765],{},"Định nghĩa: trộn đầu vào mới với trí nhớ cũ mỗi bước.",[989,58767,58768],{},"Trọng số dùng chung nên dài bao nhiêu cũng đủ.",[989,58770,58771],{},"Ví dụ đời thường: như ghi chú lề cập nhật từng trang.",[989,58773,58774],{},"Viết đè toàn bộ trí nhớ nên hay quên xa.",[989,58776,58777],{},"Dữ liệu xếp thành batch, bước thời gian, đặc trưng.",[981,58779,58781],{"id":58780},"bptt","BPTT",[986,58783,58784,58787,58790,58793,58796],{},[989,58785,58786],{},"Định nghĩa: lan truyền ngược mở ra theo thời gian.",[989,58788,58789],{},"Lỗi cuối chuỗi chảy ngược về từng bước trước.",[989,58791,58792],{},"Ví dụ đời thường: như truy lại băng ghi hình từng phút.",[989,58794,58795],{},"Chuỗi dài thì gradient teo hoặc nổ dần.",[989,58797,58798],{},"Cần cắt ngắn và kẹp gradient để chạy ổn.",[968,58800,1433],{"id":1432},[986,58802,58803,58806],{},[989,58804,58805],{},"Input: \"phim hay quá\" -> Output: nhãn khen.",[989,58807,58808],{},"Giải thích: many-to-one đọc cả chuỗi rồi chốt 1 nhãn.",[1352,58810,58812],{"className":3538,"code":58811,"language":3540,"meta":1357,"style":1357},"# Cell RNN cập nhật trí nhớ mỗi bước\nh = tanh(x @ Wx + h_cu @ Wh + b)  # trộn mới và cũ\nprint(h)  # trí nhớ mới\n",[992,58813,58814,58819,58824],{"__ignoreMap":1357},[1023,58815,58816],{"class":1362,"line":63},[1023,58817,58818],{},"# Cell RNN cập nhật trí nhớ mỗi bước\n",[1023,58820,58821],{"class":1362,"line":68},[1023,58822,58823],{},"h = tanh(x @ Wx + h_cu @ Wh + b)  # trộn mới và cũ\n",[1023,58825,58826],{"class":1362,"line":73},[1023,58827,58828],{},"print(h)  # trí nhớ mới\n",[968,58830,1482],{"id":1481},[973,58832,1485,58833,56746,58835,56750,58837,1517],{},[1487,58834,13531],{},[1487,58836,56749],{},[992,58838,58839],{},"day-100\u002F",[981,58841,58843],{"id":58842},"bài-1-rnn-cell-tự-cài","Bài 1: RNN cell tự cài",[1352,58845,58847],{"className":3538,"code":58846,"language":3540,"meta":1357,"style":1357},"class RNNCell:\n    def __init__(self, input_size, hidden_size, seed=0): ...\n    def forward(self, xs: np.ndarray, h0=None) -> tuple[np.ndarray, list]:\n        \"\"\"xs: (T, input_size). h_t = tanh(x_t Wx + h_{t-1} Wh + b). Trả (hs: (T, hidden), cache).\"\"\"\n    def backward(self, dhs, cache) -> dict: ...   # BPTT, trả dWx, dWh, db\n",[992,58848,58849,58854,58859,58864,58869],{"__ignoreMap":1357},[1023,58850,58851],{"class":1362,"line":63},[1023,58852,58853],{},"class RNNCell:\n",[1023,58855,58856],{"class":1362,"line":68},[1023,58857,58858],{},"    def __init__(self, input_size, hidden_size, seed=0): ...\n",[1023,58860,58861],{"class":1362,"line":73},[1023,58862,58863],{},"    def forward(self, xs: np.ndarray, h0=None) -> tuple[np.ndarray, list]:\n",[1023,58865,58866],{"class":1362,"line":78},[1023,58867,58868],{},"        \"\"\"xs: (T, input_size). h_t = tanh(x_t Wx + h_{t-1} Wh + b). Trả (hs: (T, hidden), cache).\"\"\"\n",[1023,58870,58871],{"class":1362,"line":83},[1023,58872,58873],{},"    def backward(self, dhs, cache) -> dict: ...   # BPTT, trả dWx, dWh, db\n",[2273,58875,58876,58882],{},[989,58877,58878,58879,1517],{},"Gradient check với sai phân trung tâm trên chuỗi ",[992,58880,58881],{},"T = 5",[989,58883,58884,58885,58887],{},"Xác nhận số tham số không đổi khi ",[992,58886,38209],{}," từ 5 lên 100.",[1352,58889,58892],{"className":58890,"code":58891,"language":2241,"meta":1357},[2239],"input_size=3, hidden=4 -> số tham số = 3*4 + 4*4 + 4 = 32, bất kể T\n",[992,58893,58891],{"__ignoreMap":1357},[981,58895,58897],{"id":58896},"bài-2-gradient-teo-và-nổ","Bài 2: Gradient teo và nổ",[2273,58899,58900,59017,59024],{},[989,58901,58902,58903,58906,58907,59010,59011,59013,59014,59016],{},"Chuỗi ",[992,58904,58905],{},"T = 50",". Đặt loss chỉ ở bước cuối. In chuẩn ",[1023,58908,58910,58941],{"className":58909},[1026],[1023,58911,58913],{"className":58912},[1030],[1032,58914,58915],{"xmlns":1034},[1036,58916,58917,58938],{},[1039,58918,58919,58921,58924,58926,58928,58930,58936],{},[1046,58920,18125],{"stretchy":1048},[1042,58922,58923],{"mathvariant":2460},"∂",[1042,58925,4772],{},[1042,58927,2461],{"mathvariant":2460},[1042,58929,58923],{"mathvariant":2460},[17690,58931,58932,58934],{},[1042,58933,7908],{},[1042,58935,29580],{},[1046,58937,18125],{"stretchy":1048},[1058,58939,58940],{"encoding":1060},"\\lVert \\partial L \u002F \\partial h_t \\rVert",[1023,58942,58944],{"className":58943,"ariaHidden":1066},[1065],[1023,58945,58947,58950,58953,58957,58960,58963,58966,59007],{"className":58946},[1070],[1023,58948],{"className":58949,"style":1075},[1074],[1023,58951,18125],{"className":58952},[1085],[1023,58954,58923],{"className":58955,"style":58956},[1079],"margin-right:0.0556em;",[1023,58958,4772],{"className":58959},[1079,1080],[1023,58961,2461],{"className":58962},[1079],[1023,58964,58923],{"className":58965,"style":58956},[1079],[1023,58967,58969,58972],{"className":58968},[1079],[1023,58970,7908],{"className":58971},[1079,1080],[1023,58973,58975],{"className":58974},[2383],[1023,58976,58978,58999],{"className":58977},[2387,17732],[1023,58979,58981,58996],{"className":58980},[2391],[1023,58982,58985],{"className":58983,"style":58984},[2395],"height:0.2806em;",[1023,58986,58987,58990],{"style":17783},[1023,58988],{"className":58989,"style":2403},[2402],[1023,58991,58993],{"className":58992},[2407,2408,2409,2410],[1023,58994,29580],{"className":58995},[1079,1080,2410],[1023,58997,17797],{"className":58998},[17796],[1023,59000,59002],{"className":59001},[2391],[1023,59003,59005],{"className":59004,"style":17804},[2395],[1023,59006],{},[1023,59008,18125],{"className":59009},[1092]," cho từng ",[992,59012,29580],{},". Vẽ theo ",[992,59015,29580],{}," (trục y log).",[989,59018,59019,59020,59023],{},"Nhân ",[992,59021,59022],{},"Wh"," với 0.5 và với 2.0. Vẽ lại. Chỉ ra trường hợp teo và trường hợp nổ.",[989,59025,6760,59026,59029,59030,49043,59092,1517],{},[1487,59027,59028],{},"gradient clipping"," theo chuẩn: nếu ",[1023,59031,59033,59056],{"className":59032},[1026],[1023,59034,59036],{"className":59035},[1030],[1032,59037,59038],{"xmlns":1034},[1036,59039,59040,59053],{},[1039,59041,59042,59044,59046,59048,59051],{},[1046,59043,18125],{"stretchy":1048},[1042,59045,7690],{},[1046,59047,18125],{"stretchy":1048},[1046,59049,59050],{},">",[1051,59052,2334],{},[1058,59054,59055],{"encoding":1060},"\\lVert g \\rVert > 5",[1023,59057,59059,59083],{"className":59058,"ariaHidden":1066},[1065],[1023,59060,59062,59065,59068,59071,59074,59077,59080],{"className":59061},[1070],[1023,59063],{"className":59064,"style":1075},[1074],[1023,59066,18125],{"className":59067},[1085],[1023,59069,7690],{"className":59070,"style":7723},[1079,1080],[1023,59072,18125],{"className":59073},[1092],[1023,59075],{"className":59076,"style":2355},[2354],[1023,59078,59050],{"className":59079},[2359],[1023,59081],{"className":59082,"style":2355},[2354],[1023,59084,59086,59089],{"className":59085},[1070],[1023,59087],{"className":59088,"style":10020},[1074],[1023,59090,2334],{"className":59091},[1079],[1023,59093,59095,59124],{"className":59094},[1026],[1023,59096,59098],{"className":59097},[1030],[1032,59099,59100],{"xmlns":1034},[1036,59101,59102,59121],{},[1039,59103,59104,59106,59109,59111,59113,59115,59117,59119],{},[1042,59105,7690],{},[1046,59107,59108],{},"←",[1051,59110,2334],{},[1042,59112,7690],{},[1042,59114,2461],{"mathvariant":2460},[1046,59116,18125],{"stretchy":1048},[1042,59118,7690],{},[1046,59120,18125],{"stretchy":1048},[1058,59122,59123],{"encoding":1060},"g \\leftarrow 5 g \u002F \\lVert g \\rVert",[1023,59125,59127,59146],{"className":59126,"ariaHidden":1066},[1065],[1023,59128,59130,59134,59137,59140,59143],{"className":59129},[1070],[1023,59131],{"className":59132,"style":59133},[1074],"height:0.625em;vertical-align:-0.1944em;",[1023,59135,7690],{"className":59136,"style":7723},[1079,1080],[1023,59138],{"className":59139,"style":2355},[2354],[1023,59141,59108],{"className":59142},[2359],[1023,59144],{"className":59145,"style":2355},[2354],[1023,59147,59149,59152,59155,59158,59161,59164,59167],{"className":59148},[1070],[1023,59150],{"className":59151,"style":1075},[1074],[1023,59153,2334],{"className":59154},[1079],[1023,59156,7690],{"className":59157,"style":7723},[1079,1080],[1023,59159,2461],{"className":59160},[1079],[1023,59162,18125],{"className":59163},[1085],[1023,59165,7690],{"className":59166,"style":7723},[1079,1080],[1023,59168,18125],{"className":59169},[1092],[981,59171,59173],{"id":59172},"bài-3-các-kiểu-bài-toán-chuỗi-nâng-cao","Bài 3: Các kiểu bài toán chuỗi (nâng cao)",[973,59175,2699,59176,4437],{},[992,59177,59178],{},"torch.nn.RNN",[2273,59180,59181,59194,59200,59207],{},[989,59182,59183,59186,59187,59189,59190,59193],{},[1487,59184,59185],{},"Many-to-one:"," đếm số chữ ",[992,59188,6207],{}," trong chuỗi ngẫu nhiên dài 10-30 ký tự ",[992,59191,59192],{},"{a, b}",". Hồi quy ra số lượng.",[989,59195,59196,59199],{},[1487,59197,59198],{},"Many-to-many đồng bộ:"," với chuỗi bit, xuất tại mỗi bước tổng các bit tới đó mod 2 (parity chạy).",[989,59201,59202,59203,59206],{},"Chuẩn bị batch chuỗi khác độ dài: pad bằng 0 và dùng ",[992,59204,59205],{},"pack_padded_sequence",". Kiểm tra kết quả không phụ thuộc phần pad.",[989,59208,4938,59209,59211],{},[992,59210,2513],{},", viết mỗi kiểu (one-to-many, many-to-one, many-to-many đồng bộ, lệch) 1 ví dụ bài toán thật.",[981,59213,2711],{"id":2710},[986,59215,59217,59223,59231,59237],{"className":59216},[2715],[989,59218,59220,59222],{"className":59219},[2719],[2721,59221],{"disabled":2723,"type":2724}," Gradient check BPTT pass.",[989,59224,59226,59228,59229,1517],{"className":59225},[2719],[2721,59227],{"disabled":2723,"type":2724}," Có hình chuẩn gradient theo bước thời gian cho 3 mức ",[992,59230,59022],{},[989,59232,59234,59236],{"className":59233},[2719],[2721,59235],{"disabled":2723,"type":2724}," 2 bài many-to-one và many-to-many đạt accuracy trên 95%.",[989,59238,59240,59242],{"className":59239},[2719],[2721,59241],{"disabled":2723,"type":2724}," Kết quả không đổi khi thay độ dài pad.",[968,59244,2890],{"id":2889},[986,59246,59247,59250,59253,59256],{},[989,59248,59249],{},"Thứ tự từ vì sao quan trọng?",[989,59251,59252],{},"4 kiểu chuỗi khác nhau sao?",[989,59254,59255],{},"Cell RNN nhớ bằng gì?",[989,59257,59258],{},"BPTT khác backprop thường ở đâu?",[3014,59260],{},[973,59262,59263],{},"🌕 Bạn đã hoàn thành ngày 100. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,59265,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":59267},[59268,59269,59274,59275,59281],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":59270},[59271,59272,59273],{"id":58679,"depth":73,"text":58680},{"id":58759,"depth":73,"text":58760},{"id":58780,"depth":73,"text":58781},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":59276},[59277,59278,59279,59280],{"id":58842,"depth":73,"text":58843},{"id":58896,"depth":73,"text":58897},{"id":59172,"depth":73,"text":59173},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Dữ liệu tuần tự, bốn kiểu one-to-many many-to-one many-to-many, cell nhớ hidden state và lan truyền ngược theo thời gian.",{},[8149,4669],{"title":555,"description":59282},[59287],"rnn","qB_l1zqX3u0EemWMbIwlnc6a--lnxw7ESkIs0c08qmI",{"id":59290,"title":560,"body":59291,"category":8797,"day":563,"description":60892,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":60893,"navigation":2723,"outcomes":3047,"path":561,"prerequisites":60894,"seo":60895,"stem":562,"tags":60896,"__hash__":60897},"challenges\u002Fchallenges\u002F101.lstm-gru.md",{"type":965,"value":59292,"toc":60876},[59293,59295,59298,59300,59304,59321,59325,59342,59388,59392,59406,59408,59416,59436,59438,59449,59453,60687,60704,60708,60718,60724,60730,60734,60737,60751,60753,60853,60855,60869,60871,60874],[968,59294,971],{"id":970},[973,59296,59297],{},"Bài này học cổng nhớ dài của LSTM và GRU gọn.\nDùng để nhớ ý đầu câu khi đọc tới cuối đoạn.",[968,59299,979],{"id":978},[981,59301,59303],{"id":59302},"lstm","LSTM",[986,59305,59306,59309,59312,59315,59318],{},[989,59307,59308],{},"Định nghĩa: thêm đường cell chạy suốt chuỗi ít bị ghi đè.",[989,59310,59311],{},"Cổng quên quyết giữ bao nhiêu trí nhớ cũ.",[989,59313,59314],{},"Cổng nạp quyết thêm bao nhiêu điều mới.",[989,59316,59317],{},"Ví dụ đời thường: như sổ tay chỉ xóa dòng hết hạn.",[989,59319,59320],{},"Cổng ra quyết lộ bao nhiêu thành đáp án hiện tại.",[981,59322,59324],{"id":59323},"gru","GRU",[986,59326,59327,59330,59333,59336,59339],{},[989,59328,59329],{},"Định nghĩa: bản gọn với 2 cổng, không tách cell riêng.",[989,59331,59332],{},"Cổng cập nhật pha trộn giữa nhớ cũ và đề xuất mới.",[989,59334,59335],{},"Cổng đặt lại quyết bỏ bao nhiêu quá khứ khi đề xuất.",[989,59337,59338],{},"Ví dụ đời thường: như gộp sổ nháp và sổ chính làm một.",[989,59340,59341],{},"Ẩn vừa là trí nhớ vừa là đầu ra luôn.",[1099,59343,59344,59355],{},[1102,59345,59346],{},[1105,59347,59348,59350,59352],{},[1108,59349,41062],{},[1108,59351,56648],{},[1108,59353,59354],{},"Trí nhớ",[1118,59356,59357,59368,59378],{},[1105,59358,59359,59362,59365],{},[1123,59360,59361],{},"RNN cơ bản",[1123,59363,59364],{},"Ít nhất, nhanh nhất",[1123,59366,59367],{},"Chỉ nhớ ngắn",[1105,59369,59370,59372,59375],{},[1123,59371,59324],{},[1123,59373,59374],{},"Vừa, huấn luyện nhanh",[1123,59376,59377],{},"Nhớ trung và dài",[1105,59379,59380,59382,59385],{},[1123,59381,59303],{},[1123,59383,59384],{},"Nhiều nhất, chậm nhất",[1123,59386,59387],{},"Nhớ dài tốt nhất",[981,59389,59391],{"id":59390},"khi-nào-chọn","Khi nào chọn",[986,59393,59394,59397,59400,59403],{},[989,59395,59396],{},"Chuỗi ngắn thì RNN cơ bản đã đủ và nhanh.",[989,59398,59399],{},"Dữ liệu vừa thì GRU là điểm cân bằng tốt.",[989,59401,59402],{},"Chuỗi rất dài thì LSTM giữ xa tốt hơn.",[989,59404,59405],{},"Luôn kẹp gradient và chuẩn hóa để ổn định.",[968,59407,1433],{"id":1432},[986,59409,59410,59413],{},[989,59411,59412],{},"Input: câu dài 30 từ, ý ở từ số 2 -> Output: LSTM nhớ, RNN quên.",[989,59414,59415],{},"Giải thích: đường cell bảo toàn trí nhớ xa tốt hơn.",[1352,59417,59419],{"className":3538,"code":59418,"language":3540,"meta":1357,"style":1357},"# Cổng quên quyết giữ bao nhiêu cũ\nf = sigmoid(x @ Wf + h_cu @ Uf)  # gần 1 là giữ\ncell = f * cell_cu + i * ung_vien  # cập nhật nhẹ\n",[992,59420,59421,59426,59431],{"__ignoreMap":1357},[1023,59422,59423],{"class":1362,"line":63},[1023,59424,59425],{},"# Cổng quên quyết giữ bao nhiêu cũ\n",[1023,59427,59428],{"class":1362,"line":68},[1023,59429,59430],{},"f = sigmoid(x @ Wf + h_cu @ Uf)  # gần 1 là giữ\n",[1023,59432,59433],{"class":1362,"line":73},[1023,59434,59435],{},"cell = f * cell_cu + i * ung_vien  # cập nhật nhẹ\n",[968,59437,1482],{"id":1481},[973,59439,1485,59440,59442,59443,59445,59446,1517],{},[1487,59441,13531],{}," với NumPy cho Bài 1, ",[1487,59444,56749],{}," cho Bài 2-3. Nộp vào ",[992,59447,59448],{},"day-101\u002F",[981,59450,59452],{"id":59451},"bài-1-lstm-và-gru-cell-tự-cài-forward","Bài 1: LSTM và GRU cell tự cài (forward)",[1099,59454,59455,59465],{},[1102,59456,59457],{},[1105,59458,59459,59462],{},[1108,59460,59461],{},"Cell",[1108,59463,59464],{},"Công thức cần cài",[1118,59466,59467,60100],{},[1105,59468,59469,59471],{},[1123,59470,59303],{},[1123,59472,59473,1656,59569,1656,59677,1656,59927],{},[1023,59474,59476,59510],{"className":59475},[1026],[1023,59477,59479],{"className":59478},[1030],[1032,59480,59481],{"xmlns":1034},[1036,59482,59483,59507],{},[1039,59484,59485,59488,59490,59492,59494,59496,59498,59501,59503,59505],{},[1042,59486,59487],{},"f",[1046,59489,13897],{"separator":1066},[1042,59491,1837],{},[1046,59493,13897],{"separator":1066},[1042,59495,7687],{},[1046,59497,2325],{},[1042,59499,59500],{},"σ",[1046,59502,1049],{"stretchy":1048},[1046,59504,18118],{},[1046,59506,1056],{"stretchy":1048},[1058,59508,59509],{"encoding":1060},"f, i, o = \\sigma(\\cdot)",[1023,59511,59513,59551],{"className":59512,"ariaHidden":1066},[1065],[1023,59514,59516,59520,59524,59527,59530,59533,59536,59539,59542,59545,59548],{"className":59515},[1070],[1023,59517],{"className":59518,"style":59519},[1074],"height:0.8889em;vertical-align:-0.1944em;",[1023,59521,59487],{"className":59522,"style":59523},[1079,1080],"margin-right:0.1076em;",[1023,59525,13897],{"className":59526},[13943],[1023,59528],{"className":59529,"style":8434},[2354],[1023,59531,1837],{"className":59532},[1079,1080],[1023,59534,13897],{"className":59535},[13943],[1023,59537],{"className":59538,"style":8434},[2354],[1023,59540,7687],{"className":59541},[1079,1080],[1023,59543],{"className":59544,"style":2355},[2354],[1023,59546,2325],{"className":59547},[2359],[1023,59549],{"className":59550,"style":2355},[2354],[1023,59552,59554,59557,59560,59563,59566],{"className":59553},[1070],[1023,59555],{"className":59556,"style":1075},[1074],[1023,59558,59500],{"className":59559,"style":7723},[1079,1080],[1023,59561,1049],{"className":59562},[1085],[1023,59564,18118],{"className":59565},[1079],[1023,59567,1056],{"className":59568},[1092],[1023,59570,59572,59604],{"className":59571},[1026],[1023,59573,59575],{"className":59574},[1030],[1032,59576,59577],{"xmlns":1034},[1036,59578,59579,59601],{},[1039,59580,59581,59589,59591,59593,59595,59597,59599],{},[59582,59583,59584,59586],"mover",{"accent":1066},[1042,59585,1356],{},[1046,59587,59588],{},"~",[1046,59590,2325],{},[1042,59592,56026],{},[1046,59594,8400],{},[1046,59596,1049],{"stretchy":1048},[1046,59598,18118],{},[1046,59600,1056],{"stretchy":1048},[1058,59602,59603],{"encoding":1060},"\\tilde c = \\tanh(\\cdot)",[1023,59605,59607,59659],{"className":59606,"ariaHidden":1066},[1065],[1023,59608,59610,59614,59650,59653,59656],{"className":59609},[1070],[1023,59611],{"className":59612,"style":59613},[1074],"height:0.6679em;",[1023,59615,59618],{"className":59616},[1079,59617],"accent",[1023,59619,59621],{"className":59620},[2387],[1023,59622,59624],{"className":59623},[2391],[1023,59625,59627,59636],{"className":59626,"style":59613},[2395],[1023,59628,59630,59633],{"style":59629},"top:-3em;",[1023,59631],{"className":59632,"style":18194},[2402],[1023,59634,1356],{"className":59635},[1079,1080],[1023,59637,59639,59642],{"style":59638},"top:-3.35em;",[1023,59640],{"className":59641,"style":18194},[2402],[1023,59643,59647],{"className":59644,"style":59646},[59645],"accent-body","left:-0.1944em;",[1023,59648,59588],{"className":59649},[1079],[1023,59651],{"className":59652,"style":2355},[2354],[1023,59654,2325],{"className":59655},[2359],[1023,59657],{"className":59658,"style":2355},[2354],[1023,59660,59662,59665,59668,59671,59674],{"className":59661},[1070],[1023,59663],{"className":59664,"style":1075},[1074],[1023,59666,56026],{"className":59667},[8426],[1023,59669,1049],{"className":59670},[1085],[1023,59672,18118],{"className":59673},[1079],[1023,59675,1056],{"className":59676},[1092],[1023,59678,59680,59729],{"className":59679},[1026],[1023,59681,59683],{"className":59682},[1030],[1032,59684,59685],{"xmlns":1034},[1036,59686,59687,59726],{},[1039,59688,59689,59695,59697,59699,59702,59714,59716,59718,59720],{},[17690,59690,59691,59693],{},[1042,59692,1356],{},[1042,59694,29580],{},[1046,59696,2325],{},[1042,59698,59487],{},[1046,59700,59701],{},"⊙",[17690,59703,59704,59706],{},[1042,59705,1356],{},[1039,59707,59708,59710,59712],{},[1042,59709,29580],{},[1046,59711,17698],{},[1051,59713,1053],{},[1046,59715,21881],{},[1042,59717,1837],{},[1046,59719,59701],{},[59582,59721,59722,59724],{"accent":1066},[1042,59723,1356],{},[1046,59725,59588],{},[1058,59727,59728],{"encoding":1060},"c_t = f \\odot c_{t-1} + i \\odot \\tilde c",[1023,59730,59732,59787,59805,59871,59890],{"className":59731,"ariaHidden":1066},[1065],[1023,59733,59735,59738,59778,59781,59784],{"className":59734},[1070],[1023,59736],{"className":59737,"style":54000},[1074],[1023,59739,59741,59744],{"className":59740},[1079],[1023,59742,1356],{"className":59743},[1079,1080],[1023,59745,59747],{"className":59746},[2383],[1023,59748,59750,59770],{"className":59749},[2387,17732],[1023,59751,59753,59767],{"className":59752},[2391],[1023,59754,59756],{"className":59755,"style":58984},[2395],[1023,59757,59758,59761],{"style":17783},[1023,59759],{"className":59760,"style":2403},[2402],[1023,59762,59764],{"className":59763},[2407,2408,2409,2410],[1023,59765,29580],{"className":59766},[1079,1080,2410],[1023,59768,17797],{"className":59769},[17796],[1023,59771,59773],{"className":59772},[2391],[1023,59774,59776],{"className":59775,"style":17804},[2395],[1023,59777],{},[1023,59779],{"className":59780,"style":2355},[2354],[1023,59782,2325],{"className":59783},[2359],[1023,59785],{"className":59786,"style":2355},[2354],[1023,59788,59790,59793,59796,59799,59802],{"className":59789},[1070],[1023,59791],{"className":59792,"style":59519},[1074],[1023,59794,59487],{"className":59795,"style":59523},[1079,1080],[1023,59797],{"className":59798,"style":13790},[2354],[1023,59800,59701],{"className":59801},[13794],[1023,59803],{"className":59804,"style":13790},[2354],[1023,59806,59808,59812,59862,59865,59868],{"className":59807},[1070],[1023,59809],{"className":59810,"style":59811},[1074],"height:0.7917em;vertical-align:-0.2083em;",[1023,59813,59815,59818],{"className":59814},[1079],[1023,59816,1356],{"className":59817},[1079,1080],[1023,59819,59821],{"className":59820},[2383],[1023,59822,59824,59853],{"className":59823},[2387,17732],[1023,59825,59827,59850],{"className":59826},[2391],[1023,59828,59830],{"className":59829,"style":54019},[2395],[1023,59831,59832,59835],{"style":17783},[1023,59833],{"className":59834,"style":2403},[2402],[1023,59836,59838],{"className":59837},[2407,2408,2409,2410],[1023,59839,59841,59844,59847],{"className":59840},[1079,2410],[1023,59842,29580],{"className":59843},[1079,1080,2410],[1023,59845,17698],{"className":59846},[13794,2410],[1023,59848,1053],{"className":59849},[1079,2410],[1023,59851,17797],{"className":59852},[17796],[1023,59854,59856],{"className":59855},[2391],[1023,59857,59860],{"className":59858,"style":59859},[2395],"height:0.2083em;",[1023,59861],{},[1023,59863],{"className":59864,"style":13790},[2354],[1023,59866,21881],{"className":59867},[13794],[1023,59869],{"className":59870,"style":13790},[2354],[1023,59872,59874,59878,59881,59884,59887],{"className":59873},[1070],[1023,59875],{"className":59876,"style":59877},[1074],"height:0.7429em;vertical-align:-0.0833em;",[1023,59879,1837],{"className":59880},[1079,1080],[1023,59882],{"className":59883,"style":13790},[2354],[1023,59885,59701],{"className":59886},[13794],[1023,59888],{"className":59889,"style":13790},[2354],[1023,59891,59893,59896],{"className":59892},[1070],[1023,59894],{"className":59895,"style":59613},[1074],[1023,59897,59899],{"className":59898},[1079,59617],[1023,59900,59902],{"className":59901},[2387],[1023,59903,59905],{"className":59904},[2391],[1023,59906,59908,59916],{"className":59907,"style":59613},[2395],[1023,59909,59910,59913],{"style":59629},[1023,59911],{"className":59912,"style":18194},[2402],[1023,59914,1356],{"className":59915},[1079,1080],[1023,59917,59918,59921],{"style":59638},[1023,59919],{"className":59920,"style":18194},[2402],[1023,59922,59924],{"className":59923,"style":59646},[59645],[1023,59925,59588],{"className":59926},[1079],[1023,59928,59930,59968],{"className":59929},[1026],[1023,59931,59933],{"className":59932},[1030],[1032,59934,59935],{"xmlns":1034},[1036,59936,59937,59965],{},[1039,59938,59939,59945,59947,59949,59951,59953,59955,59957,59963],{},[17690,59940,59941,59943],{},[1042,59942,7908],{},[1042,59944,29580],{},[1046,59946,2325],{},[1042,59948,7687],{},[1046,59950,59701],{},[1042,59952,56026],{},[1046,59954,8400],{},[1046,59956,1049],{"stretchy":1048},[17690,59958,59959,59961],{},[1042,59960,1356],{},[1042,59962,29580],{},[1046,59964,1056],{"stretchy":1048},[1058,59966,59967],{"encoding":1060},"h_t = o \\odot \\tanh(c_t)",[1023,59969,59971,60027,60045],{"className":59970,"ariaHidden":1066},[1065],[1023,59972,59974,59978,60018,60021,60024],{"className":59973},[1070],[1023,59975],{"className":59976,"style":59977},[1074],"height:0.8444em;vertical-align:-0.15em;",[1023,59979,59981,59984],{"className":59980},[1079],[1023,59982,7908],{"className":59983},[1079,1080],[1023,59985,59987],{"className":59986},[2383],[1023,59988,59990,60010],{"className":59989},[2387,17732],[1023,59991,59993,60007],{"className":59992},[2391],[1023,59994,59996],{"className":59995,"style":58984},[2395],[1023,59997,59998,60001],{"style":17783},[1023,59999],{"className":60000,"style":2403},[2402],[1023,60002,60004],{"className":60003},[2407,2408,2409,2410],[1023,60005,29580],{"className":60006},[1079,1080,2410],[1023,60008,17797],{"className":60009},[17796],[1023,60011,60013],{"className":60012},[2391],[1023,60014,60016],{"className":60015,"style":17804},[2395],[1023,60017],{},[1023,60019],{"className":60020,"style":2355},[2354],[1023,60022,2325],{"className":60023},[2359],[1023,60025],{"className":60026,"style":2355},[2354],[1023,60028,60030,60033,60036,60039,60042],{"className":60029},[1070],[1023,60031],{"className":60032,"style":13783},[1074],[1023,60034,7687],{"className":60035},[1079,1080],[1023,60037],{"className":60038,"style":13790},[2354],[1023,60040,59701],{"className":60041},[13794],[1023,60043],{"className":60044,"style":13790},[2354],[1023,60046,60048,60051,60054,60057,60097],{"className":60047},[1070],[1023,60049],{"className":60050,"style":1075},[1074],[1023,60052,56026],{"className":60053},[8426],[1023,60055,1049],{"className":60056},[1085],[1023,60058,60060,60063],{"className":60059},[1079],[1023,60061,1356],{"className":60062},[1079,1080],[1023,60064,60066],{"className":60065},[2383],[1023,60067,60069,60089],{"className":60068},[2387,17732],[1023,60070,60072,60086],{"className":60071},[2391],[1023,60073,60075],{"className":60074,"style":58984},[2395],[1023,60076,60077,60080],{"style":17783},[1023,60078],{"className":60079,"style":2403},[2402],[1023,60081,60083],{"className":60082},[2407,2408,2409,2410],[1023,60084,29580],{"className":60085},[1079,1080,2410],[1023,60087,17797],{"className":60088},[17796],[1023,60090,60092],{"className":60091},[2391],[1023,60093,60095],{"className":60094,"style":17804},[2395],[1023,60096],{},[1023,60098,1056],{"className":60099},[1092],[1105,60101,60102,60104],{},[1123,60103,59324],{},[1123,60105,60106,1656,60187,1656,60408],{},[1023,60107,60109,60138],{"className":60108},[1026],[1023,60110,60112],{"className":60111},[1030],[1032,60113,60114],{"xmlns":1034},[1036,60115,60116,60135],{},[1039,60117,60118,60121,60123,60125,60127,60129,60131,60133],{},[1042,60119,60120],{},"z",[1046,60122,13897],{"separator":1066},[1042,60124,12970],{},[1046,60126,2325],{},[1042,60128,59500],{},[1046,60130,1049],{"stretchy":1048},[1046,60132,18118],{},[1046,60134,1056],{"stretchy":1048},[1058,60136,60137],{"encoding":1060},"z, r = \\sigma(\\cdot)",[1023,60139,60141,60169],{"className":60140,"ariaHidden":1066},[1065],[1023,60142,60144,60147,60151,60154,60157,60160,60163,60166],{"className":60143},[1070],[1023,60145],{"className":60146,"style":59133},[1074],[1023,60148,60120],{"className":60149,"style":60150},[1079,1080],"margin-right:0.044em;",[1023,60152,13897],{"className":60153},[13943],[1023,60155],{"className":60156,"style":8434},[2354],[1023,60158,12970],{"className":60159,"style":1081},[1079,1080],[1023,60161],{"className":60162,"style":2355},[2354],[1023,60164,2325],{"className":60165},[2359],[1023,60167],{"className":60168,"style":2355},[2354],[1023,60170,60172,60175,60178,60181,60184],{"className":60171},[1070],[1023,60173],{"className":60174,"style":1075},[1074],[1023,60176,59500],{"className":60177,"style":7723},[1079,1080],[1023,60179,1049],{"className":60180},[1085],[1023,60182,18118],{"className":60183},[1079],[1023,60185,1056],{"className":60186},[1092],[1023,60188,60190,60247],{"className":60189},[1026],[1023,60191,60193],{"className":60192},[1030],[1032,60194,60195],{"xmlns":1034},[1036,60196,60197,60244],{},[1039,60198,60199,60205,60207,60209,60211,60213,60215,60217,60219,60222,60224,60226,60228,60240,60242],{},[59582,60200,60201,60203],{"accent":1066},[1042,60202,7908],{},[1046,60204,59588],{},[1046,60206,2325],{},[1042,60208,56026],{},[1046,60210,8400],{},[1046,60212,1049],{"stretchy":1048},[1042,60214,56943],{},[1042,60216,3904],{},[1046,60218,21881],{},[1042,60220,60221],{},"U",[1046,60223,1049],{"stretchy":1048},[1042,60225,12970],{},[1046,60227,59701],{},[17690,60229,60230,60232],{},[1042,60231,7908],{},[1039,60233,60234,60236,60238],{},[1042,60235,29580],{},[1046,60237,17698],{},[1051,60239,1053],{},[1046,60241,1056],{"stretchy":1048},[1046,60243,1056],{"stretchy":1048},[1058,60245,60246],{"encoding":1060},"\\tilde h = \\tanh(W x + U (r \\odot h_{t-1}))",[1023,60248,60250,60299,60326,60350],{"className":60249,"ariaHidden":1066},[1065],[1023,60251,60253,60257,60290,60293,60296],{"className":60252},[1070],[1023,60254],{"className":60255,"style":60256},[1074],"height:0.9313em;",[1023,60258,60260],{"className":60259},[1079,59617],[1023,60261,60263],{"className":60262},[2387],[1023,60264,60266],{"className":60265},[2391],[1023,60267,60269,60277],{"className":60268,"style":60256},[2395],[1023,60270,60271,60274],{"style":59629},[1023,60272],{"className":60273,"style":18194},[2402],[1023,60275,7908],{"className":60276},[1079,1080],[1023,60278,60280,60283],{"style":60279},"top:-3.6134em;",[1023,60281],{"className":60282,"style":18194},[2402],[1023,60284,60287],{"className":60285,"style":60286},[59645],"left:-0.25em;",[1023,60288,59588],{"className":60289},[1079],[1023,60291],{"className":60292,"style":2355},[2354],[1023,60294,2325],{"className":60295},[2359],[1023,60297],{"className":60298,"style":2355},[2354],[1023,60300,60302,60305,60308,60311,60314,60317,60320,60323],{"className":60301},[1070],[1023,60303],{"className":60304,"style":1075},[1074],[1023,60306,56026],{"className":60307},[8426],[1023,60309,1049],{"className":60310},[1085],[1023,60312,56943],{"className":60313,"style":37429},[1079,1080],[1023,60315,3904],{"className":60316},[1079,1080],[1023,60318],{"className":60319,"style":13790},[2354],[1023,60321,21881],{"className":60322},[13794],[1023,60324],{"className":60325,"style":13790},[2354],[1023,60327,60329,60332,60335,60338,60341,60344,60347],{"className":60328},[1070],[1023,60330],{"className":60331,"style":1075},[1074],[1023,60333,60221],{"className":60334,"style":20451},[1079,1080],[1023,60336,1049],{"className":60337},[1085],[1023,60339,12970],{"className":60340,"style":1081},[1079,1080],[1023,60342],{"className":60343,"style":13790},[2354],[1023,60345,59701],{"className":60346},[13794],[1023,60348],{"className":60349,"style":13790},[2354],[1023,60351,60353,60356,60405],{"className":60352},[1070],[1023,60354],{"className":60355,"style":1075},[1074],[1023,60357,60359,60362],{"className":60358},[1079],[1023,60360,7908],{"className":60361},[1079,1080],[1023,60363,60365],{"className":60364},[2383],[1023,60366,60368,60397],{"className":60367},[2387,17732],[1023,60369,60371,60394],{"className":60370},[2391],[1023,60372,60374],{"className":60373,"style":54019},[2395],[1023,60375,60376,60379],{"style":17783},[1023,60377],{"className":60378,"style":2403},[2402],[1023,60380,60382],{"className":60381},[2407,2408,2409,2410],[1023,60383,60385,60388,60391],{"className":60384},[1079,2410],[1023,60386,29580],{"className":60387},[1079,1080,2410],[1023,60389,17698],{"className":60390},[13794,2410],[1023,60392,1053],{"className":60393},[1079,2410],[1023,60395,17797],{"className":60396},[17796],[1023,60398,60400],{"className":60399},[2391],[1023,60401,60403],{"className":60402,"style":59859},[2395],[1023,60404],{},[1023,60406,47920],{"className":60407},[1092],[1023,60409,60411,60467],{"className":60410},[1026],[1023,60412,60414],{"className":60413},[1030],[1032,60415,60416],{"xmlns":1034},[1036,60417,60418,60464],{},[1039,60419,60420,60426,60428,60430,60432,60434,60436,60438,60440,60452,60454,60456,60458],{},[17690,60421,60422,60424],{},[1042,60423,7908],{},[1042,60425,29580],{},[1046,60427,2325],{},[1046,60429,1049],{"stretchy":1048},[1051,60431,1053],{},[1046,60433,17698],{},[1042,60435,60120],{},[1046,60437,1056],{"stretchy":1048},[1046,60439,59701],{},[17690,60441,60442,60444],{},[1042,60443,7908],{},[1039,60445,60446,60448,60450],{},[1042,60447,29580],{},[1046,60449,17698],{},[1051,60451,1053],{},[1046,60453,21881],{},[1042,60455,60120],{},[1046,60457,59701],{},[59582,60459,60460,60462],{"accent":1066},[1042,60461,7908],{},[1046,60463,59588],{},[1058,60465,60466],{"encoding":1060},"h_t = (1 - z) \\odot h_{t-1} + z \\odot \\tilde h",[1023,60468,60470,60525,60546,60567,60632,60650],{"className":60469,"ariaHidden":1066},[1065],[1023,60471,60473,60476,60516,60519,60522],{"className":60472},[1070],[1023,60474],{"className":60475,"style":59977},[1074],[1023,60477,60479,60482],{"className":60478},[1079],[1023,60480,7908],{"className":60481},[1079,1080],[1023,60483,60485],{"className":60484},[2383],[1023,60486,60488,60508],{"className":60487},[2387,17732],[1023,60489,60491,60505],{"className":60490},[2391],[1023,60492,60494],{"className":60493,"style":58984},[2395],[1023,60495,60496,60499],{"style":17783},[1023,60497],{"className":60498,"style":2403},[2402],[1023,60500,60502],{"className":60501},[2407,2408,2409,2410],[1023,60503,29580],{"className":60504},[1079,1080,2410],[1023,60506,17797],{"className":60507},[17796],[1023,60509,60511],{"className":60510},[2391],[1023,60512,60514],{"className":60513,"style":17804},[2395],[1023,60515],{},[1023,60517],{"className":60518,"style":2355},[2354],[1023,60520,2325],{"className":60521},[2359],[1023,60523],{"className":60524,"style":2355},[2354],[1023,60526,60528,60531,60534,60537,60540,60543],{"className":60527},[1070],[1023,60529],{"className":60530,"style":1075},[1074],[1023,60532,1049],{"className":60533},[1085],[1023,60535,1053],{"className":60536},[1079],[1023,60538],{"className":60539,"style":13790},[2354],[1023,60541,17698],{"className":60542},[13794],[1023,60544],{"className":60545,"style":13790},[2354],[1023,60547,60549,60552,60555,60558,60561,60564],{"className":60548},[1070],[1023,60550],{"className":60551,"style":1075},[1074],[1023,60553,60120],{"className":60554,"style":60150},[1079,1080],[1023,60556,1056],{"className":60557},[1092],[1023,60559],{"className":60560,"style":13790},[2354],[1023,60562,59701],{"className":60563},[13794],[1023,60565],{"className":60566,"style":13790},[2354],[1023,60568,60570,60574,60623,60626,60629],{"className":60569},[1070],[1023,60571],{"className":60572,"style":60573},[1074],"height:0.9028em;vertical-align:-0.2083em;",[1023,60575,60577,60580],{"className":60576},[1079],[1023,60578,7908],{"className":60579},[1079,1080],[1023,60581,60583],{"className":60582},[2383],[1023,60584,60586,60615],{"className":60585},[2387,17732],[1023,60587,60589,60612],{"className":60588},[2391],[1023,60590,60592],{"className":60591,"style":54019},[2395],[1023,60593,60594,60597],{"style":17783},[1023,60595],{"className":60596,"style":2403},[2402],[1023,60598,60600],{"className":60599},[2407,2408,2409,2410],[1023,60601,60603,60606,60609],{"className":60602},[1079,2410],[1023,60604,29580],{"className":60605},[1079,1080,2410],[1023,60607,17698],{"className":60608},[13794,2410],[1023,60610,1053],{"className":60611},[1079,2410],[1023,60613,17797],{"className":60614},[17796],[1023,60616,60618],{"className":60617},[2391],[1023,60619,60621],{"className":60620,"style":59859},[2395],[1023,60622],{},[1023,60624],{"className":60625,"style":13790},[2354],[1023,60627,21881],{"className":60628},[13794],[1023,60630],{"className":60631,"style":13790},[2354],[1023,60633,60635,60638,60641,60644,60647],{"className":60634},[1070],[1023,60636],{"className":60637,"style":13783},[1074],[1023,60639,60120],{"className":60640,"style":60150},[1079,1080],[1023,60642],{"className":60643,"style":13790},[2354],[1023,60645,59701],{"className":60646},[13794],[1023,60648],{"className":60649,"style":13790},[2354],[1023,60651,60653,60656],{"className":60652},[1070],[1023,60654],{"className":60655,"style":60256},[1074],[1023,60657,60659],{"className":60658},[1079,59617],[1023,60660,60662],{"className":60661},[2387],[1023,60663,60665],{"className":60664},[2391],[1023,60666,60668,60676],{"className":60667,"style":60256},[2395],[1023,60669,60670,60673],{"style":59629},[1023,60671],{"className":60672,"style":18194},[2402],[1023,60674,7908],{"className":60675},[1079,1080],[1023,60677,60678,60681],{"style":60279},[1023,60679],{"className":60680,"style":18194},[2402],[1023,60682,60684],{"className":60683,"style":60286},[59645],[1023,60685,59588],{"className":60686},[1079],[2273,60688,60689,60701],{},[989,60690,60691,60692,1509,60695,60698,60699,1517],{},"Copy trọng số từ ",[992,60693,60694],{},"torch.nn.LSTMCell",[992,60696,60697],{},"torch.nn.GRUCell"," (chú ý thứ tự cổng trong PyTorch) sang bản NumPy. Output phải khớp sai số ",[992,60700,32245],{},[989,60702,60703],{},"Đếm tham số: LSTM gấp 4 lần RNN, GRU gấp 3 lần. Kiểm tra bằng số.",[981,60705,60707],{"id":60706},"bài-2-bài-toán-nhớ-xa","Bài 2: Bài toán nhớ xa",[973,60709,60710,60711,60713,60714,60717],{},"Chuỗi dài ",[992,60712,38209],{}," gồm số ngẫu nhiên. Nhãn là ",[1487,60715,60716],{},"phần tử thứ 2"," của chuỗi. Mô hình chỉ đọc hết chuỗi rồi đoán (many-to-one).",[1352,60719,60722],{"className":60720,"code":60721,"language":2241,"meta":1357},[2239],"T       RNN_acc    GRU_acc    LSTM_acc\n10      ...\n30      ...\n100     ...\n",[992,60723,60721],{"__ignoreMap":1357},[973,60725,60726,60727,60729],{},"Cùng số epoch, cùng hidden size, có gradient clipping. Chỉ ra ",[992,60728,38209],{}," mà RNN bắt đầu thua.",[981,60731,60733],{"id":60732},"bài-3-dự-báo-chuỗi-thời-gian-nâng-cao","Bài 3: Dự báo chuỗi thời gian (nâng cao)",[973,60735,60736],{},"Dữ liệu: nhiệt độ hằng ngày (dữ liệu công khai) hoặc sóng sin cộng nhiễu.",[2273,60738,60739,60742,60745,60748],{},[989,60740,60741],{},"Cửa sổ 30 ngày, đoán ngày 31. Chuẩn hóa bằng mean\u002Fstd của tập train.",[989,60743,60744],{},"Chia theo thời gian 70\u002F15\u002F15, không xáo trộn.",[989,60746,60747],{},"So LSTM, GRU và baseline \"ngày mai bằng hôm nay\". In MAE test.",[989,60749,60750],{},"Vẽ dự báo chồng lên giá trị thật trên tập test.",[981,60752,2711],{"id":2710},[986,60754,60756,60762,60771,60777],{"className":60755},[2715],[989,60757,60759,60761],{"className":60758},[2719],[2721,60760],{"disabled":2723,"type":2724}," Cell NumPy khớp PyTorch.",[989,60763,60765,60767,60768,60770],{"className":60764},[2719],[2721,60766],{"disabled":2723,"type":2724}," Bảng nhớ xa có số thật, thấy rõ RNN thua ở ",[992,60769,38209],{}," lớn.",[989,60772,60774,60776],{"className":60773},[2719],[2721,60775],{"disabled":2723,"type":2724}," Bài 3 có baseline và LSTM\u002FGRU thắng baseline.",[989,60778,60780,60782,60783,1517],{"className":60779},[2719],[2721,60781],{"disabled":2723,"type":2724}," Giải thích được vai trò cổng quên bằng công thức ",[1023,60784,60786,60804],{"className":60785},[1026],[1023,60787,60789],{"className":60788},[1030],[1032,60790,60791],{"xmlns":1034},[1036,60792,60793,60801],{},[1039,60794,60795],{},[17690,60796,60797,60799],{},[1042,60798,1356],{},[1042,60800,29580],{},[1058,60802,60803],{"encoding":1060},"c_t",[1023,60805,60807],{"className":60806,"ariaHidden":1066},[1065],[1023,60808,60810,60813],{"className":60809},[1070],[1023,60811],{"className":60812,"style":54000},[1074],[1023,60814,60816,60819],{"className":60815},[1079],[1023,60817,1356],{"className":60818},[1079,1080],[1023,60820,60822],{"className":60821},[2383],[1023,60823,60825,60845],{"className":60824},[2387,17732],[1023,60826,60828,60842],{"className":60827},[2391],[1023,60829,60831],{"className":60830,"style":58984},[2395],[1023,60832,60833,60836],{"style":17783},[1023,60834],{"className":60835,"style":2403},[2402],[1023,60837,60839],{"className":60838},[2407,2408,2409,2410],[1023,60840,29580],{"className":60841},[1079,1080,2410],[1023,60843,17797],{"className":60844},[17796],[1023,60846,60848],{"className":60847},[2391],[1023,60849,60851],{"className":60850,"style":17804},[2395],[1023,60852],{},[968,60854,2890],{"id":2889},[986,60856,60857,60860,60863,60866],{},[989,60858,60859],{},"Đường cell khác trí nhớ RNN sao?",[989,60861,60862],{},"Cổng quên làm gì?",[989,60864,60865],{},"GRU gọn hơn LSTM ở đâu?",[989,60867,60868],{},"Chuỗi ngắn nên dùng gì?",[3014,60870],{},[973,60872,60873],{},"🌕 Bạn đã hoàn thành ngày 101. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,60875,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":60877},[60878,60879,60884,60885,60891],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":60880},[60881,60882,60883],{"id":59302,"depth":73,"text":59303},{"id":59323,"depth":73,"text":59324},{"id":59390,"depth":73,"text":59391},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":60886},[60887,60888,60889,60890],{"id":59451,"depth":73,"text":59452},{"id":60706,"depth":73,"text":60707},{"id":60732,"depth":73,"text":60733},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cổng quên cổng cập nhật, trạng thái cell, so sánh LSTM GRU RNN cơ bản và thí nghiệm chuỗi trong bài này.",{},[15144],{"title":560,"description":60892},[59287],"WHOUzuvepGge6ZYhHBX52Lx2-APcpJ0S8dCl7b7E0qA",{"id":60899,"title":565,"body":60900,"category":8797,"day":568,"description":61247,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":61248,"navigation":2723,"outcomes":3047,"path":566,"prerequisites":61249,"seo":61250,"stem":567,"tags":61251,"__hash__":61253},"challenges\u002Fchallenges\u002F102.attention-transformer.md",{"type":965,"value":60901,"toc":61231},[60902,60904,60907,60909,60913,60930,60934,60951,61000,61004,61021,61023,61031,61051,61053,61062,61066,61096,61102,61107,61111,61140,61144,61147,61174,61176,61208,61210,61224,61226,61229],[968,60903,971],{"id":970},[973,60905,60906],{},"Bài này học nhìn lại chỗ quan trọng khi dịch câu.\nDùng để sửa bệnh nhồi cả câu vào 1 vector.",[968,60908,979],{"id":978},[981,60910,60912],{"id":60911},"nút-thắt-thought-vector","Nút thắt thought vector",[986,60914,60915,60918,60921,60924,60927],{},[989,60916,60917],{},"Định nghĩa: nhồi cả câu dài vào 1 vector duy nhất.",[989,60919,60920],{},"Câu ngắn còn xoay sở, câu dài mất đầu câu.",[989,60922,60923],{},"Ví dụ đời thường: như tóm tắt sách vào 1 mẩu giấy.",[989,60925,60926],{},"Đây là động lực sinh ra attention.",[989,60928,60929],{},"Muốn dịch dài phải cho nhìn lại nguồn.",[981,60931,60933],{"id":60932},"cơ-chế-chú-ý","Cơ chế chú ý",[986,60935,60936,60939,60942,60945,60948],{},[989,60937,60938],{},"Định nghĩa: mỗi từ ra tham khảo lại mọi từ vào.",[989,60940,60941],{},"Truy vấn là thứ đang cần viết hiện tại.",[989,60943,60944],{},"Khóa là nhãn từng vị trí nguồn, giá trị là nội dung.",[989,60946,60947],{},"Ví dụ đời thường: như tra mục lục trước khi chép.",[989,60949,60950],{},"Trọng số cao rơi đúng chỗ cần tham khảo nhất.",[1099,60952,60953,60965],{},[1102,60954,60955],{},[1105,60956,60957,60959,60962],{},[1108,60958,2544],{},[1108,60960,60961],{},"Vai trò",[1108,60963,60964],{},"Ví như",[1118,60966,60967,60978,60989],{},[1105,60968,60969,60972,60975],{},[1123,60970,60971],{},"Truy vấn",[1123,60973,60974],{},"Thứ đang cần viết",[1123,60976,60977],{},"Câu hỏi hiện tại",[1105,60979,60980,60983,60986],{},[1123,60981,60982],{},"Khóa",[1123,60984,60985],{},"Nhãn vị trí nguồn",[1123,60987,60988],{},"Mục lục sách",[1105,60990,60991,60994,60997],{},[1123,60992,60993],{},"Giá trị",[1123,60995,60996],{},"Nội dung mang theo",[1123,60998,60999],{},"Trang sách thật",[981,61001,61003],{"id":61002},"self-attention-và-transformer","Self-attention và Transformer",[986,61005,61006,61009,61012,61015,61018],{},[989,61007,61008],{},"Định nghĩa: mỗi từ trong cùng câu hỏi lẫn nhau.",[989,61010,61011],{},"Từ đa nghĩa kéo ngữ cảnh khác nên nghĩa cuối khác.",[989,61013,61014],{},"Ví dụ đời thường: như chữ \"quả\" trong táo và bóng.",[989,61016,61017],{},"Transformer bỏ RNN, chỉ dùng attention nên song song tốt.",[989,61019,61020],{},"Encoder hiểu 2 chiều, decoder sinh từng từ một.",[968,61022,1433],{"id":1432},[986,61024,61025,61028],{},[989,61026,61027],{},"Input: dịch \"con mèo đen\" -> Output: viết \"mèo\" thì nhìn vùng \"mèo\".",[989,61029,61030],{},"Giải thích: trọng số chú ý dồn đúng chỗ đang dịch.",[1352,61032,61034],{"className":3538,"code":61033,"language":3540,"meta":1357,"style":1357},"# Trung bình có trọng số theo chú ý\nngu_canh = sum(w * v for w, v in zip(trong_so, gia_tri))\nprint(ngu_canh)  # ngữ cảnh động\n",[992,61035,61036,61041,61046],{"__ignoreMap":1357},[1023,61037,61038],{"class":1362,"line":63},[1023,61039,61040],{},"# Trung bình có trọng số theo chú ý\n",[1023,61042,61043],{"class":1362,"line":68},[1023,61044,61045],{},"ngu_canh = sum(w * v for w, v in zip(trong_so, gia_tri))\n",[1023,61047,61048],{"class":1362,"line":73},[1023,61049,61050],{},"print(ngu_canh)  # ngữ cảnh động\n",[968,61052,1482],{"id":1481},[973,61054,1485,61055,56746,61057,56750,61059,1517],{},[1487,61056,13531],{},[1487,61058,56749],{},[992,61060,61061],{},"day-102\u002F",[981,61063,61065],{"id":61064},"bài-1-scaled-dot-product-attention","Bài 1: Scaled dot-product attention",[1352,61067,61069],{"className":3538,"code":61068,"language":3540,"meta":1357,"style":1357},"def softmax(x, axis=-1): ...          # trừ max để ổn định số\ndef attention(Q, K, V, mask=None):\n    \"\"\"Q: (n_q, d_k), K: (n_k, d_k), V: (n_k, d_v).\n       Trả (output: (n_q, d_v), weights: (n_q, n_k)). weights = softmax(Q K^T \u002F sqrt(d_k)).\n       mask: True ở vị trí cấm, gán -inf trước softmax.\"\"\"\n",[992,61070,61071,61076,61081,61086,61091],{"__ignoreMap":1357},[1023,61072,61073],{"class":1362,"line":63},[1023,61074,61075],{},"def softmax(x, axis=-1): ...          # trừ max để ổn định số\n",[1023,61077,61078],{"class":1362,"line":68},[1023,61079,61080],{},"def attention(Q, K, V, mask=None):\n",[1023,61082,61083],{"class":1362,"line":73},[1023,61084,61085],{},"    \"\"\"Q: (n_q, d_k), K: (n_k, d_k), V: (n_k, d_v).\n",[1023,61087,61088],{"class":1362,"line":78},[1023,61089,61090],{},"       Trả (output: (n_q, d_v), weights: (n_q, n_k)). weights = softmax(Q K^T \u002F sqrt(d_k)).\n",[1023,61092,61093],{"class":1362,"line":83},[1023,61094,61095],{},"       mask: True ở vị trí cấm, gán -inf trước softmax.\"\"\"\n",[1352,61097,61100],{"className":61098,"code":61099,"language":2241,"meta":1357},[2239],"Mỗi hàng weights tổng bằng 1\nQ trùng hẳn 1 hàng của K, d_k lớn -> weight hàng đó gần 1\nCausal mask 4x4 -> weights là tam giác dưới\n",[992,61101,61099],{"__ignoreMap":1357},[973,61103,37059,61104,1517],{},[992,61105,61106],{},"torch.nn.functional.scaled_dot_product_attention",[981,61108,61110],{"id":61109},"bài-2-multi-head-self-attention-và-positional-encoding","Bài 2: Multi-head self-attention và positional encoding",[2273,61112,61113,61126,61133],{},[989,61114,6760,61115,61118,61119,61121,61122,61125],{},[992,61116,61117],{},"MultiHeadSelfAttention(d_model, n_heads)",": chiếu ",[992,61120,38206],{}," thành Q, K, V, tách ",[992,61123,61124],{},"n_heads"," đầu, attention từng đầu, ghép và chiếu ra.",[989,61127,61128,61129,61132],{},"Cài sinusoidal positional encoding. Vẽ heatmap ",[992,61130,61131],{},"PE"," cho 50 vị trí, 64 chiều.",[989,61134,61135,61136,61139],{},"Chứng minh self-attention ",[1487,61137,61138],{},"không có"," positional encoding thì hoán vị input chỉ hoán vị output tương ứng (tương biến hoán vị).",[981,61141,61143],{"id":61142},"bài-3-transformer-nhỏ-đảo-chuỗi-nâng-cao","Bài 3: Transformer nhỏ đảo chuỗi (nâng cao)",[973,61145,61146],{},"Bài toán: input là chuỗi 10 chữ số, output là chuỗi đảo ngược.",[2273,61148,61149,61159,61162,61171],{},[989,61150,61151,61152,61155,61156,16014],{},"Dựng ",[992,61153,61154],{},"nn.Transformer"," nhỏ (2 lớp encoder, 2 lớp decoder, ",[992,61157,61158],{},"d_model = 64",[989,61160,61161],{},"Huấn luyện tới accuracy từng token trên 99%.",[989,61163,61164,61165,61167,61168,1517],{},"Vẽ heatmap cross-attention của decoder cho 1 ví dụ. Chỉ ra đường chéo ngược: vị trí ra ",[992,61166,1837],{}," nhìn vào vị trí vào ",[992,61169,61170],{},"9 - i",[989,61172,61173],{},"So thời gian 1 epoch với seq2seq LSTM cùng số tham số.",[981,61175,2711],{"id":2710},[986,61177,61179,61190,61196,61202],{"className":61178},[2715],[989,61180,61182,2308,61184,57251,61187,61189],{"className":61181},[2719],[2721,61183],{"disabled":2723,"type":2724},[992,61185,61186],{},"attention",[992,61188,32245],{},", mask đúng.",[989,61191,61193,61195],{"className":61192},[2719],[2721,61194],{"disabled":2723,"type":2724}," Có heatmap positional encoding và chứng minh tương biến hoán vị.",[989,61197,61199,61201],{"className":61198},[2719],[2721,61200],{"disabled":2723,"type":2724}," Transformer đảo chuỗi đạt 99%, có heatmap attention.",[989,61203,61205,61207],{"className":61204},[2719],[2721,61206],{"disabled":2723,"type":2724}," Giải thích được vai trò Q, K, V bằng ví dụ dịch câu.",[968,61209,2890],{"id":2889},[986,61211,61212,61215,61218,61221],{},[989,61213,61214],{},"Nút thắt thought vector là gì?",[989,61216,61217],{},"3 thành phần chú ý là gì?",[989,61219,61220],{},"Self-attention khác attention sao?",[989,61222,61223],{},"Vì sao Transformer song song tốt?",[3014,61225],{},[973,61227,61228],{},"🌕 Bạn đã hoàn thành ngày 102. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,61230,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":61232},[61233,61234,61239,61240,61246],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":61235},[61236,61237,61238],{"id":60911,"depth":73,"text":60912},{"id":60932,"depth":73,"text":60933},{"id":61002,"depth":73,"text":61003},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":61241},[61242,61243,61244,61245],{"id":61064,"depth":73,"text":61065},{"id":61109,"depth":73,"text":61110},{"id":61142,"depth":73,"text":61143},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nút thắt thought vector, cơ chế chú ý ba khía cạnh, self-attention, encoder hai chiều decoder và vì sao Transformer tỏa sáng.",{},[14055],{"title":565,"description":61247},[61252],"transformer","lqo1TKMkemJGXECkit-lDUc4-tWEBXWFweUGIX-XSFo",{"id":61255,"title":570,"body":61256,"category":8797,"day":573,"description":61605,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":61606,"navigation":2723,"outcomes":3047,"path":571,"prerequisites":61607,"seo":61608,"stem":572,"tags":61609,"__hash__":61610},"challenges\u002Fchallenges\u002F103.gpt-bert.md",{"type":965,"value":61257,"toc":61589},[61258,61260,61263,61265,61269,61286,61290,61307,61355,61358,61375,61377,61385,61405,61407,61420,61424,61430,61451,61455,61466,61518,61522,61537,61539,61566,61568,61582,61584,61587],[968,61259,971],{"id":970},[973,61261,61262],{},"Bài này học GPT chuyên viết và BERT chuyên hiểu.\nDùng để chọn đúng mô hình cho sinh hay phân loại.",[968,61264,979],{"id":978},[981,61266,61268],{"id":61267},"seq2seq-và-nút-cổ-chai","Seq2Seq và nút cổ chai",[986,61270,61271,61274,61277,61280,61283],{},[989,61272,61273],{},"Định nghĩa: encoder đọc vào, decoder viết ra chuỗi.",[989,61275,61276],{},"Thought vector là 1 vector nối giữa 2 bên.",[989,61278,61279],{},"Ví dụ đời thường: như dịch qua 1 mẩu giấy trung gian.",[989,61281,61282],{},"Câu dài thì mẩu giấy mất chi tiết sớm.",[989,61284,61285],{},"Attention sinh ra để nới nút cổ chai này.",[981,61287,61289],{"id":61288},"gpt","GPT",[986,61291,61292,61295,61298,61301,61304],{},[989,61293,61294],{},"Định nghĩa: đọc trái sang phải, đoán từ tiếp theo.",[989,61296,61297],{},"Đoán đúng thì trượt cửa sổ đi tiếp để viết.",[989,61299,61300],{},"Ví dụ đời thường: như gõ phím đoán chữ tiếp theo.",[989,61302,61303],{},"Dùng bộ giải mã nên giỏi sinh văn bản.",[989,61305,61306],{},"Mạnh ở kể chuyện, sinh mã, đối thoại.",[1099,61308,61309,61321],{},[1102,61310,61311],{},[1105,61312,61313,61315,61318],{},[1108,61314,41062],{},[1108,61316,61317],{},"Nhìn hướng nào",[1108,61319,61320],{},"Giỏi việc gì",[1118,61322,61323,61333,61344],{},[1105,61324,61325,61327,61330],{},[1123,61326,61289],{},[1123,61328,61329],{},"Trái sang phải",[1123,61331,61332],{},"Viết, sinh, chat",[1105,61334,61335,61338,61341],{},[1123,61336,61337],{},"BERT",[1123,61339,61340],{},"Cả 2 chiều",[1123,61342,61343],{},"Hiểu, phân loại",[1105,61345,61346,61349,61352],{},[1123,61347,61348],{},"Seq2Seq cũ",[1123,61350,61351],{},"1 vector giữa",[1123,61353,61354],{},"Dịch ngắn đơn giản",[981,61356,61337],{"id":61357},"bert",[986,61359,61360,61363,61366,61369,61372],{},[989,61361,61362],{},"Định nghĩa: che vài từ rồi dùng 2 phía đoán chỗ trống.",[989,61364,61365],{},"Nhìn cả trái và phải để hiểu từ hiện tại.",[989,61367,61368],{},"Ví dụ đời thường: như điền từ vào ô trống giữa câu.",[989,61370,61371],{},"Dùng bộ mã hóa 2 chiều nên giỏi hiểu ngữ cảnh.",[989,61373,61374],{},"Mạnh ở phân loại, trích đáp án, gán nhãn.",[968,61376,1433],{"id":1432},[986,61378,61379,61382],{},[989,61380,61381],{},"Input: \"Tôi ăn ___\" -> Output: GPT viết tiếp, BERT điền giữa.",[989,61383,61384],{},"Giải thích: GPT nhìn quá khứ để sinh, BERT nhìn 2 phía để hiểu.",[1352,61386,61388],{"className":3538,"code":61387,"language":3540,"meta":1357,"style":1357},"# GPT đoán từ tiếp theo từ quá khứ\ntu_tiep = model.predict([\"Tôi\", \"ăn\"])  # chỉ nhìn trái\nprint(tu_tiep)  # ví dụ: \"cơm\"\n",[992,61389,61390,61395,61400],{"__ignoreMap":1357},[1023,61391,61392],{"class":1362,"line":63},[1023,61393,61394],{},"# GPT đoán từ tiếp theo từ quá khứ\n",[1023,61396,61397],{"class":1362,"line":68},[1023,61398,61399],{},"tu_tiep = model.predict([\"Tôi\", \"ăn\"])  # chỉ nhìn trái\n",[1023,61401,61402],{"class":1362,"line":73},[1023,61403,61404],{},"print(tu_tiep)  # ví dụ: \"cơm\"\n",[968,61406,1482],{"id":1481},[973,61408,1485,61409,7386,61411,1509,61413,61416,61417,1517],{},[1487,61410,13531],{},[1487,61412,56749],{},[992,61414,61415],{},"transformers"," (Hugging Face). Nộp vào ",[992,61418,61419],{},"day-103\u002F",[981,61421,61423],{"id":61422},"bài-1-nút-cổ-chai-của-seq2seq","Bài 1: Nút cổ chai của seq2seq",[973,61425,61426,61427,1517],{},"Bài toán đảo chuỗi ngày 102 với độ dài ",[992,61428,61429],{},"L = 5, 10, 20, 40",[2273,61431,61432,61439,61445],{},[989,61433,61434,61435,61438],{},"Seq2seq LSTM ",[1487,61436,61437],{},"không attention",": encoder nén thành 1 vector, decoder sinh từ vector đó.",[989,61440,61434,61441,61444],{},[1487,61442,61443],{},"có attention"," (Bahdanau hoặc dot-product).",[989,61446,61447,61448,61450],{},"In accuracy chuỗi đúng hoàn toàn theo ",[992,61449,4772],{},". Vẽ đồ thị 2 đường.",[981,61452,61454],{"id":61453},"bài-2-gpt-sinh-tiếp-và-bert-điền-chỗ-trống","Bài 2: GPT sinh tiếp và BERT điền chỗ trống",[973,61456,61457,61458,61461,61462,61465],{},"Dùng mô hình có sẵn: ",[992,61459,61460],{},"gpt2"," (hoặc mô hình tiếng Việt tương đương) và ",[992,61463,61464],{},"bert-base-uncased"," (hoặc PhoBERT).",[1099,61467,61468,61477],{},[1102,61469,61470],{},[1105,61471,61472,61475],{},[1108,61473,61474],{},"Việc",[1108,61476,2547],{},[1118,61478,61479,61487,61495,61506],{},[1105,61480,61481,61484],{},[1123,61482,61483],{},"GPT sinh tiếp",[1123,61485,61486],{},"Cho câu mở đầu, sinh 30 token với greedy, top-k=50, temperature 0.7 và 1.5. So 3 kết quả",[1105,61488,61489,61492],{},[1123,61490,61491],{},"Xác suất token kế",[1123,61493,61494],{},"In top 10 token kế tiếp và xác suất cho câu \"The capital of France is\"",[1105,61496,61497,61500],{},[1123,61498,61499],{},"BERT điền chỗ trống",[1123,61501,61502,61503],{},"In top 5 cho ",[992,61504,61505],{},"\"I ate a [MASK] for breakfast.\"",[1105,61507,61508,61511],{},[1123,61509,61510],{},"So hướng đọc",[1123,61512,61513,61514,61517],{},"Câu ",[992,61515,61516],{},"\"The [MASK] barked at the mailman.\"",": BERT dùng được từ phía sau, GPT thì không. Giải thích",[981,61519,61521],{"id":61520},"bài-3-tinh-chỉnh-bert-phân-loại-nâng-cao","Bài 3: Tinh chỉnh BERT phân loại (nâng cao)",[2273,61523,61524,61531,61534],{},[989,61525,61526,61527,61530],{},"Tinh chỉnh ",[992,61528,61529],{},"distilbert-base-uncased"," trên 2000 review IMDB (hoặc bộ review tiếng Việt) trong 2 epoch.",[989,61532,61533],{},"So accuracy với Naive Bayes ngày 54 và embedding trung bình ngày 99 trên cùng tập test.",[989,61535,61536],{},"In 3 ví dụ BERT đúng mà Naive Bayes sai (thường là câu có phủ định hoặc mỉa mai).",[981,61538,2711],{"id":2710},[986,61540,61542,61548,61554,61560],{"className":61541},[2715],[989,61543,61545,61547],{"className":61544},[2719],[2721,61546],{"disabled":2723,"type":2724}," Đồ thị accuracy theo độ dài cho seq2seq có và không có attention.",[989,61549,61551,61553],{"className":61550},[2719],[2721,61552],{"disabled":2723,"type":2724}," Bảng sinh văn bản 3 cấu hình và top 10 token kế tiếp.",[989,61555,61557,61559],{"className":61556},[2719],[2721,61558],{"disabled":2723,"type":2724}," Bảng so sánh 3 mô hình sentiment có số thật.",[989,61561,61563,61565],{"className":61562},[2719],[2721,61564],{"disabled":2723,"type":2724}," Giải thích được GPT dùng decoder, BERT dùng encoder, và hệ quả.",[968,61567,2890],{"id":2889},[986,61569,61570,61573,61576,61579],{},[989,61571,61572],{},"Nút cổ chai Seq2Seq nằm ở đâu?",[989,61574,61575],{},"GPT đoán từ theo hướng nào?",[989,61577,61578],{},"BERT học bằng trò gì?",[989,61580,61581],{},"Viết văn nên dùng GPT hay BERT?",[3014,61583],{},[973,61585,61586],{},"🌕 Bạn đã hoàn thành ngày 103. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,61588,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":61590},[61591,61592,61597,61598,61604],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":61593},[61594,61595,61596],{"id":61267,"depth":73,"text":61268},{"id":61288,"depth":73,"text":61289},{"id":61357,"depth":73,"text":61337},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":61599},[61600,61601,61602,61603],{"id":61422,"depth":73,"text":61423},{"id":61453,"depth":73,"text":61454},{"id":61520,"depth":73,"text":61521},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Autoencoder, Seq2Seq, attention trong LLM, so sánh GPT giải mã và BERT mã hóa hai chiều, mô hình sâu rộng.",{},[14055],{"title":570,"description":61605},[61252],"cgAsKhnqXv8pSABBXwde8GniIO_pfs8ZztXTl1KxAbI",{"id":61612,"title":575,"body":61613,"category":5189,"day":578,"description":62056,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":62057,"navigation":2723,"outcomes":3047,"path":576,"prerequisites":62058,"seo":62059,"stem":577,"tags":62060,"__hash__":62062},"challenges\u002Fchallenges\u002F104.chain-flyweight.md",{"type":965,"value":61614,"toc":62040},[61615,61617,61620,61622,61626,61643,61647,61664,61712,61716,61733,61735,61743,61773,61775,61782,61786,61829,61889,61895,61906,61910,61916,61943,61947,61967,61985,61987,62017,62019,62033,62035,62038],[968,61616,971],{"id":970},[973,61618,61619],{},"Bài này học chuyền yêu cầu qua chuỗi và chia sẻ object.\nDùng để duyệt mua nhiều cấp và vẽ rừng ngàn cây.",[968,61621,979],{"id":978},[981,61623,61625],{"id":61624},"chain-of-responsibility","Chain of Responsibility",[986,61627,61628,61631,61634,61637,61640],{},[989,61629,61630],{},"Định nghĩa: chuyền yêu cầu dọc chuỗi tới khi có người xử lý.",[989,61632,61633],{},"Mỗi mắt xích tự xử hoặc chuyền cho người kế tiếp.",[989,61635,61636],{},"Ví dụ đời thường: như đơn xin duyệt qua từng cấp trên.",[989,61638,61639],{},"Người gửi chỉ đưa đầu chuỗi, không cần biết ai xử.",[989,61641,61642],{},"Thêm cấp mới chỉ cần chen 1 mắt xích vào.",[981,61644,61646],{"id":61645},"ví-dụ-chuỗi-duyệt-mua","Ví dụ chuỗi duyệt mua",[986,61648,61649,61652,61655,61658,61661],{},[989,61650,61651],{},"Trưởng nhóm duyệt dưới 1 triệu.",[989,61653,61654],{},"Trưởng phòng duyệt dưới 10 triệu.",[989,61656,61657],{},"Giám đốc duyệt mọi mức còn lại.",[989,61659,61660],{},"Ví dụ đời thường: đơn 5 triệu dừng ở trưởng phòng.",[989,61662,61663],{},"Cần mắt chặn cuối để đơn không rơi mất.",[1099,61665,61666,61678],{},[1102,61667,61668],{},[1105,61669,61670,61673,61676],{},[1108,61671,61672],{},"Mắt xích",[1108,61674,61675],{},"Hạn mức",[1108,61677,27321],{},[1118,61679,61680,61691,61701],{},[1105,61681,61682,61685,61688],{},[1123,61683,61684],{},"Trưởng nhóm",[1123,61686,61687],{},"Dưới 1 triệu",[1123,61689,61690],{},"Tự duyệt hoặc chuyền",[1105,61692,61693,61696,61699],{},[1123,61694,61695],{},"Trưởng phòng",[1123,61697,61698],{},"Dưới 10 triệu",[1123,61700,61690],{},[1105,61702,61703,61706,61709],{},[1123,61704,61705],{},"Giám đốc",[1123,61707,61708],{},"Mọi mức còn lại",[1123,61710,61711],{},"Chặn cuối chuỗi",[981,61713,61715],{"id":61714},"flyweight","Flyweight",[986,61717,61718,61721,61724,61727,61730],{},[989,61719,61720],{},"Định nghĩa: chia sẻ phần chung, tách riêng phần khác biệt.",[989,61722,61723],{},"Ngàn cây chung vài nét vẽ, khác vị trí và màu.",[989,61725,61726],{},"Ví dụ đời thường: như dùng chung khuôn in thay ngàn bản.",[989,61728,61729],{},"Cache phần chung nên RAM giảm mạnh.",[989,61731,61732],{},"Phần riêng lưu ngoài, truyền vào khi vẽ.",[968,61734,1433],{"id":1432},[986,61736,61737,61740],{},[989,61738,61739],{},"Input: đơn mua 5 triệu -> Output: trưởng phòng duyệt.",[989,61741,61742],{},"Giải thích: trưởng nhóm chuyền, trưởng phòng đủ hạn mức xử lý.",[1352,61744,61746],{"className":3538,"code":61745,"language":3540,"meta":1357,"style":1357},"# Mắt xích tự xử hoặc chuyền tiếp\ndef xu_ly(yeu_cau):\n    if yeu_cau \u003C= han_muc:  # đủ quyền thì xử\n        return \"duyệt\"\n    return nguoi_ke.xu_ly(yeu_cau)  # không thì chuyền\n",[992,61747,61748,61753,61758,61763,61768],{"__ignoreMap":1357},[1023,61749,61750],{"class":1362,"line":63},[1023,61751,61752],{},"# Mắt xích tự xử hoặc chuyền tiếp\n",[1023,61754,61755],{"class":1362,"line":68},[1023,61756,61757],{},"def xu_ly(yeu_cau):\n",[1023,61759,61760],{"class":1362,"line":73},[1023,61761,61762],{},"    if yeu_cau \u003C= han_muc:  # đủ quyền thì xử\n",[1023,61764,61765],{"class":1362,"line":78},[1023,61766,61767],{},"        return \"duyệt\"\n",[1023,61769,61770],{"class":1362,"line":83},[1023,61771,61772],{},"    return nguoi_ke.xu_ly(yeu_cau)  # không thì chuyền\n",[968,61774,1482],{"id":1481},[973,61776,1485,61777,4801,61779,1517],{},[1487,61778,4800],{},[992,61780,61781],{},"day-104\u002F",[981,61783,61785],{"id":61784},"bài-1-chuỗi-duyệt-chi-tiêu","Bài 1: Chuỗi duyệt chi tiêu",[1352,61787,61789],{"className":1393,"code":61788,"language":1395,"meta":1357,"style":1357},"struct Request { std::string id; long long amount; std::string purpose; };\nclass Approver {\n protected: std::shared_ptr\u003CApprover> next;\n public:\n  std::shared_ptr\u003CApprover> setNext(std::shared_ptr\u003CApprover> n);   \u002F\u002F trả n để nối chuỗi\n  virtual std::string handle(const Request &r);                      \u002F\u002F mặc định: chuyền tiếp\n  virtual ~Approver() = default;\n};\n",[992,61790,61791,61796,61801,61806,61810,61815,61820,61825],{"__ignoreMap":1357},[1023,61792,61793],{"class":1362,"line":63},[1023,61794,61795],{},"struct Request { std::string id; long long amount; std::string purpose; };\n",[1023,61797,61798],{"class":1362,"line":68},[1023,61799,61800],{},"class Approver {\n",[1023,61802,61803],{"class":1362,"line":73},[1023,61804,61805],{}," protected: std::shared_ptr\u003CApprover> next;\n",[1023,61807,61808],{"class":1362,"line":78},[1023,61809,4836],{},[1023,61811,61812],{"class":1362,"line":83},[1023,61813,61814],{},"  std::shared_ptr\u003CApprover> setNext(std::shared_ptr\u003CApprover> n);   \u002F\u002F trả n để nối chuỗi\n",[1023,61816,61817],{"class":1362,"line":88},[1023,61818,61819],{},"  virtual std::string handle(const Request &r);                      \u002F\u002F mặc định: chuyền tiếp\n",[1023,61821,61822],{"class":1362,"line":93},[1023,61823,61824],{},"  virtual ~Approver() = default;\n",[1023,61826,61827],{"class":1362,"line":98},[1023,61828,4866],{},[1099,61830,61831,61840],{},[1102,61832,61833],{},[1105,61834,61835,61837],{},[1108,61836,61672],{},[1108,61838,61839],{},"Duyệt khi",[1118,61841,61842,61854,61866,61878],{},[1105,61843,61844,61849],{},[1123,61845,61846],{},[992,61847,61848],{},"TeamLead",[1123,61850,61851],{},[992,61852,61853],{},"amount \u003C 1.000.000",[1105,61855,61856,61861],{},[1123,61857,61858],{},[992,61859,61860],{},"Manager",[1123,61862,61863],{},[992,61864,61865],{},"amount \u003C 10.000.000",[1105,61867,61868,61873],{},[1123,61869,61870],{},[992,61871,61872],{},"Director",[1123,61874,61875],{},[992,61876,61877],{},"amount \u003C 100.000.000",[1105,61879,61880,61886],{},[1123,61881,61882,61885],{},[992,61883,61884],{},"Board"," (chặn cuối)",[1123,61887,61888],{},"Mọi mức còn lại, trả \"cần họp HĐQT\"",[1352,61890,61893],{"className":61891,"code":61892,"language":2241,"meta":1357},[2239],"5.000.000   -> \"Manager duyệt\"\n500.000     -> \"TeamLead duyệt\"\n2 tỉ        -> \"cần họp HĐQT\"\nChuỗi không có Board, 2 tỉ -> \"không ai xử lý\" (không crash, không rơi mất)\n",[992,61894,61892],{"__ignoreMap":1357},[973,61896,61897,61898,61901,61902,61905],{},"Chen thêm ",[992,61899,61900],{},"FraudCheck"," ở đầu chuỗi: từ chối nếu ",[992,61903,61904],{},"purpose"," chứa từ khóa đen. Không sửa lớp nào khác.",[981,61907,61909],{"id":61908},"bài-2-middleware-http","Bài 2: Middleware HTTP",[973,61911,61912,61913,1517],{},"Viết chuỗi xử lý request giả lập: ",[992,61914,61915],{},"Logging -> Auth -> RateLimit -> Router",[986,61917,61918,61927,61933],{},[989,61919,61920,61923,61924,1517],{},[992,61921,61922],{},"Auth"," từ chối (401) nếu thiếu header ",[992,61925,61926],{},"Authorization",[989,61928,61929,61932],{},[992,61930,61931],{},"RateLimit"," từ chối (429) nếu 1 IP quá 5 request\u002Fgiây (dùng đồng hồ giả).",[989,61934,61935,61938,61939,61942],{},[992,61936,61937],{},"Logging"," ghi lại mọi request ",[1487,61940,61941],{},"kể cả"," bị từ chối ở sau (cần xử lý khi chuỗi trả về).",[981,61944,61946],{"id":61945},"bài-3-flyweight-cho-rừng-cây-nâng-cao","Bài 3: Flyweight cho rừng cây (nâng cao)",[1352,61948,61950],{"className":1393,"code":61949,"language":1395,"meta":1357,"style":1357},"struct TreeType { std::string name; std::string color; std::vector\u003Cuint8_t> texture; };  \u002F\u002F texture 64 KB\nstruct Tree { int x, y; const TreeType *type; };\nclass TreeFactory { public: const TreeType *get(const std::string &name, const std::string &color); size_t typeCount() const; };\n",[992,61951,61952,61957,61962],{"__ignoreMap":1357},[1023,61953,61954],{"class":1362,"line":63},[1023,61955,61956],{},"struct TreeType { std::string name; std::string color; std::vector\u003Cuint8_t> texture; };  \u002F\u002F texture 64 KB\n",[1023,61958,61959],{"class":1362,"line":68},[1023,61960,61961],{},"struct Tree { int x, y; const TreeType *type; };\n",[1023,61963,61964],{"class":1362,"line":73},[1023,61965,61966],{},"class TreeFactory { public: const TreeType *get(const std::string &name, const std::string &color); size_t typeCount() const; };\n",[2273,61968,61969,61972,61978],{},[989,61970,61971],{},"Trồng 1.000.000 cây với 5 loại. In bộ nhớ ước lượng khi mỗi cây giữ texture riêng và khi dùng Flyweight.",[989,61973,61974,61977],{},[992,61975,61976],{},"typeCount()"," phải bằng 5.",[989,61979,61980,61981,61984],{},"Đo bộ nhớ thật bằng ",[992,61982,61983],{},"\u002Fproc\u002Fself\u002Fstatus"," (VmRSS) cho 2 cách.",[981,61986,2711],{"id":2710},[986,61988,61990,61996,62005,62011],{"className":61989},[2715],[989,61991,61993,61995],{"className":61992},[2719],[2721,61994],{"disabled":2723,"type":2724}," Test chuỗi duyệt pass, không yêu cầu nào rơi mất.",[989,61997,61999,62001,62002,62004],{"className":61998},[2719],[2721,62000],{"disabled":2723,"type":2724}," Chen ",[992,62003,61900],{}," không sửa lớp cũ.",[989,62006,62008,62010],{"className":62007},[2719],[2721,62009],{"disabled":2723,"type":2724}," Middleware ghi log cả request bị từ chối.",[989,62012,62014,62016],{"className":62013},[2719],[2721,62015],{"disabled":2723,"type":2724}," Bảng bộ nhớ Flyweight có số thật.",[968,62018,2890],{"id":2889},[986,62020,62021,62024,62027,62030],{},[989,62022,62023],{},"Ai quyết định chuyền trong chain?",[989,62025,62026],{},"Mắt chặn cuối để làm gì?",[989,62028,62029],{},"Flyweight chia sẻ cái gì?",[989,62031,62032],{},"Phần riêng lưu ở đâu?",[3014,62034],{},[973,62036,62037],{},"🌕 Bạn đã hoàn thành ngày 104. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,62039,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":62041},[62042,62043,62048,62049,62055],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":62044},[62045,62046,62047],{"id":61624,"depth":73,"text":61625},{"id":61645,"depth":73,"text":61646},{"id":61714,"depth":73,"text":61715},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":62050},[62051,62052,62053,62054],{"id":61784,"depth":73,"text":61785},{"id":61908,"depth":73,"text":61909},{"id":61945,"depth":73,"text":61946},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Chuỗi xử lý yêu cầu mua thư viện email, và chia sẻ nét vẽ cây trong rừng ngàn cây của Flyweight.",{},[5194,17499],{"title":575,"description":62056},[41703,62061,61714],"chain","zoRN85bDHHMwKb6axG0eL_6gnXlj-OsqvLG9SJJkuBU",{"id":62064,"title":580,"body":62065,"category":8797,"day":583,"description":62450,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":62451,"navigation":2723,"outcomes":3047,"path":581,"prerequisites":62452,"seo":62453,"stem":582,"tags":62454,"__hash__":62456},"challenges\u002Fchallenges\u002F105.stream-processing.md",{"type":965,"value":62066,"toc":62434},[62067,62069,62072,62074,62078,62095,62099,62116,62165,62169,62186,62188,62196,62221,62223,62234,62238,62252,62315,62321,62325,62351,62355,62365,62382,62384,62411,62413,62427,62429,62432],[968,62068,971],{"id":970},[973,62070,62071],{},"Bài này học xử lý dòng sự kiện ngay khi tới.\nDùng để bắt gian lận thẻ và cảnh báo camera.",[968,62073,979],{"id":978},[981,62075,62077],{"id":62076},"batch-và-stream","Batch và stream",[986,62079,62080,62083,62086,62089,62092],{},[989,62081,62082],{},"Định nghĩa: batch gom mẻ rồi tính, stream tính ngay.",[989,62084,62085],{},"Batch trễ phút giờ, hợp báo cáo cuối ngày.",[989,62087,62088],{},"Stream trễ mili giây, hợp giá cổ phiếu và cảm biến.",[989,62090,62091],{},"Ví dụ đời thường: như phát trực tiếp thay vì chờ cuối ngày.",[989,62093,62094],{},"Stream phải chịu dữ liệu muộn và rối thứ tự.",[981,62096,62098],{"id":62097},"cửa-sổ-và-watermark","Cửa sổ và watermark",[986,62100,62101,62104,62107,62110,62113],{},[989,62102,62103],{},"Định nghĩa: cửa sổ cắt dòng vô hạn thành miếng tính được.",[989,62105,62106],{},"Trượt: tính N phút gần nhất, cập nhật liên tục.",[989,62108,62109],{},"Cố định (tumbling): chia thành mẻ rời nhau, mỗi sự kiện thuộc đúng 1 cửa sổ, tiết kiệm hơn.",[989,62111,62112],{},"Ví dụ đời thường: như chỉ nhìn 5 phút camera gần nhất.",[989,62114,62115],{},"Watermark là mốc an toàn, sự kiện sau mốc là muộn.",[1099,62117,62118,62130],{},[1102,62119,62120],{},[1105,62121,62122,62125,62127],{},[1108,62123,62124],{},"Kiểu gửi",[1108,62126,7744],{},[1108,62128,62129],{},"Khi dùng",[1118,62131,62132,62143,62154],{},[1105,62133,62134,62137,62140],{},[1123,62135,62136],{},"Ít nhất 1 lần",[1123,62138,62139],{},"Dễ trùng, cần khử",[1123,62141,62142],{},"Không được mất",[1105,62144,62145,62148,62151],{},[1123,62146,62147],{},"Tối đa 1 lần",[1123,62149,62150],{},"Nhanh, có thể mất",[1123,62152,62153],{},"Chấp nhận sót",[1105,62155,62156,62159,62162],{},[1123,62157,62158],{},"Đúng 1 lần",[1123,62160,62161],{},"Chuẩn, tốn kém",[1123,62163,62164],{},"Tiền tệ, thanh toán",[981,62166,62168],{"id":62167},"streamsensing","StreamSensing",[986,62170,62171,62174,62177,62180,62183],{},[989,62172,62173],{},"Định nghĩa: framework trích đặc trưng ngay trên dòng video.",[989,62175,62176],{},"Chỉ lưu đoạn đáng ngờ thay vì cả video dài.",[989,62178,62179],{},"Ví dụ đời thường: như bảo vệ chỉ ghi lúc có động.",[989,62181,62182],{},"Giảm trễ từ phút xuống giây nhờ cửa sổ.",[989,62184,62185],{},"Khi quá tải thì giữ sự kiện quan trọng trước.",[968,62187,1433],{"id":1432},[986,62189,62190,62193],{},[989,62191,62192],{},"Input: giao dịch thẻ lúc 10 giờ -> Output: cảnh báo trong 1 giây.",[989,62194,62195],{},"Giải thích: stream tính ngay thay vì chờ batch đêm.",[1352,62197,62199],{"className":3538,"code":62198,"language":3540,"meta":1357,"style":1357},"# Trung bình trượt trên cửa sổ gần nhất\ncua_so = giu_n_phut_cuoi(su_kien, n=5)  # cắt dòng vô hạn\ntb = sum(cua_so) \u002F len(cua_so)  # tính ngay\nprint(tb)\n",[992,62200,62201,62206,62211,62216],{"__ignoreMap":1357},[1023,62202,62203],{"class":1362,"line":63},[1023,62204,62205],{},"# Trung bình trượt trên cửa sổ gần nhất\n",[1023,62207,62208],{"class":1362,"line":68},[1023,62209,62210],{},"cua_so = giu_n_phut_cuoi(su_kien, n=5)  # cắt dòng vô hạn\n",[1023,62212,62213],{"class":1362,"line":73},[1023,62214,62215],{},"tb = sum(cua_so) \u002F len(cua_so)  # tính ngay\n",[1023,62217,62218],{"class":1362,"line":78},[1023,62219,62220],{},"print(tb)\n",[968,62222,1482],{"id":1481},[973,62224,1485,62225,62227,62228,62230,62231,1517],{},[1487,62226,13531],{}," (thư viện chuẩn và ",[992,62229,40031],{},"). Không dùng framework stream có sẵn cho Bài 1-2. Nộp vào ",[992,62232,62233],{},"day-105\u002F",[981,62235,62237],{"id":62236},"bài-1-cửa-sổ-thời-gian","Bài 1: Cửa sổ thời gian",[973,62239,62240,62241,1962,62244,62247,62248,62251],{},"Mỗi sự kiện: ",[992,62242,62243],{},"Event(ts: float, key: str, value: float)",[992,62245,62246],{},"ts"," là thời gian ",[1487,62249,62250],{},"sự kiện"," (giây).",[1099,62253,62254,62262],{},[1102,62255,62256],{},[1105,62257,62258,62260],{},[1108,62259,4881],{},[1108,62261,2547],{},[1118,62263,62264,62284,62301],{},[1105,62265,62266,62271],{},[1123,62267,62268],{},[992,62269,62270],{},"TumblingWindow(size)",[1123,62272,62273,62274,1656,62277,62280,62281],{},"Cửa sổ rời ",[992,62275,62276],{},"[0,10)",[992,62278,62279],{},"[10,20)","... Đóng cửa sổ thì phát ",[992,62282,62283],{},"(start, key, count, sum, avg)",[1105,62285,62286,62291],{},[1123,62287,62288],{},[992,62289,62290],{},"SlidingWindow(size, slide)",[1123,62292,62293,62294,62296,62297,62300],{},"Cửa sổ dài ",[992,62295,994],{},", nhảy mỗi ",[992,62298,62299],{},"slide"," giây. 1 sự kiện thuộc nhiều cửa sổ",[1105,62302,62303,62308],{},[1123,62304,62305],{},[992,62306,62307],{},"SessionWindow(gap)",[1123,62309,62310,62311,62314],{},"Nhóm sự kiện cùng key cách nhau dưới ",[992,62312,62313],{},"gap"," giây",[1352,62316,62319],{"className":62317,"code":62318,"language":2241,"meta":1357},[2239],"Tumbling(10): sự kiện ts = 1, 3, 12, 15, 25 -> [0,10): 2 sự kiện, [10,20): 2, [20,30): 1\nSliding(10, 5): ts = 7 thuộc [0,10) và [5,15)\nSession(gap=5): ts = 1, 3, 20, 22 -> 2 phiên\n",[992,62320,62318],{"__ignoreMap":1357},[981,62322,62324],{"id":62323},"bài-2-watermark-và-dữ-liệu-muộn","Bài 2: Watermark và dữ liệu muộn",[2273,62326,62327,62334,62341,62348],{},[989,62328,62329,62330,62333],{},"Sự kiện đến ",[1487,62331,62332],{},"không theo thứ tự",", trễ ngẫu nhiên 0-8 giây.",[989,62335,62336,62337,62340],{},"Watermark = ",[992,62338,62339],{},"max_ts_đã_thấy - 5",". Cửa sổ chỉ đóng khi watermark vượt cuối cửa sổ.",[989,62342,62343,62344,62347],{},"Sự kiện đến sau khi cửa sổ đã đóng: đưa vào ",[992,62345,62346],{},"late_events"," và đếm.",[989,62349,62350],{},"Thử độ trễ cho phép 0, 5, 10 giây. In số sự kiện muộn bị bỏ và độ trễ phát kết quả trung bình.",[981,62352,62354],{"id":62353},"bài-3-phát-hiện-gian-lận-thẻ-thời-gian-thực-nâng-cao","Bài 3: Phát hiện gian lận thẻ thời gian thực (nâng cao)",[973,62356,62357,62358,62361,62362,62364],{},"Luồng giao dịch ",[992,62359,62360],{},"(ts, card_id, amount, city)"," sinh bằng ",[992,62363,40031],{},", 1000 sự kiện\u002Fgiây.",[2273,62366,62367,62370,62373,62376],{},[989,62368,62369],{},"Cảnh báo khi 1 thẻ có hơn 5 giao dịch trong 60 giây (cửa sổ trượt).",[989,62371,62372],{},"Cảnh báo khi 1 thẻ giao dịch ở 2 thành phố cách nhau dưới 10 phút.",[989,62374,62375],{},"Đo độ trễ từ lúc sự kiện đến tới lúc phát cảnh báo (p50, p99). Mục tiêu dưới 1 giây.",[989,62377,62378,62381],{},[1487,62379,62380],{},"Quá tải:"," tăng lên 10.000 sự kiện\u002Fgiây với hàng đợi giới hạn. Khi đầy, bỏ giao dịch nhỏ hơn 100.000đ trước. Đếm số bị bỏ.",[981,62383,2711],{"id":2710},[986,62385,62387,62393,62399,62405],{"className":62386},[2715],[989,62388,62390,62392],{"className":62389},[2719],[2721,62391],{"disabled":2723,"type":2724}," Test mẫu 3 loại cửa sổ pass.",[989,62394,62396,62398],{"className":62395},[2719],[2721,62397],{"disabled":2723,"type":2724}," Bảng đánh đổi độ trễ cho phép và số sự kiện muộn.",[989,62400,62402,62404],{"className":62401},[2719],[2721,62403],{"disabled":2723,"type":2724}," Bài 3 phát cảnh báo đúng với dữ liệu cài sẵn gian lận, có số p50\u002Fp99.",[989,62406,62408,62410],{"className":62407},[2719],[2721,62409],{"disabled":2723,"type":2724}," Giải thích được khác biệt giữa thời gian sự kiện và thời gian xử lý.",[968,62412,2890],{"id":2889},[986,62414,62415,62418,62421,62424],{},[989,62416,62417],{},"Batch khác stream ở đâu?",[989,62419,62420],{},"Cửa sổ trượt là gì?",[989,62422,62423],{},"Watermark để làm gì?",[989,62425,62426],{},"Khi nào cần đúng 1 lần?",[3014,62428],{},[973,62430,62431],{},"🌕 Bạn đã hoàn thành ngày 105. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,62433,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":62435},[62436,62437,62442,62443,62449],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":62438},[62439,62440,62441],{"id":62076,"depth":73,"text":62077},{"id":62097,"depth":73,"text":62098},{"id":62167,"depth":73,"text":62168},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":62444},[62445,62446,62447,62448],{"id":62236,"depth":73,"text":62237},{"id":62323,"depth":73,"text":62324},{"id":62353,"depth":73,"text":62354},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Batch và stream, cửa sổ trượt, trễ và thông lượng, framework StreamSensing xử lý multimedia thời gian thực.",{},[14055],{"title":580,"description":62450},[62455],"streaming","Gscgx9csCSuvtITHuVroKuH3dJfsMq2RbVYM-0vP6AA",{"id":62458,"title":585,"body":62459,"category":8797,"day":588,"description":62853,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":62854,"navigation":2723,"outcomes":3047,"path":586,"prerequisites":62855,"seo":62856,"stem":587,"tags":62857,"__hash__":62858},"challenges\u002Fchallenges\u002F106.crypto-nang-cao.md",{"type":965,"value":62460,"toc":62837},[62461,62463,62466,62468,62472,62489,62493,62510,62560,62564,62581,62583,62591,62616,62618,62627,62632,62636,62723,62729,62733,62754,62758,62785,62787,62814,62816,62830,62832,62835],[968,62462,971],{"id":970},[973,62464,62465],{},"Bài này học khóa công khai, chứng chỉ và chống nghe lén.\nDùng để giữ mô hình ML an toàn khi triển khai.",[968,62467,979],{"id":978},[981,62469,62471],{"id":62470},"mã-bất-đối-xứng","Mã bất đối xứng",[986,62473,62474,62477,62480,62483,62486],{},[989,62475,62476],{},"Định nghĩa: cặp khóa công khai mã hóa, bí mật giải mã.",[989,62478,62479],{},"Ai cũng bỏ thư vào hòm, chỉ chủ hòm mở được.",[989,62481,62482],{},"Ví dụ đời thường: như khe hòm thư ai cũng nhét được.",[989,62484,62485],{},"Chậm hơn đối xứng hàng trăm lần thực tế.",[989,62487,62488],{},"Nên dùng lai: bất đối xứng trao khóa, đối xứng mã data.",[981,62490,62492],{"id":62491},"tls-và-pki","TLS và PKI",[986,62494,62495,62498,62501,62504,62507],{},[989,62496,62497],{},"Định nghĩa: TLS bắt tay rồi chuyển sang mã nhanh.",[989,62499,62500],{},"Trình duyệt kiểm chứng chỉ trước khi tin máy chủ.",[989,62502,62503],{},"PKI là hệ nhà cấp chứng chỉ xác minh danh tính.",[989,62505,62506],{},"Ví dụ đời thường: như kiểm căn cước trước khi giao chìa.",[989,62508,62509],{},"Không có PKI thì kẻ gian tự xưng tên người khác.",[1099,62511,62512,62525],{},[1102,62513,62514],{},[1105,62515,62516,62519,62522],{},[1108,62517,62518],{},"Lớp phòng thủ",[1108,62520,62521],{},"Chống gì",[1108,62523,62524],{},"Bằng gì",[1118,62526,62527,62538,62549],{},[1105,62528,62529,62532,62535],{},[1123,62530,62531],{},"Nghe lén",[1123,62533,62534],{},"Đọc trộm",[1123,62536,62537],{},"TLS, mã hóa",[1105,62539,62540,62543,62546],{},[1123,62541,62542],{},"Mạo danh",[1123,62544,62545],{},"Giả máy chủ",[1123,62547,62548],{},"Chứng chỉ, ghim",[1105,62550,62551,62554,62557],{},[1123,62552,62553],{},"Lộ khóa",[1123,62555,62556],{},"Dùng mãi 1 khóa",[1123,62558,62559],{},"Xoay và thu hồi",[981,62561,62563],{"id":62562},"blockchain-và-mitm","Blockchain và MITM",[986,62565,62566,62569,62572,62575,62578],{},[989,62567,62568],{},"Định nghĩa: khối sau chứa băm khối trước nên khó sửa.",[989,62570,62571],{},"Nhiều bên không tin nhau vẫn đồng ý 1 sổ chung.",[989,62573,62574],{},"MITM là kẻ chen giữa đọc sửa lưu lượng đi qua.",[989,62576,62577],{},"Ví dụ đời thường: như người đưa thư lén mở thư.",[989,62579,62580],{},"Sửa bằng mã hóa lúc nghỉ và kiểm toàn vẹn model.",[968,62582,1433],{"id":1432},[986,62584,62585,62588],{},[989,62586,62587],{},"Input: tải model qua mạng không TLS -> Output: MITM tráo model độc.",[989,62589,62590],{},"Giải thích: thiếu chứng chỉ nên không phát hiện giả mạo.",[1352,62592,62594],{"className":3538,"code":62593,"language":3540,"meta":1357,"style":1357},"# Kiểm toàn vẹn trước khi tải model\nimport hashlib\nbam = hashlib.sha256(open(\"m.bin\",\"rb\").read()).hexdigest()\nprint(bam == bam_chuan)  # True mới dùng\n",[992,62595,62596,62601,62606,62611],{"__ignoreMap":1357},[1023,62597,62598],{"class":1362,"line":63},[1023,62599,62600],{},"# Kiểm toàn vẹn trước khi tải model\n",[1023,62602,62603],{"class":1362,"line":68},[1023,62604,62605],{},"import hashlib\n",[1023,62607,62608],{"class":1362,"line":73},[1023,62609,62610],{},"bam = hashlib.sha256(open(\"m.bin\",\"rb\").read()).hexdigest()\n",[1023,62612,62613],{"class":1362,"line":78},[1023,62614,62615],{},"print(bam == bam_chuan)  # True mới dùng\n",[968,62617,1482],{"id":1481},[973,62619,1485,62620,7386,62622,5599,62624,1517],{},[1487,62621,13531],{},[992,62623,40796],{},[992,62625,62626],{},"day-106\u002F",[40801,62628,62629],{},[973,62630,62631],{},"RSA tự cài ở Bài 1 chỉ để hiểu toán. Không dùng để bảo vệ dữ liệu thật. Mọi việc thật dùng thư viện đã kiểm định.",[981,62633,62635],{"id":62634},"bài-1-rsa-tí-hon","Bài 1: RSA tí hon",[1099,62637,62638,62646],{},[1102,62639,62640],{},[1105,62641,62642,62644],{},[1108,62643,1566],{},[1108,62645,2547],{},[1118,62647,62648,62658,62671,62684,62702],{},[1105,62649,62650,62655],{},[1123,62651,62652],{},[992,62653,62654],{},"is_probable_prime(n, k=20)",[1123,62656,62657],{},"Miller-Rabin",[1105,62659,62660,62665],{},[1123,62661,62662],{},[992,62663,62664],{},"gen_prime(bits)",[1123,62666,62667,62668],{},"Sinh số nguyên tố ngẫu nhiên bằng ",[992,62669,62670],{},"secrets",[1105,62672,62673,62681],{},[1123,62674,62675,1656,62678],{},[992,62676,62677],{},"egcd",[992,62679,62680],{},"modinv",[1123,62682,62683],{},"Nghịch đảo modulo",[1105,62685,62686,62691],{},[1123,62687,62688],{},[992,62689,62690],{},"keygen(bits=512)",[1123,62692,62693,21733,62696,1509,62699],{},[992,62694,62695],{},"e = 65537",[992,62697,62698],{},"(n, e)",[992,62700,62701],{},"(n, d)",[1105,62703,62704,62718],{},[1123,62705,62706,1656,62709,1656,62712,1656,62715],{},[992,62707,62708],{},"encrypt(m, pub)",[992,62710,62711],{},"decrypt(c, priv)",[992,62713,62714],{},"sign(m, priv)",[992,62716,62717],{},"verify(m, s, pub)",[1123,62719,62720],{},[992,62721,62722],{},"pow(m, e, n)",[1352,62724,62727],{"className":62725,"code":62726,"language":2241,"meta":1357},[2239],"decrypt(encrypt(m)) == m với 100 m ngẫu nhiên \u003C n\nverify(m, sign(m)) = True; sửa 1 bit của m -> False\np = 61, q = 53, e = 17 -> n = 3233, d = 2753; encrypt(65) = 2790\n",[992,62728,62726],{"__ignoreMap":1357},[981,62730,62732],{"id":62731},"bài-2-mã-hóa-lai-và-chứng-chỉ","Bài 2: Mã hóa lai và chứng chỉ",[2273,62734,62735,62744,62747],{},[989,62736,2699,62737,62739,62740,62743],{},[992,62738,40796],{},": sinh cặp khóa RSA 2048. Mã hóa file 10 MB bằng ",[1487,62741,62742],{},"mã hóa lai",": khóa AES-256 ngẫu nhiên mã hóa file (AES-GCM), RSA-OAEP mã hóa khóa AES.",[989,62745,62746],{},"So thời gian: mã hóa 10 MB trực tiếp bằng RSA (theo khối) và bằng lai.",[989,62748,62749,62750,62753],{},"Tự tạo CA gốc, cấp chứng chỉ cho ",[992,62751,62752],{},"localhost",". Kiểm tra chữ ký chứng chỉ bằng khóa công khai CA. Sửa 1 byte trong chứng chỉ: kiểm tra thất bại.",[981,62755,62757],{"id":62756},"bài-3-blockchain-tí-hon-và-mitm-nâng-cao","Bài 3: Blockchain tí hon và MITM (nâng cao)",[2273,62759,62760,62769,62779],{},[989,62761,62762,7386,62765,62768],{},[992,62763,62764],{},"Block(index, timestamp, data, prev_hash, nonce)",[992,62766,62767],{},"hash = sha256(...)",". Proof-of-work: hash bắt đầu bằng 4 số 0.",[989,62770,62771,62774,62775,62778],{},[992,62772,62773],{},"Chain.is_valid()",". Sửa ",[992,62776,62777],{},"data"," của khối 3: chuỗi không hợp lệ, trừ khi đào lại mọi khối sau. Đo thời gian đào lại.",[989,62780,62781,62784],{},[1487,62782,62783],{},"MITM:"," giả lập client tải file model từ server qua kênh không mã hóa, kẻ giữa tráo file. Sửa bằng 2 cách: kiểm tra SHA-256 công bố trước, và chữ ký số của server. Viết test cho cả 2.",[981,62786,2711],{"id":2710},[986,62788,62790,62796,62802,62808],{"className":62789},[2715],[989,62791,62793,62795],{"className":62792},[2719],[2721,62794],{"disabled":2723,"type":2724}," RSA tí hon pass ví dụ số nhỏ và test ngẫu nhiên.",[989,62797,62799,62801],{"className":62798},[2719],[2721,62800],{"disabled":2723,"type":2724}," Bảng thời gian RSA trực tiếp và mã hóa lai.",[989,62803,62805,62807],{"className":62804},[2719],[2721,62806],{"disabled":2723,"type":2724}," Chứng chỉ bị sửa thì kiểm tra thất bại.",[989,62809,62811,62813],{"className":62810},[2719],[2721,62812],{"disabled":2723,"type":2724}," Bài 3 phát hiện được file bị tráo.",[968,62815,2890],{"id":2889},[986,62817,62818,62821,62824,62827],{},[989,62819,62820],{},"Khóa công khai khác khóa bí mật sao?",[989,62822,62823],{},"TLS dùng lai thế nào?",[989,62825,62826],{},"PKI tin ai đầu tiên?",[989,62828,62829],{},"MITM chen vào đâu?",[3014,62831],{},[973,62833,62834],{},"🌕 Bạn đã hoàn thành ngày 106. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,62836,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":62838},[62839,62840,62845,62846,62852],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":62841},[62842,62843,62844],{"id":62470,"depth":73,"text":62471},{"id":62491,"depth":73,"text":62492},{"id":62562,"depth":73,"text":62563},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":62847},[62848,62849,62850,62851],{"id":62634,"depth":73,"text":62635},{"id":62731,"depth":73,"text":62732},{"id":62756,"depth":73,"text":62757},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mã bất đối xứng, bắt tay SSL TLS, hạ tầng khóa công khai, blockchain và phòng chống MITM khi triển khai ML.",{},[15143],{"title":585,"description":62853},[40796],"0ULuRPgQ5N40tvIN8sO1SiBH0yyo_XY9ze9_Wl2Xrbc",{"id":62860,"title":590,"body":62861,"category":5189,"day":593,"description":63308,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":63309,"navigation":2723,"outcomes":3047,"path":591,"prerequisites":63310,"seo":63311,"stem":592,"tags":63312,"__hash__":63315},"challenges\u002Fchallenges\u002F107.mvc-compound.md",{"type":965,"value":62862,"toc":63291},[62863,62865,62868,62870,62874,62891,62895,62912,62962,62966,62983,62987,62995,62997,63005,63030,63032,63040,63044,63102,63108,63112,63172,63178,63190,63194,63234,63236,63268,63270,63284,63286,63289],[968,62864,971],{"id":970},[973,62866,62867],{},"Bài này học tách dữ liệu, hiển thị và điều khiển riêng.\nDùng để thêm màn hình mới không sửa ruột cũ.",[968,62869,979],{"id":978},[981,62871,62873],{"id":62872},"compound-và-3-tầng","Compound và 3 tầng",[986,62875,62876,62879,62882,62885,62888],{},[989,62877,62878],{},"Định nghĩa: compound là cụm pattern cùng giải 1 bài.",[989,62880,62881],{},"Model giữ nhịp nhạc và luật đổi nhịp.",[989,62883,62884],{},"View chỉ hiển thị số và đèn chớp theo nhịp.",[989,62886,62887],{},"Ví dụ đời thường: như DJ, loa, nút vặn riêng nhau.",[989,62889,62890],{},"Controller nhận nút bấm rồi gọi model đổi.",[981,62892,62894],{"id":62893},"luồng-người-dùng","Luồng người dùng",[986,62896,62897,62900,62903,62906,62909],{},[989,62898,62899],{},"DJ bấm tăng nhịp trên controller.",[989,62901,62902],{},"Controller gọi model đổi nhịp mới.",[989,62904,62905],{},"Model báo cho mọi view đang nghe.",[989,62907,62908],{},"Ví dụ đời thường: như vặn nút rồi loa đổi theo.",[989,62910,62911],{},"Thêm view mới chỉ cần đăng ký nghe model.",[1099,62913,62914,62927],{},[1102,62915,62916],{},[1105,62917,62918,62921,62924],{},[1108,62919,62920],{},"Tầng",[1108,62922,62923],{},"Việc duy nhất",[1108,62925,62926],{},"Không làm việc",[1118,62928,62929,62940,62951],{},[1105,62930,62931,62934,62937],{},[1123,62932,62933],{},"Model",[1123,62935,62936],{},"Giữ nhịp và luật",[1123,62938,62939],{},"Không vẽ màn hình",[1105,62941,62942,62945,62948],{},[1123,62943,62944],{},"View",[1123,62946,62947],{},"Vẽ theo số mới",[1123,62949,62950],{},"Không tự đổi số",[1105,62952,62953,62956,62959],{},[1123,62954,62955],{},"Controller",[1123,62957,62958],{},"Nhận nút bấm",[1123,62960,62961],{},"Không giữ dữ liệu",[981,62963,62965],{"id":62964},"luồng-nhịp-đập","Luồng nhịp đập",[986,62967,62968,62971,62974,62977,62980],{},[989,62969,62970],{},"Model tự sinh nhịp đều đặn theo giờ.",[989,62972,62973],{},"Mỗi nhịp báo cho các view đang nghe.",[989,62975,62976],{},"View đèn chớp 1 cái, view số giữ nguyên.",[989,62978,62979],{},"Ví dụ đời thường: như metronome gõ đều cho band.",[989,62981,62982],{},"Model không biết có mấy view đang nghe.",[981,62984,62986],{"id":62985},"mvc-trên-web","MVC trên web",[986,62988,62989,62992],{},[989,62990,62991],{},"Ứng dụng web chia MVC qua request: trình duyệt gửi request tới controller, controller gọi model, rồi chọn view để dựng trang trả về.",[989,62993,62994],{},"Khác MVC trên máy: view thường không đăng ký nghe model trực tiếp (Observer), mà nhận dữ liệu mỗi lần controller dựng trang.",[968,62996,1433],{"id":1432},[986,62998,62999,63002],{},[989,63000,63001],{},"Input: bấm tăng từ 100 lên 120 -> Output: số và đèn cùng đổi.",[989,63003,63004],{},"Giải thích: model đổi 1 lần, mọi view tự vẽ lại.",[1352,63006,63008],{"className":3538,"code":63007,"language":3540,"meta":1357,"style":1357},"# Controller gọi model, model báo view\nmodel.set_nhip(120)  # đổi dữ liệu\nfor v in views:  # báo từng view\n    v.ve_lai(model.nhip)\n",[992,63009,63010,63015,63020,63025],{"__ignoreMap":1357},[1023,63011,63012],{"class":1362,"line":63},[1023,63013,63014],{},"# Controller gọi model, model báo view\n",[1023,63016,63017],{"class":1362,"line":68},[1023,63018,63019],{},"model.set_nhip(120)  # đổi dữ liệu\n",[1023,63021,63022],{"class":1362,"line":73},[1023,63023,63024],{},"for v in views:  # báo từng view\n",[1023,63026,63027],{"class":1362,"line":78},[1023,63028,63029],{},"    v.ve_lai(model.nhip)\n",[968,63031,1482],{"id":1481},[973,63033,1485,63034,63036,63037,1517],{},[1487,63035,4800],{}," (hoặc Java). Giao diện dạng console, cập nhật bằng in lại dòng. Nộp vào ",[992,63038,63039],{},"day-107\u002F",[981,63041,63043],{"id":63042},"bài-1-model-nhịp-dj","Bài 1: Model nhịp DJ",[1352,63045,63047],{"className":1393,"code":63046,"language":1395,"meta":1357,"style":1357},"struct BeatObserver { virtual void updateBeat() = 0; virtual ~BeatObserver() = default; };\nstruct BPMObserver  { virtual void updateBPM() = 0;  virtual ~BPMObserver() = default; };\nclass BeatModel {\n public:\n  void on(); void off();\n  void setBPM(int bpm);     \u002F\u002F kẹp trong [40, 240]\n  int  getBPM() const;\n  void tick();              \u002F\u002F gọi từ vòng lặp thời gian, báo mọi BeatObserver\n  void registerObserver(BeatObserver*); void registerObserver(BPMObserver*);\n  void removeObserver(BeatObserver*);   void removeObserver(BPMObserver*);\n};\n",[992,63048,63049,63054,63059,63064,63068,63073,63078,63083,63088,63093,63098],{"__ignoreMap":1357},[1023,63050,63051],{"class":1362,"line":63},[1023,63052,63053],{},"struct BeatObserver { virtual void updateBeat() = 0; virtual ~BeatObserver() = default; };\n",[1023,63055,63056],{"class":1362,"line":68},[1023,63057,63058],{},"struct BPMObserver  { virtual void updateBPM() = 0;  virtual ~BPMObserver() = default; };\n",[1023,63060,63061],{"class":1362,"line":73},[1023,63062,63063],{},"class BeatModel {\n",[1023,63065,63066],{"class":1362,"line":78},[1023,63067,4836],{},[1023,63069,63070],{"class":1362,"line":83},[1023,63071,63072],{},"  void on(); void off();\n",[1023,63074,63075],{"class":1362,"line":88},[1023,63076,63077],{},"  void setBPM(int bpm);     \u002F\u002F kẹp trong [40, 240]\n",[1023,63079,63080],{"class":1362,"line":93},[1023,63081,63082],{},"  int  getBPM() const;\n",[1023,63084,63085],{"class":1362,"line":98},[1023,63086,63087],{},"  void tick();              \u002F\u002F gọi từ vòng lặp thời gian, báo mọi BeatObserver\n",[1023,63089,63090],{"class":1362,"line":103},[1023,63091,63092],{},"  void registerObserver(BeatObserver*); void registerObserver(BPMObserver*);\n",[1023,63094,63095],{"class":1362,"line":108},[1023,63096,63097],{},"  void removeObserver(BeatObserver*);   void removeObserver(BPMObserver*);\n",[1023,63099,63100],{"class":1362,"line":113},[1023,63101,4866],{},[1352,63103,63106],{"className":63104,"code":63105,"language":2241,"meta":1357},[2239],"setBPM(120) -> mọi BPMObserver nhận updateBPM, getBPM = 120\nsetBPM(500) -> getBPM = 240\noff()       -> BPM = 0, tick không phát\n",[992,63107,63105],{"__ignoreMap":1357},[981,63109,63111],{"id":63110},"bài-2-view-và-controller","Bài 2: View và Controller",[1099,63113,63114,63122],{},[1102,63115,63116],{},[1105,63117,63118,63120],{},[1108,63119,2544],{},[1108,63121,1569],{},[1118,63123,63124,63141,63165],{},[1105,63125,63126,63131],{},[1123,63127,63128],{},[992,63129,63130],{},"DJView",[1123,63132,63133,63134,63137,63138,63140],{},"Đăng ký cả 2 loại observer. In ",[992,63135,63136],{},"\"BPM: 120\""," và 1 ký tự ",[992,63139,29688],{}," mỗi nhịp",[1105,63142,63143,63148],{},[1123,63144,63145],{},[992,63146,63147],{},"BeatController",[1123,63149,63150,63151,1656,63154,1656,63157,1656,63159,1656,63161,63164],{},"Nhận lệnh ",[992,63152,63153],{},"start",[992,63155,63156],{},"stop",[992,63158,21881],{},[992,63160,47939],{},[992,63162,63163],{},"set N"," từ bàn phím. Gọi model. Bật tắt nút trên view (in trạng thái nút)",[1105,63166,63167,63169],{},[1123,63168,7137],{},[1123,63170,63171],{},"View chỉ gọi controller, controller có thể thay bằng lớp khác",[1352,63173,63176],{"className":63174,"code":63175,"language":2241,"meta":1357},[2239],"start; + ; + ; + ; set 90; stop\n-> BPM: 60 -> 61 -> 62 -> 63 -> 90 -> 0, nút Start\u002FStop đổi trạng thái đúng\n",[992,63177,63175],{"__ignoreMap":1357},[973,63179,5030,63180,63183,63184,63186,63187,1517],{},[992,63181,63182],{},"BPMGraphView"," in thanh ",[992,63185,15983],{}," dài theo BPM. Không sửa ",[992,63188,63189],{},"BeatModel",[981,63191,63193],{"id":63192},"bài-3-tái-dùng-view-với-model-khác-nâng-cao","Bài 3: Tái dùng view với model khác (nâng cao)",[2273,63195,63196,63206,63217,63228],{},[989,63197,1505,63198,63201,63202,63205],{},[992,63199,63200],{},"HeartModel"," có interface khác (",[992,63203,63204],{},"getHeartRate()",", observer riêng).",[989,63207,1505,63208,63211,63212,63214,63215,1517],{},[992,63209,63210],{},"HeartAdapter"," để ",[992,63213,63130],{}," dùng được ",[992,63216,63200],{},[989,63218,1505,63219,63222,63223,1656,63225,63227],{},[992,63220,63221],{},"HeartController"," (không cho đổi nhịp tim: lệnh ",[992,63224,21881],{},[992,63226,47939],{}," bị bỏ qua, in cảnh báo).",[989,63229,63230,63231,63233],{},"Liệt kê trong ",[992,63232,2513],{},": MVC này dùng những pattern nào, ở đâu (Observer, Strategy, Composite nếu có, Adapter).",[981,63235,2711],{"id":2710},[986,63237,63239,63245,63251,63262],{"className":63238},[2715],[989,63240,63242,63244],{"className":63241},[2719],[2721,63243],{"disabled":2723,"type":2724}," Test model pass (kẹp BPM, bật tắt, observer).",[989,63246,63248,63250],{"className":63247},[2719],[2721,63249],{"disabled":2723,"type":2724}," Thêm view mới không sửa model.",[989,63252,63254,2308,63256,63258,63259,63261],{"className":63253},[2719],[2721,63255],{"disabled":2723,"type":2724},[992,63257,63130],{}," chạy với ",[992,63260,63200],{}," qua adapter.",[989,63263,63265,63267],{"className":63264},[2719],[2721,63266],{"disabled":2723,"type":2724}," Bảng pattern trong MVC chỉ đúng vị trí trong code.",[968,63269,2890],{"id":2889},[986,63271,63272,63275,63278,63281],{},[989,63273,63274],{},"Model giữ cái gì?",[989,63276,63277],{},"View có được đổi số không?",[989,63279,63280],{},"Ai nhận nút bấm?",[989,63282,63283],{},"Thêm view có sửa model không?",[3014,63285],{},[973,63287,63288],{},"🌕 Bạn đã hoàn thành ngày 107. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,63290,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":63292},[63293,63294,63300,63301,63307],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":63295},[63296,63297,63298,63299],{"id":62872,"depth":73,"text":62873},{"id":62893,"depth":73,"text":62894},{"id":62964,"depth":73,"text":62965},{"id":62985,"depth":73,"text":62986},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":63302},[63303,63304,63305,63306],{"id":63042,"depth":73,"text":63043},{"id":63110,"depth":73,"text":63111},{"id":63192,"depth":73,"text":63193},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mô hình khung nhìn điều khiển qua ứng dụng nhịp DJ, cách ba tầng nói chuyện và compound pattern là gì.",{},[5194,5195],{"title":590,"description":63308},[63313,63314],"mvc","compound","Dirp4LNOrnQ8nY6JbKAOJSWsTjISjunH-5y4GLWfOeg",{"id":63317,"title":595,"body":63318,"category":5189,"day":598,"description":63774,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":63775,"navigation":2723,"outcomes":3047,"path":596,"prerequisites":63776,"seo":63777,"stem":597,"tags":63778,"__hash__":63780},"challenges\u002Fchallenges\u002F108.compound-ducks.md",{"type":965,"value":63319,"toc":63758},[63320,63322,63325,63327,63331,63348,63352,63369,63427,63429,63446,63448,63456,63486,63488,63496,63500,63509,63595,63601,63605,63671,63677,63687,63691,63706,63708,63735,63737,63751,63753,63756],[968,63321,971],{"id":970},[973,63323,63324],{},"Bài này học ghép 4 pattern trong 1 app vịt.\nDùng để đếm tiếng kêu không sửa lớp vịt cũ.",[968,63326,979],{"id":978},[981,63328,63330],{"id":63329},"strategy-và-decorator","Strategy và Decorator",[986,63332,63333,63336,63339,63342,63345],{},[989,63334,63335],{},"Strategy: mỗi vịt giữ kiểu kêu và bay riêng.",[989,63337,63338],{},"Decorator đếm: bọc vịt thật, kêu thì tăng đếm 1.",[989,63340,63341],{},"Ví dụ đời thường: như đeo vòng đếm bước không mổ xẻ.",[989,63343,63344],{},"Không sửa lớp vịt nào mà vẫn đếm được.",[989,63346,63347],{},"Kêu thật trước, tăng đếm ngay sau đó.",[981,63349,63351],{"id":63350},"factory-và-composite","Factory và Composite",[986,63353,63354,63357,63360,63363,63366],{},[989,63355,63356],{},"Factory đếm: xưởng tạo vịt đã bọc sẵn bộ đếm.",[989,63358,63359],{},"Khách gọi xưởng như gọi vịt thường mỗi ngày.",[989,63361,63362],{},"Composite đàn: đàn là 1 vịt chứa nhiều vịt con.",[989,63364,63365],{},"Gọi kêu trên đàn thì cả đàn cùng kêu.",[989,63367,63368],{},"Ví dụ đời thường: như hô 1 lớp là cả lớp thưa.",[1099,63370,63371,63382],{},[1102,63372,63373],{},[1105,63374,63375,63377,63380],{},[1108,63376,41388],{},[1108,63378,63379],{},"Việc trong app",[1108,63381,60964],{},[1118,63383,63384,63394,63405,63416],{},[1105,63385,63386,63388,63391],{},[1123,63387,7137],{},[1123,63389,63390],{},"Giữ kiểu kêu bay",[1123,63392,63393],{},"Tính cách mỗi vịt",[1105,63395,63396,63399,63402],{},[1123,63397,63398],{},"Decorator",[1123,63400,63401],{},"Đếm tiếng kêu",[1123,63403,63404],{},"Vòng đếm bước",[1105,63406,63407,63410,63413],{},[1123,63408,63409],{},"Factory",[1123,63411,63412],{},"Tạo vịt đã bọc",[1123,63414,63415],{},"Dây chuyền đóng gói",[1105,63417,63418,63421,63424],{},[1123,63419,63420],{},"Composite",[1123,63422,63423],{},"Gom đàn vịt",[1123,63425,63426],{},"Lớp học nhiều tổ",[981,63428,8903],{"id":9251},[986,63430,63431,63434,63437,63440,63443],{},[989,63432,63433],{},"Định nghĩa: nhà nghiên cứu đăng ký nghe từng vịt.",[989,63435,63436],{},"Mỗi tiếng quạc là 1 tin báo tự động tới.",[989,63438,63439],{},"Ví dụ đời thường: như follow kênh là nhận tin mới.",[989,63441,63442],{},"Thêm người nghe không sửa code vịt cũ.",[989,63444,63445],{},"Đàn kêu thì mỗi con báo riêng 1 tin.",[968,63447,1433],{"id":1432},[986,63449,63450,63453],{},[989,63451,63452],{},"Input: đàn 3 vịt kêu 1 lượt -> Output: đếm tổng tăng 3.",[989,63454,63455],{},"Giải thích: mỗi bộ bọc tăng 1 rồi cộng dồn lại.",[1352,63457,63459],{"className":3538,"code":63458,"language":3540,"meta":1357,"style":1357},"# Bộ đếm bọc ngoài vịt thật\nclass DemQuac:\n    def keu(self):\n        self.vit.keu()  # vịt trong kêu\n        DemQuac.tong += 1  # tăng đếm chung\n",[992,63460,63461,63466,63471,63476,63481],{"__ignoreMap":1357},[1023,63462,63463],{"class":1362,"line":63},[1023,63464,63465],{},"# Bộ đếm bọc ngoài vịt thật\n",[1023,63467,63468],{"class":1362,"line":68},[1023,63469,63470],{},"class DemQuac:\n",[1023,63472,63473],{"class":1362,"line":73},[1023,63474,63475],{},"    def keu(self):\n",[1023,63477,63478],{"class":1362,"line":78},[1023,63479,63480],{},"        self.vit.keu()  # vịt trong kêu\n",[1023,63482,63483],{"class":1362,"line":83},[1023,63484,63485],{},"        DemQuac.tong += 1  # tăng đếm chung\n",[968,63487,1482],{"id":1481},[973,63489,1485,63490,4801,63492,63495],{},[1487,63491,4800],{},[992,63493,63494],{},"day-108\u002F",". Bài này xây dần từng pattern, mỗi bước 1 commit.",[981,63497,63499],{"id":63498},"bài-1-vịt-ngỗng-và-đếm-tiếng-kêu","Bài 1: Vịt, ngỗng và đếm tiếng kêu",[1352,63501,63503],{"className":1393,"code":63502,"language":1395,"meta":1357,"style":1357},"struct Quackable { virtual std::string quack() = 0; virtual ~Quackable() = default; };\n",[992,63504,63505],{"__ignoreMap":1357},[1023,63506,63507],{"class":1362,"line":63},[1023,63508,63502],{},[1099,63510,63511,63521],{},[1102,63512,63513],{},[1105,63514,63515,63517,63519],{},[1108,63516,36178],{},[1108,63518,1569],{},[1108,63520,41388],{},[1118,63522,63523,63545,63563,63580],{},[1105,63524,63525,63527,63543],{},[1123,63526,1053],{},[1123,63528,63529,1656,63531,1656,63534,1656,63537,63539,63540],{},[992,63530,7303],{},[992,63532,63533],{},"RedheadDuck",[992,63535,63536],{},"DuckCall",[992,63538,7306],{}," cài ",[992,63541,63542],{},"Quackable",[1123,63544],{},[1105,63546,63547,63549,63561],{},[1123,63548,2457],{},[1123,63550,63551,5059,63554,7423,63557,63560],{},[992,63552,63553],{},"Goose",[992,63555,63556],{},"honk()",[992,63558,63559],{},"GooseAdapter"," để ngỗng vào được đàn",[1123,63562,24469],{},[1105,63564,63565,63567,63578],{},[1123,63566,13826],{},[1123,63568,63569,63572,63573,63575,63576],{},[992,63570,63571],{},"QuackCounter"," bọc 1 ",[992,63574,63542],{},", mỗi lần kêu tăng biến đếm ",[992,63577,16213],{},[1123,63579,63398],{},[1105,63581,63582,63584,63593],{},[1123,63583,25255],{},[1123,63585,63586,7386,63589,63592],{},[992,63587,63588],{},"AbstractDuckFactory",[992,63590,63591],{},"CountingDuckFactory"," trả vịt đã bọc bộ đếm",[1123,63594,46261],{},[1352,63596,63599],{"className":63597,"code":63598,"language":2241,"meta":1357},[2239],"Tạo 4 vịt qua CountingDuckFactory + 1 GooseAdapter không bọc đếm\nMỗi con kêu 1 lần -> QuackCounter::count() = 4 (ngỗng không được đếm)\n",[992,63600,63598],{"__ignoreMap":1357},[981,63602,63604],{"id":63603},"bài-2-đàn-vịt-và-người-quan-sát","Bài 2: Đàn vịt và người quan sát",[1099,63606,63607,63617],{},[1102,63608,63609],{},[1105,63610,63611,63613,63615],{},[1108,63612,36178],{},[1108,63614,1569],{},[1108,63616,41388],{},[1118,63618,63619,63637,63648],{},[1105,63620,63621,63623,63635],{},[1123,63622,2334],{},[1123,63624,63625,63628,63629,1838,63632,63634],{},[992,63626,63627],{},"Flock : Quackable"," chứa ",[992,63630,63631],{},"std::vector\u003Cstd::shared_ptr\u003CQuackable>>",[992,63633,16747],{}," gọi mọi con",[1123,63636,63420],{},[1105,63638,63639,63641,63646],{},[1123,63640,6866],{},[1123,63642,63643,63644,1056],{},"Iterator duyệt đàn (có thể dùng iterator của ",[992,63645,2535],{},[1123,63647,27856],{},[1105,63649,63650,63652,63669],{},[1123,63651,21986],{},[1123,63653,63654,7386,63657,1656,63660,1838,63663,16828,63666],{},[992,63655,63656],{},"QuackObservable",[992,63658,63659],{},"registerObserver",[992,63661,63662],{},"notifyObservers",[992,63664,63665],{},"Quackologist",[992,63667,63668],{},"\"Nhà nghiên cứu: \u003Ctên> vừa kêu\"",[1123,63670,8903],{},[1352,63672,63675],{"className":63673,"code":63674,"language":2241,"meta":1357},[2239],"Đàn lớn = 3 vịt + đàn vịt trời (4 con) -> quack() -> đếm tăng 7\nNhà nghiên cứu đăng ký cả đàn lớn -> nhận đúng 7 tin, mỗi tin ghi tên vịt thật (không phải \"QuackCounter\")\n",[992,63676,63674],{"__ignoreMap":1357},[2245,63678,63679],{},[973,63680,6826,63681,63683,63684,63686],{},[992,63682,63571],{}," bọc vịt, tin báo phải mang tên vịt bên trong. Hãy để decorator chuyển lời ",[992,63685,63659],{}," vào vịt được bọc.",[981,63688,63690],{"id":63689},"bài-3-nhìn-lại-nâng-cao","Bài 3: Nhìn lại (nâng cao)",[2273,63692,63693,63700,63703],{},[989,63694,63695,63696,63699],{},"Vẽ sơ đồ lớp cả hệ thống (Mermaid ",[992,63697,63698],{},"classDiagram","), đánh dấu 6 pattern.",[989,63701,63702],{},"Viết 1 câu cho mỗi pattern: vấn đề nó giải quyết trong bài này.",[989,63704,63705],{},"Phản biện: đâu là chỗ dùng pattern thừa nếu yêu cầu chỉ là \"đếm tiếng kêu của 5 con vịt\"? Viết bản tối giản và so số dòng.",[981,63707,2711],{"id":2710},[986,63709,63711,63717,63723,63729],{"className":63710},[2715],[989,63712,63714,63716],{"className":63713},[2719],[2721,63715],{"disabled":2723,"type":2724}," Mỗi bước có 1 commit, test của bước trước vẫn pass.",[989,63718,63720,63722],{"className":63719},[2719],[2721,63721],{"disabled":2723,"type":2724}," Test đếm và test tin báo của Bài 2 pass.",[989,63724,63726,63728],{"className":63725},[2719],[2721,63727],{"disabled":2723,"type":2724}," Sơ đồ lớp đánh dấu đủ 6 pattern.",[989,63730,63732,63734],{"className":63731},[2719],[2721,63733],{"disabled":2723,"type":2724}," Có phản biện và bản tối giản.",[968,63736,2890],{"id":2889},[986,63738,63739,63742,63745,63748],{},[989,63740,63741],{},"Ai đếm tiếng quạc?",[989,63743,63744],{},"Xưởng tạo ra hàng gì?",[989,63746,63747],{},"Đàn kêu thì ai kêu?",[989,63749,63750],{},"Tin báo gửi tới ai?",[3014,63752],{},[973,63754,63755],{},"🌕 Bạn đã hoàn thành ngày 108. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,63757,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":63759},[63760,63761,63766,63767,63773],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":63762},[63763,63764,63765],{"id":63329,"depth":73,"text":63330},{"id":63350,"depth":73,"text":63351},{"id":9251,"depth":73,"text":8903},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":63768},[63769,63770,63771,63772],{"id":63498,"depth":73,"text":63499},{"id":63603,"depth":73,"text":63604},{"id":63689,"depth":73,"text":63690},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Mô phỏng vịt dùng chung Strategy Observer Decorator Factory, đếm tiếng quạc và đàn vịt an toàn.",{},[5195],{"title":595,"description":63774},[63314,63779],"ducks","Fl5Q2VEk3_mb68bdWAr2Wzuf7o1gRNgiXRTIl1-w_4E",{"id":63782,"title":600,"body":63783,"category":8797,"day":603,"description":64327,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":64328,"navigation":2723,"outcomes":3047,"path":601,"prerequisites":64329,"seo":64330,"stem":602,"tags":64331,"__hash__":64334},"challenges\u002Fchallenges\u002F109.spark-large-scale.md",{"type":965,"value":63784,"toc":64311},[63785,63787,63790,63792,63796,63813,63817,63834,63873,63877,63894,63896,63904,63929,63931,63945,63949,63987,63993,63997,64062,64096,64100,64259,64261,64288,64290,64304,64306,64309],[968,63786,971],{"id":970},[973,63788,63789],{},"Bài này học chia việc nhiều máy và giữ data trong RAM.\nDùng để chạy job lớn nhanh mà tiền thuê rẻ.",[968,63791,979],{"id":978},[981,63793,63795],{"id":63794},"ba-trụ-hệ-lớn","Ba trụ hệ lớn",[986,63797,63798,63801,63804,63807,63810],{},[989,63799,63800],{},"Đàn hồi: đông thì nở máy, vắng thì co lại.",[989,63802,63803],{},"Cân bằng tải: chia việc đều, không máy chết dí.",[989,63805,63806],{},"Ví dụ đời thường: như siêu thị mở thêm quầy lúc đông.",[989,63808,63809],{},"Việc phải chia nhỏ độc lập để chạy song song.",[989,63811,63812],{},"Giảm nói chuyện giữa các máy để đỡ nghẽn.",[981,63814,63816],{"id":63815},"spark-trong-ram","Spark trong RAM",[986,63818,63819,63822,63825,63828,63831],{},[989,63820,63821],{},"Định nghĩa: chia data thành miếng, mỗi máy tính cục bộ.",[989,63823,63824],{},"Giữ trung gian trong RAM thay vì ghi đĩa mỗi vòng.",[989,63826,63827],{},"Ví dụ đời thường: như giữ đồ trên bàn thay vì cất kho.",[989,63829,63830],{},"Vòng lặp học máy nhanh hơn hàng chục lần đĩa.",[989,63832,63833],{},"Mất miếng nào tính lại đúng miếng đó nhờ dòng dõi.",[1099,63835,63836,63849],{},[1102,63837,63838],{},[1105,63839,63840,63843,63846],{},[1108,63841,63842],{},"Cách chạy",[1108,63844,63845],{},"Mỗi vòng lặp",[1108,63847,63848],{},"Tốc độ lặp",[1118,63850,63851,63862],{},[1105,63852,63853,63856,63859],{},[1123,63854,63855],{},"MapReduce cũ",[1123,63857,63858],{},"Ghi đĩa 100GB",[1123,63860,63861],{},"Chậm, chờ đĩa",[1105,63863,63864,63867,63870],{},[1123,63865,63866],{},"Spark RAM",[1123,63868,63869],{},"Giữ RAM, ít ghi",[1123,63871,63872],{},"Nhanh hơn nhiều",[981,63874,63876],{"id":63875},"đa-tài-nguyên","Đa tài nguyên",[986,63878,63879,63882,63885,63888,63891],{},[989,63880,63881],{},"CPU hợp logic rẽ nhánh phức tạp mỗi ngày.",[989,63883,63884],{},"GPU hợp ma trận đều nhau hàng loạt lớn.",[989,63886,63887],{},"RAM giữ cache nóng, đĩa mạng giữ checkpoint.",[989,63889,63890],{},"Ví dụ đời thường: như bếp chia dao thớt lò riêng.",[989,63892,63893],{},"Thiếu 1 tài nguyên là nghẽn cả hệ thống.",[968,63895,1433],{"id":1432},[986,63897,63898,63901],{},[989,63899,63900],{},"Input: job lặp 10 vòng trên 100GB -> Output: Spark nhanh hơn hẳn.",[989,63902,63903],{},"Giải thích: không ghi đĩa mỗi vòng nên đỡ chờ đọc.",[1352,63905,63907],{"className":3538,"code":63906,"language":3540,"meta":1357,"style":1357},"# Đếm từ phân tán kiểu Spark\ndem = rdd.flatMap(lambda d: d.split())  # chia nhỏ\ndem = dem.map(lambda w: (w, 1)).reduceByKey(lambda a, b: a + b)\nprint(dem.collect())  # gộp kết quả\n",[992,63908,63909,63914,63919,63924],{"__ignoreMap":1357},[1023,63910,63911],{"class":1362,"line":63},[1023,63912,63913],{},"# Đếm từ phân tán kiểu Spark\n",[1023,63915,63916],{"class":1362,"line":68},[1023,63917,63918],{},"dem = rdd.flatMap(lambda d: d.split())  # chia nhỏ\n",[1023,63920,63921],{"class":1362,"line":73},[1023,63922,63923],{},"dem = dem.map(lambda w: (w, 1)).reduceByKey(lambda a, b: a + b)\n",[1023,63925,63926],{"class":1362,"line":78},[1023,63927,63928],{},"print(dem.collect())  # gộp kết quả\n",[968,63930,1482],{"id":1481},[973,63932,1485,63933,7386,63935,63938,63939,3568,63942,1517],{},[1487,63934,13531],{},[1487,63936,63937],{},"PySpark"," (chạy local ",[992,63940,63941],{},"local[*]",[992,63943,63944],{},"day-109\u002F",[981,63946,63948],{"id":63947},"bài-1-rdd-và-dataframe-cơ-bản","Bài 1: RDD và DataFrame cơ bản",[2273,63950,63951,63958,63965,63978],{},[989,63952,63953,63954,63957],{},"Cài PySpark, tạo ",[992,63955,63956],{},"SparkSession"," local.",[989,63959,63960,63961,63964],{},"Word count bằng RDD: ",[992,63962,63963],{},"textFile -> flatMap -> map -> reduceByKey",". In top 20.",[989,63966,63967,63968,1656,63970,1656,63973,1656,63976,16014],{},"Cùng bài bằng DataFrame API (",[992,63969,41973],{},[992,63971,63972],{},"explode",[992,63974,63975],{},"groupBy",[992,63977,27900],{},[989,63979,9007,63980,18407,63983,63986],{},[1487,63981,63982],{},"kế hoạch thực thi",[992,63984,63985],{},"explain()",") của bản DataFrame. Chỉ ra bước shuffle.",[1352,63988,63991],{"className":63989,"code":63990,"language":2241,"meta":1357},[2239],"Kết quả RDD và DataFrame giống nhau\nKết quả giống khung MapReduce tự viết ngày 50\n",[992,63992,63990],{"__ignoreMap":1357},[981,63994,63996],{"id":63995},"bài-2-cache-và-dòng-dõi","Bài 2: Cache và dòng dõi",[973,63998,63999,64000,64061],{},"K-means trên ",[1023,64001,64003,64020],{"className":64002},[1026],[1023,64004,64006],{"className":64005},[1030],[1032,64007,64008],{"xmlns":1034},[1036,64009,64010,64018],{},[1039,64011,64012],{},[2327,64013,64014,64016],{},[1051,64015,2331],{},[1051,64017,6866],{},[1058,64019,6869],{"encoding":1060},[1023,64021,64023],{"className":64022,"ariaHidden":1066},[1065],[1023,64024,64026,64029,64032],{"className":64025},[1070],[1023,64027],{"className":64028,"style":2369},[1074],[1023,64030,1053],{"className":64031},[1079],[1023,64033,64035,64038],{"className":64034},[1079],[1023,64036,2379],{"className":64037},[1079],[1023,64039,64041],{"className":64040},[2383],[1023,64042,64044],{"className":64043},[2387],[1023,64045,64047],{"className":64046},[2391],[1023,64048,64050],{"className":64049,"style":2369},[2395],[1023,64051,64052,64055],{"style":2398},[1023,64053],{"className":64054,"style":2403},[2402],[1023,64056,64058],{"className":64057},[2407,2408,2409,2410],[1023,64059,6866],{"className":64060},[1079,2410]," điểm (tự cài bằng RDD, không dùng MLlib):",[2273,64063,64064,64073,64084,64090],{},[989,64065,64066,64067,2308,64069,64072],{},"Chạy 10 vòng ",[1487,64068,41587],{},[992,64070,64071],{},"cache()"," dữ liệu. Đo thời gian.",[989,64074,64075,64076,64079,64080,64083],{},"Chạy lại có ",[992,64077,64078],{},"points.cache()",". Đo thời gian. Mở Spark UI (",[992,64081,64082],{},"localhost:4040",") chụp tab Storage.",[989,64085,9007,64086,64089],{},[992,64087,64088],{},"toDebugString()"," của RDD kết quả để thấy dòng dõi.",[989,64091,64092,64093,64095],{},"So với bản ",[992,64094,35455],{}," ngày 87.",[981,64097,64099],{"id":64098},"bài-3-phân-vùng-và-lệch-dữ-liệu-nâng-cao","Bài 3: Phân vùng và lệch dữ liệu (nâng cao)",[2273,64101,64102,64243,64246,64253],{},[989,64103,64104,64105,18407,64108,64169,64170,18407,64173,64234,64235,64238,64239,64242],{},"Join 2 bảng: ",[992,64106,64107],{},"orders",[1023,64109,64111,64128],{"className":64110},[1026],[1023,64112,64114],{"className":64113},[1030],[1032,64115,64116],{"xmlns":1034},[1036,64117,64118,64126],{},[1039,64119,64120],{},[2327,64121,64122,64124],{},[1051,64123,2331],{},[1051,64125,6866],{},[1058,64127,6869],{"encoding":1060},[1023,64129,64131],{"className":64130,"ariaHidden":1066},[1065],[1023,64132,64134,64137,64140],{"className":64133},[1070],[1023,64135],{"className":64136,"style":2369},[1074],[1023,64138,1053],{"className":64139},[1079],[1023,64141,64143,64146],{"className":64142},[1079],[1023,64144,2379],{"className":64145},[1079],[1023,64147,64149],{"className":64148},[2383],[1023,64150,64152],{"className":64151},[2387],[1023,64153,64155],{"className":64154},[2391],[1023,64156,64158],{"className":64157,"style":2369},[2395],[1023,64159,64160,64163],{"style":2398},[1023,64161],{"className":64162,"style":2403},[2402],[1023,64164,64166],{"className":64165},[2407,2408,2409,2410],[1023,64167,6866],{"className":64168},[1079,2410]," dòng) và ",[992,64171,64172],{},"customers",[1023,64174,64176,64193],{"className":64175},[1026],[1023,64177,64179],{"className":64178},[1030],[1032,64180,64181],{"xmlns":1034},[1036,64182,64183,64191],{},[1039,64184,64185],{},[2327,64186,64187,64189],{},[1051,64188,2331],{},[1051,64190,25255],{},[1058,64192,25339],{"encoding":1060},[1023,64194,64196],{"className":64195,"ariaHidden":1066},[1065],[1023,64197,64199,64202,64205],{"className":64198},[1070],[1023,64200],{"className":64201,"style":2369},[1074],[1023,64203,1053],{"className":64204},[1079],[1023,64206,64208,64211],{"className":64207},[1079],[1023,64209,2379],{"className":64210},[1079],[1023,64212,64214],{"className":64213},[2383],[1023,64215,64217],{"className":64216},[2387],[1023,64218,64220],{"className":64219},[2391],[1023,64221,64223],{"className":64222,"style":2369},[2395],[1023,64224,64225,64228],{"style":2398},[1023,64226],{"className":64227,"style":2403},[2402],[1023,64229,64231],{"className":64230},[2407,2408,2409,2410],[1023,64232,25255],{"className":64233},[1079,2410]," dòng). So ",[992,64236,64237],{},"join"," thường và ",[992,64240,64241],{},"broadcast"," join. In thời gian và kế hoạch.",[989,64244,64245],{},"Tạo dữ liệu lệch: 50% đơn thuộc 1 khách hàng. Quan sát 1 task chạy lâu trong Spark UI.",[989,64247,64248,64249,64252],{},"Sửa lệch bằng ",[1487,64250,64251],{},"salting",": thêm hậu tố ngẫu nhiên 0..9 vào khóa nóng, join, rồi gộp lại. So thời gian.",[989,64254,37875,64255,64258],{},[992,64256,64257],{},"spark.sql.shuffle.partitions = 8, 200, 1000",". In thời gian.",[981,64260,2711],{"id":2710},[986,64262,64264,64270,64276,64282],{"className":64263},[2715],[989,64265,64267,64269],{"className":64266},[2719],[2721,64268],{"disabled":2723,"type":2724}," Word count RDD và DataFrame khớp nhau.",[989,64271,64273,64275],{"className":64272},[2719],[2721,64274],{"disabled":2723,"type":2724}," Bảng thời gian có và không có cache, có ảnh Spark UI.",[989,64277,64279,64281],{"className":64278},[2719],[2721,64280],{"disabled":2723,"type":2724}," Bài 3 có số liệu broadcast join và salting.",[989,64283,64285,64287],{"className":64284},[2719],[2721,64286],{"disabled":2723,"type":2724}," Giải thích được vì sao Spark nhanh hơn MapReduce với thuật toán lặp.",[968,64289,2890],{"id":2889},[986,64291,64292,64295,64298,64301],{},[989,64293,64294],{},"Đàn hồi là gì?",[989,64296,64297],{},"Cân bằng tải để làm gì?",[989,64299,64300],{},"Spark giữ gì trong RAM?",[989,64302,64303],{},"Mất 1 miếng thì sao?",[3014,64305],{},[973,64307,64308],{},"🌕 Bạn đã hoàn thành ngày 109. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,64310,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":64312},[64313,64314,64319,64320,64326],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":64315},[64316,64317,64318],{"id":63794,"depth":73,"text":63795},{"id":63815,"depth":73,"text":63816},{"id":63875,"depth":73,"text":63876},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":64321},[64322,64323,64324,64325],{"id":63947,"depth":73,"text":63948},{"id":63995,"depth":73,"text":63996},{"id":64098,"depth":73,"text":64099},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thuật toán quy mô lớn, cân bằng tải, co giãn đàn hồi, Spark tính toán trong bộ nhớ và ví dụ đám mây.",{},[14055,17499],{"title":600,"description":64327},[64332,64333],"large-scale","spark","uewKw-0ObE5dKLzcggDHRrg7O9ySqoORqlgUF5tHNb0",{"id":64336,"title":605,"body":64337,"category":8797,"day":608,"description":64966,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":64967,"navigation":2723,"outcomes":3047,"path":606,"prerequisites":64968,"seo":64969,"stem":607,"tags":64970,"__hash__":64971},"challenges\u002Fchallenges\u002F110.hieu-nang-tinh-toan.md",{"type":965,"value":64338,"toc":64950},[64339,64341,64344,64346,64350,64367,64371,64388,64434,64438,64455,64457,64465,64490,64492,64504,64508,64664,64670,64742,64746,64823,64827,64830,64898,64900,64927,64929,64943,64945,64948],[968,64340,971],{"id":970},[973,64342,64343],{},"Bài này học trần song song và cách dùng GPU đúng.\nDùng để biết khi nào thêm máy là phí tiền.",[968,64345,979],{"id":978},[981,64347,64349],{"id":64348},"luật-amdahl","Luật Amdahl",[986,64351,64352,64355,64358,64361,64364],{},[989,64353,64354],{},"Định nghĩa: phần tuần tự quyết trần tăng tốc tối đa.",[989,64356,64357],{},"10% tuần tự thì vô hạn máy cũng tối đa 10 lần.",[989,64359,64360],{},"Ví dụ đời thường: như đoàn xe chờ 1 cầu hẹp.",[989,64362,64363],{},"Phải đo tỉ lệ tuần tự trước khi mua máy.",[989,64365,64366],{},"Sửa phần tuần tự thường lời hơn thêm máy mới.",[981,64368,64370],{"id":64369},"cuda-và-gpu","CUDA và GPU",[986,64372,64373,64376,64379,64382,64385],{},[989,64374,64375],{},"CPU như vài đầu bếp giỏi làm món khó lẻ.",[989,64377,64378],{},"GPU như nghìn phụ bếp cùng thái rau giống nhau.",[989,64380,64381],{},"Điều kiện thắng: data lớn, phép đều, ít rẽ nhánh.",[989,64383,64384],{},"Ví dụ đời thường: như in 1000 tờ cùng mẫu thì nhanh.",[989,64386,64387],{},"Data nhỏ và rẽ nhánh nhiều thì CPU vẫn thắng.",[1099,64389,64390,64400],{},[1102,64391,64392],{},[1105,64393,64394,64396,64398],{},[1108,64395,61474],{},[1108,64397,42235],{},[1108,64399,55198],{},[1118,64401,64402,64413,64424],{},[1105,64403,64404,64407,64410],{},[1123,64405,64406],{},"Ma trận LLM lớn",[1123,64408,64409],{},"GPU",[1123,64411,64412],{},"Ngàn nhân cùng tính",[1105,64414,64415,64418,64421],{},[1123,64416,64417],{},"Logic rẽ nhánh",[1123,64419,64420],{},"CPU",[1123,64422,64423],{},"Ít nhân nhưng khôn",[1105,64425,64426,64429,64431],{},[1123,64427,64428],{},"Copy RAM-VRAM nặng",[1123,64430,64420],{},[1123,64432,64433],{},"Phí chuyển nuốt lợi",[981,64435,64437],{"id":64436},"locality","Locality",[986,64439,64440,64443,64446,64449,64452],{},[989,64441,64442],{},"Định nghĩa: chở tính tới chỗ data rẻ hơn ngược lại.",[989,64444,64445],{},"Mỗi máy tính trên miếng data nó đang có.",[989,64447,64448],{},"Giữ nóng cache RAM, tính và truyền gối nhau.",[989,64450,64451],{},"Ví dụ đời thường: như nấu tại chợ thay vì chở rau xa.",[989,64453,64454],{},"Thêm GPU mà quên locality thì trễ vẫn chững lại.",[968,64456,1433],{"id":1432},[986,64458,64459,64462],{},[989,64460,64461],{},"Input: 95% song song, 64 máy -> Output: chỉ nhanh ~15 lần.",[989,64463,64464],{},"Giải thích: 5% tuần tự thành trần cứng theo Amdahl.",[1352,64466,64468],{"className":3538,"code":64467,"language":3540,"meta":1357,"style":1357},"# Ước trần Amdahl\ntuan_tu = 0.05  # 5% bắt buộc nối tiếp\ntran = 1 \u002F tuan_tu  # máy vô hạn cũng vậy\nprint(tran)  # 20 lần là trần\n",[992,64469,64470,64475,64480,64485],{"__ignoreMap":1357},[1023,64471,64472],{"class":1362,"line":63},[1023,64473,64474],{},"# Ước trần Amdahl\n",[1023,64476,64477],{"class":1362,"line":68},[1023,64478,64479],{},"tuan_tu = 0.05  # 5% bắt buộc nối tiếp\n",[1023,64481,64482],{"class":1362,"line":73},[1023,64483,64484],{},"tran = 1 \u002F tuan_tu  # máy vô hạn cũng vậy\n",[1023,64486,64487],{"class":1362,"line":78},[1023,64488,64489],{},"print(tran)  # 20 lần là trần\n",[968,64491,1482],{"id":1481},[973,64493,1485,64494,64496,64497,64500,64501,1517],{},[1487,64495,4800],{}," với OpenMP (Bài 1-2), ",[1487,64498,64499],{},"Python"," với NumPy\u002FCuPy hoặc PyTorch (Bài 3). Nộp vào ",[992,64502,64503],{},"day-110\u002F",[981,64505,64507],{"id":64506},"bài-1-định-luật-amdahl","Bài 1: Định luật Amdahl",[2273,64509,64510,64655],{},[989,64511,1505,64512,15881,64515,1517],{},[992,64513,64514],{},"double amdahl(double p, int n)",[1023,64516,64518,64554],{"className":64517},[1026],[1023,64519,64521],{"className":64520},[1030],[1032,64522,64523],{"xmlns":1034},[1036,64524,64525,64551],{},[1039,64526,64527],{},[18110,64528,64529,64531],{},[1051,64530,1053],{},[1039,64532,64533,64535,64537,64539,64541,64543,64545,64547,64549],{},[1046,64534,1049],{"stretchy":1048},[1051,64536,1053],{},[1046,64538,17698],{},[1042,64540,973],{},[1046,64542,1056],{"stretchy":1048},[1046,64544,21881],{},[1042,64546,973],{},[1042,64548,2461],{"mathvariant":2460},[1042,64550,1262],{},[1058,64552,64553],{"encoding":1060},"\\frac{1}{(1 - p) + p \u002F n}",[1023,64555,64557],{"className":64556,"ariaHidden":1066},[1065],[1023,64558,64560,64563],{"className":64559},[1070],[1023,64561],{"className":64562,"style":31764},[1074],[1023,64564,64566,64569,64652],{"className":64565},[1079],[1023,64567],{"className":64568},[1085,18174],[1023,64570,64572],{"className":64571},[18110],[1023,64573,64575,64644],{"className":64574},[2387,17732],[1023,64576,64578,64641],{"className":64577},[2391],[1023,64579,64581,64619,64627],{"className":64580,"style":31783},[2395],[1023,64582,64583,64586],{"style":18190},[1023,64584],{"className":64585,"style":18194},[2402],[1023,64587,64589],{"className":64588},[2407,2408,2409,2410],[1023,64590,64592,64595,64598,64601,64604,64607,64610,64613,64616],{"className":64591},[1079,2410],[1023,64593,1049],{"className":64594},[1085,2410],[1023,64596,1053],{"className":64597},[1079,2410],[1023,64599,17698],{"className":64600},[13794,2410],[1023,64602,973],{"className":64603},[1079,1080,2410],[1023,64605,1056],{"className":64606},[1092,2410],[1023,64608,21881],{"className":64609},[13794,2410],[1023,64611,973],{"className":64612},[1079,1080,2410],[1023,64614,2461],{"className":64615},[1079,2410],[1023,64617,1262],{"className":64618},[1079,1080,2410],[1023,64620,64621,64624],{"style":18221},[1023,64622],{"className":64623,"style":18194},[2402],[1023,64625],{"className":64626,"style":18229},[18228],[1023,64628,64629,64632],{"style":18232},[1023,64630],{"className":64631,"style":18194},[2402],[1023,64633,64635],{"className":64634},[2407,2408,2409,2410],[1023,64636,64638],{"className":64637},[1079,2410],[1023,64639,1053],{"className":64640},[1079,2410],[1023,64642,17797],{"className":64643},[17796],[1023,64645,64647],{"className":64646},[2391],[1023,64648,64650],{"className":64649,"style":18260},[2395],[1023,64651],{},[1023,64653],{"className":64654},[1092,18174],[989,64656,64657,64658,1509,64661,1517],{},"In bảng tăng tốc lý thuyết với ",[992,64659,64660],{},"p = 0.5, 0.9, 0.95, 0.99",[992,64662,64663],{},"n = 1, 2, 4, 8, 16, 64, 1024",[1352,64665,64668],{"className":64666,"code":64667,"language":2241,"meta":1357},[2239],"p = 0.95, n = 64   -> ~15.4\np = 0.90, n = vô hạn -> 10\n",[992,64669,64667],{"__ignoreMap":1357},[2273,64671,64672],{"start":73},[989,64673,64674,64675,64678,64679,64741],{},"Viết chương trình có phần tuần tự (đọc file, 20% thời gian) và phần song song bằng ",[992,64676,64677],{},"#pragma omp parallel for"," (tính tổng bình phương ",[1023,64680,64682,64700],{"className":64681},[1026],[1023,64683,64685],{"className":64684},[1030],[1032,64686,64687],{"xmlns":1034},[1036,64688,64689,64697],{},[1039,64690,64691],{},[2327,64692,64693,64695],{},[1051,64694,2331],{},[1051,64696,14650],{},[1058,64698,64699],{"encoding":1060},"10^8",[1023,64701,64703],{"className":64702,"ariaHidden":1066},[1065],[1023,64704,64706,64709,64712],{"className":64705},[1070],[1023,64707],{"className":64708,"style":2369},[1074],[1023,64710,1053],{"className":64711},[1079],[1023,64713,64715,64718],{"className":64714},[1079],[1023,64716,2379],{"className":64717},[1079],[1023,64719,64721],{"className":64720},[2383],[1023,64722,64724],{"className":64723},[2387],[1023,64725,64727],{"className":64726},[2391],[1023,64728,64730],{"className":64729,"style":2369},[2395],[1023,64731,64732,64735],{"style":2398},[1023,64733],{"className":64734,"style":2403},[2402],[1023,64736,64738],{"className":64737},[2407,2408,2409,2410],[1023,64739,14650],{"className":64740},[1079,2410]," số). Đo tăng tốc thật với 1, 2, 4, 8 luồng. So với Amdahl.",[981,64743,64745],{"id":64744},"bài-2-data-locality-và-cache","Bài 2: Data locality và cache",[2273,64747,64748,64814,64820],{},[989,64749,64750,64751,64803,64804,1656,64807,1656,64810,64813],{},"Nhân 2 ma trận ",[1023,64752,64754,64773],{"className":64753},[1026],[1023,64755,64757],{"className":64756},[1030],[1032,64758,64759],{"xmlns":1034},[1036,64760,64761,64770],{},[1039,64762,64763,64766,64768],{},[1051,64764,64765],{},"1024",[1046,64767,13768],{},[1051,64769,64765],{},[1058,64771,64772],{"encoding":1060},"1024 \\times 1024",[1023,64774,64776,64794],{"className":64775,"ariaHidden":1066},[1065],[1023,64777,64779,64782,64785,64788,64791],{"className":64778},[1070],[1023,64780],{"className":64781,"style":18148},[1074],[1023,64783,64765],{"className":64784},[1079],[1023,64786],{"className":64787,"style":13790},[2354],[1023,64789,13768],{"className":64790},[13794],[1023,64792],{"className":64793,"style":13790},[2354],[1023,64795,64797,64800],{"className":64796},[1070],[1023,64798],{"className":64799,"style":10020},[1074],[1023,64801,64765],{"className":64802},[1079]," bằng 3 thứ tự vòng lặp: ",[992,64805,64806],{},"ijk",[992,64808,64809],{},"ikj",[992,64811,64812],{},"jki",". In thời gian. Giải thích bằng cách truy cập bộ nhớ theo hàng.",[989,64815,51158,64816,64819],{},[1487,64817,64818],{},"chia khối"," (tiling) khối 32 và 64. So thời gian.",[989,64821,64822],{},"Duyệt mảng 2D theo hàng và theo cột với kích thước từ 1 MB tới 256 MB. Vẽ thời gian, chỉ ra các mốc cache L1, L2, L3.",[981,64824,64826],{"id":64825},"bài-3-cpu-và-gpu-nâng-cao","Bài 3: CPU và GPU (nâng cao)",[973,64828,64829],{},"Nếu không có GPU, dùng Google Colab.",[2273,64831,64832,64889,64895],{},[989,64833,64834,64835,7386,64885,64888],{},"Nhân ma trận ",[1023,64836,64838,64855],{"className":64837},[1026],[1023,64839,64841],{"className":64840},[1030],[1032,64842,64843],{"xmlns":1034},[1036,64844,64845,64853],{},[1039,64846,64847,64849,64851],{},[1042,64848,1262],{},[1046,64850,13768],{},[1042,64852,1262],{},[1058,64854,13773],{"encoding":1060},[1023,64856,64858,64876],{"className":64857,"ariaHidden":1066},[1065],[1023,64859,64861,64864,64867,64870,64873],{"className":64860},[1070],[1023,64862],{"className":64863,"style":13783},[1074],[1023,64865,1262],{"className":64866},[1079,1080],[1023,64868],{"className":64869,"style":13790},[2354],[1023,64871,13768],{"className":64872},[13794],[1023,64874],{"className":64875,"style":13790},[2354],[1023,64877,64879,64882],{"className":64878},[1070],[1023,64880],{"className":64881,"style":2347},[1074],[1023,64883,1262],{"className":64884},[1079,1080],[992,64886,64887],{},"n = 64, 256, 1024, 4096"," trên NumPy (CPU) và CuPy hoặc PyTorch CUDA (GPU). Đo cả thời gian chép dữ liệu sang GPU.",[989,64890,64891,64892,64894],{},"Chỉ ra ",[992,64893,1262],{}," mà GPU bắt đầu thắng khi tính cả thời gian chép.",[989,64896,64897],{},"Bài nhiều rẽ nhánh: với mỗi phần tử, lặp Collatz tới 1 và đếm bước. So CPU (Numba hoặc C++) và GPU.",[981,64899,2711],{"id":2710},[986,64901,64903,64909,64915,64921],{"className":64902},[2715],[989,64904,64906,64908],{"className":64905},[2719],[2721,64907],{"disabled":2723,"type":2724}," Bảng Amdahl và số đo thật so với lý thuyết.",[989,64910,64912,64914],{"className":64911},[2719],[2721,64913],{"disabled":2723,"type":2724}," Bảng 3 thứ tự vòng lặp và bản tiling có số thật.",[989,64916,64918,64920],{"className":64917},[2719],[2721,64919],{"disabled":2723,"type":2724}," Hình thời gian duyệt theo kích thước mảng.",[989,64922,64924,64926],{"className":64923},[2719],[2721,64925],{"disabled":2723,"type":2724}," Bảng CPU vs GPU có cột thời gian chép dữ liệu.",[968,64928,2890],{"id":2889},[986,64930,64931,64934,64937,64940],{},[989,64932,64933],{},"Trần Amdahl do đâu?",[989,64935,64936],{},"GPU thắng CPU khi nào?",[989,64938,64939],{},"Locality nghĩa là gì?",[989,64941,64942],{},"Vì sao thêm GPU bị chững?",[3014,64944],{},[973,64946,64947],{},"🌕 Bạn đã hoàn thành ngày 110. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,64949,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":64951},[64952,64953,64958,64959,64965],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":64954},[64955,64956,64957],{"id":64348,"depth":73,"text":64349},{"id":64369,"depth":73,"text":64370},{"id":64436,"depth":73,"text":64437},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":64960},[64961,64962,64963,64964],{"id":64506,"depth":73,"text":64507},{"id":64744,"depth":73,"text":64745},{"id":64825,"depth":73,"text":64826},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Giới hạn song song Amdahl, GPU CUDA, locality dữ liệu và case song song LLM lợi nhuận giảm dần.",{},[17499],{"title":605,"description":64966},[64332],"RXJhfkkIG5hXzFSeNEQeENPT6HK5Z2IszzE35qaw7ZE",{"id":64973,"title":610,"body":64974,"category":8797,"day":613,"description":65336,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":65337,"navigation":2723,"outcomes":3047,"path":611,"prerequisites":65338,"seo":65339,"stem":612,"tags":65340,"__hash__":65341},"challenges\u002Fchallenges\u002F111.gradient-descent.md",{"type":965,"value":64975,"toc":65320},[64976,64978,64981,64983,64987,65004,65008,65025,65073,65076,65093,65095,65102,65122,65124,65132,65136,65179,65182,65188,65191,65195,65233,65237,65265,65267,65297,65299,65313,65315,65318],[968,64977,971],{"id":970},[973,64979,64980],{},"Bài này học đi xuống dốc để tìm lời giải đẹp.\nDùng để vẽ đồ thị ít giao cắt và huấn luyện model.",[968,64982,979],{"id":978},[981,64984,64986],{"id":64985},"cost-và-đáy-địa-phương","Cost và đáy địa phương",[986,64988,64989,64992,64995,64998,65001],{},[989,64990,64991],{},"Định nghĩa: cost là 1 số đo độ xấu, càng nhỏ càng đẹp.",[989,64993,64994],{},"Đáy địa phương: dịch chút nào cũng xấu hơn tạm thời.",[989,64996,64997],{},"Bước lớn thì nhảy qua đáy, bước bé thì bò mãi.",[989,64999,65000],{},"Ví dụ đời thường: như xuống núi trong sương mù dày.",[989,65002,65003],{},"Lấy mẫu ngẫu nhiên: thử nhiều chỗ rồi giữ chỗ tốt.",[981,65005,65007],{"id":65006},"gradient-descent","Gradient descent",[986,65009,65010,65013,65016,65019,65022],{},[989,65011,65012],{},"Định nghĩa: bước ngược hướng dốc một đoạn theo tốc độ học.",[989,65014,65015],{},"Đạo hàm mách hướng lên, ta đi hướng ngược lại xuống.",[989,65017,65018],{},"Ví dụ đời thường: như sờ dốc dưới chân rồi bước xuống.",[989,65020,65021],{},"Thêm xung lượng để vượt gợn nhỏ trên đường.",[989,65023,65024],{},"Chuẩn hóa data để thung lũng tròn dễ đi hơn.",[1099,65026,65027,65038],{},[1102,65028,65029],{},[1105,65030,65031,65034,65036],{},[1108,65032,65033],{},"Bước đi",[1108,65035,54331],{},[1108,65037,54334],{},[1118,65039,65040,65051,65062],{},[1105,65041,65042,65045,65048],{},[1123,65043,65044],{},"Quá lớn",[1123,65046,65047],{},"Loss vọt lên xuống",[1123,65049,65050],{},"Giảm tốc độ học",[1105,65052,65053,65056,65059],{},[1123,65054,65055],{},"Quá bé",[1123,65057,65058],{},"Học mãi không tới",[1123,65060,65061],{},"Tăng bước hoặc xung lượng",[1105,65063,65064,65067,65070],{},[1123,65065,65066],{},"Vừa",[1123,65068,65069],{},"Loss giảm êm",[1123,65071,65072],{},"Giữ và giảm dần cuối",[981,65074,48447],{"id":65075},"giới-hạn",[986,65077,65078,65081,65084,65087,65090],{},[989,65079,65080],{},"Cần hàm trơn có đạo hàm tính được mỗi ngày.",[989,65082,65083],{},"Dễ kẹt đáy gần nhất và lượn ở thung hẹp.",[989,65085,65086],{},"Điểm yên ngựa: dốc gần 0 nhưng chưa phải đáy.",[989,65088,65089],{},"Ví dụ đời thường: như đèo phẳng tưởng đỉnh nhưng chưa.",[989,65091,65092],{},"Hàm rời rạc nhiều đáy nên dùng ủ nhiệt sau.",[968,65094,1433],{"id":1432},[986,65096,65097,65099],{},[989,65098,55639],{},[989,65100,65101],{},"Giải thích: bước nhảy qua đáy liên tục nên không chốt được.",[1352,65103,65105],{"className":3538,"code":65104,"language":3540,"meta":1357,"style":1357},"# Một bước gradient descent\nx = x - toc_do * dao_ham(x)  # bước ngược dốc\nprint(x)  # vị trí mới thấp hơn\n",[992,65106,65107,65112,65117],{"__ignoreMap":1357},[1023,65108,65109],{"class":1362,"line":63},[1023,65110,65111],{},"# Một bước gradient descent\n",[1023,65113,65114],{"class":1362,"line":68},[1023,65115,65116],{},"x = x - toc_do * dao_ham(x)  # bước ngược dốc\n",[1023,65118,65119],{"class":1362,"line":73},[1023,65120,65121],{},"print(x)  # vị trí mới thấp hơn\n",[968,65123,1482],{"id":1481},[973,65125,1485,65126,65128,65129,1517],{},[1487,65127,13531],{}," với NumPy và matplotlib. Nộp vào ",[992,65130,65131],{},"day-111\u002F",[981,65133,65135],{"id":65134},"bài-1-gradient-descent-trên-hàm-1-biến-và-2-biến","Bài 1: Gradient descent trên hàm 1 biến và 2 biến",[1099,65137,65138,65146],{},[1102,65139,65140],{},[1105,65141,65142,65144],{},[1108,65143,1566],{},[1108,65145,2547],{},[1118,65147,65148,65160,65170],{},[1105,65149,65150,65155],{},[1123,65151,65152],{},[992,65153,65154],{},"numerical_grad(f, x, h=1e-5)",[1123,65156,65157,65158],{},"Sai phân trung tâm cho vector ",[992,65159,3904],{},[1105,65161,65162,65167],{},[1123,65163,65164],{},[992,65165,65166],{},"gd(f, grad, x0, lr, steps)",[1123,65168,65169],{},"Trả toàn bộ quỹ đạo",[1105,65171,65172,65177],{},[1123,65173,65174],{},[992,65175,65176],{},"gd_momentum(f, grad, x0, lr, beta, steps)",[1123,65178],{},[973,65180,65181],{},"Hàm thử:",[1352,65183,65186],{"className":65184,"code":65185,"language":2241,"meta":1357},[2239],"f(x) = (x - 3)^2                    -> hội tụ về 3 với lr = 0.1\nf(x) = (x - 3)^2, lr = 1.1          -> phân kỳ (in 10 bước đầu)\nf(x, y) = x^2 + 10 y^2              -> thung hẹp, GD đi zic zắc\nRosenbrock (1-x)^2 + 100(y-x^2)^2   -> đáy (1, 1)\n",[992,65187,65185],{"__ignoreMap":1357},[973,65189,65190],{},"Vẽ quỹ đạo trên contour của từng hàm 2 biến.",[981,65192,65194],{"id":65193},"bài-2-tốc-độ-học-và-xung-lượng","Bài 2: Tốc độ học và xung lượng",[2273,65196,65197,65219,65226],{},[989,65198,65199,65200,65203,65204,38397,65207,10880,65210,65212,65213,10052,65216,65218],{},"Trên ",[992,65201,65202],{},"x^2 + 10 y^2",", quét ",[992,65205,65206],{},"lr",[992,65208,65209],{},"0.001",[992,65211,22396],{},". Vẽ số bước tới ",[992,65214,65215],{},"|grad| \u003C 1e-6",[992,65217,65206],{},". Chỉ ra ngưỡng phân kỳ và giải thích bằng hệ số 10.",[989,65220,65221,65222,65225],{},"So GD, momentum (",[992,65223,65224],{},"beta = 0.9","), và Adam tự cài trên Rosenbrock. In số bước và vẽ quỹ đạo.",[989,65227,65228,65229,65232],{},"Chuẩn hóa biến ",[992,65230,65231],{},"y' = sqrt(10) y",". Chạy lại GD. Giải thích vì sao thung tròn dễ đi.",[981,65234,65236],{"id":65235},"bài-3-nhiều-đáy-và-điểm-yên-ngựa-nâng-cao","Bài 3: Nhiều đáy và điểm yên ngựa (nâng cao)",[2273,65238,65239,65245,65251],{},[989,65240,65241,65242,1517],{},"Hàm Rastrigin 2D có nhiều đáy địa phương. Chạy GD từ 100 điểm ngẫu nhiên. Đếm số lần tới đáy toàn cục ",[992,65243,65244],{},"(0, 0)",[989,65246,65247,65250],{},[1487,65248,65249],{},"Random restart:"," giữ nghiệm tốt nhất của 100 lần. So với 1 lần.",[989,65252,24234,65253,65256,65257,65260,65261,65264],{},[992,65254,65255],{},"f(x, y) = x^2 - y^2",". Xuất phát tại ",[992,65258,65259],{},"(1, 0)",": GD kẹt ở điểm yên ngựa. Xuất phát tại ",[992,65262,65263],{},"(1, 1e-6)",": thoát. Vẽ 2 quỹ đạo.",[981,65266,2711],{"id":2710},[986,65268,65270,65279,65285,65291],{"className":65269},[2715],[989,65271,65273,65275,65276,13981],{"className":65272},[2719],[2721,65274],{"disabled":2723,"type":2724}," Test hội tụ và phân kỳ trên ",[992,65277,65278],{},"(x-3)^2",[989,65280,65282,65284],{"className":65281},[2719],[2721,65283],{"disabled":2723,"type":2724}," Có hình quỹ đạo trên contour cho 3 hàm 2 biến.",[989,65286,65288,65290],{"className":65287},[2719],[2721,65289],{"disabled":2723,"type":2724}," Bảng GD, momentum, Adam trên Rosenbrock có số thật.",[989,65292,65294,65296],{"className":65293},[2719],[2721,65295],{"disabled":2723,"type":2724}," Có minh họa điểm yên ngựa.",[968,65298,2890],{"id":2889},[986,65300,65301,65304,65307,65310],{},[989,65302,65303],{},"Cost đo cái gì?",[989,65305,65306],{},"Gradient mách hướng nào?",[989,65308,65309],{},"Bước lớn gây gì?",[989,65311,65312],{},"Khi nào gradient kẹt?",[3014,65314],{},[973,65316,65317],{},"🌕 Bạn đã hoàn thành ngày 111. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,65319,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":65321},[65322,65323,65328,65329,65335],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":65324},[65325,65326,65327],{"id":64985,"depth":73,"text":64986},{"id":65006,"depth":73,"text":65007},{"id":65075,"depth":73,"text":48447},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":65330},[65331,65332,65333,65334],{"id":65134,"depth":73,"text":65135},{"id":65193,"depth":73,"text":65194},{"id":65235,"depth":73,"text":65236},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Heuristic số giao cắt, tối ưu hàm chi phí, bước đi, lấy mẫu ngẫu nhiên và toán hình học gradient descent.",{},[15144],{"title":610,"description":65336},[47532],"uakPKW3jO63uegxPDqidzT-u50ZZJNnTu_5iEC_LlTE",{"id":65343,"title":615,"body":65344,"category":8797,"day":618,"description":65743,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":65744,"navigation":2723,"outcomes":3047,"path":616,"prerequisites":65745,"seo":65746,"stem":617,"tags":65747,"__hash__":65748},"challenges\u002Fchallenges\u002F112.gradient-ung-dung.md",{"type":965,"value":65345,"toc":65727},[65346,65348,65351,65353,65357,65374,65378,65395,65445,65449,65466,65468,65476,65501,65503,65513,65517,65532,65548,65552,65572,65583,65587,65675,65677,65704,65706,65720,65722,65725],[968,65347,971],{"id":970},[973,65349,65350],{},"Bài này học tìm đường thẳng khớp điểm và vẽ đồ thị.\nDùng để hồi quy giá và xếp đỉnh cho đẹp mắt.",[968,65352,979],{"id":978},[981,65354,65356],{"id":65355},"hồi-quy-bằng-gradient","Hồi quy bằng gradient",[986,65358,65359,65362,65365,65368,65371],{},[989,65360,65361],{},"Định nghĩa: tìm đường thẳng cho tổng lỗi bình phương nhỏ nhất.",[989,65363,65364],{},"Bắt đầu đường bừa rồi nghiêng dịch theo hướng giảm lỗi.",[989,65366,65367],{},"Ví dụ đời thường: như xoay thước cho gần hết đinh nhất.",[989,65369,65370],{},"Phải chuẩn hóa để thung lũng tròn dễ đi hơn.",[989,65372,65373],{},"Bài nhỏ có công thức đóng, bài lớn cần gradient.",[981,65375,65377],{"id":65376},"nhúng-đồ-thị","Nhúng đồ thị",[986,65379,65380,65383,65386,65389,65392],{},[989,65381,65382],{},"Định nghĩa: mỗi đỉnh là 1 điểm cần tìm tọa độ đẹp.",[989,65384,65385],{},"Cost đo giao cắt, cạnh lộn xộn, đỉnh dồn cục.",[989,65387,65388],{},"Gradient mách mỗi đỉnh nên dịch hướng nào đẹp lên.",[989,65390,65391],{},"Ví dụ đời thường: như gỡ rối dây tai nghe từng nút.",[989,65393,65394],{},"Đếm giao cắt thật nhưng gãy khúc, lực hướng trơn hơn.",[1099,65396,65397,65410],{},[1102,65398,65399],{},[1105,65400,65401,65404,65407],{},[1108,65402,65403],{},"Tiêu chí vẽ",[1108,65405,65406],{},"Đẹp ở đâu",[1108,65408,65409],{},"Yếu ở đâu",[1118,65411,65412,65423,65434],{},[1105,65413,65414,65417,65420],{},[1123,65415,65416],{},"Ít giao cắt",[1123,65418,65419],{},"Sơ đồ dễ đọc",[1123,65421,65422],{},"Khó đạo hàm",[1105,65424,65425,65428,65431],{},[1123,65426,65427],{},"Lực hướng",[1123,65429,65430],{},"Cụm đẹp, trơn",[1123,65432,65433],{},"Vẫn còn cắt",[1105,65435,65436,65439,65442],{},[1123,65437,65438],{},"Giữ khoảng cách",[1123,65440,65441],{},"Giống bản đồ",[1123,65443,65444],{},"Cần khoảng mong muốn",[981,65446,65448],{"id":65447},"vòng-lặp-cài-đặt","Vòng lặp cài đặt",[986,65450,65451,65454,65457,65460,65463],{},[989,65452,65453],{},"Khởi tạo đỉnh ngẫu nhiên hoặc theo vòng tròn.",[989,65455,65456],{},"Tính cost, tính gradient, dịch toàn bộ 1 bước.",[989,65458,65459],{},"Giảm bước dần, dừng khi dịch quá nhỏ.",[989,65461,65462],{},"Ví dụ đời thường: như phơi ảnh lặp tới khi nét hẳn.",[989,65464,65465],{},"Đồ thị lớn thì lấy mẫu cặp để chạy nổi.",[968,65467,1433],{"id":1432},[986,65469,65470,65473],{},[989,65471,65472],{},"Input: 1 đặc trưng lớn gấp 1000 lần kia -> Output: chuẩn hóa trước.",[989,65474,65475],{},"Giải thích: thung lũng méo làm gradient lượn vòng mãi.",[1352,65477,65479],{"className":3538,"code":65478,"language":3540,"meta":1357,"style":1357},"# Cập nhật đường hồi quy y = a*x + b\na = a - toc_do * dao_ham_a  # chỉnh độ dốc\nb = b - toc_do * dao_ham_b  # chỉnh điểm cắt\nprint(a, b)\n",[992,65480,65481,65486,65491,65496],{"__ignoreMap":1357},[1023,65482,65483],{"class":1362,"line":63},[1023,65484,65485],{},"# Cập nhật đường hồi quy y = a*x + b\n",[1023,65487,65488],{"class":1362,"line":68},[1023,65489,65490],{},"a = a - toc_do * dao_ham_a  # chỉnh độ dốc\n",[1023,65492,65493],{"class":1362,"line":73},[1023,65494,65495],{},"b = b - toc_do * dao_ham_b  # chỉnh điểm cắt\n",[1023,65497,65498],{"class":1362,"line":78},[1023,65499,65500],{},"print(a, b)\n",[968,65502,1482],{"id":1481},[973,65504,1485,65505,52181,65507,65509,65510,1517],{},[1487,65506,13531],{},[992,65508,31660],{}," (chỉ để tạo và vẽ đồ thị). Nộp vào ",[992,65511,65512],{},"day-112\u002F",[981,65514,65516],{"id":65515},"bài-1-hồi-quy-tuyến-tính-bằng-gradient-descent","Bài 1: Hồi quy tuyến tính bằng gradient descent",[1352,65518,65520],{"className":3538,"code":65519,"language":3540,"meta":1357,"style":1357},"def fit_gd(X, y, lr=0.01, epochs=1000, batch_size=None, seed=0) -> tuple[np.ndarray, list[float]]:\n    \"\"\"batch_size=None: full batch; 1: SGD; k: mini-batch. Trả (w có bias, lịch sử MSE).\"\"\"\n",[992,65521,65522,65527],{"__ignoreMap":1357},[1023,65523,65524],{"class":1362,"line":63},[1023,65525,65526],{},"def fit_gd(X, y, lr=0.01, epochs=1000, batch_size=None, seed=0) -> tuple[np.ndarray, list[float]]:\n",[1023,65528,65529],{"class":1362,"line":68},[1023,65530,65531],{},"    \"\"\"batch_size=None: full batch; 1: SGD; k: mini-batch. Trả (w có bias, lịch sử MSE).\"\"\"\n",[2273,65533,65534,65539,65545],{},[989,65535,65536,65537,1517],{},"So hệ số với công thức đóng ngày 55 trên California Housing (đã chuẩn hóa). Sai số dưới ",[992,65538,18406],{},[989,65540,65541,65542,65544],{},"Chạy lại ",[1487,65543,41587],{}," chuẩn hóa. Ghi số epoch cần thiết hoặc hiện tượng phân kỳ.",[989,65546,65547],{},"So full batch, mini-batch 32, SGD: vẽ MSE theo số lần duyệt dữ liệu.",[981,65549,65551],{"id":65550},"bài-2-vẽ-đồ-thị-bằng-lực-force-directed","Bài 2: Vẽ đồ thị bằng lực (force-directed)",[1352,65553,65555],{"className":3538,"code":65554,"language":3540,"meta":1357,"style":1357},"def layout(G, iters=500, lr=0.05, k=1.0, seed=0) -> dict[node, np.ndarray]:\n    \"\"\"Lực đẩy mọi cặp: k^2 \u002F d. Lực hút mỗi cạnh: d^2 \u002F k.\n       Mỗi vòng dịch mọi đỉnh theo tổng lực, giảm lr dần. Dừng khi dịch tối đa \u003C 1e-4.\"\"\"\n",[992,65556,65557,65562,65567],{"__ignoreMap":1357},[1023,65558,65559],{"class":1362,"line":63},[1023,65560,65561],{},"def layout(G, iters=500, lr=0.05, k=1.0, seed=0) -> dict[node, np.ndarray]:\n",[1023,65563,65564],{"class":1362,"line":68},[1023,65565,65566],{},"    \"\"\"Lực đẩy mọi cặp: k^2 \u002F d. Lực hút mỗi cạnh: d^2 \u002F k.\n",[1023,65568,65569],{"class":1362,"line":73},[1023,65570,65571],{},"       Mỗi vòng dịch mọi đỉnh theo tổng lực, giảm lr dần. Dừng khi dịch tối đa \u003C 1e-4.\"\"\"\n",[2273,65573,65574,65577,65580],{},[989,65575,65576],{},"Chạy trên lưới 6x6, cây nhị phân 31 đỉnh, và Karate Club.",[989,65578,65579],{},"Vẽ kết quả. Đếm giao cắt bằng hàm ngày 79.",[989,65581,65582],{},"Vẽ tổng năng lượng theo vòng lặp: phải giảm.",[981,65584,65586],{"id":65585},"bài-3-tăng-tốc-và-so-sánh-nâng-cao","Bài 3: Tăng tốc và so sánh (nâng cao)",[2273,65588,65589,65666,65672],{},[989,65590,65591,65592,65665],{},"Lực đẩy mọi cặp là ",[1023,65593,65595,65618],{"className":65594},[1026],[1023,65596,65598],{"className":65597},[1030],[1032,65599,65600],{"xmlns":1034},[1036,65601,65602,65616],{},[1039,65603,65604,65606,65608,65614],{},[1042,65605,1044],{},[1046,65607,1049],{"stretchy":1048},[2327,65609,65610,65612],{},[1042,65611,1262],{},[1051,65613,2457],{},[1046,65615,1056],{"stretchy":1048},[1058,65617,2839],{"encoding":1060},[1023,65619,65621],{"className":65620,"ariaHidden":1066},[1065],[1023,65622,65624,65627,65630,65633,65662],{"className":65623},[1070],[1023,65625],{"className":65626,"style":2476},[1074],[1023,65628,1044],{"className":65629,"style":1081},[1079,1080],[1023,65631,1049],{"className":65632},[1085],[1023,65634,65636,65639],{"className":65635},[1079],[1023,65637,1262],{"className":65638},[1079,1080],[1023,65640,65642],{"className":65641},[2383],[1023,65643,65645],{"className":65644},[2387],[1023,65646,65648],{"className":65647},[2391],[1023,65649,65651],{"className":65650,"style":2369},[2395],[1023,65652,65653,65656],{"style":2398},[1023,65654],{"className":65655,"style":2403},[2402],[1023,65657,65659],{"className":65658},[2407,2408,2409,2410],[1023,65660,2457],{"className":65661},[1079,2410],[1023,65663,1056],{"className":65664},[1092],". Cài xấp xỉ: chỉ tính lực đẩy với 50 đỉnh lấy mẫu ngẫu nhiên mỗi vòng, nhân hệ số bù. Chạy trên đồ thị 2000 đỉnh.",[989,65667,65668,65669,1517],{},"So thời gian và số giao cắt với bản đầy đủ và với ",[992,65670,65671],{},"networkx.spring_layout",[989,65673,65674],{},"Khởi tạo vòng tròn và khởi tạo ngẫu nhiên. So kết quả cuối.",[981,65676,2711],{"id":2710},[986,65678,65680,65686,65692,65698],{"className":65679},[2715],[989,65681,65683,65685],{"className":65682},[2719],[2721,65684],{"disabled":2723,"type":2724}," Hệ số GD khớp công thức đóng.",[989,65687,65689,65691],{"className":65688},[2719],[2721,65690],{"disabled":2723,"type":2724}," Có số liệu cho thấy không chuẩn hóa thì chậm hoặc phân kỳ.",[989,65693,65695,65697],{"className":65694},[2719],[2721,65696],{"disabled":2723,"type":2724}," Hình layout 3 đồ thị và hình năng lượng giảm dần.",[989,65699,65701,65703],{"className":65700},[2719],[2721,65702],{"disabled":2723,"type":2724}," Bảng thời gian và giao cắt Bài 3.",[968,65705,2890],{"id":2889},[986,65707,65708,65711,65714,65717],{},[989,65709,65710],{},"Hồi quy tối thiểu cái gì?",[989,65712,65713],{},"Vì sao phải chuẩn hóa?",[989,65715,65716],{},"Cost vẽ đồ thị đo gì?",[989,65718,65719],{},"Khi nào dừng vòng lặp?",[3014,65721],{},[973,65723,65724],{},"🌕 Bạn đã hoàn thành ngày 112. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,65726,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":65728},[65729,65730,65735,65736,65742],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":65731},[65732,65733,65734],{"id":65355,"depth":73,"text":65356},{"id":65376,"depth":73,"text":65377},{"id":65447,"depth":73,"text":65448},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":65737},[65738,65739,65740,65741],{"id":65515,"depth":73,"text":65516},{"id":65550,"depth":73,"text":65551},{"id":65585,"depth":73,"text":65586},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Gradient cho hồi quy, nhúng đồ thị, tiêu chí vẽ khác nhau và cài đặt lặp tối ưu vị trí đỉnh.",{},[17499],{"title":615,"description":65743},[47532,18472],"PIgZZG6Q5mzORp-TzllDTCW48GAmz2xE5O_MvhrZJQk",{"id":65750,"title":620,"body":65751,"category":8797,"day":623,"description":66193,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":66194,"navigation":2723,"outcomes":3047,"path":621,"prerequisites":66195,"seo":66196,"stem":622,"tags":66197,"__hash__":66198},"challenges\u002Fchallenges\u002F113.simulated-annealing.md",{"type":965,"value":65752,"toc":66177},[65753,65755,65758,65760,65764,65781,65785,65802,65850,65854,65871,65873,65881,65906,65908,65916,65920,65950,65963,65969,65973,66010,66014,66020,66080,66082,66154,66156,66170,66172,66175],[968,65754,971],{"id":970},[973,65756,65757],{},"Bài này học thỉnh thoảng chịu xấu để thoát đáy nông.\nDùng để tìm tour và tranh vẽ khi nhiều đáy lừa.",[968,65759,979],{"id":978},[981,65761,65763],{"id":65762},"ý-tưởng-ủ-nhiệt","Ý tưởng ủ nhiệt",[986,65765,65766,65769,65772,65775,65778],{},[989,65767,65768],{},"Định nghĩa: tốt hơn nhận ngay, xấu hơn nhận theo nhiệt.",[989,65770,65771],{},"Đầu nóng thì leo thoải mái để khám phá xa.",[989,65773,65774],{},"Cuối nguội thì chỉ đi xuống để chốt đáy sâu.",[989,65776,65777],{},"Ví dụ đời thường: như nung sắt nóng rồi nguội dần.",[989,65779,65780],{},"Đôi khi phải leo lên mới xuống được đáy thật.",[981,65782,65784],{"id":65783},"chuyển-ngắn-và-dài","Chuyển ngắn và dài",[986,65786,65787,65790,65793,65796,65799],{},[989,65788,65789],{},"Ngắn: đổi 2 thành phố kề, tinh chỉnh kỹ vùng gần.",[989,65791,65792],{},"Dài: đảo cả đoạn lớn, thoát xa nhưng dễ phá.",[989,65794,65795],{},"Ví dụ đời thường: như nhích ghế và bê cả bàn đi.",[989,65797,65798],{},"Lúc nóng dùng dài để khám, lúc nguội dùng ngắn.",[989,65800,65801],{},"Luôn ghi nghiệm tốt nhất riêng vì đường đi leo lên.",[1099,65803,65804,65815],{},[1102,65805,65806],{},[1105,65807,65808,65811,65813],{},[1108,65809,65810],{},"Cách chuyển",[1108,65812,16149],{},[1108,65814,16152],{},[1118,65816,65817,65828,65839],{},[1105,65818,65819,65822,65825],{},[1123,65820,65821],{},"Ngắn",[1123,65823,65824],{},"Giữ cấu trúc tốt",[1123,65826,65827],{},"Thoát chậm",[1105,65829,65830,65833,65836],{},[1123,65831,65832],{},"Dài",[1123,65834,65835],{},"Thoát đáy nhanh",[1123,65837,65838],{},"Dễ phá tour đẹp",[1105,65840,65841,65844,65847],{},[1123,65842,65843],{},"Trộn cả 2",[1123,65845,65846],{},"Khám rồi chốt",[1123,65848,65849],{},"Phải chỉnh lịch",[981,65851,65853],{"id":65852},"so-với-gradient","So với gradient",[986,65855,65856,65859,65862,65865,65868],{},[989,65857,65858],{},"Gradient cần trơn có đạo hàm, đi tham nên nhanh.",[989,65860,65861],{},"Ủ nhiệt không cần đạo hàm, đi được rời rạc.",[989,65863,65864],{},"Ví dụ đời thường: như xe đua và xe địa hình leo đồi.",[989,65866,65867],{},"Gradient kẹt đáy gần, ủ nhiệt thoát tốt hơn.",[989,65869,65870],{},"Thực tế ủ tìm vùng rồi giao leo đồi chốt.",[968,65872,1433],{"id":1432},[986,65874,65875,65878],{},[989,65876,65877],{},"Input: nguội ngay từ đầu và kẹt đáy đầu -> Output: tăng nhiệt đầu.",[989,65879,65880],{},"Giải thích: thiếu thăm dò nên giống leo tham thuần túy.",[1352,65882,65884],{"className":3538,"code":65883,"language":3540,"meta":1357,"style":1357},"# Nhận nghiệm xấu theo nhiệt độ\nif tot_hon or random() \u003C exp(-(xau - tot) \u002F T):\n    hien_tai = moi  # thỉnh thoảng leo lên\nT *= 0.95  # nguội dần\n",[992,65885,65886,65891,65896,65901],{"__ignoreMap":1357},[1023,65887,65888],{"class":1362,"line":63},[1023,65889,65890],{},"# Nhận nghiệm xấu theo nhiệt độ\n",[1023,65892,65893],{"class":1362,"line":68},[1023,65894,65895],{},"if tot_hon or random() \u003C exp(-(xau - tot) \u002F T):\n",[1023,65897,65898],{"class":1362,"line":73},[1023,65899,65900],{},"    hien_tai = moi  # thỉnh thoảng leo lên\n",[1023,65902,65903],{"class":1362,"line":78},[1023,65904,65905],{},"T *= 0.95  # nguội dần\n",[968,65907,1482],{"id":1481},[973,65909,1485,65910,65912,65913,1517],{},[1487,65911,13531],{}," (hoặc C++). Nộp vào ",[992,65914,65915],{},"day-113\u002F",[981,65917,65919],{"id":65918},"bài-1-khung-simulated-annealing-tổng-quát","Bài 1: Khung simulated annealing tổng quát",[1352,65921,65923],{"className":3538,"code":65922,"language":3540,"meta":1357,"style":1357},"def anneal(init, cost, neighbor, T0: float, alpha: float, steps_per_T: int, T_min: float,\n           seed=0) -> tuple[object, float, list[tuple[float, float, float]]]:\n    \"\"\"Nhận nghiệm mới nếu tốt hơn, hoặc với xác suất exp(-(delta) \u002F T).\n       Giữ riêng nghiệm tốt nhất. Làm nguội T *= alpha.\n       Trả (best, best_cost, lịch sử (T, current_cost, best_cost)).\"\"\"\n",[992,65924,65925,65930,65935,65940,65945],{"__ignoreMap":1357},[1023,65926,65927],{"class":1362,"line":63},[1023,65928,65929],{},"def anneal(init, cost, neighbor, T0: float, alpha: float, steps_per_T: int, T_min: float,\n",[1023,65931,65932],{"class":1362,"line":68},[1023,65933,65934],{},"           seed=0) -> tuple[object, float, list[tuple[float, float, float]]]:\n",[1023,65936,65937],{"class":1362,"line":73},[1023,65938,65939],{},"    \"\"\"Nhận nghiệm mới nếu tốt hơn, hoặc với xác suất exp(-(delta) \u002F T).\n",[1023,65941,65942],{"class":1362,"line":78},[1023,65943,65944],{},"       Giữ riêng nghiệm tốt nhất. Làm nguội T *= alpha.\n",[1023,65946,65947],{"class":1362,"line":83},[1023,65948,65949],{},"       Trả (best, best_cost, lịch sử (T, current_cost, best_cost)).\"\"\"\n",[973,65951,65952,65953,2528,65956,65959,65960,1517],{},"Thử trên hàm 1 biến nhiều đáy ",[992,65954,65955],{},"f(x) = x^2 + 10 sin(3x)",[992,65957,65958],{},"[-10, 10]",", láng giềng là ",[992,65961,65962],{},"x + N(0, 1)",[1352,65964,65967],{"className":65965,"code":65966,"language":2241,"meta":1357},[2239],"Hill climbing (T0 = 0) từ x = 8 -> kẹt đáy địa phương\nSA với T0 = 50 từ x = 8          -> tìm đáy toàn cục (so với quét lưới 10^6 điểm)\n",[992,65968,65966],{"__ignoreMap":1357},[981,65970,65972],{"id":65971},"bài-2-lịch-nhiệt-độ","Bài 2: Lịch nhiệt độ",[2273,65974,65975,65989,65992,66001],{},[989,65976,65977,65978,65981,65982,65985,65986,1517],{},"So 3 lịch nguội: hình học ",[992,65979,65980],{},"T *= alpha",", tuyến tính ",[992,65983,65984],{},"T -= c",", logarit ",[992,65987,65988],{},"T0 \u002F log(1 + k)",[989,65990,65991],{},"Chạy mỗi lịch 50 lần. In cost tốt nhất trung bình và độ lệch chuẩn.",[989,65993,35212,65994,1509,65997,66000],{},[992,65995,65996],{},"current_cost",[992,65998,65999],{},"best_cost"," theo bước cho 1 lần chạy. Chỉ ra đoạn leo lên.",[989,66002,53934,66003,66006,66007,66009],{},[992,66004,66005],{},"T0"," bằng cách lấy mẫu 100 bước ngẫu nhiên và đặt ",[992,66008,66005],{}," sao cho xác suất nhận bước xấu trung bình là 0.8.",[981,66011,66013],{"id":66012},"bài-3-bài-toán-rời-rạc-nâng-cao","Bài 3: Bài toán rời rạc (nâng cao)",[973,66015,66016,66019],{},[1487,66017,66018],{},"Bài toán xếp N quân hậu"," (N = 50): nghiệm là hoán vị, cost là số cặp hậu ăn nhau theo đường chéo.",[2273,66021,66022,66025,66074],{},[989,66023,66024],{},"Láng giềng: đổi chỗ 2 cột.",[989,66026,39487,66027,2528,66030,66073],{},[992,66028,66029],{},"delta",[1023,66031,66033,66052],{"className":66032},[1026],[1023,66034,66036],{"className":66035},[1030],[1032,66037,66038],{"xmlns":1034},[1036,66039,66040,66050],{},[1039,66041,66042,66044,66046,66048],{},[1042,66043,1044],{},[1046,66045,1049],{"stretchy":1048},[1051,66047,1053],{},[1046,66049,1056],{"stretchy":1048},[1058,66051,1061],{"encoding":1060},[1023,66053,66055],{"className":66054,"ariaHidden":1066},[1065],[1023,66056,66058,66061,66064,66067,66070],{"className":66057},[1070],[1023,66059],{"className":66060,"style":1075},[1074],[1023,66062,1044],{"className":66063,"style":1081},[1079,1080],[1023,66065,1049],{"className":66066},[1085],[1023,66068,1053],{"className":66069},[1079],[1023,66071,1056],{"className":66072},[1092]," nhờ đếm số hậu trên mỗi đường chéo, không tính lại toàn bộ.",[989,66075,66076,66077,1517],{},"In số bước tới cost 0 cho ",[992,66078,66079],{},"N = 50, 100, 500",[981,66081,2711],{"id":2710},[986,66083,66085,66091,66097,66148],{"className":66084},[2715],[989,66086,66088,66090],{"className":66087},[2719],[2721,66089],{"disabled":2723,"type":2724}," SA thoát đáy địa phương mà hill climbing kẹt.",[989,66092,66094,66096],{"className":66093},[2719],[2721,66095],{"disabled":2723,"type":2724}," Bảng 3 lịch nguội có số thật và hình quỹ đạo cost.",[989,66098,66100,66102,66103,2308,66105,1517],{"className":66099},[2719],[2721,66101],{"disabled":2723,"type":2724}," N-queens N = 500 giải được, ",[992,66104,66029],{},[1023,66106,66108,66127],{"className":66107},[1026],[1023,66109,66111],{"className":66110},[1030],[1032,66112,66113],{"xmlns":1034},[1036,66114,66115,66125],{},[1039,66116,66117,66119,66121,66123],{},[1042,66118,1044],{},[1046,66120,1049],{"stretchy":1048},[1051,66122,1053],{},[1046,66124,1056],{"stretchy":1048},[1058,66126,1061],{"encoding":1060},[1023,66128,66130],{"className":66129,"ariaHidden":1066},[1065],[1023,66131,66133,66136,66139,66142,66145],{"className":66132},[1070],[1023,66134],{"className":66135,"style":1075},[1074],[1023,66137,1044],{"className":66138,"style":1081},[1079,1080],[1023,66140,1049],{"className":66141},[1085],[1023,66143,1053],{"className":66144},[1079],[1023,66146,1056],{"className":66147},[1092],[989,66149,66151,66153],{"className":66150},[2719],[2721,66152],{"disabled":2723,"type":2724}," Giải thích được vì sao phải leo lên mới xuống được đáy sâu.",[968,66155,2890],{"id":2889},[986,66157,66158,66161,66164,66167],{},[989,66159,66160],{},"Nhiệt cao thì nhận xấu thế nào?",[989,66162,66163],{},"Chuyển ngắn khác dài sao?",[989,66165,66166],{},"Vì sao ghi tốt nhất riêng?",[989,66168,66169],{},"Ủ hơn gradient ở đâu?",[3014,66171],{},[973,66173,66174],{},"🌕 Bạn đã hoàn thành ngày 113. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,66176,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":66178},[66179,66180,66185,66186,66192],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":66181},[66182,66183,66184],{"id":65762,"depth":73,"text":65763},{"id":65783,"depth":73,"text":65784},{"id":65852,"depth":73,"text":65853},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":66187},[66188,66189,66190,66191],{"id":65918,"depth":73,"text":65919},{"id":65971,"depth":73,"text":65972},{"id":66012,"depth":73,"text":66013},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Ủ nhiệt mô phỏng, chấp nhận nghiệm xấu có kiểm soát, chuyển ngắn dài, biến thể và so với gradient descent.",{},[18469,15144],{"title":620,"description":66193},[47532],"_AgTEG1KHSYdcVjAsvAaVb4qwrapKJc1-ACrnmYOW7U",{"id":66200,"title":625,"body":66201,"category":8797,"day":628,"description":66539,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":66540,"navigation":2723,"outcomes":3047,"path":626,"prerequisites":66541,"seo":66542,"stem":627,"tags":66543,"__hash__":66544},"challenges\u002Fchallenges\u002F114.sa-tsp.md",{"type":965,"value":66202,"toc":66523},[66203,66205,66208,66210,66214,66231,66235,66252,66301,66305,66322,66324,66332,66357,66359,66367,66371,66386,66403,66409,66413,66434,66440,66443,66447,66469,66471,66500,66502,66516,66518,66521],[968,66204,971],{"id":970},[973,66206,66207],{},"Bài này học tìm tour ngắn thăm mọi thành phố.\nDùng để giao hàng, khoan mạch và xếp lịch chạy.",[968,66209,979],{"id":978},[981,66211,66213],{"id":66212},"tsp-đúng-và-xấp-xỉ","TSP đúng và xấp xỉ",[986,66215,66216,66219,66222,66225,66228],{},[989,66217,66218],{},"Định nghĩa: thăm mỗi thành phố 1 lần rồi về chỗ cũ.",[989,66220,66221],{},"Vét cạn chỉ nổi tới khoảng 10-12 thành phố, quy hoạch động Held-Karp tới khoảng 25.",[989,66223,66224],{},"Xấp xỉ gồm tham lam, 2-opt, ủ nhiệt, di truyền.",[989,66226,66227],{},"Ví dụ đời thường: như shipper tìm vòng giao nhanh nhất.",[989,66229,66230],{},"Tour đẹp gọn ít cắt, tour xấu nhiều chéo đan nhau.",[981,66232,66234],{"id":66233},"_2-opt-gỡ-rối","2-opt gỡ rối",[986,66236,66237,66240,66243,66246,66249],{},[989,66238,66239],{},"Định nghĩa: cắt 2 cạnh chéo rồi nối chéo lại hết cắt.",[989,66241,66242],{},"Tour ngắn ngay mà không tính lại toàn bộ đường.",[989,66244,66245],{},"Lặp tới khi hết cặp cải thiện thì dừng lại.",[989,66247,66248],{},"Ví dụ đời thường: như gỡ 2 dây đan bằng cách đổi đầu.",[989,66250,66251],{},"Giữ danh sách cạnh gần để chạy nổi trăm thành phố.",[1099,66253,66254,66266],{},[1102,66255,66256],{},[1105,66257,66258,66261,66264],{},[1108,66259,66260],{},"Cách đổi",[1108,66262,66263],{},"Độ nhảy",[1108,66265,62129],{},[1118,66267,66268,66279,66290],{},[1105,66269,66270,66273,66276],{},[1123,66271,66272],{},"Đổi kề",[1123,66274,66275],{},"Nhỏ, tinh chỉnh",[1123,66277,66278],{},"Lúc nguội cuối",[1105,66280,66281,66284,66287],{},[1123,66282,66283],{},"Đảo đoạn",[1123,66285,66286],{},"Lớn, thoát nhanh",[1123,66288,66289],{},"Lúc nóng đầu",[1105,66291,66292,66295,66298],{},[1123,66293,66294],{},"2-opt",[1123,66296,66297],{},"Gỡ chéo trực tiếp",[1123,66299,66300],{},"Mọi giai đoạn",[981,66302,66304],{"id":66303},"tỉa-miền","Tỉa miền",[986,66306,66307,66310,66313,66316,66319],{},[989,66308,66309],{},"Định nghĩa: dùng tri thức cắt bớt không gian tìm kiếm.",[989,66311,66312],{},"Gom điểm theo quận rồi giải từng cụm nhỏ trước.",[989,66314,66315],{},"Cấm cạnh quá dài vượt ngưỡng cho phép.",[989,66317,66318],{},"Ví dụ đời thường: như chia quận giao rồi mới nối liên quận.",[989,66320,66321],{},"Giảm chục lần số tour mà hiếm mất nghiệm tốt.",[968,66323,1433],{"id":1432},[986,66325,66326,66329],{},[989,66327,66328],{},"Input: tour có 2 cạnh chéo nhau -> Output: 2-opt nối lại ngắn hơn.",[989,66330,66331],{},"Giải thích: hết cắt chéo là tổng đường giảm ngay.",[1352,66333,66335],{"className":3538,"code":66334,"language":3540,"meta":1357,"style":1357},"# Thử 2-opt trên 1 cặp cạnh\nif dai(a, c) + dai(b, d) \u003C dai(a, b) + dai(c, d):\n    tour = noi_lai(tour, i, j)  # gỡ chéo, giữ ngắn\nprint(do_dai(tour))\n",[992,66336,66337,66342,66347,66352],{"__ignoreMap":1357},[1023,66338,66339],{"class":1362,"line":63},[1023,66340,66341],{},"# Thử 2-opt trên 1 cặp cạnh\n",[1023,66343,66344],{"class":1362,"line":68},[1023,66345,66346],{},"if dai(a, c) + dai(b, d) \u003C dai(a, b) + dai(c, d):\n",[1023,66348,66349],{"class":1362,"line":73},[1023,66350,66351],{},"    tour = noi_lai(tour, i, j)  # gỡ chéo, giữ ngắn\n",[1023,66353,66354],{"class":1362,"line":78},[1023,66355,66356],{},"print(do_dai(tour))\n",[968,66358,1482],{"id":1481},[973,66360,1485,66361,66363,66364,1517],{},[1487,66362,1493],{}," (khuyến nghị vì nhiều vòng lặp) hoặc Python có Numba. Dùng lại code ngày 16, 78. Nộp vào ",[992,66365,66366],{},"day-114\u002F",[981,66368,66370],{"id":66369},"bài-1-2-opt-nhanh","Bài 1: 2-opt nhanh",[1352,66372,66374],{"className":1393,"code":66373,"language":1395,"meta":1357,"style":1357},"double twoOptDelta(const std::vector\u003Cint> &tour, int i, int j, const Matrix &d);   \u002F\u002F O(1)\nvoid   apply2Opt(std::vector\u003Cint> &tour, int i, int j);                             \u002F\u002F đảo đoạn i+1..j\n",[992,66375,66376,66381],{"__ignoreMap":1357},[1023,66377,66378],{"class":1362,"line":63},[1023,66379,66380],{},"double twoOptDelta(const std::vector\u003Cint> &tour, int i, int j, const Matrix &d);   \u002F\u002F O(1)\n",[1023,66382,66383],{"class":1362,"line":68},[1023,66384,66385],{},"void   apply2Opt(std::vector\u003Cint> &tour, int i, int j);                             \u002F\u002F đảo đoạn i+1..j\n",[973,66387,66388,7386,66391,1656,66394,1656,66397,1656,66400,1517],{},[992,66389,66390],{},"delta = d(a,c) + d(b,d) - d(a,b) - d(c,d)",[992,66392,66393],{},"a = tour[i]",[992,66395,66396],{},"b = tour[i+1]",[992,66398,66399],{},"c = tour[j]",[992,66401,66402],{},"d = tour[j+1]",[1352,66404,66407],{"className":66405,"code":66406,"language":2241,"meta":1357},[2239],"Tour có 2 cạnh chéo nhau -> delta \u003C 0, sau apply2Opt hết chéo\nTest: delta tính O(1) bằng tourLength(sau) - tourLength(trước) trên 1000 cặp ngẫu nhiên\n",[992,66408,66406],{"__ignoreMap":1357},[981,66410,66412],{"id":66411},"bài-2-sa-cho-tsp","Bài 2: SA cho TSP",[2273,66414,66415,66424,66427],{},[989,66416,66417,66418,48427,66421,1517],{},"Láng giềng: chọn ngẫu nhiên ",[992,66419,66420],{},"(i, j)",[992,66422,66423],{},"twoOptDelta",[989,66425,66426],{},"Lịch nhiệt hình học. Khởi tạo bằng tham lam.",[989,66428,66429,66430,66433],{},"Chạy trên bộ ",[1487,66431,66432],{},"berlin52"," (TSPLIB, tối ưu đã biết = 7542) và 1 bộ 200 điểm ngẫu nhiên.",[1352,66435,66438],{"className":66436,"code":66437,"language":2241,"meta":1357},[2239],"bộ            greedy    greedy+2opt    SA       tối_ưu\nberlin52      ...       ...            ...      7542\nrandom200     ...       ...            ...      (không biết)\n",[992,66439,66437],{"__ignoreMap":1357},[973,66441,66442],{},"Vẽ tour tốt nhất của SA trên berlin52.",[981,66444,66446],{"id":66445},"bài-3-tỉa-cành-bằng-danh-sách-láng-giềng-nâng-cao","Bài 3: Tỉa cành bằng danh sách láng giềng (nâng cao)",[2273,66448,66449,66452,66460,66463],{},[989,66450,66451],{},"Với mỗi thành phố, giữ 10 thành phố gần nhất (dùng k-d tree ngày 69).",[989,66453,66454,66455,66457,66458,1517],{},"Chỉ thử 2-opt với ",[992,66456,1356],{}," nằm trong danh sách láng giềng của ",[992,66459,6207],{},[989,66461,66462],{},"Chạy trên 2000 điểm ngẫu nhiên. So thời gian và độ dài tour với bản không tỉa.",[989,66464,5030,66465,66468],{},[1487,66466,66467],{},"Or-opt"," (dời 1-3 thành phố liên tiếp sang chỗ khác). So kết quả.",[981,66470,2711],{"id":2710},[986,66472,66474,66482,66488,66494],{"className":66473},[2715],[989,66475,66477,2308,66479,66481],{"className":66476},[2719],[2721,66478],{"disabled":2723,"type":2724},[992,66480,66423],{}," khớp tính lại toàn bộ trên 1000 cặp.",[989,66483,66485,66487],{"className":66484},[2719],[2721,66486],{"disabled":2723,"type":2724}," SA trên berlin52 trong vòng 5% tối ưu.",[989,66489,66491,66493],{"className":66490},[2719],[2721,66492],{"disabled":2723,"type":2724}," Bảng so sánh có số thật và hình tour.",[989,66495,66497,66499],{"className":66496},[2719],[2721,66498],{"disabled":2723,"type":2724}," Bài 3 cho thấy tỉa cành nhanh hơn rõ mà tour gần như không dài hơn.",[968,66501,2890],{"id":2889},[986,66503,66504,66507,66510,66513],{},[989,66505,66506],{},"TSP cần tìm gì?",[989,66508,66509],{},"2-opt gỡ cái gì?",[989,66511,66512],{},"Đổi kề khác đảo đoạn sao?",[989,66514,66515],{},"Tỉa miền để làm gì?",[3014,66517],{},[973,66519,66520],{},"🌕 Bạn đã hoàn thành ngày 114. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,66522,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":66524},[66525,66526,66531,66532,66538],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":66527},[66528,66529,66530],{"id":66212,"depth":73,"text":66213},{"id":66233,"depth":73,"text":66234},{"id":66303,"depth":73,"text":66304},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":66533},[66534,66535,66536,66537],{"id":66369,"depth":73,"text":66370},{"id":66411,"depth":73,"text":66412},{"id":66445,"depth":73,"text":66446},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"TSP nghiệm đúng và xấp xỉ, trực quan chi phí, tỉa miền, chuyển trạng thái và so kề đổi ngẫu nhiên.",{},[15143],{"title":625,"description":66539},[47532,48823],"G4U1i3kBH9eoEpc9klF-ruXK7UDwcswBy6ymutm4nOU",{"id":66546,"title":630,"body":66547,"category":8797,"day":633,"description":66925,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":66926,"navigation":2723,"outcomes":3047,"path":631,"prerequisites":66927,"seo":66928,"stem":632,"tags":66929,"__hash__":66931},"challenges\u002Fchallenges\u002F115.genetic-co-ban.md",{"type":965,"value":66548,"toc":66909},[66549,66551,66554,66556,66560,66577,66581,66598,66646,66650,66667,66669,66677,66702,66704,66712,66716,66736,66794,66800,66804,66807,66832,66836,66851,66857,66859,66886,66888,66902,66904,66907],[968,66550,971],{"id":970},[973,66552,66553],{},"Bài này học nuôi đàn lời giải tiến hóa qua từng đời.\nDùng để tìm tour và lịch khi hàm gãy khúc.",[968,66555,979],{"id":978},[981,66557,66559],{"id":66558},"mã-hóa-và-fitness","Mã hóa và fitness",[986,66561,66562,66565,66568,66571,66574],{},[989,66563,66564],{},"Định nghĩa: chromosome là chuỗi gen tả 1 lời giải.",[989,66566,66567],{},"Tour TSP là hoán vị thành phố trên chuỗi gen.",[989,66569,66570],{},"Fitness là điểm khỏe, tour ngắn thì điểm cao.",[989,66572,66573],{},"Ví dụ đời thường: như điểm thi quyết ai được chọn.",[989,66575,66576],{},"Phạt nặng gen vi phạm ràng buộc bài toán.",[981,66578,66580],{"id":66579},"chọn-lọc","Chọn lọc",[986,66582,66583,66586,66589,66592,66595],{},[989,66584,66585],{},"Giữ khỏe bỏ yếu qua nhiều thế hệ liên tiếp.",[989,66587,66588],{},"Bánh xe: theo tỉ lệ fitness nhưng dễ lấn át sớm.",[989,66590,66591],{},"Giải đấu: lấy tốt nhất nhóm ngẫu nhiên ổn định hơn.",[989,66593,66594],{},"Ví dụ đời thường: như chọn đội tuyển qua vòng loại nhỏ.",[989,66596,66597],{},"Giữ tinh hoa vài cá thể tốt sang thẳng đời sau.",[1099,66599,66600,66611],{},[1102,66601,66602],{},[1105,66603,66604,66607,66609],{},[1108,66605,66606],{},"Cách chọn",[1108,66608,16149],{},[1108,66610,16152],{},[1118,66612,66613,66624,66635],{},[1105,66614,66615,66618,66621],{},[1123,66616,66617],{},"Bánh xe",[1123,66619,66620],{},"Đơn giản, nhanh",[1123,66622,66623],{},"Siêu cá thể lấn át",[1105,66625,66626,66629,66632],{},[1123,66627,66628],{},"Giải đấu",[1123,66630,66631],{},"Ổn định, dễ chỉnh",[1123,66633,66634],{},"Chậm hơn một chút",[1105,66636,66637,66640,66643],{},[1123,66638,66639],{},"Xếp hạng",[1123,66641,66642],{},"Chặn lấn át tốt",[1123,66644,66645],{},"Phải sắp hạng cả đàn",[981,66647,66649],{"id":66648},"vòng-đời-thuật-toán","Vòng đời thuật toán",[986,66651,66652,66655,66658,66661,66664],{},[989,66653,66654],{},"Khởi tạo đàn ngẫu nhiên cộng vài mẹo tốt sẵn.",[989,66656,66657],{},"Đánh giá fitness cả đàn mỗi thế hệ mới.",[989,66659,66660],{},"Chọn, lai, đột biến, thay thế rồi lặp lại.",[989,66662,66663],{},"Ví dụ đời thường: như lai giống cây qua nhiều vụ.",[989,66665,66666],{},"Theo dõi tốt nhất để phát hiện hội tụ sớm.",[968,66668,1433],{"id":1432},[986,66670,66671,66674],{},[989,66672,66673],{},"Input: đàn 10 con cho TSP 200 -> Output: tăng đàn và giảm ép.",[989,66675,66676],{},"Giải thích: đàn bé thiếu đa dạng nên kẹt tour xấu sớm.",[1352,66678,66680],{"className":3538,"code":66679,"language":3540,"meta":1357,"style":1357},"# Giải đấu chọn bố mẹ từ nhóm ngẫu nhiên\nnhom = random.sample(dan, k=3)  # bốc 3 con\nbo_me = max(nhom, key=fitness)  # giữ con khỏe nhất\nprint(bo_me)\n",[992,66681,66682,66687,66692,66697],{"__ignoreMap":1357},[1023,66683,66684],{"class":1362,"line":63},[1023,66685,66686],{},"# Giải đấu chọn bố mẹ từ nhóm ngẫu nhiên\n",[1023,66688,66689],{"class":1362,"line":68},[1023,66690,66691],{},"nhom = random.sample(dan, k=3)  # bốc 3 con\n",[1023,66693,66694],{"class":1362,"line":73},[1023,66695,66696],{},"bo_me = max(nhom, key=fitness)  # giữ con khỏe nhất\n",[1023,66698,66699],{"class":1362,"line":78},[1023,66700,66701],{},"print(bo_me)\n",[968,66703,1482],{"id":1481},[973,66705,1485,66706,66708,66709,1517],{},[1487,66707,13531],{}," với NumPy. Nộp vào ",[992,66710,66711],{},"day-115\u002F",[981,66713,66715],{"id":66714},"bài-1-ga-cho-bài-toán-onemax-và-ba-lô","Bài 1: GA cho bài toán OneMax và ba lô",[1352,66717,66719],{"className":3538,"code":66718,"language":3540,"meta":1357,"style":1357},"def ga(pop_size, n_genes, fitness, init, select, crossover, mutate,\n       generations, elite=2, seed=0) -> tuple[object, float, list[tuple[float, float]]]:\n    \"\"\"Trả (tốt nhất, fitness tốt nhất, lịch sử (best, trung bình) mỗi thế hệ).\"\"\"\n",[992,66720,66721,66726,66731],{"__ignoreMap":1357},[1023,66722,66723],{"class":1362,"line":63},[1023,66724,66725],{},"def ga(pop_size, n_genes, fitness, init, select, crossover, mutate,\n",[1023,66727,66728],{"class":1362,"line":68},[1023,66729,66730],{},"       generations, elite=2, seed=0) -> tuple[object, float, list[tuple[float, float]]]:\n",[1023,66732,66733],{"class":1362,"line":73},[1023,66734,66735],{},"    \"\"\"Trả (tốt nhất, fitness tốt nhất, lịch sử (best, trung bình) mỗi thế hệ).\"\"\"\n",[1099,66737,66738,66747],{},[1102,66739,66740],{},[1105,66741,66742,66745],{},[1108,66743,66744],{},"Toán tử",[1108,66746,2547],{},[1118,66748,66749,66762,66772,66782],{},[1105,66750,66751,66756],{},[1123,66752,66753],{},[992,66754,66755],{},"tournament(pop, fit, k=3)",[1123,66757,66758,66759,66761],{},"Chọn tốt nhất trong ",[992,66760,4022],{}," cá thể ngẫu nhiên",[1105,66763,66764,66769],{},[1123,66765,66766],{},[992,66767,66768],{},"roulette(pop, fit)",[1123,66770,66771],{},"Xác suất tỉ lệ fitness",[1105,66773,66774,66779],{},[1123,66775,66776],{},[992,66777,66778],{},"one_point_crossover(a, b)",[1123,66780,66781],{},"Cho chuỗi bit",[1105,66783,66784,66789],{},[1123,66785,66786],{},[992,66787,66788],{},"bit_flip(x, p)",[1123,66790,66791,66792],{},"Lật mỗi bit với xác suất ",[992,66793,973],{},[1352,66795,66798],{"className":66796,"code":66797,"language":2241,"meta":1357},[2239],"OneMax 100 bit (fitness = số bit 1) -> đạt 100 trong dưới 200 thế hệ\nBa lô 0-1 (dữ liệu ngày 77) -> khớp nghiệm DP; nghiệm quá tải bị phạt fitness\n",[992,66799,66797],{"__ignoreMap":1357},[981,66801,66803],{"id":66802},"bài-2-tham-số-và-áp-lực-chọn","Bài 2: Tham số và áp lực chọn",[973,66805,66806],{},"Trên OneMax 200 bit:",[2273,66808,66809,66821,66827],{},[989,66810,49241,66811,1656,66814,1656,66817,66820],{},[992,66812,66813],{},"tournament(k=2)",[992,66815,66816],{},"tournament(k=7)",[992,66818,66819],{},"roulette",". Vẽ fitness tốt nhất và trung bình theo thế hệ.",[989,66822,37875,66823,66826],{},[992,66824,66825],{},"elite = 0, 2, 10",". Chỉ ra khi nào hội tụ sớm.",[989,66828,28501,66829,66831],{},[1487,66830,39499],{},": khoảng cách Hamming trung bình giữa các cá thể theo thế hệ.",[981,66833,66835],{"id":66834},"bài-3-ga-cho-tsp-nâng-cao","Bài 3: GA cho TSP (nâng cao)",[2273,66837,66838,66845,66848],{},[989,66839,66840,66841,66844],{},"Nhiễm sắc thể là hoán vị. Lai bằng ",[1487,66842,66843],{},"Order Crossover (OX)",". Đột biến bằng đảo đoạn (như 2-opt).",[989,66846,66847],{},"Chạy trên berlin52. So với SA ngày 114 cùng số lần tính fitness.",[989,66849,66850],{},"Khởi tạo 10% đàn bằng tham lam từ các điểm xuất phát khác nhau. So tốc độ hội tụ.",[1352,66852,66855],{"className":66853,"code":66854,"language":2241,"meta":1357},[2239],"OX của cha [1,2,3,4,5,6,7,8] và mẹ [8,6,4,2,7,5,3,1] với đoạn cắt [3..5]\n-> con giữ 4,5,6 ở vị trí 3..5, các vị trí còn lại điền theo thứ tự của mẹ, không trùng\n",[992,66856,66854],{"__ignoreMap":1357},[981,66858,2711],{"id":2710},[986,66860,66862,66868,66874,66880],{"className":66861},[2715],[989,66863,66865,66867],{"className":66864},[2719],[2721,66866],{"disabled":2723,"type":2724}," OneMax đạt tối ưu, ba lô khớp DP.",[989,66869,66871,66873],{"className":66870},[2719],[2721,66872],{"disabled":2723,"type":2724}," Hình fitness và độ đa dạng theo thế hệ cho các cấu hình.",[989,66875,66877,66879],{"className":66876},[2719],[2721,66878],{"disabled":2723,"type":2724}," OX luôn ra hoán vị hợp lệ (test 10.000 lần).",[989,66881,66883,66885],{"className":66882},[2719],[2721,66884],{"disabled":2723,"type":2724}," Bảng GA vs SA trên berlin52.",[968,66887,2890],{"id":2889},[986,66889,66890,66893,66896,66899],{},[989,66891,66892],{},"Chromosome là gì?",[989,66894,66895],{},"Fitness để làm gì?",[989,66897,66898],{},"Giải đấu khác bánh xe sao?",[989,66900,66901],{},"Lai và đột biến làm gì?",[3014,66903],{},[973,66905,66906],{},"🌕 Bạn đã hoàn thành ngày 115. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,66908,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":66910},[66911,66912,66917,66918,66924],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":66913},[66914,66915,66916],{"id":66558,"depth":73,"text":66559},{"id":66579,"depth":73,"text":66580},{"id":66648,"depth":73,"text":66649},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":66919},[66920,66921,66922,66923],{"id":66714,"depth":73,"text":66715},{"id":66802,"depth":73,"text":66803},{"id":66834,"depth":73,"text":66835},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cảm hứng tự nhiên, quần thể nhiễm sắc thể, fitness chọn lọc và khuôn mẫu thuật toán di truyền.",{},[18469],{"title":630,"description":66925},[66930],"genetic","KNIg_JJU0XWgRz_5TL87B4ZMYsIQ79BKWiVwnNp5oHo",{"id":66933,"title":635,"body":66934,"category":5189,"day":638,"description":67345,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":67346,"navigation":2723,"outcomes":3047,"path":636,"prerequisites":67347,"seo":67348,"stem":637,"tags":67349,"__hash__":67350},"challenges\u002Fchallenges\u002F116.project-simuduck.md",{"type":965,"value":66935,"toc":67329},[66936,66938,66941,66943,66947,66964,66968,66985,67033,67037,67054,67056,67064,67084,67086,67094,67098,67103,67149,67156,67160,67165,67235,67241,67245,67250,67267,67269,67306,67308,67322,67324,67327],[968,66937,971],{"id":970},[973,66939,66940],{},"Bài này refactor đàn vịt kế thừa cứng sang ủy thác.\nDùng để đổi cánh tên lửa lúc chạy không vỡ code.",[968,66942,979],{"id":978},[981,66944,66946],{"id":66945},"mùi-code-cũ","Mùi code cũ",[986,66948,66949,66952,66955,66958,66961],{},[989,66950,66951],{},"Lớp cha ôm bay kêu bơi hiển thị tất cả.",[989,66953,66954],{},"Vịt cao su kế thừa nên biết bay sai bét.",[989,66956,66957],{},"Logic bay lặp lại ở nhiều lớp con khác.",[989,66959,66960],{},"Ví dụ đời thường: như 1 remote điều khiển cả nhà sai.",[989,66962,66963],{},"Thêm vịt mới là phải mở lớp cũ ra vá.",[981,66965,66967],{"id":66966},"strategy-tách-bay-kêu","Strategy tách bay kêu",[986,66969,66970,66973,66976,66979,66982],{},[989,66971,66972],{},"Tách họ bay: cánh, không bay, tên lửa riêng.",[989,66974,66975],{},"Tách họ kêu: quạc, chíp, im lặng riêng biệt.",[989,66977,66978],{},"Vịt chỉ giữ 2 tham chiếu rồi ủy thác việc.",[989,66980,66981],{},"Ví dụ đời thường: như thay pin thay lưỡi dao rời.",[989,66983,66984],{},"Đổi hành vi lúc chạy mà vịt khác không ảnh hưởng.",[1099,66986,66987,66999],{},[1102,66988,66989],{},[1105,66990,66991,66993,66996],{},[1108,66992,61474],{},[1108,66994,66995],{},"Code cũ",[1108,66997,66998],{},"Code mới",[1118,67000,67001,67011,67022],{},[1105,67002,67003,67006,67009],{},[1123,67004,67005],{},"Thêm vịt",[1123,67007,67008],{},"Sửa lớp cha",[1123,67010,46732],{},[1105,67012,67013,67016,67019],{},[1123,67014,67015],{},"Đổi bay",[1123,67017,67018],{},"Ghi đè vá víu",[1123,67020,67021],{},"Gán hành vi mới",[1105,67023,67024,67027,67030],{},[1123,67025,67026],{},"Đếm kêu",[1123,67028,67029],{},"Đếm tay thủ công",[1123,67031,67032],{},"Observer báo tự động",[981,67034,67036],{"id":67035},"observer-đếm-báo","Observer đếm báo",[986,67038,67039,67042,67045,67048,67051],{},[989,67040,67041],{},"Mỗi vịt là 1 chủ đề nhỏ phát tin kêu.",[989,67043,67044],{},"Bảng đếm và nhà nghiên cứu đăng ký nghe tin.",[989,67046,67047],{},"Mỗi tiếng kêu là 1 tin báo tự động gửi.",[989,67049,67050],{},"Ví dụ đời thường: như follow vịt là nhận tiếng kêu.",[989,67052,67053],{},"Bảng mới chỉ cần đăng ký, không sửa vịt.",[968,67055,1433],{"id":1432},[986,67057,67058,67061],{},[989,67059,67060],{},"Input: vịt mồi đang chạy xin cánh tên lửa -> Output: chỉ nó bay đổi.",[989,67062,67063],{},"Giải thích: ủy thác nên gán lại 1 tham chiếu là xong.",[1352,67065,67067],{"className":3538,"code":67066,"language":3540,"meta":1357,"style":1357},"# Đổi hành vi lúc chạy không sửa lớp\nvit_moi.kieu_bay = TenLua()  # gán hành vi mới\nvit_moi.bay()  # bay tên lửa ngay\n",[992,67068,67069,67074,67079],{"__ignoreMap":1357},[1023,67070,67071],{"class":1362,"line":63},[1023,67072,67073],{},"# Đổi hành vi lúc chạy không sửa lớp\n",[1023,67075,67076],{"class":1362,"line":68},[1023,67077,67078],{},"vit_moi.kieu_bay = TenLua()  # gán hành vi mới\n",[1023,67080,67081],{"class":1362,"line":73},[1023,67082,67083],{},"vit_moi.bay()  # bay tên lửa ngay\n",[968,67085,1482],{"id":1481},[973,67087,1485,67088,67090,67091,1517],{},[1487,67089,4800],{}," (hoặc Java). Đây là project, dành 90 phút. Nộp vào ",[992,67092,67093],{},"day-116-simuduck\u002F",[981,67095,67097],{"id":67096},"bài-1-code-cũ-cần-refactor","Bài 1: Code cũ cần refactor",[973,67099,67100,67101,4437],{},"Viết lại đúng phiên bản \"trước refactor\" trong ",[992,67102,4808],{},[1352,67104,67106],{"className":1393,"code":67105,"language":1395,"meta":1357,"style":1357},"class Duck {\n public:\n  virtual std::string display() const = 0;\n  std::string quack() const { return \"Quạc\"; }\n  std::string fly() const { return \"Bay bằng cánh\"; }\n  std::string swim() const { return \"Bơi\"; }\n};\nclass RubberDuck : public Duck { \u002F* ghi đè quack bằng \"Chít\", fly... không ghi đè được vì không virtual *\u002F };\nclass DecoyDuck : public Duck { ... };\n",[992,67107,67108,67112,67116,67120,67125,67130,67135,67139,67144],{"__ignoreMap":1357},[1023,67109,67110],{"class":1362,"line":63},[1023,67111,7191],{},[1023,67113,67114],{"class":1362,"line":68},[1023,67115,4836],{},[1023,67117,67118],{"class":1362,"line":73},[1023,67119,7225],{},[1023,67121,67122],{"class":1362,"line":78},[1023,67123,67124],{},"  std::string quack() const { return \"Quạc\"; }\n",[1023,67126,67127],{"class":1362,"line":83},[1023,67128,67129],{},"  std::string fly() const { return \"Bay bằng cánh\"; }\n",[1023,67131,67132],{"class":1362,"line":88},[1023,67133,67134],{},"  std::string swim() const { return \"Bơi\"; }\n",[1023,67136,67137],{"class":1362,"line":93},[1023,67138,4866],{},[1023,67140,67141],{"class":1362,"line":98},[1023,67142,67143],{},"class RubberDuck : public Duck { \u002F* ghi đè quack bằng \"Chít\", fly... không ghi đè được vì không virtual *\u002F };\n",[1023,67145,67146],{"class":1362,"line":103},[1023,67147,67148],{},"class DecoyDuck : public Duck { ... };\n",[973,67150,67151,67152,67155],{},"Viết test ",[992,67153,67154],{},"before_test.cpp"," chỉ ra 3 lỗi: vịt cao su bay được, vịt mồi kêu được, muốn đổi hành vi lúc chạy thì không thể.",[981,67157,67159],{"id":67158},"bài-2-refactor-bằng-strategy-và-observer","Bài 2: Refactor bằng Strategy và Observer",[973,67161,67162,67163,4437],{},"Thư mục ",[992,67164,4811],{},[1099,67166,67167,67175],{},[1102,67168,67169],{},[1105,67170,67171,67173],{},[1108,67172,2547],{},[1108,67174,14241],{},[1118,67176,67177,67195,67213,67224],{},[1105,67178,67179,67181],{},[1123,67180,7137],{},[1123,67182,67183,67184,1656,67187,67190,67191,67194],{},"2 họ ",[992,67185,67186],{},"FlyBehavior",[992,67188,67189],{},"QuackBehavior",". Vịt giữ con trỏ, ",[992,67192,67193],{},"set..."," đổi lúc chạy",[1105,67196,67197,67199],{},[1123,67198,8903],{},[1123,67200,67201,67202,67205,67206,67209,67210],{},"Mỗi vịt là subject. ",[992,67203,67204],{},"QuackCounterBoard"," đếm tổng tiếng kêu. ",[992,67207,67208],{},"ResearcherLog"," ghi ",[992,67211,67212],{},"\"\u003Ctên>: \u003Ctiếng kêu>\"",[1105,67214,67215,67218],{},[1123,67216,67217],{},"Không phá hành vi",[1123,67219,67220,67221,67223],{},"Mọi hành vi đúng của ",[992,67222,4808],{}," giữ nguyên",[1105,67225,67226,67229],{},[1123,67227,67228],{},"Mở rộng",[1123,67230,5030,67231,67234],{},[992,67232,67233],{},"RobotDuck"," (bay bằng tên lửa, kêu \"Bíp\") chỉ bằng file mới",[1352,67236,67239],{"className":67237,"code":67238,"language":2241,"meta":1357},[2239],"RubberDuck.performFly()                        -> \"Không bay được\"\nDecoyDuck.setFlyBehavior(Rocket); performFly() -> \"Bay bằng tên lửa\"; các vịt khác không đổi\n3 vịt kêu mỗi con 2 lần                         -> board đếm 6, log có 6 dòng\n",[992,67240,67238],{"__ignoreMap":1357},[981,67242,67244],{"id":67243},"bài-3-báo-cáo-refactor-nâng-cao","Bài 3: Báo cáo refactor (nâng cao)",[973,67246,1505,67247,4437],{},[992,67248,67249],{},"REFACTOR.md",[2273,67251,67252,67255,67264],{},[989,67253,67254],{},"Sơ đồ lớp trước và sau (Mermaid).",[989,67256,67257,67258,67260,67261,67263],{},"Bảng: yêu cầu thay đổi, số file phải sửa ở ",[992,67259,4808],{},", số file phải sửa ở ",[992,67262,4811],{},". Ít nhất 4 yêu cầu (thêm vịt, thêm kiểu bay, đổi bay lúc chạy, thêm người quan sát).",[989,67265,67266],{},"Nguyên lý thiết kế đã áp dụng (đóng gói phần thay đổi, ưu tiên composition, lập trình theo interface) và chỗ áp dụng trong code.",[981,67268,2711],{"id":2710},[986,67270,67272,67280,67292,67300],{"className":67271},[2715],[989,67273,67275,2308,67277,67279],{"className":67274},[2719],[2721,67276],{"disabled":2723,"type":2724},[992,67278,67154],{}," chỉ ra đủ 3 lỗi.",[989,67281,67283,67285,67286,67288,67289,67291],{"className":67282},[2719],[2721,67284],{"disabled":2723,"type":2724}," Test ",[992,67287,4811],{}," pass, ",[992,67290,67233],{}," chỉ là file mới.",[989,67293,67295,2308,67297,67299],{"className":67294},[2719],[2721,67296],{"disabled":2723,"type":2724},[992,67298,67249],{}," có 2 sơ đồ và bảng 4 yêu cầu.",[989,67301,67303,67305],{"className":67302},[2719],[2721,67304],{"disabled":2723,"type":2724}," Commit tách rõ: code cũ, test lỗi, refactor Strategy, thêm Observer.",[968,67307,2890],{"id":2889},[986,67309,67310,67313,67316,67319],{},[989,67311,67312],{},"Mùi lớn nhất của kế thừa là gì?",[989,67314,67315],{},"Strategy tách cái gì ra?",[989,67317,67318],{},"Ai nhận tin khi vịt kêu?",[989,67320,67321],{},"Thêm bảng mới có sửa vịt không?",[3014,67323],{},[973,67325,67326],{},"🌕 Bạn đã hoàn thành ngày 116. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,67328,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":67330},[67331,67332,67337,67338,67344],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":67333},[67334,67335,67336],{"id":66945,"depth":73,"text":66946},{"id":66966,"depth":73,"text":66967},{"id":67035,"depth":73,"text":67036},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":67339},[67340,67341,67342,67343],{"id":67096,"depth":73,"text":67097},{"id":67158,"depth":73,"text":67159},{"id":67243,"depth":73,"text":67244},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đề refactor đàn vịt kế thừa cứng nhắc sang Strategy và gắn bảng quan sát, kèm rubric chấm bốn mức.",{},[5194],{"title":635,"description":67345},[17502,7552,9251],"i7NwrWXZvaH17SNiUlEPtR0Kt-55iUW1_KPXT0jvTyI",{"id":67352,"title":640,"body":67353,"category":5189,"day":643,"description":67800,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":67801,"navigation":2723,"outcomes":3047,"path":641,"prerequisites":67802,"seo":67803,"stem":642,"tags":67804,"__hash__":67805},"challenges\u002Fchallenges\u002F117.project-pizza.md",{"type":965,"value":67354,"toc":67784},[67355,67357,67360,67362,67366,67383,67387,67404,67449,67453,67470,67472,67480,67510,67512,67520,67524,67599,67603,67679,67691,67697,67701,67708,67729,67732,67734,67761,67763,67777,67779,67782],[968,67356,971],{"id":970},[973,67358,67359],{},"Bài này xây tiệm pizza 2 vùng và cộng topping dồn.\nDùng để thêm vùng mới không sửa khung cũ.",[968,67361,979],{"id":978},[981,67363,67365],{"id":67364},"khung-factory-method","Khung Factory Method",[986,67367,67368,67371,67374,67377,67380],{},[989,67369,67370],{},"Khung chung giữ quy trình đặt nướng cắt đóng hộp.",[989,67372,67373],{},"Mỗi vùng tự định nghĩa khâu tạo pizza riêng mình.",[989,67375,67376],{},"Khung không biết tên pizza cụ thể của vùng.",[989,67378,67379],{},"Ví dụ đời thường: như trụ sở ra quy trình, chi nhánh nấu.",[989,67381,67382],{},"Thêm vùng California chỉ thêm 1 chi nhánh mới.",[981,67384,67386],{"id":67385},"xưởng-abstract-factory","Xưởng Abstract Factory",[986,67388,67389,67392,67395,67398,67401],{},[989,67390,67391],{},"Mỗi vùng có xưởng bột sốt phô mai riêng biệt.",[989,67393,67394],{},"Pizza hỏi từng món ở bước chuẩn bị nấu.",[989,67396,67397],{},"Đảm bảo 1 chiếc cùng vùng không lẫn nguyên liệu.",[989,67399,67400],{},"Ví dụ đời thường: như combo bếp vùng không lẫn vị.",[989,67402,67403],{},"Pizza không biết tên xưởng cụ thể phía sau.",[1099,67405,67406,67417],{},[1102,67407,67408],{},[1105,67409,67410,67413,67415],{},[1108,67411,67412],{},"Khâu",[1108,67414,41388],{},[1108,67416,62923],{},[1118,67418,67419,67429,67439],{},[1105,67420,67421,67424,67426],{},[1123,67422,67423],{},"Tạo pizza vùng",[1123,67425,20694],{},[1123,67427,67428],{},"Chi nhánh tự tạo",[1105,67430,67431,67434,67436],{},[1123,67432,67433],{},"Bộ nguyên liệu",[1123,67435,46261],{},[1123,67437,67438],{},"Cùng vùng đồng bộ",[1105,67440,67441,67444,67446],{},[1123,67442,67443],{},"Cộng topping",[1123,67445,63398],{},[1123,67447,67448],{},"Bọc và cộng dồn",[981,67450,67452],{"id":67451},"decorator-topping","Decorator topping",[986,67454,67455,67458,67461,67464,67467],{},[989,67456,67457],{},"Mỗi topping là 1 lớp bọc giữ pizza bên trong.",[989,67459,67460],{},"Hỏi giá thì cộng dồn, hỏi tên thì nối chuỗi.",[989,67462,67463],{},"Thêm ô liu chỉ thêm 1 lớp bọc mới.",[989,67465,67466],{},"Ví dụ đời thường: như dán sticker giá cộng dồn nhau.",[989,67468,67469],{},"Không sửa pizza cũ khi thêm topping mới.",[968,67471,1433],{"id":1432},[986,67473,67474,67477],{},[989,67475,67476],{},"Input: pizza phô mai + sữa + nấm -> Output: giá cộng 3 lớp.",[989,67478,67479],{},"Giải thích: mỗi bọc cộng 1 phần rồi chuyển vào trong.",[1352,67481,67483],{"className":3538,"code":67482,"language":3540,"meta":1357,"style":1357},"# Bọc topping cộng dồn giá\nbanh = PizzaPhoMai()  # bánh gốc\nbanh = Sua(banh)  # bọc sữa\nbanh = Nam(banh)  # bọc nấm\nprint(banh.gia())  # tổng 3 lớp\n",[992,67484,67485,67490,67495,67500,67505],{"__ignoreMap":1357},[1023,67486,67487],{"class":1362,"line":63},[1023,67488,67489],{},"# Bọc topping cộng dồn giá\n",[1023,67491,67492],{"class":1362,"line":68},[1023,67493,67494],{},"banh = PizzaPhoMai()  # bánh gốc\n",[1023,67496,67497],{"class":1362,"line":73},[1023,67498,67499],{},"banh = Sua(banh)  # bọc sữa\n",[1023,67501,67502],{"class":1362,"line":78},[1023,67503,67504],{},"banh = Nam(banh)  # bọc nấm\n",[1023,67506,67507],{"class":1362,"line":83},[1023,67508,67509],{},"print(banh.gia())  # tổng 3 lớp\n",[968,67511,1482],{"id":1481},[973,67513,1485,67514,67516,67517,1517],{},[1487,67515,4800],{}," (hoặc Java). Đây là project, dành 90 phút. Dùng lại code ngày 12, 25, 74. Nộp vào ",[992,67518,67519],{},"day-117-pizza\u002F",[981,67521,67523],{"id":67522},"bài-1-khung-cửa-hàng-và-nguyên-liệu","Bài 1: Khung cửa hàng và nguyên liệu",[1099,67525,67526,67536],{},[1102,67527,67528],{},[1105,67529,67530,67532,67534],{},[1108,67531,2544],{},[1108,67533,41388],{},[1108,67535,2547],{},[1118,67537,67538,67556,67575,67587],{},[1105,67539,67540,67545,67547],{},[1123,67541,67542],{},[992,67543,67544],{},"PizzaStore::orderPizza(type)",[1123,67546,20694],{},[1123,67548,67549,67550,1838,67553,67555],{},"Quy trình chung ",[992,67551,67552],{},"prepare, bake, cut, box",[992,67554,20867],{}," để chi nhánh ghi đè",[1105,67557,67558,67564,67566],{},[1123,67559,67560,1656,67562],{},[992,67561,20821],{},[992,67563,20841],{},[1123,67565],{},[1123,67567,67568,67569,1656,67571,1656,67573],{},"Mỗi chi nhánh bán ",[992,67570,46827],{},[992,67572,46917],{},[992,67574,46830],{},[1105,67576,67577,67582,67584],{},[1123,67578,67579],{},[992,67580,67581],{},"PizzaIngredientFactory",[1123,67583,46261],{},[1123,67585,67586],{},"1 xưởng mỗi vùng: bột, sốt, phô mai, rau, nghêu",[1105,67588,67589,67594,67596],{},[1123,67590,67591],{},[992,67592,67593],{},"Pizza",[1123,67595],{},[1123,67597,67598],{},"Không biết vùng nào, chỉ hỏi xưởng",[981,67600,67602],{"id":67601},"bài-2-topping-và-hóa-đơn","Bài 2: Topping và hóa đơn",[1099,67604,67605,67615],{},[1102,67606,67607],{},[1105,67608,67609,67611,67613],{},[1108,67610,2544],{},[1108,67612,41388],{},[1108,67614,2547],{},[1118,67616,67617,67638,67665],{},[1105,67618,67619,67631,67633],{},[1123,67620,67621,67624,67625,1656,67628,1056],{},[992,67622,67623],{},"PizzaItem"," (interface có ",[992,67626,67627],{},"description()",[992,67629,67630],{},"cost()",[1123,67632],{},[1123,67634,67635,67637],{},[992,67636,67593],{}," cài interface này",[1105,67639,67640,67645,67647],{},[1123,67641,67642],{},[992,67643,67644],{},"ToppingDecorator",[1123,67646,63398],{},[1123,67648,67649,67652,67653,67656,67657,67660,67661,67664],{},[992,67650,67651],{},"ExtraCheese"," +15k, ",[992,67654,67655],{},"Olive"," +10k, ",[992,67658,67659],{},"Mushroom"," +12k, ",[992,67662,67663],{},"Bacon"," +20k",[1105,67666,67667,67671,67673],{},[1123,67668,67669],{},[992,67670,4893],{},[1123,67672],{},[1123,67674,67675,67676,67678],{},"Nhiều ",[992,67677,67623],{},", in hóa đơn có từng dòng và tổng",[973,67680,67681,67682,67684,67685,67687,67688,67690],{},"Giá gốc: ",[992,67683,46827],{}," 120k, ",[992,67686,46917],{}," 110k, ",[992,67689,46830],{}," 150k. Chicago cộng 20k mỗi pizza vì đế dày.",[1352,67692,67695],{"className":67693,"code":67694,"language":2241,"meta":1357},[2239],"NY cheese + ExtraCheese + Olive    -> \"NY Cheese Pizza, thêm phô mai, ô liu\" = 145000\nChicago clam + Bacon               -> 190000\nHóa đơn 2 món trên                 -> tổng 335000\n",[992,67696,67694],{"__ignoreMap":1357},[981,67698,67700],{"id":67699},"bài-3-mở-rộng-và-kiểm-chứng-nâng-cao","Bài 3: Mở rộng và kiểm chứng (nâng cao)",[973,67702,67703,67704,8530,67706,4437],{},"Thực hiện 3 thay đổi, mỗi thay đổi 1 commit, ghi ",[992,67705,14320],{},[992,67707,2513],{},[2273,67709,67710,67713,67720],{},[989,67711,67712],{},"Thêm vùng California (xưởng nguyên liệu và chi nhánh mới).",[989,67714,67715,67716,67719],{},"Thêm topping ",[992,67717,67718],{},"Pineapple"," +8k.",[989,67721,67722,67723,67725,67726,1517],{},"Thêm khuyến mãi \"mua 2 giảm 10%\" vào ",[992,67724,4893],{}," bằng Strategy ",[992,67727,67728],{},"DiscountPolicy",[973,67730,67731],{},"Viết test tích hợp: đặt 5 đơn ở 3 vùng với topping khác nhau, kiểm tra nguyên liệu đúng vùng, giá đúng, tổng hóa đơn đúng.",[981,67733,2711],{"id":2710},[986,67735,67737,67743,67749,67755],{"className":67736},[2715],[989,67738,67740,67742],{"className":67739},[2719],[2721,67741],{"disabled":2723,"type":2724}," Test mẫu giá pass.",[989,67744,67746,67748],{"className":67745},[2719],[2721,67747],{"disabled":2723,"type":2724}," Không pizza nào lẫn nguyên liệu vùng khác (có test).",[989,67750,67752,67754],{"className":67751},[2719],[2721,67753],{"disabled":2723,"type":2724}," 3 thay đổi Bài 3 chỉ thêm file mới hoặc sửa đúng 1 chỗ đăng ký.",[989,67756,67758,67760],{"className":67757},[2719],[2721,67759],{"disabled":2723,"type":2724}," Sơ đồ lớp đánh dấu 3 pattern: Factory Method, Abstract Factory, Decorator.",[968,67762,2890],{"id":2889},[986,67764,67765,67768,67771,67774],{},[989,67766,67767],{},"Ai định nghĩa khâu tạo pizza?",[989,67769,67770],{},"Xưởng vùng đảm bảo gì?",[989,67772,67773],{},"Topping cộng giá thế nào?",[989,67775,67776],{},"Thêm topping có sửa pizza không?",[3014,67778],{},[973,67780,67781],{},"🌕 Bạn đã hoàn thành ngày 117. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,67783,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":67785},[67786,67787,67792,67793,67799],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":67788},[67789,67790,67791],{"id":67364,"depth":73,"text":67365},{"id":67385,"depth":73,"text":67386},{"id":67451,"depth":73,"text":67452},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":67794},[67795,67796,67797,67798],{"id":67522,"depth":73,"text":67523},{"id":67601,"depth":73,"text":67602},{"id":67699,"depth":73,"text":67700},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đề xây Pizza Store đa vùng bằng Factory Method Abstract Factory và cộng topping bằng Decorator, kèm rubric.",{},[5194],{"title":640,"description":67800},[17502,16071,12056],"EhMki-STVF56Y4M7WckG1OcRQfuchA4GwO2mWbwXoXY",{"id":67807,"title":645,"body":67808,"category":5189,"day":648,"description":68132,"difficulty":42171,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":68133,"navigation":2723,"outcomes":3047,"path":646,"prerequisites":68134,"seo":68135,"stem":647,"tags":68136,"__hash__":68138},"challenges\u002Fchallenges\u002F118.patterns-phong-van.md",{"type":965,"value":67809,"toc":68116},[67810,67812,67815,67817,67821,67838,67842,67859,67920,67924,67938,67940,67948,67968,67970,67977,67981,67991,68008,68011,68015,68023,68027,68030,68062,68064,68093,68095,68109,68111,68114],[968,67811,971],{"id":970},[973,67813,67814],{},"Bài này luyện kể chuyện thiết kế trong 2 phút.\nDùng để qua vòng phỏng vấn pattern khó nhằn.",[968,67816,979],{"id":978},[981,67818,67820],{"id":67819},"khung-trả-lời-4-nhịp","Khung trả lời 4 nhịp",[986,67822,67823,67826,67829,67832,67835],{},[989,67824,67825],{},"Nhịp 1: nỗi đau gặp ở đâu trong dự án.",[989,67827,67828],{},"Nhịp 2: 2 cách đầu và vì sao hỏng.",[989,67830,67831],{},"Nhịp 3: pattern chọn với vai và quan hệ.",[989,67833,67834],{},"Ví dụ đời thường: như kể bệnh, thuốc thử, thuốc chốt.",[989,67836,67837],{},"Nhịp 4: đánh đổi và khi nào không dùng.",[981,67839,67841],{"id":67840},"ba-chuyện-thuộc-lòng","Ba chuyện thuộc lòng",[986,67843,67844,67847,67850,67853,67856],{},[989,67845,67846],{},"SimUDuck cho Strategy: vịt cao su biết bay sai.",[989,67848,67849],{},"Tách bay kêu rồi ủy thác, đổi tên lửa lúc chạy.",[989,67851,67852],{},"Trạm thời tiết cho Observer: thêm bảng không sửa trạm.",[989,67854,67855],{},"Ví dụ đời thường: như 3 chuyện tủ mang đi thi.",[989,67857,67858],{},"Starbuzz cho Decorator: bọc cộng giá thay bùng lớp.",[1099,67860,67861,67874],{},[1102,67862,67863],{},[1105,67864,67865,67868,67871],{},[1108,67866,67867],{},"Cặp dễ nhầm",[1108,67869,67870],{},"Khác ở",[1108,67872,67873],{},"Nhớ bằng",[1118,67875,67876,67887,67898,67909],{},[1105,67877,67878,67881,67884],{},[1123,67879,67880],{},"Strategy-State",[1123,67882,67883],{},"Ai quyết đổi",[1123,67885,67886],{},"Ngoài hay trong",[1105,67888,67889,67892,67895],{},[1123,67890,67891],{},"Decorator-Proxy",[1123,67893,67894],{},"Thêm hay chặn",[1123,67896,67897],{},"Làm thêm hay gác cổng",[1105,67899,67900,67903,67906],{},[1123,67901,67902],{},"Adapter-Facade",[1123,67904,67905],{},"Dịch 1 hay gom hệ",[1123,67907,67908],{},"Phiên dịch hay lễ tân",[1105,67910,67911,67914,67917],{},[1123,67912,67913],{},"Factory 2 loại",[1123,67915,67916],{},"1 món hay cả họ",[1123,67918,67919],{},"Món lẻ hay combo",[981,67921,67923],{"id":67922},"solid-gọn","SOLID gọn",[986,67925,67926,67929,67932,67935],{},[989,67927,67928],{},"Đơn trách nhiệm: 1 lớp chỉ 1 lý do đổi.",[989,67930,67931],{},"Đóng mở: thêm mới không sửa cũ đang chạy.",[989,67933,67934],{},"Thay thế: lớp con dùng được chỗ lớp cha.",[989,67936,67937],{},"Ví dụ đời thường: như dao chỉ cắt, không kiêm nĩa.",[968,67939,1433],{"id":1432},[986,67941,67942,67945],{},[989,67943,67944],{},"Input: \"Khi nào dùng Strategy?\" -> Output: kể SimUDuck 4 nhịp 2 phút.",[989,67946,67947],{},"Giải thích: đủ đau, hỏng, chọn, đánh đổi là đạt điểm.",[1352,67949,67951],{"className":3538,"code":67950,"language":3540,"meta":1357,"style":1357},"# Khung kể 2 phút cho mọi pattern\ntra_loi = [noi_dau, cach_hong, pattern_chon, danh_doi]\nprint(len(tra_loi) == 4)  # đủ 4 nhịp\n",[992,67952,67953,67958,67963],{"__ignoreMap":1357},[1023,67954,67955],{"class":1362,"line":63},[1023,67956,67957],{},"# Khung kể 2 phút cho mọi pattern\n",[1023,67959,67960],{"class":1362,"line":68},[1023,67961,67962],{},"tra_loi = [noi_dau, cach_hong, pattern_chon, danh_doi]\n",[1023,67964,67965],{"class":1362,"line":73},[1023,67966,67967],{},"print(len(tra_loi) == 4)  # đủ 4 nhịp\n",[968,67969,1482],{"id":1481},[973,67971,67972,67973,67976],{},"Không cần code mới. Dùng code các ngày trước làm ví dụ. Nộp vào ",[992,67974,67975],{},"day-118\u002F"," gồm file Markdown và bản ghi âm hoặc video.",[981,67978,67980],{"id":67979},"bài-1-kể-chuyện-4-nhịp","Bài 1: Kể chuyện 4 nhịp",[973,67982,1505,67983,67986,67987,67990],{},[992,67984,67985],{},"stories.md"," gồm 6 câu chuyện, mỗi câu chuyện ",[1487,67988,67989],{},"tối đa 200 từ",", đúng 4 nhịp:",[2273,67992,67993,67996,67999,68002],{},[989,67994,67995],{},"Nỗi đau gặp ở đâu (bối cảnh có số liệu: bao nhiêu lớp, bao nhiêu file phải sửa).",[989,67997,67998],{},"Hai cách đầu tiên và vì sao hỏng.",[989,68000,68001],{},"Pattern chọn: vai trò các lớp và quan hệ (kèm sơ đồ 5-10 dòng Mermaid).",[989,68003,68004,68005,68007],{},"Đánh đổi và khi nào ",[1487,68006,41587],{}," dùng.",[973,68009,68010],{},"Pattern bắt buộc: Strategy, Observer, Decorator, Factory Method, Command, State. Ví dụ lấy từ code chính bạn đã viết (ghi đường dẫn file).",[981,68012,68014],{"id":68013},"bài-2-luyện-nói","Bài 2: Luyện nói",[2273,68016,68017,68020],{},[989,68018,68019],{},"Tự ghi âm kể 3 câu chuyện, mỗi câu tối đa 2 phút. Nghe lại và ghi chú: chỗ ấp úng, chỗ dùng thuật ngữ sai, chỗ quá dài.",[989,68021,68022],{},"Kể lại lần 2, so thời lượng.",[981,68024,68026],{"id":68025},"bài-3-câu-hỏi-phỏng-vấn-thường-gặp-nâng-cao","Bài 3: Câu hỏi phỏng vấn thường gặp (nâng cao)",[973,68028,68029],{},"Viết câu trả lời ngắn (tối đa 80 từ) cho 10 câu:",[2273,68031,68032,68035,68038,68041,68044,68047,68050,68053,68056,68059],{},[989,68033,68034],{},"Strategy khác State ở đâu?",[989,68036,68037],{},"Decorator khác Proxy ở đâu?",[989,68039,68040],{},"Adapter khác Facade ở đâu?",[989,68042,68043],{},"Khi nào Singleton là anti-pattern?",[989,68045,68046],{},"Factory Method khác Abstract Factory ở đâu?",[989,68048,68049],{},"SOLID chữ nào bạn hay vi phạm nhất? Ví dụ.",[989,68051,68052],{},"Composition over inheritance nghĩa là gì? Ví dụ trong code của bạn.",[989,68054,68055],{},"Observer có nhược điểm gì với hệ thống lớn?",[989,68057,68058],{},"Pattern nào bạn thấy bị lạm dụng nhiều nhất?",[989,68060,68061],{},"Kể 1 lần bạn gỡ bỏ một pattern vì nó thừa.",[981,68063,2711],{"id":2710},[986,68065,68067,68075,68081,68087],{"className":68066},[2715],[989,68068,68070,2308,68072,68074],{"className":68069},[2719],[2721,68071],{"disabled":2723,"type":2724},[992,68073,67985],{}," đủ 6 câu chuyện, mỗi câu dưới 200 từ, có sơ đồ và đường dẫn code.",[989,68076,68078,68080],{"className":68077},[2719],[2721,68079],{"disabled":2723,"type":2724}," Có 2 lần ghi âm và ghi chú cải thiện.",[989,68082,68084,68086],{"className":68083},[2719],[2721,68085],{"disabled":2723,"type":2724}," 10 câu trả lời dưới 80 từ mỗi câu.",[989,68088,68090,68092],{"className":68089},[2719],[2721,68091],{"disabled":2723,"type":2724}," Mỗi câu chuyện có nhịp 4 \"khi nào không dùng\".",[968,68094,2890],{"id":2889},[986,68096,68097,68100,68103,68106],{},[989,68098,68099],{},"4 nhịp trả lời là gì?",[989,68101,68102],{},"SimUDuck đau ở đâu?",[989,68104,68105],{},"Decorator khác Proxy sao?",[989,68107,68108],{},"2 Factory khác nhau gì?",[3014,68110],{},[973,68112,68113],{},"🌕 Bạn đã hoàn thành ngày 118. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,68115,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":68117},[68118,68119,68124,68125,68131],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":68120},[68121,68122,68123],{"id":67819,"depth":73,"text":67820},{"id":67840,"depth":73,"text":67841},{"id":67922,"depth":73,"text":67923},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":68126},[68127,68128,68129,68130],{"id":67979,"depth":73,"text":67980},{"id":68013,"depth":73,"text":68014},{"id":68025,"depth":73,"text":68026},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Ôn thi phỏng vấn patterns: kể SimUDuck Weather Starbuzz trong hai phút, trả lời khi nào dùng và so sánh cặp đôi dễ nhầm.",{},[5195],{"title":645,"description":68132},[68137,5199],"interview","uoRrkNjjOioG5iM60NCbGIJ3gXEjYiAAOmVmWLUUEeQ",{"id":68140,"title":650,"body":68141,"category":8797,"day":653,"description":68558,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":68560,"navigation":2723,"outcomes":3047,"path":651,"prerequisites":68561,"seo":68562,"stem":652,"tags":68563,"__hash__":68566},"challenges\u002Fchallenges\u002F119.ss-tree-similarity.md",{"type":965,"value":68142,"toc":68541},[68143,68145,68148,68150,68154,68171,68175,68192,68239,68243,68260,68264,68272,68274,68282,68306,68308,68323,68327,68384,68433,68439,68443,68454,68458,68487,68489,68518,68520,68534,68536,68539],[968,68144,971],{"id":970},[973,68146,68147],{},"Bài này học tìm ảnh giống nhau bằng cây siêu cầu.\nDùng để truy xuất ảnh nhanh khi nhiều chiều.",[968,68149,979],{"id":978},[981,68151,68153],{"id":68152},"vì-sao-cần-ss-tree","Vì sao cần SS-tree",[986,68155,68156,68159,68162,68165,68168],{},[989,68157,68158],{},"Mỗi ảnh là 1 điểm trong không gian nhiều chiều.",[989,68160,68161],{},"k-d tree cắt theo trục nên ôm cụm xiên kém.",[989,68163,68164],{},"Hộp R-tree nhiều góc thừa ở chiều cao lớn.",[989,68166,68167],{},"Ví dụ đời thường: như hộp vuông đựng bóng tròn phí chỗ.",[989,68169,68170],{},"Siêu cầu ôm cụm ảnh khít hơn hộp chữ nhật.",[981,68172,68174],{"id":68173},"siêu-cầu-và-chèn","Siêu cầu và chèn",[986,68176,68177,68180,68183,68186,68189],{},[989,68178,68179],{},"Mỗi nút là 1 cầu gồm tâm và bán kính bao.",[989,68181,68182],{},"Tâm là trung bình điểm con, bán kính bao hết.",[989,68184,68185],{},"Chèn chọn cầu nới ít nhất rồi cập nhật ngược lên.",[989,68187,68188],{},"Ví dụ đời thường: như chọn vòng dây nới ít nhất.",[989,68190,68191],{},"Nút lưu trung bình và phương sai để tách sau.",[1099,68193,68194,68206],{},[1102,68195,68196],{},[1105,68197,68198,68200,68203],{},[1108,68199,29909],{},[1108,68201,68202],{},"Bao bằng",[1108,68204,68205],{},"Hợp khi",[1118,68207,68208,68218,68228],{},[1105,68209,68210,68212,68215],{},[1123,68211,33279],{},[1123,68213,68214],{},"Mặt phẳng trục",[1123,68216,68217],{},"Chiều thấp",[1105,68219,68220,68222,68225],{},[1123,68221,33290],{},[1123,68223,68224],{},"Hộp chữ nhật",[1123,68226,68227],{},"Bản đồ 2 chiều",[1105,68229,68230,68233,68236],{},[1123,68231,68232],{},"SS-tree",[1123,68234,68235],{},"Siêu cầu",[1123,68237,68238],{},"Ảnh nhiều chiều",[981,68240,68242],{"id":68241},"tách-xóa-và-truy-vấn","Tách xóa và truy vấn",[986,68244,68245,68248,68251,68254,68257],{},[989,68246,68247],{},"Tràn thì tách theo chiều phương sai lớn nhất.",[989,68249,68250],{},"Chọn điểm cắt trên chiều đó sao cho tổng phương sai của hai nửa nhỏ nhất, mỗi nửa đủ số điểm tối thiểu.",[989,68252,68253],{},"Xóa thì thu cầu, vơi quá thì chèn lại mồ côi.",[989,68255,68256],{},"Truy vấn xấp xỉ cho dừng sớm để lấy nhanh.",[989,68258,68259],{},"Nới ngưỡng càng mạnh càng nhanh nhưng dễ sót.",[981,68261,68263],{"id":68262},"ss-tree","SS+-tree",[986,68265,68266,68269],{},[989,68267,68268],{},"Siêu cầu vẫn chồng lên nhau nhiều ở chiều cao, làm truy vấn phải lặn nhiều nhánh.",[989,68270,68271],{},"SS+-tree cải thiện bằng cách dùng tâm là tâm cầu bao nhỏ nhất (thay cho trung bình), tách nút bằng heuristic tốt hơn (ví dụ gom cụm 2 nhóm), và định kỳ chèn lại để giảm chồng lấn.",[968,68273,1433],{"id":1432},[986,68275,68276,68279],{},[989,68277,68278],{},"Input: 6 điểm 2 cụm rõ -> Output: 2 cầu ôm khít hơn 2 hộp.",[989,68280,68281],{},"Giải thích: cầu tròn ít góc chết nên ít vào nhánh rỗng.",[1352,68283,68285],{"className":3538,"code":68284,"language":3540,"meta":1357,"style":1357},"# Kiểm cầu có giao truy vấn không\nimport math\nd = math.dist(tam, diem_hoi)  # khoảng tới tâm\nprint(d \u003C= ban_kinh + nguong)  # True thì vào nhánh\n",[992,68286,68287,68292,68296,68301],{"__ignoreMap":1357},[1023,68288,68289],{"class":1362,"line":63},[1023,68290,68291],{},"# Kiểm cầu có giao truy vấn không\n",[1023,68293,68294],{"class":1362,"line":68},[1023,68295,58238],{},[1023,68297,68298],{"class":1362,"line":73},[1023,68299,68300],{},"d = math.dist(tam, diem_hoi)  # khoảng tới tâm\n",[1023,68302,68303],{"class":1362,"line":78},[1023,68304,68305],{},"print(d \u003C= ban_kinh + nguong)  # True thì vào nhánh\n",[968,68307,1482],{"id":1481},[973,68309,1485,68310,68312,68313,32553,68316,68318,68319,68322],{},[1487,68311,1493],{}," (hoặc Python với NumPy). Nộp vào ",[992,68314,68315],{},"day-119\u002F",[992,68317,4780],{}," chiều (",[992,68320,68321],{},"D = 64"," cho vector ảnh).",[981,68324,68326],{"id":68325},"bài-1-ss-tree","Bài 1: SS-tree",[1352,68328,68330],{"className":1393,"code":68329,"language":1395,"meta":1357,"style":1357},"struct SSNode {\n  std::vector\u003Cfloat> centroid; float radius;\n  bool leaf; std::vector\u003Cstd::vector\u003Cfloat>> points; std::vector\u003CSSNode*> children;\n};\nclass SSTree {\n public:\n  SSTree(int D, int M = 16, int m = 6);\n  void insert(const std::vector\u003Cfloat> &p);\n  std::vector\u003Cint> knn(const std::vector\u003Cfloat> &q, int k) const;   \u002F\u002F chính xác\n  bool check() const;   \u002F\u002F mọi điểm con nằm trong cầu cha\n};\n",[992,68331,68332,68337,68342,68347,68351,68356,68360,68365,68370,68375,68380],{"__ignoreMap":1357},[1023,68333,68334],{"class":1362,"line":63},[1023,68335,68336],{},"struct SSNode {\n",[1023,68338,68339],{"class":1362,"line":68},[1023,68340,68341],{},"  std::vector\u003Cfloat> centroid; float radius;\n",[1023,68343,68344],{"class":1362,"line":73},[1023,68345,68346],{},"  bool leaf; std::vector\u003Cstd::vector\u003Cfloat>> points; std::vector\u003CSSNode*> children;\n",[1023,68348,68349],{"class":1362,"line":78},[1023,68350,4866],{},[1023,68352,68353],{"class":1362,"line":83},[1023,68354,68355],{},"class SSTree {\n",[1023,68357,68358],{"class":1362,"line":88},[1023,68359,4836],{},[1023,68361,68362],{"class":1362,"line":93},[1023,68363,68364],{},"  SSTree(int D, int M = 16, int m = 6);\n",[1023,68366,68367],{"class":1362,"line":98},[1023,68368,68369],{},"  void insert(const std::vector\u003Cfloat> &p);\n",[1023,68371,68372],{"class":1362,"line":103},[1023,68373,68374],{},"  std::vector\u003Cint> knn(const std::vector\u003Cfloat> &q, int k) const;   \u002F\u002F chính xác\n",[1023,68376,68377],{"class":1362,"line":108},[1023,68378,68379],{},"  bool check() const;   \u002F\u002F mọi điểm con nằm trong cầu cha\n",[1023,68381,68382],{"class":1362,"line":113},[1023,68383,4866],{},[1099,68385,68386,68394],{},[1102,68387,68388],{},[1105,68389,68390,68392],{},[1108,68391,36178],{},[1108,68393,2547],{},[1118,68395,68396,68404,68412,68422],{},[1105,68397,68398,68401],{},[1123,68399,68400],{},"Chọn nhánh",[1123,68402,68403],{},"Con có tâm gần điểm mới nhất",[1105,68405,68406,68409],{},[1123,68407,68408],{},"Cập nhật cầu",[1123,68410,68411],{},"Tâm là trung bình, bán kính bao hết con (cộng bán kính con với nút trong)",[1105,68413,68414,68417],{},[1123,68415,68416],{},"Tách",[1123,68418,68419,68420],{},"Chiều có phương sai lớn nhất, cắt ở vị trí làm tổng phương sai 2 nửa nhỏ nhất, mỗi nửa ít nhất ",[992,68421,15437],{},[1105,68423,68424,68427],{},[1123,68425,68426],{},"Cắt nhánh k-NN",[1123,68428,68429,68430],{},"Bỏ nút khi ",[992,68431,68432],{},"dist(q, centroid) - radius > khoảng cách thứ k hiện tại",[1352,68434,68437],{"className":68435,"code":68436,"language":2241,"meta":1357},[2239],"10^4 điểm ngẫu nhiên D=8 -> check = true; knn khớp quét tuyến tính trên 1000 truy vấn\n",[992,68438,68436],{"__ignoreMap":1357},[981,68440,68442],{"id":68441},"bài-2-tìm-ảnh-tương-tự","Bài 2: Tìm ảnh tương tự",[2273,68444,68445,68448,68451],{},[989,68446,68447],{},"Biến 5000 ảnh (CIFAR-10 hoặc thư mục ảnh của bạn) thành vector 64 chiều: histogram màu 4x4x4 chuẩn hóa. (Ngày 140 sẽ dùng CNN.)",[989,68449,68450],{},"Nạp vào SS-tree. Với 5 ảnh truy vấn, hiện 8 ảnh gần nhất thành 1 lưới ảnh.",[989,68452,68453],{},"So thời gian truy vấn với quét tuyến tính và k-d tree ngày 69.",[981,68455,68457],{"id":68456},"bài-3-tìm-kiếm-xấp-xỉ-nâng-cao","Bài 3: Tìm kiếm xấp xỉ (nâng cao)",[2273,68459,68460,68469,68475],{},[989,68461,8526,68462,68465,68466,1517],{},[992,68463,68464],{},"epsilon",": bỏ nút khi ",[992,68467,68468],{},"dist - radius > (khoảng cách thứ k) \u002F (1 + epsilon)",[989,68470,68471,68472,1517],{},"Thêm giới hạn số lá được thăm ",[992,68473,68474],{},"max_leaves",[989,68476,28501,68477,68479,68480,1509,68483,68486],{},[1487,68478,39493],{}," (tỉ lệ kết quả trùng với đáp án chính xác) và thời gian với ",[992,68481,68482],{},"epsilon = 0, 0.1, 0.5, 1",[992,68484,68485],{},"max_leaves = 5, 20, 100",". Vẽ đường recall theo thời gian.",[981,68488,2711],{"id":2710},[986,68490,68492,68500,68506,68512],{"className":68491},[2715],[989,68493,68495,2308,68497,68499],{"className":68494},[2719],[2721,68496],{"disabled":2723,"type":2724},[992,68498,44248],{}," đúng và k-NN chính xác khớp quét tuyến tính.",[989,68501,68503,68505],{"className":68502},[2719],[2721,68504],{"disabled":2723,"type":2724}," Có lưới ảnh kết quả cho 5 truy vấn.",[989,68507,68509,68511],{"className":68508},[2719],[2721,68510],{"disabled":2723,"type":2724}," Bảng thời gian 3 cách tìm.",[989,68513,68515,68517],{"className":68514},[2719],[2721,68516],{"disabled":2723,"type":2724}," Đường recall-thời gian của bản xấp xỉ.",[968,68519,2890],{"id":2889},[986,68521,68522,68525,68528,68531],{},[989,68523,68524],{},"Siêu cầu gồm gì?",[989,68526,68527],{},"Chèn chọn nhánh nào?",[989,68529,68530],{},"Tách nút theo gì?",[989,68532,68533],{},"Xấp xỉ đánh đổi gì?",[3014,68535],{},[973,68537,68538],{},"🌕 Bạn đã hoàn thành ngày 119. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,68540,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":68542},[68543,68544,68550,68551,68557],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":68545},[68546,68547,68548,68549],{"id":68152,"depth":73,"text":68153},{"id":68173,"depth":73,"text":68174},{"id":68241,"depth":73,"text":68242},{"id":68262,"depth":73,"text":68263},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":68552},[68553,68554,68555,68556],{"id":68325,"depth":73,"text":68326},{"id":68441,"depth":73,"text":68442},{"id":68456,"depth":73,"text":68457},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Cây tìm kiếm tương đồng SS-tree: siêu cầu, chèn bằng phương sai và hình chiếu, tách nút, xóa, truy vấn xấp xỉ và cải tiến SS cộng tree.","chuyen-gia",{},[14055,18469],{"title":650,"description":68558},[68262,68564,68565],"similarity-search","image-retrieval","HggK9NqFoSNmx6geREj74uqUvXAyi_SUQh8zSyVmSDc",{"id":68568,"title":655,"body":68569,"category":8797,"day":658,"description":68954,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":68955,"navigation":2723,"outcomes":3047,"path":656,"prerequisites":68956,"seo":68957,"stem":657,"tags":68958,"__hash__":68959},"challenges\u002Fchallenges\u002F120.planarity-crossing.md",{"type":965,"value":68570,"toc":68938},[68571,68573,68576,68578,68582,68599,68603,68620,68670,68674,68691,68693,68701,68726,68728,68738,68742,68745,68807,68813,68817,68850,68854,68883,68885,68915,68917,68931,68933,68936],[968,68572,971],{"id":970},[973,68574,68575],{},"Bài này học kiểm đồ thị vẽ phẳng không rối dây.\nDùng để vẽ sơ đồ mạch và luồng đọc dễ.",[968,68577,979],{"id":978},[981,68579,68581],{"id":68580},"kiểm-tra-phẳng","Kiểm tra phẳng",[986,68583,68584,68587,68590,68593,68596],{},[989,68585,68586],{},"Định nghĩa: đồ thị phẳng là vẽ được không cắt nhau.",[989,68588,68589],{},"Naive thử mọi cách xếp nên chỉ nổi đồ thị bé.",[989,68591,68592],{},"Thuật toán nhanh thêm từng đỉnh giữ biên phẳng.",[989,68594,68595],{},"Ví dụ đời thường: như xếp dây sạc không rối nhau.",[989,68597,68598],{},"Đồ thị lớn phải dùng bản tuyến tính theo đỉnh cạnh.",[981,68600,68602],{"id":68601},"số-giao-cắt","Số giao cắt",[986,68604,68605,68608,68611,68614,68617],{},[989,68606,68607],{},"Định nghĩa: số cặp cạnh cắt ít nhất mọi cách vẽ.",[989,68609,68610],{},"Cho cong thì luồn dễ, ít cắt hơn bắt thẳng.",[989,68612,68613],{},"Bắt thẳng gọn mắt nhưng thường cắt nhiều hơn.",[989,68615,68616],{},"Ví dụ đời thường: như dây cong luồn dễ hơn que thẳng.",[989,68618,68619],{},"Tìm tối thiểu là khó nên dùng heuristic dần.",[1099,68621,68622,68635],{},[1102,68623,68624],{},[1105,68625,68626,68629,68632],{},[1108,68627,68628],{},"Kiểu cạnh",[1108,68630,68631],{},"Tính giao",[1108,68633,68634],{},"Đẹp khi",[1118,68636,68637,68648,68659],{},[1105,68638,68639,68642,68645],{},[1123,68640,68641],{},"Đoạn thẳng",[1123,68643,68644],{},"Nhanh, định hướng",[1123,68646,68647],{},"Sơ đồ kỹ thuật",[1105,68649,68650,68653,68656],{},[1123,68651,68652],{},"Đa tuyến",[1123,68654,68655],{},"Từng đoạn một",[1123,68657,68658],{},"Gấp khúc vừa",[1105,68660,68661,68664,68667],{},[1123,68662,68663],{},"Bezier cong",[1123,68665,68666],{},"Giải bậc 2, chia nhỏ",[1123,68668,68669],{},"Sơ đồ nhỏ cần mềm",[981,68671,68673],{"id":68672},"tính-giao-hình-học","Tính giao hình học",[986,68675,68676,68679,68682,68685,68688],{},[989,68677,68678],{},"Hai đoạn cắt khi đầu này khác phía đường kia.",[989,68680,68681],{},"Thẳng hàng thì kiểm tra hộp bao chứa nhau.",[989,68683,68684],{},"Đa tuyến kiểm tra từng cặp đoạn thẳng nhỏ.",[989,68686,68687],{},"Bezier giao thẳng cần giải bậc 2 hoặc chia nhỏ.",[989,68689,68690],{},"Lọc bằng hộp bao trước rồi mới tính chính xác.",[968,68692,1433],{"id":1432},[986,68694,68695,68698],{},[989,68696,68697],{},"Input: đồ thị 5000 nút kiểm naive treo -> Output: đổi thuật toán tuyến tính.",[989,68699,68700],{},"Giải thích: thử mọi cách bùng nổ nên không chạy nổi.",[1352,68702,68704],{"className":3538,"code":68703,"language":3540,"meta":1357,"style":1357},"# Hai đoạn cắt khi khác phía nhau\ndef khac_phia(a, b, c, d):\n    return dinh_huong(a, b, c) * dinh_huong(a, b, d) \u003C 0\nprint(\"cat nhau\" if khac_phia else \"khong cat\")\n",[992,68705,68706,68711,68716,68721],{"__ignoreMap":1357},[1023,68707,68708],{"class":1362,"line":63},[1023,68709,68710],{},"# Hai đoạn cắt khi khác phía nhau\n",[1023,68712,68713],{"class":1362,"line":68},[1023,68714,68715],{},"def khac_phia(a, b, c, d):\n",[1023,68717,68718],{"class":1362,"line":73},[1023,68719,68720],{},"    return dinh_huong(a, b, c) * dinh_huong(a, b, d) \u003C 0\n",[1023,68722,68723],{"class":1362,"line":78},[1023,68724,68725],{},"print(\"cat nhau\" if khac_phia else \"khong cat\")\n",[968,68727,1482],{"id":1481},[973,68729,1485,68730,56503,68732,68734,68735,1517],{},[1487,68731,13531],{},[992,68733,31660],{}," để đối chiếu). Nộp vào ",[992,68736,68737],{},"day-120\u002F",[981,68739,68741],{"id":68740},"bài-1-giao-cắt-chính-xác-cho-mọi-trường-hợp","Bài 1: Giao cắt chính xác cho mọi trường hợp",[973,68743,68744],{},"Nâng cấp hàm ngày 79:",[1099,68746,68747,68755],{},[1102,68748,68749],{},[1105,68750,68751,68753],{},[1108,68752,1566],{},[1108,68754,2547],{},[1118,68756,68757,68771,68787,68797],{},[1105,68758,68759,68764],{},[1123,68760,68761],{},[992,68762,68763],{},"orientation(p, q, r)",[1123,68765,68766,68767,68770],{},"Trả -1, 0, 1. Dùng số nguyên hoặc ",[992,68768,68769],{},"fractions.Fraction"," để tránh sai số",[1105,68772,68773,68778],{},[1123,68774,68775],{},[992,68776,68777],{},"on_segment(p, q, r)",[1123,68779,68780,68782,68783,68786],{},[992,68781,43520],{}," nằm trên đoạn ",[992,68784,68785],{},"pr"," khi thẳng hàng",[1105,68788,68789,68794],{},[1123,68790,68791],{},[992,68792,68793],{},"segments_intersect(a, b, c, d)",[1123,68795,68796],{},"Xử lý cả trường hợp thẳng hàng chồng nhau và chạm đầu mút",[1105,68798,68799,68804],{},[1123,68800,68801],{},[992,68802,68803],{},"polyline_crossings(e1, e2)",[1123,68805,68806],{},"Đếm giao cắt giữa 2 đa tuyến",[1352,68808,68811],{"className":68809,"code":68810,"language":2241,"meta":1357},[2239],"(0,0)-(2,2) và (0,2)-(2,0)   -> cắt\n(0,0)-(2,0) và (1,0)-(3,0)   -> chồng (thẳng hàng)\n(0,0)-(1,1) và (1,1)-(2,0)   -> chạm đầu mút (không tính nếu 2 cạnh chung đỉnh)\n(0,0)-(1,0) và (2,0)-(3,0)   -> không cắt\n",[992,68812,68810],{"__ignoreMap":1357},[981,68814,68816],{"id":68815},"bài-2-kiểm-tra-phẳng-tăng-dần","Bài 2: Kiểm tra phẳng tăng dần",[2273,68818,68819,68836,68844],{},[989,68820,6760,68821,68824,68825,68828,68829,68832,68833,68835],{},[1487,68822,68823],{},"kiểm tra phẳng ngây thơ"," cho đồ thị nhỏ (",[992,68826,68827],{},"n \u003C= 8","): thử mọi hoán vị đỉnh trên vòng tròn ",[1487,68830,68831],{},"và"," kiểm tra định lý Kuratowski bằng cách tìm đồ thị con đồng phôi với K5, K3,3 (có thể dùng ",[992,68834,31660],{}," để tìm, rồi tự kiểm tra kết quả).",[989,68837,32239,68838,68840,68841,1517],{},[992,68839,49211],{}," trên 200 đồ thị ngẫu nhiên ",[992,68842,68843],{},"n = 6..8",[989,68845,6845,68846,68849],{},[992,68847,68848],{},"check_planarity"," trên đồ thị phẳng lớn (lưới 100x100 và tam giác hóa Delaunay 10^4 điểm). Xác nhận thời gian gần tuyến tính.",[981,68851,68853],{"id":68852},"bài-3-crossing-number-nhỏ-nâng-cao","Bài 3: Crossing number nhỏ (nâng cao)",[2273,68855,68856,68865,68880],{},[989,68857,23993,68858,68861,68862,68864],{},[1487,68859,68860],{},"vẽ thẳng",", viết heuristic giảm giao cắt: bắt đầu từ ",[992,68863,49247],{},", lặp dời 1 đỉnh tới vị trí làm giảm giao cắt nhiều nhất trong 50 vị trí thử.",[989,68866,68867,68868,1656,68871,1656,68874,1656,68877,1517],{},"Chạy trên K5, K6, K3,3, K4,4. So với giá trị đã biết: ",[992,68869,68870],{},"cr(K5) = 1",[992,68872,68873],{},"cr(K6) = 3",[992,68875,68876],{},"cr(K3,3) = 1",[992,68878,68879],{},"cr(K4,4) = 4",[989,68881,68882],{},"Vẽ bức tranh tốt nhất cho mỗi đồ thị.",[981,68884,2711],{"id":2710},[986,68886,68888,68894,68903,68909],{"className":68887},[2715],[989,68889,68891,68893],{"className":68890},[2719],[2721,68892],{"disabled":2723,"type":2724}," 4 test giao cắt pass, không dùng số thực cho phép so sánh.",[989,68895,68897,68899,68900,68902],{"className":68896},[2719],[2721,68898],{"disabled":2723,"type":2724}," Kiểm tra phẳng khớp ",[992,68901,31660],{}," trên 200 đồ thị.",[989,68904,68906,68908],{"className":68905},[2719],[2721,68907],{"disabled":2723,"type":2724}," Bảng số giao cắt heuristic so với giá trị đã biết.",[989,68910,68912,68914],{"className":68911},[2719],[2721,68913],{"disabled":2723,"type":2724}," Có hình 4 đồ thị.",[968,68916,2890],{"id":2889},[986,68918,68919,68922,68925,68928],{},[989,68920,68921],{},"Đồ thị phẳng là gì?",[989,68923,68924],{},"Vì sao naive chỉ chạy bé?",[989,68926,68927],{},"Cong khác thẳng ở gì?",[989,68929,68930],{},"Hộp bao để làm gì?",[3014,68932],{},[973,68934,68935],{},"🌕 Bạn đã hoàn thành ngày 120. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,68937,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":68939},[68940,68941,68946,68947,68953],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":68942},[68943,68944,68945],{"id":68580,"depth":73,"text":68581},{"id":68601,"depth":73,"text":68602},{"id":68672,"depth":73,"text":68673},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":68948},[68949,68950,68951,68952],{"id":68740,"depth":73,"text":68741},{"id":68815,"depth":73,"text":68816},{"id":68852,"depth":73,"text":68853},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Kiểm tra phẳng naive tới hiệu quả, số giao cắt và giao cắt thẳng, giao đoạn thẳng đa tuyến Bezier.",{},[15143],{"title":655,"description":68954},[29786],"qTwNzvMDV_TaAZwp4uJiaRizX2k2w2uGfHIbC8xlMCs",{"id":68961,"title":660,"body":68962,"category":8797,"day":663,"description":69287,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":69288,"navigation":2723,"outcomes":3047,"path":661,"prerequisites":69289,"seo":69290,"stem":662,"tags":69291,"__hash__":69292},"challenges\u002Fchallenges\u002F121.sa-graph-drawing.md",{"type":965,"value":68963,"toc":69271},[68964,68966,68969,68971,68975,68989,68993,69007,69054,69058,69072,69074,69085,69115,69117,69125,69129,69164,69170,69174,69185,69189,69195,69216,69218,69248,69250,69264,69266,69269],[968,68965,971],{"id":970},[973,68967,68968],{},"Bài này học cách xếp đỉnh đồ thị cho đẹp. Tranh đẹp giúp đọc cụm và đường đi dễ hơn.",[968,68970,979],{"id":978},[981,68972,68974],{"id":68973},"cost-vẽ-đồ-thị-là-gì","Cost vẽ đồ thị là gì",[986,68976,68977,68980,68983,68986],{},[989,68978,68979],{},"Cost là điểm xấu của tranh, càng thấp càng đẹp.",[989,68981,68982],{},"Gồm 3 ý: số cạnh cắt nhau, cạnh dài ngắn lệch, đỉnh dồn cục.",[989,68984,68985],{},"Ví dụ đời thường: xếp bàn tiệc sao cho dây điện ít cắt nhau.",[989,68987,68988],{},"Dịch 1 đỉnh là 1 bước đi, giữ nếu tranh đẹp lên.",[981,68990,68992],{"id":68991},"đếm-giao-cắt-và-vẽ-hướng-lực","Đếm giao cắt và vẽ hướng lực",[986,68994,68995,68998,69001,69004],{},[989,68996,68997],{},"Đếm giao cắt: đếm cặp cạnh cắt nhau, đúng mục tiêu.",[989,68999,69000],{},"Hướng lực: lò xo kéo đỉnh kề lại, lực đẩy tách đỉnh xa.",[989,69002,69003],{},"Ví dụ đời thường: bạn bè ngồi gần, người lạ giữ khoảng cách.",[989,69005,69006],{},"Thực tế: dùng hướng lực trước, đếm giao cắt để chấm cuối.",[1099,69008,69009,69019],{},[1102,69010,69011],{},[1105,69012,69013,69015,69017],{},[1108,69014,14526],{},[1108,69016,27324],{},[1108,69018,35828],{},[1118,69020,69021,69032,69043],{},[1105,69022,69023,69026,69029],{},[1123,69024,69025],{},"Đếm giao cắt",[1123,69027,69028],{},"Đúng mục tiêu đọc",[1123,69030,69031],{},"Chậm, gãy khúc",[1105,69033,69034,69037,69040],{},[1123,69035,69036],{},"Hướng lực",[1123,69038,69039],{},"Nhanh, cụm đẹp",[1123,69041,69042],{},"Không đếm cắt trực tiếp",[1105,69044,69045,69048,69051],{},[1123,69046,69047],{},"Phối hợp",[1123,69049,69050],{},"Nhanh mà chuẩn",[1123,69052,69053],{},"Cần 2 bước",[981,69055,69057],{"id":69056},"chuyển-đỉnh-theo-nhiệt-độ","Chuyển đỉnh theo nhiệt độ",[986,69059,69060,69063,69066,69069],{},[989,69061,69062],{},"Nóng: dịch xa, đảo cả cụm để thử bố cục mới.",[989,69064,69065],{},"Nguội: dịch nhỏ để nắn từng cạnh.",[989,69067,69068],{},"Ví dụ đời thường: lúc đầu dọn nhà mạnh tay, cuối chỉ chỉnh lọ hoa.",[989,69070,69071],{},"Chạy nhiều seed rồi giữ tranh đẹp nhất.",[968,69073,1433],{"id":1432},[986,69075,69076,69079,69082],{},[989,69077,69078],{},"Input: 4 đỉnh nối thành vòng, xếp gấp chéo. Output: SA bung ra thành hình vuông.",[989,69080,69081],{},"Giải thích: chấp nhận xấu tạm vài bước mới gỡ được chỗ gấp.",[989,69083,69084],{},"Code minh họa cost đơn giản:",[1352,69086,69088],{"className":3538,"code":69087,"language":3540,"meta":1357,"style":1357},"# Tính cost: đếm giao cắt + phạt dồn cục\ndef cost(pos, edges):\n    cut = count_crossing(pos, edges)  # số cặp cạnh cắt nhau\n    crowd = crowd_penalty(pos)  # đỉnh quá gần nhau\n    return cut * 10 + crowd\n",[992,69089,69090,69095,69100,69105,69110],{"__ignoreMap":1357},[1023,69091,69092],{"class":1362,"line":63},[1023,69093,69094],{},"# Tính cost: đếm giao cắt + phạt dồn cục\n",[1023,69096,69097],{"class":1362,"line":68},[1023,69098,69099],{},"def cost(pos, edges):\n",[1023,69101,69102],{"class":1362,"line":73},[1023,69103,69104],{},"    cut = count_crossing(pos, edges)  # số cặp cạnh cắt nhau\n",[1023,69106,69107],{"class":1362,"line":78},[1023,69108,69109],{},"    crowd = crowd_penalty(pos)  # đỉnh quá gần nhau\n",[1023,69111,69112],{"class":1362,"line":83},[1023,69113,69114],{},"    return cut * 10 + crowd\n",[968,69116,1482],{"id":1481},[973,69118,1485,69119,69121,69122,1517],{},[1487,69120,13531],{}," (hoặc C++). Dùng SA ngày 113, đếm giao cắt ngày 120, force-directed ngày 112. Nộp vào ",[992,69123,69124],{},"day-121\u002F",[981,69126,69128],{"id":69127},"bài-1-hàm-cost-cho-bức-vẽ","Bài 1: Hàm cost cho bức vẽ",[1352,69130,69132],{"className":3538,"code":69131,"language":3540,"meta":1357,"style":1357},"def cost(G, pos, w_cross=10.0, w_len=1.0, w_close=5.0, ideal=1.0, min_dist=0.3) -> float:\n    \"\"\"w_cross * số giao cắt\n     + w_len   * tổng (độ dài cạnh - ideal)^2\n     + w_close * số cặp đỉnh gần hơn min_dist\"\"\"\ndef delta_move(G, pos, v, new_xy, ...) -> float:\n    \"\"\"Chỉ tính lại phần cost liên quan tới đỉnh v, không tính lại toàn bộ.\"\"\"\n",[992,69133,69134,69139,69144,69149,69154,69159],{"__ignoreMap":1357},[1023,69135,69136],{"class":1362,"line":63},[1023,69137,69138],{},"def cost(G, pos, w_cross=10.0, w_len=1.0, w_close=5.0, ideal=1.0, min_dist=0.3) -> float:\n",[1023,69140,69141],{"class":1362,"line":68},[1023,69142,69143],{},"    \"\"\"w_cross * số giao cắt\n",[1023,69145,69146],{"class":1362,"line":73},[1023,69147,69148],{},"     + w_len   * tổng (độ dài cạnh - ideal)^2\n",[1023,69150,69151],{"class":1362,"line":78},[1023,69152,69153],{},"     + w_close * số cặp đỉnh gần hơn min_dist\"\"\"\n",[1023,69155,69156],{"class":1362,"line":83},[1023,69157,69158],{},"def delta_move(G, pos, v, new_xy, ...) -> float:\n",[1023,69160,69161],{"class":1362,"line":88},[1023,69162,69163],{},"    \"\"\"Chỉ tính lại phần cost liên quan tới đỉnh v, không tính lại toàn bộ.\"\"\"\n",[1352,69165,69168],{"className":69166,"code":69167,"language":2241,"meta":1357},[2239],"Vòng 4 đỉnh xếp gấp chéo -> 1 giao cắt; xếp hình vuông -> 0\ndelta_move khớp cost(sau) - cost(trước) trên 1000 lần dời ngẫu nhiên\n",[992,69169,69167],{"__ignoreMap":1357},[981,69171,69173],{"id":69172},"bài-2-sa-vẽ-đồ-thị","Bài 2: SA vẽ đồ thị",[2273,69175,69176,69179,69182],{},[989,69177,69178],{},"Láng giềng: dời 1 đỉnh ngẫu nhiên một đoạn tỉ lệ với nhiệt độ hiện tại (nóng dời xa, nguội dời gần).",[989,69180,69181],{},"Chạy trên: vòng 4 đỉnh gấp chéo, lưới 5x5 xáo trộn, cây nhị phân 31 đỉnh, Karate Club.",[989,69183,69184],{},"Mỗi đồ thị chạy 5 seed, giữ tranh tốt nhất. In số giao cắt và vẽ trước\u002Fsau.",[981,69186,69188],{"id":69187},"bài-3-kết-hợp-và-so-sánh-nâng-cao","Bài 3: Kết hợp và so sánh (nâng cao)",[1352,69190,69193],{"className":69191,"code":69192,"language":2241,"meta":1357},[2239],"đồ_thị      spring_layout   force(ngày 112)   SA_từ_ngẫu_nhiên   force_rồi_SA   thời_gian\nlưới 5x5    ...\ncây 31      ...\nKarate      ...\n",[992,69194,69192],{"__ignoreMap":1357},[2273,69196,69197,69200,69203],{},[989,69198,69199],{},"Chiến lược \"force rồi SA\": chạy force-directed trước, rồi SA ở nhiệt độ thấp để nắn giao cắt.",[989,69201,69202],{},"Vẽ cost theo bước của SA. Chỉ ra đoạn cost tăng tạm thời.",[989,69204,69205,69206,1656,69209,1656,69212,69215],{},"Tinh chỉnh trọng số ",[992,69207,69208],{},"w_cross",[992,69210,69211],{},"w_len",[992,69213,69214],{},"w_close",". Mô tả ảnh hưởng của mỗi trọng số lên bức vẽ.",[981,69217,2711],{"id":2710},[986,69219,69221,69230,69236,69242],{"className":69220},[2715],[989,69222,69224,2308,69226,69229],{"className":69223},[2719],[2721,69225],{"disabled":2723,"type":2724},[992,69227,69228],{},"delta_move"," khớp tính lại toàn bộ.",[989,69231,69233,69235],{"className":69232},[2719],[2721,69234],{"disabled":2723,"type":2724}," Vòng 4 đỉnh gấp chéo được bung ra thành hình vuông.",[989,69237,69239,69241],{"className":69238},[2719],[2721,69240],{"disabled":2723,"type":2724}," Bảng so sánh 4 cách có số thật và hình trước\u002Fsau.",[989,69243,69245,69247],{"className":69244},[2719],[2721,69246],{"disabled":2723,"type":2724}," Giải thích ảnh hưởng của 3 trọng số.",[968,69249,2890],{"id":2889},[986,69251,69252,69255,69258,69261],{},[989,69253,69254],{},"Cost vẽ đồ thị gồm những số hạng nào?",[989,69256,69257],{},"Đếm giao cắt khác vẽ hướng lực ở điểm gì?",[989,69259,69260],{},"Lúc nóng và lúc nguội dịch đỉnh khác nhau thế nào?",[989,69262,69263],{},"Vì sao phải chấp nhận xấu tạm mới thoát bố cục rối?",[3014,69265],{},[973,69267,69268],{},"🌕 Bạn đã hoàn thành ngày 121. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,69270,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":69272},[69273,69274,69279,69280,69286],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":69275},[69276,69277,69278],{"id":68973,"depth":73,"text":68974},{"id":68991,"depth":73,"text":68992},{"id":69056,"depth":73,"text":69057},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":69281},[69282,69283,69284,69285],{"id":69127,"depth":73,"text":69128},{"id":69172,"depth":73,"text":69173},{"id":69187,"depth":73,"text":69188},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Ủ nhiệt cho nhúng đồ thị, tối thiểu giao cắt cạnh và vẽ hướng lực cho sơ đồ đẹp.",{},[15144],{"title":660,"description":69287},[47532,29786],"FCpbRLEDc4CXvXk4VdzzN2iOLFlGpRYnV17C9iOI41w",{"id":69294,"title":665,"body":69295,"category":8797,"day":668,"description":69639,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":69640,"navigation":2723,"outcomes":3047,"path":666,"prerequisites":69641,"seo":69642,"stem":667,"tags":69643,"__hash__":69644},"challenges\u002Fchallenges\u002F122.genetic-nang-cao.md",{"type":965,"value":69296,"toc":69623},[69297,69299,69302,69304,69308,69322,69326,69340,69344,69358,69405,69407,69432,69434,69442,69446,69503,69509,69513,69516,69522,69528,69532,69565,69571,69573,69602,69604,69618,69620],[968,69298,971],{"id":970},[973,69300,69301],{},"Bài này học thuật toán di truyền với lai và đột biến. Dùng nó để tìm đường đi ngắn và tập đỉnh phủ rẻ.",[968,69303,979],{"id":978},[981,69305,69307],{"id":69306},"lai-và-đột-biến-là-gì","Lai và đột biến là gì",[986,69309,69310,69313,69316,69319],{},[989,69311,69312],{},"Lai là trộn gen 2 bố mẹ thành con.",[989,69314,69315],{},"Đột biến là sửa nhỏ ngẫu nhiên để giữ đa dạng.",[989,69317,69318],{},"Ví dụ đời thường: con lấy mắt bố, mũi mẹ, thêm nốt ruồi riêng.",[989,69320,69321],{},"Lai giúp hội tụ nhanh, đột biến giúp khỏi kẹt sớm.",[981,69323,69325],{"id":69324},"lai-cho-tsp-dạng-hoán-vị","Lai cho TSP dạng hoán vị",[986,69327,69328,69331,69334,69337],{},[989,69329,69330],{},"TSP là tour thăm mỗi thành phố đúng 1 lần.",[989,69332,69333],{},"Lai cắt đơn hay tạo tour trùng và thiếu thành phố.",[989,69335,69336],{},"Lai OX giữ 1 đoạn của bố, điền phần còn lại theo thứ tự mẹ.",[989,69338,69339],{},"Ví dụ: bố 1-2-3-4, mẹ 4-3-2-1, con vẫn đủ 4 thành phố.",[981,69341,69343],{"id":69342},"ga-cho-phủ-đỉnh-dạng-bit","GA cho phủ đỉnh dạng bit",[986,69345,69346,69349,69352,69355],{},[989,69347,69348],{},"Phủ đỉnh là chọn ít đỉnh sao cho mọi cạnh đều chạm đỉnh chọn.",[989,69350,69351],{},"Mã hóa bit: 1 là chọn đỉnh, 0 là bỏ.",[989,69353,69354],{},"Fitness = số đỉnh chọn + phạt nặng mỗi cạnh hở.",[989,69356,69357],{},"Ví dụ đời thường: đặt camera sao cho mọi hành lang đều có camera soi.",[1099,69359,69360,69375],{},[1102,69361,69362],{},[1105,69363,69364,69366,69369,69372],{},[1108,69365,30679],{},[1108,69367,69368],{},"Mã hóa",[1108,69370,69371],{},"Lai hợp lệ",[1108,69373,69374],{},"Đột biến",[1118,69376,69377,69391],{},[1105,69378,69379,69382,69385,69388],{},[1123,69380,69381],{},"TSP",[1123,69383,69384],{},"Hoán vị",[1123,69386,69387],{},"OX, PMX",[1123,69389,69390],{},"Đổi 2 thành phố",[1105,69392,69393,69396,69399,69402],{},[1123,69394,69395],{},"Phủ đỉnh",[1123,69397,69398],{},"Chuỗi bit",[1123,69400,69401],{},"Lai 1 điểm, lai đều",[1123,69403,69404],{},"Lật 1 bit",[968,69406,1433],{"id":1432},[986,69408,69409,69423,69426,69429],{},[989,69410,69411,69412,1509,69415,69418,69419,69422],{},"Input: 2 tour cha ",[1023,69413,69414],{},"1 2 3 4 5",[1023,69416,69417],{},"5 4 3 2 1",". Output: con OX ",[1023,69420,69421],{},"1 2 3 5 4"," hợp lệ đủ 5 thành phố.",[989,69424,69425],{},"Giải thích: con giữ khung tốt của bố mà không trùng thiếu.",[989,69427,69428],{},"Input: phủ đỉnh 4 nút hình vuông, nghiệm 1010. Output: fitness = 2 đỉnh + 0 phạt = 2.",[989,69430,69431],{},"Giải thích: 2 đỉnh đối nhau đã phủ hết 4 cạnh.",[968,69433,1482],{"id":1481},[973,69435,1485,69436,69438,69439,1517],{},[1487,69437,13531],{}," với NumPy (hoặc C++). Dùng khung GA ngày 115. Nộp vào ",[992,69440,69441],{},"day-122\u002F",[981,69443,69445],{"id":69444},"bài-1-toán-tử-lai-và-đột-biến-cho-hoán-vị","Bài 1: Toán tử lai và đột biến cho hoán vị",[1099,69447,69448,69456],{},[1102,69449,69450],{},[1105,69451,69452,69454],{},[1108,69453,66744],{},[1108,69455,2547],{},[1118,69457,69458,69468,69478,69488],{},[1105,69459,69460,69465],{},[1123,69461,69462],{},[992,69463,69464],{},"order_crossover(p1, p2, rng)",[1123,69466,69467],{},"OX",[1105,69469,69470,69475],{},[1123,69471,69472],{},[992,69473,69474],{},"pmx(p1, p2, rng)",[1123,69476,69477],{},"Partially Mapped Crossover",[1105,69479,69480,69485],{},[1123,69481,69482],{},[992,69483,69484],{},"edge_recombination(p1, p2, rng)",[1123,69486,69487],{},"Giữ cạnh chung của 2 cha",[1105,69489,69490,69501],{},[1123,69491,69492,1656,69495,1656,69498],{},[992,69493,69494],{},"swap_mutation",[992,69496,69497],{},"inversion_mutation",[992,69499,69500],{},"scramble_mutation",[1123,69502],{},[1352,69504,69507],{"className":69505,"code":69506,"language":2241,"meta":1357},[2239],"OX: cha [1 2 3 4 5], mẹ [5 4 3 2 1], đoạn cắt vị trí 0..2 -> con [1 2 3 5 4]\nMọi toán tử luôn trả hoán vị hợp lệ (test 10.000 lần mỗi toán tử)\n",[992,69508,69506],{"__ignoreMap":1357},[981,69510,69512],{"id":69511},"bài-2-so-toán-tử-trên-tsp","Bài 2: So toán tử trên TSP",[973,69514,69515],{},"Chạy GA trên berlin52, cùng số lần tính fitness (ví dụ 200.000).",[1352,69517,69520],{"className":69518,"code":69519,"language":2241,"meta":1357},[2239],"lai       đột_biến     best     trung_bình_10_lần   độ_lệch\nOX        inversion    ...\nPMX       inversion    ...\nERX       inversion    ...\nOX        swap         ...\n",[992,69521,69519],{"__ignoreMap":1357},[973,69523,5030,69524,69527],{},[1487,69525,69526],{},"memetic",": sau khi tạo con, chạy 2-opt cục bộ vài bước. So với GA thường.",[981,69529,69531],{"id":69530},"bài-3-ga-cho-phủ-đỉnh-nâng-cao","Bài 3: GA cho phủ đỉnh (nâng cao)",[2273,69533,69534,69541,69547,69558],{},[989,69535,69536,69537,69540],{},"Mã hóa bit. Fitness (tối thiểu hóa) = số đỉnh chọn + ",[992,69538,69539],{},"penalty"," × số cạnh chưa phủ.",[989,69542,5030,69543,69546],{},[1487,69544,69545],{},"toán tử sửa",": với mỗi cạnh chưa phủ, chọn thêm đỉnh có bậc lớn hơn.",[989,69548,69549,69550],{},"Chạy trên đồ thị ngẫu nhiên 100 đỉnh, 300 cạnh. So với:\n",[986,69551,69552,69555],{},[989,69553,69554],{},"Tham lam: lặp chọn đỉnh bậc lớn nhất.",[989,69556,69557],{},"Xấp xỉ 2: lấy cả 2 đầu của một cặp ghép cực đại.",[989,69559,69560,69561,69564],{},"Với đồ thị nhỏ (",[992,69562,69563],{},"n = 20","), so với nghiệm tối ưu vét cạn.",[1352,69566,69569],{"className":69567,"code":69568,"language":2241,"meta":1357},[2239],"Hình vuông 4 đỉnh, nghiệm 1010 -> 2 đỉnh, 0 cạnh hở, fitness = 2\n",[992,69570,69568],{"__ignoreMap":1357},[981,69572,2711],{"id":2710},[986,69574,69576,69582,69588,69596],{"className":69575},[2715],[989,69577,69579,69581],{"className":69578},[2719],[2721,69580],{"disabled":2723,"type":2724}," Mọi toán tử ra hoán vị hợp lệ.",[989,69583,69585,69587],{"className":69584},[2719],[2721,69586],{"disabled":2723,"type":2724}," Bảng toán tử trên berlin52 và kết quả memetic.",[989,69589,69591,69593,69594,1517],{"className":69590},[2719],[2721,69592],{"disabled":2723,"type":2724}," Phủ đỉnh: bảng GA vs tham lam vs xấp xỉ 2, và so tối ưu ở ",[992,69595,69563],{},[989,69597,69599,69601],{"className":69598},[2719],[2721,69600],{"disabled":2723,"type":2724}," Giải thích vì sao lai cắt 1 điểm không dùng được cho hoán vị.",[968,69603,2890],{"id":2889},[986,69605,69606,69609,69612,69615],{},[989,69607,69608],{},"Lai OX khác lai cắt đơn ở điểm gì?",[989,69610,69611],{},"Đột biến giữ vai trò gì trong GA?",[989,69613,69614],{},"Fitness cho TSP và phủ đỉnh tính thế nào?",[989,69616,69617],{},"Khi nào GA hợp hơn SA và gradient?",[3014,69619],{},[973,69621,69622],{},"🌕 Bạn đã hoàn thành ngày 122. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":69624},[69625,69626,69631,69632,69638],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":69627},[69628,69629,69630],{"id":69306,"depth":73,"text":69307},{"id":69324,"depth":73,"text":69325},{"id":69342,"depth":73,"text":69343},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":69633},[69634,69635,69636,69637],{"id":69444,"depth":73,"text":69445},{"id":69511,"depth":73,"text":69512},{"id":69530,"depth":73,"text":69531},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Toán tử lai đột biến, GA cho TSP và phủ đỉnh tối thiểu, chỉnh tham số và ứng dụng xa hơn.",{},[15143],{"title":665,"description":69639},[66930],"vbjbu0E2AcYuFuZkWgwTjq6UGOJqcRXJAc9PtBKnhxY",{"id":69646,"title":670,"body":69647,"category":5189,"day":673,"description":70091,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":70092,"navigation":2723,"outcomes":3047,"path":671,"prerequisites":70093,"seo":70094,"stem":672,"tags":70095,"__hash__":70098},"challenges\u002Fchallenges\u002F123.proxy-dynamic.md",{"type":965,"value":69648,"toc":70075},[69649,69651,69654,69656,69660,69674,69678,69692,69696,69699,69760,69765,69813,69815,69829,69831,69849,69853,69879,69935,69946,69952,69956,69969,69983,69987,69990,70020,70023,70025,70052,70054,70068,70070,70073],[968,69650,971],{"id":970},[973,69652,69653],{},"Bài này học proxy đứng giữa để kiểm tra quyền. Hiểu rồi bạn sẽ phân quyền gọn mà ít code.",[968,69655,979],{"id":978},[981,69657,69659],{"id":69658},"dynamic-proxy-là-gì","Dynamic proxy là gì",[986,69661,69662,69665,69668,69671],{},[989,69663,69664],{},"Dynamic proxy là đại diện do hệ thống sinh lúc chạy.",[989,69666,69667],{},"Bạn chỉ viết 1 bộ xử lý chung, hệ thống tự đúc lớp.",[989,69669,69670],{},"Ví dụ đời thường: 1 con dấu dùng chung cho nhiều loại đơn.",[989,69672,69673],{},"Thêm giao diện mới chỉ cần gắn bộ xử lý vào.",[981,69675,69677],{"id":69676},"protection-proxy-phân-quyền","Protection proxy phân quyền",[986,69679,69680,69683,69686,69689],{},[989,69681,69682],{},"Protection proxy kiểm tra quyền trước mỗi cuộc gọi.",[989,69684,69685],{},"Chính chủ được sửa thông tin, cấm tự sửa điểm đánh giá.",[989,69687,69688],{},"Người yêu được sửa đánh giá, cấm sửa thông tin người khác.",[989,69690,69691],{},"Ví dụ đời thường: lễ tân chỉ cho khách vào phòng của mình.",[981,69693,69695],{"id":69694},"vườn-thú-proxy","Vườn thú proxy",[973,69697,69698],{},"Ba loại đã học: Remote (đại diện máy ở xa), Virtual (hoãn tạo đối tượng nặng), Protection (kiểm tra quyền). Sách Head First kể thêm 6 loại:",[1099,69700,69701,69710],{},[1102,69702,69703],{},[1105,69704,69705,69708],{},[1108,69706,69707],{},"Proxy",[1108,69709,61474],{},[1118,69711,69712,69720,69728,69736,69744,69752],{},[1105,69713,69714,69717],{},[1123,69715,69716],{},"Firewall",[1123,69718,69719],{},"Chặn truy cập mạng từ nguồn không tin cậy",[1105,69721,69722,69725],{},[1123,69723,69724],{},"Smart Reference",[1123,69726,69727],{},"Làm thêm việc mỗi lần truy cập, ví dụ đếm số tham chiếu",[1105,69729,69730,69733],{},[1123,69731,69732],{},"Caching",[1123,69734,69735],{},"Lưu kết quả tốn kém để trả lại nhanh, là một dạng Virtual proxy",[1105,69737,69738,69741],{},[1123,69739,69740],{},"Synchronization",[1123,69742,69743],{},"Cho nhiều luồng truy cập đối tượng an toàn",[1105,69745,69746,69749],{},[1123,69747,69748],{},"Complexity Hiding",[1123,69750,69751],{},"Che hệ phức tạp như Facade, nhưng vẫn kiểm soát truy cập",[1105,69753,69754,69757],{},[1123,69755,69756],{},"Copy-On-Write",[1123,69758,69759],{},"Hoãn sao chép tới khi có người sửa, dạng biến thể của Virtual proxy",[986,69761,69762],{},[989,69763,69764],{},"Ví dụ đời thường: mỗi loại như 1 kiểu bảo vệ khác nhau.",[1099,69766,69767,69779],{},[1102,69768,69769],{},[1105,69770,69771,69773,69776],{},[1108,69772,14526],{},[1108,69774,69775],{},"Viết tay",[1108,69777,69778],{},"Sinh động",[1118,69780,69781,69792,69802],{},[1105,69782,69783,69786,69789],{},[1123,69784,69785],{},"Số lớp",[1123,69787,69788],{},"1 lớp cho 1 giao diện",[1123,69790,69791],{},"1 bộ xử lý cho nhiều giao diện",[1105,69793,69794,69796,69799],{},[1123,69795,44405],{},[1123,69797,69798],{},"Viết thêm lớp",[1123,69800,69801],{},"Gắn vào là xong",[1105,69803,69804,69807,69810],{},[1123,69805,69806],{},"Gỡ lỗi",[1123,69808,69809],{},"Dễ đọc",[1123,69811,69812],{},"Khó hơn vì sinh lúc chạy",[968,69814,1433],{"id":1432},[986,69816,69817,69820,69823,69826],{},[989,69818,69819],{},"Input: chính chủ gọi setRating(10) cho chính mình. Output: bị chặn, điểm giữ nguyên.",[989,69821,69822],{},"Giải thích: protection proxy cấm tự chấm điểm cho mình.",[989,69824,69825],{},"Input: người yêu gọi setRating(9). Output: cho qua và lưu thành công.",[989,69827,69828],{},"Giải thích: đúng vai trò nên được chuyển lời tới hồ sơ thật.",[968,69830,1482],{"id":1481},[973,69832,1485,69833,56503,69836,69839,69840,56503,69842,69845,69846,1517],{},[1487,69834,69835],{},"Java",[992,69837,69838],{},"java.lang.reflect.Proxy",") hoặc ",[1487,69841,64499],{},[992,69843,69844],{},"__getattr__","). C++ không có dynamic proxy sẵn. Nộp vào ",[992,69847,69848],{},"day-123\u002F",[981,69850,69852],{"id":69851},"bài-1-protection-proxy-cho-hồ-sơ-hẹn-hò","Bài 1: Protection proxy cho hồ sơ hẹn hò",[1352,69854,69858],{"className":69855,"code":69856,"language":69857,"meta":1357,"style":1357},"language-java shiki shiki-themes github-light github-light github-dark","interface Person {\n  String getName(); String getGender(); String getInterests(); int getGeekRating();\n  void setName(String n); void setGender(String g); void setInterests(String i); void setGeekRating(int r);\n}\n","java",[992,69859,69860,69865,69870,69875],{"__ignoreMap":1357},[1023,69861,69862],{"class":1362,"line":63},[1023,69863,69864],{},"interface Person {\n",[1023,69866,69867],{"class":1362,"line":68},[1023,69868,69869],{},"  String getName(); String getGender(); String getInterests(); int getGeekRating();\n",[1023,69871,69872],{"class":1362,"line":73},[1023,69873,69874],{},"  void setName(String n); void setGender(String g); void setInterests(String i); void setGeekRating(int r);\n",[1023,69876,69877],{"class":1362,"line":78},[1023,69878,4986],{},[1099,69880,69881,69894],{},[1102,69882,69883],{},[1105,69884,69885,69888,69891],{},[1108,69886,69887],{},"Handler",[1108,69889,69890],{},"Được phép",[1108,69892,69893],{},"Bị chặn",[1118,69895,69896,69917],{},[1105,69897,69898,69903,69912],{},[1123,69899,69900],{},[992,69901,69902],{},"OwnerInvocationHandler",[1123,69904,69905,69906,1656,69908,69911],{},"mọi ",[992,69907,28507],{},[992,69909,69910],{},"set"," thông tin của mình",[1123,69913,69914],{},[992,69915,69916],{},"setGeekRating",[1105,69918,69919,69924,69930],{},[1123,69920,69921],{},[992,69922,69923],{},"NonOwnerInvocationHandler",[1123,69925,69905,69926,1656,69928],{},[992,69927,28507],{},[992,69929,69916],{},[1123,69931,69905,69932,69934],{},[992,69933,69910],{}," khác",[973,69936,69937,69938,69941,69942,69945],{},"Bị chặn thì ném ",[992,69939,69940],{},"IllegalAccessException"," (bọc trong ",[992,69943,69944],{},"UndeclaredThrowableException"," với Java).",[1352,69947,69950],{"className":69948,"code":69949,"language":2241,"meta":1357},[2239],"owner.setInterests(\"leo núi\")   -> thành công\nowner.setGeekRating(10)         -> bị chặn, điểm không đổi\nother.setGeekRating(9)          -> thành công, điểm trung bình cập nhật\nother.setName(\"X\")              -> bị chặn\n",[992,69951,69949],{"__ignoreMap":1357},[981,69953,69955],{"id":69954},"bài-2-proxy-dùng-chung-cho-nhiều-interface","Bài 2: Proxy dùng chung cho nhiều interface",[973,69957,69958,69959,67209,69962,69965,69966,1517],{},"Viết 1 handler ",[992,69960,69961],{},"LoggingHandler",[992,69963,69964],{},"\"[time] Interface.method(args) -> result (ms)\""," và 1 hàm ",[992,69967,69968],{},"wrap(Object target, Class\u003C?>... interfaces)",[973,69970,69971,69972,1656,69975,69978,69979,69982],{},"Bọc 3 đối tượng khác interface: ",[992,69973,69974],{},"Person",[992,69976,69977],{},"GumballMachineRemote"," (ngày 98), ",[992,69980,69981],{},"WeatherService"," (ngày 98). Không viết lớp proxy riêng nào.",[981,69984,69986],{"id":69985},"bài-3-vườn-thú-proxy-nâng-cao","Bài 3: Vườn thú proxy (nâng cao)",[973,69988,69989],{},"Viết thêm và kết hợp:",[2273,69991,69992,70001,70007,70013],{},[989,69993,69994,69997,69998,70000],{},[992,69995,69996],{},"CachingHandler",": nhớ kết quả các phương thức ",[992,69999,28507],{}," trong 5 giây.",[989,70002,70003,70006],{},[992,70004,70005],{},"RetryHandler",": phương thức ném lỗi mạng thì thử lại tối đa 3 lần.",[989,70008,70009,70012],{},[992,70010,70011],{},"TimingHandler",": cảnh báo khi phương thức chạy quá 100 ms.",[989,70014,70015,70016,70019],{},"Chồng ",[992,70017,70018],{},"Logging(Retry(Caching(target)))",". Viết test cho thứ tự: lỗi lần 1, thành công lần 2, lần gọi sau lấy từ cache.",[973,70021,70022],{},"Viết bảng tổng hợp các loại proxy đã học: remote, virtual, protection, caching, logging, retry. Mỗi loại 1 dòng mục đích và 1 ví dụ thật.",[981,70024,2711],{"id":2710},[986,70026,70028,70034,70040,70046],{"className":70027},[2715],[989,70029,70031,70033],{"className":70030},[2719],[2721,70032],{"disabled":2723,"type":2724}," Test quyền Bài 1 pass.",[989,70035,70037,70039],{"className":70036},[2719],[2721,70038],{"disabled":2723,"type":2724}," 1 handler bọc được 3 interface khác nhau.",[989,70041,70043,70045],{"className":70042},[2719],[2721,70044],{"disabled":2723,"type":2724}," Test chồng 3 handler đúng thứ tự hành vi.",[989,70047,70049,70051],{"className":70048},[2719],[2721,70050],{"disabled":2723,"type":2724}," Bảng 6 loại proxy.",[968,70053,2890],{"id":2889},[986,70055,70056,70059,70062,70065],{},[989,70057,70058],{},"Dynamic proxy khác proxy viết tay ở điểm gì?",[989,70060,70061],{},"Protection proxy phân quyền chính chủ và người yêu thế nào?",[989,70063,70064],{},"Kể tên 4 trong 8 loại proxy?",[989,70066,70067],{},"Khi nào nên dùng proxy động?",[3014,70069],{},[973,70071,70072],{},"🌕 Bạn đã hoàn thành ngày 123. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,70074,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":70076},[70077,70078,70083,70084,70090],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":70079},[70080,70081,70082],{"id":69658,"depth":73,"text":69659},{"id":69676,"depth":73,"text":69677},{"id":69694,"depth":73,"text":69695},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":70085},[70086,70087,70088,70089],{"id":69851,"depth":73,"text":69852},{"id":69954,"depth":73,"text":69955},{"id":69985,"depth":73,"text":69986},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đại diện tạo động lúc chạy, bảo vệ theo vai trò người dùng, và bản đồ tám loại proxy trong bài này.",{},[5194],{"title":670,"description":70091},[58102,70096,70097],"dynamic-proxy","protection","oYD88jEB2BSAsy59rQPA9Zg65xZBGim6nRJaM2K9Po0",{"id":70100,"title":675,"body":70101,"category":5189,"day":678,"description":70504,"difficulty":68559,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":70505,"navigation":2723,"outcomes":3047,"path":676,"prerequisites":70506,"seo":70507,"stem":677,"tags":70508,"__hash__":70511},"challenges\u002Fchallenges\u002F124.interpreter-visitor.md",{"type":965,"value":70102,"toc":70488},[70103,70105,70108,70110,70114,70128,70132,70146,70150,70164,70201,70203,70217,70219,70227,70231,70234,70240,70307,70313,70316,70320,70329,70332,70391,70395,70407,70434,70436,70465,70467,70481,70483,70486],[968,70104,971],{"id":970},[973,70106,70107],{},"Bài này học thông dịch lệnh đơn giản và thêm việc mới. Hai mẫu này giúp code gọn khi yêu cầu đổi liên tục.",[968,70109,979],{"id":978},[981,70111,70113],{"id":70112},"interpreter-là-gì","Interpreter là gì",[986,70115,70116,70119,70122,70125],{},[989,70117,70118],{},"Interpreter diễn giải ngôn ngữ nhỏ thành hành động.",[989,70120,70121],{},"Mỗi quy tắc ngữ pháp là 1 lớp nút trong cây.",[989,70123,70124],{},"Ví dụ đời thường: đọc công thức nấu ăn rồi làm từng bước.",[989,70126,70127],{},"Câu lệnh lặp 4 lần tiến 10 bước thành cây có nút lặp và nút tiến.",[981,70129,70131],{"id":70130},"diễn-giải-bằng-đệ-quy","Diễn giải bằng đệ quy",[986,70133,70134,70137,70140,70143],{},[989,70135,70136],{},"Diễn giải là gọi đệ quy từ gốc xuống lá.",[989,70138,70139],{},"Nút lặp gọi lại cây con đúng số lần.",[989,70141,70142],{},"Nút tiến đi thẳng, nút quay xoay đúng độ.",[989,70144,70145],{},"Ví dụ: lặp 4 lần tiến rồi quay tạo hình vuông.",[981,70147,70149],{"id":70148},"visitor-là-gì","Visitor là gì",[986,70151,70152,70155,70158,70161],{},[989,70153,70154],{},"Visitor mang việc mới tới cấu trúc đã chốt.",[989,70156,70157],{},"Thêm việc chỉ cần thêm khách mới, cấu trúc giữ nguyên.",[989,70159,70160],{},"Ví dụ đời thường: đoàn kiểm tra tới từng phòng, phòng không đổi.",[989,70162,70163],{},"Kỹ thuật gọi kép: phần tử gọi ngược khách đúng kiểu của mình.",[1099,70165,70166,70178],{},[1102,70167,70168],{},[1105,70169,70170,70172,70175],{},[1108,70171,14526],{},[1108,70173,70174],{},"Thêm việc mới",[1108,70176,70177],{},"Thêm phần tử mới",[1118,70179,70180,70190],{},[1105,70181,70182,70185,70188],{},[1123,70183,70184],{},"Nhồi vào cấu trúc",[1123,70186,70187],{},"Mở hết mọi lớp",[1123,70189,51389],{},[1105,70191,70192,70195,70198],{},[1123,70193,70194],{},"Visitor",[1123,70196,70197],{},"Thêm 1 khách mới",[1123,70199,70200],{},"Sửa hết khách cũ",[968,70202,1433],{"id":1432},[986,70204,70205,70208,70211,70214],{},[989,70206,70207],{},"Input: cây lặp 4 lần tiến 10 quay 90. Output: rùa vẽ hình vuông khép kín.",[989,70209,70210],{},"Giải thích: mỗi nút chỉ làm việc của mình, đệ quy lo phần còn lại.",[989,70212,70213],{},"Input: khách thuế thăm 3 phần tử cư dân, doanh nghiệp, nhà hàng. Output: mỗi kiểu tính đúng công thức riêng.",[989,70215,70216],{},"Giải thích: gọi kép chọn đúng việc cho đúng kiểu.",[968,70218,1482],{"id":1481},[973,70220,1485,70221,70223,70224,1517],{},[1487,70222,4800],{}," (hoặc Java\u002FPython). Nộp vào ",[992,70225,70226],{},"day-124\u002F",[981,70228,70230],{"id":70229},"bài-1-interpreter-cho-ngôn-ngữ-rùa","Bài 1: Interpreter cho ngôn ngữ rùa",[973,70232,70233],{},"Ngữ pháp:",[1352,70235,70238],{"className":70236,"code":70237,"language":2241,"meta":1357},[2239],"program  := command*\ncommand  := \"tien\" NUMBER | \"quay\" NUMBER | \"lap\" NUMBER \"[\" command* \"]\"\n",[992,70239,70237],{"__ignoreMap":1357},[1099,70241,70242,70250],{},[1102,70243,70244],{},[1105,70245,70246,70248],{},[1108,70247,2544],{},[1108,70249,2547],{},[1118,70251,70252,70266,70289],{},[1105,70253,70254,70259],{},[1123,70255,70256],{},[992,70257,70258],{},"Lexer",[1123,70260,70261,70262,1656,70264],{},"Tách token: từ khóa, số, ",[992,70263,14806],{},[992,70265,14817],{},[1105,70267,70268,70273],{},[1123,70269,70270],{},[992,70271,70272],{},"Parser",[1123,70274,70275,70276,1656,70279,1656,70282,1656,70285,70288],{},"Đệ quy xuống, dựng cây ",[992,70277,70278],{},"Program",[992,70280,70281],{},"Forward",[992,70283,70284],{},"Turn",[992,70286,70287],{},"Repeat",". Lỗi cú pháp báo dòng và cột",[1105,70290,70291,70296],{},[1123,70292,70293],{},[992,70294,70295],{},"interpret(Context&)",[1123,70297,70298,70299,70302,70303,70306],{},"Mỗi nút tự diễn giải. ",[992,70300,70301],{},"Context"," giữ vị trí ",[992,70304,70305],{},"(x, y)",", hướng, danh sách đoạn thẳng đã vẽ",[1352,70308,70311],{"className":70309,"code":70310,"language":2241,"meta":1357},[2239],"\"lap 4 [ tien 10 quay 90 ]\"          -> 4 đoạn, quay về (0, 0)\n\"lap 36 [ lap 4 [ tien 5 quay 90 ] quay 10 ]\" -> 144 đoạn\n\"lap 4 [ tien 10\"                    -> lỗi cú pháp: thiếu \"]\" ở dòng 1\n",[992,70312,70310],{"__ignoreMap":1357},[973,70314,70315],{},"Xuất đường vẽ ra file SVG.",[981,70317,70319],{"id":70318},"bài-2-visitor-cho-cây-cú-pháp","Bài 2: Visitor cho cây cú pháp",[1352,70321,70323],{"className":1393,"code":70322,"language":1395,"meta":1357,"style":1357},"struct Visitor { virtual void visit(Forward&) = 0; virtual void visit(Turn&) = 0; virtual void visit(Repeat&) = 0; virtual void visit(Program&) = 0; };\n",[992,70324,70325],{"__ignoreMap":1357},[1023,70326,70327],{"class":1362,"line":63},[1023,70328,70322],{},[973,70330,70331],{},"Viết 3 visitor mà không sửa lớp nút nào:",[1099,70333,70334,70342],{},[1102,70335,70336],{},[1105,70337,70338,70340],{},[1108,70339,70194],{},[1108,70341,61474],{},[1118,70343,70344,70354,70368],{},[1105,70345,70346,70351],{},[1123,70347,70348],{},[992,70349,70350],{},"PrettyPrinter",[1123,70352,70353],{},"In lại chương trình có thụt lề",[1105,70355,70356,70361],{},[1123,70357,70358],{},[992,70359,70360],{},"StepCounter",[1123,70362,70363,70364,70367],{},"Đếm tổng số lệnh ",[992,70365,70366],{},"tien"," thực sự chạy (tính cả lặp)",[1105,70369,70370,70375],{},[1123,70371,70372],{},[992,70373,70374],{},"Optimizer",[1123,70376,70377,70378,35512,70381,70384,70385,1509,70388],{},"Gộp ",[992,70379,70380],{},"tien a tien b",[992,70382,70383],{},"tien (a+b)",", bỏ ",[992,70386,70387],{},"quay 0",[992,70389,70390],{},"quay 360",[981,70392,70394],{"id":70393},"bài-3-visitor-tính-thuế-nâng-cao","Bài 3: Visitor tính thuế (nâng cao)",[973,70396,70397,70398,1656,70401,1656,70404,1517],{},"Cấu trúc: ",[992,70399,70400],{},"Resident(income)",[992,70402,70403],{},"Business(revenue, expenses)",[992,70405,70406],{},"Restaurant(revenue, alcoholRevenue)",[2273,70408,70409,70415,70421],{},[989,70410,70411,70414],{},[992,70412,70413],{},"TaxVisitor",": cư dân 10% thu nhập trên 11 triệu, doanh nghiệp 20% lợi nhuận, nhà hàng 8% doanh thu cộng 10% doanh thu rượu.",[989,70416,70417,70420],{},[992,70418,70419],{},"ReportVisitor"," in báo cáo từng đối tượng.",[989,70422,70423,70424,70427,70428,70430,70431,70433],{},"Thêm loại mới ",[992,70425,70426],{},"Farm",". Đếm số file phải sửa. Ghi vào ",[992,70429,2513],{},": đây là điểm yếu của Visitor (thêm kiểu khó, thêm việc dễ). So với cách dùng ",[992,70432,20909],{}," thường.",[981,70435,2711],{"id":2710},[986,70437,70439,70445,70451,70459],{"className":70438},[2715],[989,70440,70442,70444],{"className":70441},[2719],[2721,70443],{"disabled":2723,"type":2724}," 3 test Interpreter pass, có file SVG.",[989,70446,70448,70450],{"className":70447},[2719],[2721,70449],{"disabled":2723,"type":2724}," 3 visitor không sửa lớp nút.",[989,70452,70454,2308,70456,70458],{"className":70453},[2719],[2721,70455],{"disabled":2723,"type":2724},[992,70457,70374],{}," giữ nguyên hình vẽ (so đoạn thẳng trước và sau).",[989,70460,70462,70464],{"className":70461},[2719],[2721,70463],{"disabled":2723,"type":2724}," Bảng \"thêm kiểu\" và \"thêm việc\" giữa Visitor và virtual thường.",[968,70466,2890],{"id":2889},[986,70468,70469,70472,70475,70478],{},[989,70470,70471],{},"Interpreter biến câu lệnh thành cây thế nào?",[989,70473,70474],{},"Diễn giải đệ quy chạy từ đâu tới đâu?",[989,70476,70477],{},"Visitor thêm việc mới mà không sửa cấu trúc ra sao?",[989,70479,70480],{},"Khi nào Visitor thắng và khi nào thua?",[3014,70482],{},[973,70484,70485],{},"🌕 Bạn đã hoàn thành ngày 124. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,70487,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":70489},[70490,70491,70496,70497,70503],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":70492},[70493,70494,70495],{"id":70112,"depth":73,"text":70113},{"id":70130,"depth":73,"text":70131},{"id":70148,"depth":73,"text":70149},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":70498},[70499,70500,70501,70502],{"id":70229,"depth":73,"text":70230},{"id":70318,"depth":73,"text":70319},{"id":70393,"depth":73,"text":70394},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thông dịch cú pháp đơn giản bằng cây biểu thức, và khách thăm thêm việc mới cho cấu trúc ổn định của Visitor.",{},[5194,8149],{"title":675,"description":70504},[41703,70509,70510],"interpreter","visitor","3PIsGjEssbgY2SoO4ZJrJYxr7Ei-m0dN9UeGM1wJAbo",{"id":70513,"title":680,"body":70514,"category":5189,"day":683,"description":70845,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":70846,"navigation":2723,"outcomes":3047,"path":681,"prerequisites":70847,"seo":70848,"stem":682,"tags":70849,"__hash__":70850},"challenges\u002Fchallenges\u002F125.project-hometheater.md",{"type":965,"value":70515,"toc":70829},[70516,70518,70521,70523,70527,70541,70545,70559,70563,70577,70624,70626,70640,70642,70650,70654,70670,70679,70700,70704,70739,70745,70749,70775,70777,70808,70810,70824,70826],[968,70517,971],{"id":970},[973,70519,70520],{},"Bài này xây mặt tiền rạp hát 2 nút và remote mở tiệc. Làm xong bạn sẽ gom thao tác rối thành nút bấm gọn.",[968,70522,979],{"id":978},[981,70524,70526],{"id":70525},"đề-bài-rạp-hát","Đề bài rạp hát",[986,70528,70529,70532,70535,70538],{},[989,70530,70531],{},"Có 6 thiết bị: máy chiếu, màn, âm thanh, đầu đĩa, đèn, bỏng ngô.",[989,70533,70534],{},"Yêu cầu 1: xem phim chỉ còn 2 nút xem và kết thúc.",[989,70536,70537],{},"Yêu cầu 2: 1 nút mở tiệc bật cả phòng, 1 nút hoàn tác.",[989,70539,70540],{},"Ví dụ đời thường: 1 nút bấm mở cả rạp phim mini tại nhà.",[981,70542,70544],{"id":70543},"facade-gom-10-bước-thành-2-nút","Facade gom 10 bước thành 2 nút",[986,70546,70547,70550,70553,70556],{},[989,70548,70549],{},"Facade là mặt tiền gọi đúng thứ tự 10 bước giúp bạn.",[989,70551,70552],{},"Bấm xem: bật tuần tự từ bỏng ngô tới đầu đĩa rồi chạy.",[989,70554,70555],{},"Bấm kết thúc: tắt theo thứ tự ngược lại.",[989,70557,70558],{},"Cửa tinh chỉnh vẫn mở để người sành chỉnh tay từng máy.",[981,70560,70562],{"id":70561},"macro-và-hoàn-tác","Macro và hoàn tác",[986,70564,70565,70568,70571,70574],{},[989,70566,70567],{},"Macro giữ danh sách lệnh nhỏ, chạy tuần tự như 1 lệnh.",[989,70569,70570],{},"Mỗi lệnh nhỏ lưu trạng thái cũ trước khi chạy.",[989,70572,70573],{},"Hoàn tác chạy ngược thứ tự để trả về đúng ban đầu.",[989,70575,70576],{},"Ví dụ đời thường: 1 nút mở tiệc bật đèn nhạc máy lạnh cùng lúc.",[1099,70578,70579,70591],{},[1102,70580,70581],{},[1105,70582,70583,70585,70588],{},[1108,70584,5414],{},[1108,70586,70587],{},"Đạt",[1108,70589,70590],{},"Chưa đạt",[1118,70592,70593,70604,70614],{},[1105,70594,70595,70598,70601],{},[1123,70596,70597],{},"Mặt tiền",[1123,70599,70600],{},"2 nút đủ 10 bước đúng thứ tự",[1123,70602,70603],{},"Người dùng vẫn gọi thẳng máy",[1105,70605,70606,70608,70611],{},[1123,70607,49749],{},[1123,70609,70610],{},"Danh sách lệnh nhỏ chạy tuần tự",[1123,70612,70613],{},"1 lệnh khổng lồ ôm hết",[1105,70615,70616,70618,70621],{},[1123,70617,49778],{},[1123,70619,70620],{},"Lưu cũ, trả ngược thứ tự",[1123,70622,70623],{},"Đoán ngược không lưu gì",[968,70625,1433],{"id":1432},[986,70627,70628,70631,70634,70637],{},[989,70629,70630],{},"Input: bấm xem khi tất cả đang tắt. Output: 6 thiết bị lên đúng thứ tự, phim chạy.",[989,70632,70633],{},"Giải thích: mặt tiền gọi đủ 10 bước không sót bước nào.",[989,70635,70636],{},"Input: chạy macro mở tiệc rồi hoàn tác. Output: cuối cùng 6 máy về đúng trạng thái trước tiệc.",[989,70638,70639],{},"Giải thích: hoàn tác ngược thứ tự dùng trạng thái đã lưu.",[968,70641,1482],{"id":1481},[973,70643,1485,70644,70646,70647,1517],{},[1487,70645,4800],{}," (hoặc Java). Đây là project, dành 90 phút. Dùng lại code ngày 31 và 81. Nộp vào ",[992,70648,70649],{},"day-125-hometheater\u002F",[981,70651,70653],{"id":70652},"bài-1-facade-cho-rạp-hát","Bài 1: Facade cho rạp hát",[973,70655,70656,70657,1656,70659,1656,70661,1656,70663,1656,70665,1656,70667,70669],{},"6 thiết bị: ",[992,70658,24648],{},[992,70660,24634],{},[992,70662,24621],{},[992,70664,24605],{},[992,70666,24565],{},[992,70668,24586],{},". Mỗi thiết bị có trạng thái đọc được (bật\u002Ftắt, âm lượng, độ sáng...).",[973,70671,70672,1509,70675,70678],{},[992,70673,70674],{},"HomeTheaterFacade::watchMovie(movie)",[992,70676,70677],{},"endMovie()"," như ngày 31. Thêm:",[986,70680,70681,70687,70693],{},[989,70682,70683,70686],{},[992,70684,70685],{},"listenToMusic(playlist)",": chỉ bật đèn 60%, amp, player.",[989,70688,70689,70690,70692],{},"Gọi ",[992,70691,24703],{}," khi đang nghe nhạc: chuyển đúng, không bật lại thiết bị đang bật.",[989,70694,70695,70696,70699],{},"Người dùng vẫn gọi thẳng ",[992,70697,70698],{},"amp.setVolume(20)"," được.",[981,70701,70703],{"id":70702},"bài-2-macro-tiệc-có-hoàn-tác","Bài 2: Macro tiệc có hoàn tác",[2273,70705,70706,70714,70720],{},[989,70707,70708,13710,70710,70713],{},[992,70709,50025],{},[992,70711,70712],{},"MacroCommand"," gồm: đèn dim 30%, amp bật âm lượng 11, player bật playlist, bỏng ngô bật.",[989,70715,70716,70717,70719],{},"Mỗi lệnh nhỏ lưu trạng thái ",[1487,70718,50377],{}," khi chạy. Hoàn tác chạy ngược thứ tự và trả về đúng trạng thái đó.",[989,70721,70722,70723,70726,70727,1656,70730,1656,70733,27926,70736,70738],{},"Remote có 4 khe: ",[992,70724,70725],{},"movie"," (lệnh gọi Facade), ",[992,70728,70729],{},"music",[992,70731,70732],{},"party",[992,70734,70735],{},"off",[992,70737,49969],{}," nhiều bước.",[1352,70740,70743],{"className":70741,"code":70742,"language":2241,"meta":1357},[2239],"Trạng thái ban đầu: đèn 80%, amp tắt\npartyOn; undo -> đèn 80%, amp tắt (không phải \"đèn 100%\")\nmovie; party; undo; undo -> mọi thiết bị về trạng thái ban đầu\n",[992,70744,70742],{"__ignoreMap":1357},[981,70746,70748],{"id":70747},"bài-3-nhật-ký-và-báo-cáo-nâng-cao","Bài 3: Nhật ký và báo cáo (nâng cao)",[2273,70750,70751,70757,70767],{},[989,70752,70753,70754,70756],{},"Mọi lệnh bọc bằng ",[992,70755,22991],{}," (ngày 28). In nhật ký 1 buổi tối: 10 thao tác.",[989,70758,70759,70762,70763,2461,70765,1517],{},[992,70760,70761],{},"snapshot()"," của cả rạp trả chuỗi trạng thái 6 thiết bị. Test so snapshot trước và sau mỗi cặp ",[992,70764,49947],{},[992,70766,49969],{},[989,70768,1505,70769,70771,70772,70774],{},[992,70770,2513],{},": sơ đồ lớp, vai trò Facade và Command, và giải thích vì sao lệnh ",[992,70773,70725],{}," gọi Facade thay vì gọi 10 thiết bị.",[981,70776,2711],{"id":2710},[986,70778,70780,70786,70794,70800],{"className":70779},[2715],[989,70781,70783,70785],{"className":70782},[2719],[2721,70784],{"disabled":2723,"type":2724}," Test chuyển từ nghe nhạc sang xem phim không bật lại thiết bị.",[989,70787,70789,70791,70792,1517],{"className":70788},[2719],[2721,70790],{"disabled":2723,"type":2724}," Undo trả đúng trạng thái trước, kiểm bằng ",[992,70793,70761],{},[989,70795,70797,70799],{"className":70796},[2719],[2721,70798],{"disabled":2723,"type":2724}," Nhật ký 10 thao tác.",[989,70801,70803,2308,70805,70807],{"className":70802},[2719],[2721,70804],{"disabled":2723,"type":2724},[992,70806,2513],{}," có sơ đồ và giải thích.",[968,70809,2890],{"id":2889},[986,70811,70812,70815,70818,70821],{},[989,70813,70814],{},"Facade gom 10 bước thành 2 nút thế nào?",[989,70816,70817],{},"Macro chạy nhiều lệnh như 1 lệnh ra sao?",[989,70819,70820],{},"Hoàn tác đúng cần lưu gì?",[989,70822,70823],{},"Vì sao không dồn macro vào mặt tiền?",[3014,70825],{},[973,70827,70828],{},"🌕 Bạn đã hoàn thành ngày 125. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":70830},[70831,70832,70837,70838,70844],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":70833},[70834,70835,70836],{"id":70525,"depth":73,"text":70526},{"id":70543,"depth":73,"text":70544},{"id":70561,"depth":73,"text":70562},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":70839},[70840,70841,70842,70843],{"id":70652,"depth":73,"text":70653},{"id":70702,"depth":73,"text":70703},{"id":70747,"depth":73,"text":70748},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Đề xây mặt tiền rạp hát hai nút và remote macro mở tiệc có hoàn tác, kèm rubric chấm bốn mức.",{},[5194],{"title":680,"description":70845},[17502,24848,23084],"vBh0Isng8oikguNJum0zgaADCCEeXlWC1iwZsM5JPDU",{"id":70852,"title":685,"body":70853,"category":8797,"day":688,"description":71474,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":71475,"navigation":2723,"outcomes":3047,"path":686,"prerequisites":71476,"seo":71477,"stem":687,"tags":71478,"__hash__":71481},"challenges\u002Fchallenges\u002F126.app-autocomplete.md",{"type":965,"value":70854,"toc":71458},[70855,70857,70860,70862,70866,70925,70929,71008,71012,71069,71114,71116,71130,71132,71140,71144,71182,71317,71323,71327,71362,71365,71369,71394,71400,71402,71435,71437,71451,71453,71456],[968,70856,971],{"id":970},[973,70858,70859],{},"Bài này xây app gợi ý từ khi gõ phím. Gõ vài chữ là thấy từ cần tìm ngay.",[968,70861,979],{"id":978},[981,70863,70865],{"id":70864},"trie-lưu-từ-điển","Trie lưu từ điển",[986,70867,70868,70871,70874,70877],{},[989,70869,70870],{},"Trie là cây chia sẻ tiền tố, tra prefix rất nhanh.",[989,70872,70873],{},"Mỗi nút terminal lưu tần suất và từ đầy đủ.",[989,70875,70876],{},"Ví dụ đời thường: mục lục từ điển nhóm chung chữ đầu.",[989,70878,70879,70880,70924],{},"Tra prefix tốn ",[1023,70881,70883,70903],{"className":70882},[1026],[1023,70884,70886],{"className":70885},[1030],[1032,70887,70888],{"xmlns":1034},[1036,70889,70890,70900],{},[1039,70891,70892,70894,70896,70898],{},[1042,70893,1044],{},[1046,70895,1049],{"stretchy":1048},[1042,70897,15437],{},[1046,70899,1056],{"stretchy":1048},[1058,70901,70902],{"encoding":1060},"O(m)",[1023,70904,70906],{"className":70905,"ariaHidden":1066},[1065],[1023,70907,70909,70912,70915,70918,70921],{"className":70908},[1070],[1023,70910],{"className":70911,"style":1075},[1074],[1023,70913,1044],{"className":70914,"style":1081},[1079,1080],[1023,70916,1049],{"className":70917},[1085],[1023,70919,15437],{"className":70920},[1079,1080],[1023,70922,1056],{"className":70923},[1092]," với m là độ dài prefix.",[981,70926,70928],{"id":70927},"heap-xếp-hạng-top-k","Heap xếp hạng top-K",[986,70930,70931,70934,70937,70940],{},[989,70932,70933],{},"Thu thập ứng viên rồi giữ K từ tốt nhất bằng min-heap.",[989,70935,70936],{},"Điểm = tần suất + thưởng khớp dài.",[989,70938,70939],{},"Ví dụ đời thường: chọn 5 món ăn được gọi nhiều nhất.",[989,70941,70942,70943,71007],{},"Heap giữ chi phí ở ",[1023,70944,70946,70974],{"className":70945},[1026],[1023,70947,70949],{"className":70948},[1030],[1032,70950,70951],{"xmlns":1034},[1036,70952,70953,70971],{},[1039,70954,70955,70957,70959,70961,70963,70965,70967,70969],{},[1042,70956,1044],{},[1046,70958,1049],{"stretchy":1048},[1042,70960,41944],{},[1042,70962,7684],{},[1042,70964,7687],{},[1042,70966,7690],{},[1042,70968,20401],{},[1046,70970,1056],{"stretchy":1048},[1058,70972,70973],{"encoding":1060},"O(R log K)",[1023,70975,70977],{"className":70976,"ariaHidden":1066},[1065],[1023,70978,70980,70983,70986,70989,70992,70995,70998,71001,71004],{"className":70979},[1070],[1023,70981],{"className":70982,"style":1075},[1074],[1023,70984,1044],{"className":70985,"style":1081},[1079,1080],[1023,70987,1049],{"className":70988},[1085],[1023,70990,41944],{"className":70991,"style":45389},[1079,1080],[1023,70993,7684],{"className":70994,"style":7716},[1079,1080],[1023,70996,7687],{"className":70997},[1079,1080],[1023,70999,7690],{"className":71000,"style":7723},[1079,1080],[1023,71002,20401],{"className":71003,"style":20466},[1079,1080],[1023,71005,1056],{"className":71006},[1092]," thay vì sắp hết.",[981,71009,71011],{"id":71010},"lru-cache-cho-prefix-nóng","LRU cache cho prefix nóng",[986,71013,71014,71060,71063,71066],{},[989,71015,71016,71017,1517],{},"LRU nhớ K prefix vừa hỏi, hỏi lại trả ngay ",[1023,71018,71020,71039],{"className":71019},[1026],[1023,71021,71023],{"className":71022},[1030],[1032,71024,71025],{"xmlns":1034},[1036,71026,71027,71037],{},[1039,71028,71029,71031,71033,71035],{},[1042,71030,1044],{},[1046,71032,1049],{"stretchy":1048},[1051,71034,1053],{},[1046,71036,1056],{"stretchy":1048},[1058,71038,1061],{"encoding":1060},[1023,71040,71042],{"className":71041,"ariaHidden":1066},[1065],[1023,71043,71045,71048,71051,71054,71057],{"className":71044},[1070],[1023,71046],{"className":71047,"style":1075},[1074],[1023,71049,1044],{"className":71050,"style":1081},[1079,1080],[1023,71052,1049],{"className":71053},[1085],[1023,71055,1053],{"className":71056},[1079],[1023,71058,1056],{"className":71059},[1092],[989,71061,71062],{},"Khi tần suất từ đổi thì xóa cache liên quan.",[989,71064,71065],{},"Ví dụ đời thường: để món hay gọi ở ngăn đầu tủ lạnh.",[989,71067,71068],{},"Hit-rate mục tiêu trên 70% với 1024 prefix.",[1352,71070,71072],{"className":3538,"code":71071,"language":3540,"meta":1357,"style":1357},"# Luồng gợi ý: cache trước, Trie sau\ndef suggest(prefix, k):\n    if cache.has(prefix):  # trúng cache trả ngay\n        return cache.get(prefix)\n    node = trie.find(prefix)  # tìm nút prefix\n    topk = ranker.topk(node, k)  # xếp hạng bằng heap\n    cache.put(prefix, topk)  # lưu lại cho lần sau\n    return topk\n",[992,71073,71074,71079,71084,71089,71094,71099,71104,71109],{"__ignoreMap":1357},[1023,71075,71076],{"class":1362,"line":63},[1023,71077,71078],{},"# Luồng gợi ý: cache trước, Trie sau\n",[1023,71080,71081],{"class":1362,"line":68},[1023,71082,71083],{},"def suggest(prefix, k):\n",[1023,71085,71086],{"class":1362,"line":73},[1023,71087,71088],{},"    if cache.has(prefix):  # trúng cache trả ngay\n",[1023,71090,71091],{"class":1362,"line":78},[1023,71092,71093],{},"        return cache.get(prefix)\n",[1023,71095,71096],{"class":1362,"line":83},[1023,71097,71098],{},"    node = trie.find(prefix)  # tìm nút prefix\n",[1023,71100,71101],{"class":1362,"line":88},[1023,71102,71103],{},"    topk = ranker.topk(node, k)  # xếp hạng bằng heap\n",[1023,71105,71106],{"class":1362,"line":93},[1023,71107,71108],{},"    cache.put(prefix, topk)  # lưu lại cho lần sau\n",[1023,71110,71111],{"class":1362,"line":98},[1023,71112,71113],{},"    return topk\n",[968,71115,1433],{"id":1432},[986,71117,71118,71121,71124,71127],{},[989,71119,71120],{},"Input: prefix \"ban\", K=5. Output: 5 từ bắt đầu bằng \"ban\" xếp theo tần suất giảm dần.",[989,71122,71123],{},"Giải thích: Trie tìm nhánh \"ban\", heap giữ 5 từ hot nhất.",[989,71125,71126],{},"Input: gõ lại 100 prefix nóng 2 vòng. Output: vòng 2 hit-rate trên 70%, p95 giảm 30%.",[989,71128,71129],{},"Giải thích: vòng 2 trúng cache nên không cần duyệt cây.",[968,71131,1482],{"id":1481},[973,71133,1485,71134,71136,71137,1517],{},[1487,71135,4800],{}," (hoặc ngôn ngữ bạn chọn cho app). Đây là app hoàn chỉnh, dành 90 phút. Dùng lại Trie ngày 35, LRU ngày 39, heap ngày 26. Nộp vào ",[992,71138,71139],{},"day-126-autocomplete\u002F",[981,71141,71143],{"id":71142},"bài-1-lõi-gợi-ý","Bài 1: Lõi gợi ý",[1352,71145,71147],{"className":1393,"code":71146,"language":1395,"meta":1357,"style":1357},"class Autocomplete {\n public:\n  void addWord(const std::string &w, uint64_t freq);        \u002F\u002F có rồi thì cộng tần suất\n  void recordSelection(const std::string &w);               \u002F\u002F người dùng chọn từ: freq += 1\n  std::vector\u003Cstd::pair\u003Cstd::string, uint64_t>> suggest(const std::string &prefix, int k);\n  static Autocomplete fromFile(const std::string &path);    \u002F\u002F mỗi dòng \"từ\u003CTAB>tần_suất\"\n};\n",[992,71148,71149,71154,71158,71163,71168,71173,71178],{"__ignoreMap":1357},[1023,71150,71151],{"class":1362,"line":63},[1023,71152,71153],{},"class Autocomplete {\n",[1023,71155,71156],{"class":1362,"line":68},[1023,71157,4836],{},[1023,71159,71160],{"class":1362,"line":73},[1023,71161,71162],{},"  void addWord(const std::string &w, uint64_t freq);        \u002F\u002F có rồi thì cộng tần suất\n",[1023,71164,71165],{"class":1362,"line":78},[1023,71166,71167],{},"  void recordSelection(const std::string &w);               \u002F\u002F người dùng chọn từ: freq += 1\n",[1023,71169,71170],{"class":1362,"line":83},[1023,71171,71172],{},"  std::vector\u003Cstd::pair\u003Cstd::string, uint64_t>> suggest(const std::string &prefix, int k);\n",[1023,71174,71175],{"class":1362,"line":88},[1023,71176,71177],{},"  static Autocomplete fromFile(const std::string &path);    \u002F\u002F mỗi dòng \"từ\u003CTAB>tần_suất\"\n",[1023,71179,71180],{"class":1362,"line":93},[1023,71181,4866],{},[1099,71183,71184,71192],{},[1102,71185,71186],{},[1105,71187,71188,71190],{},[1108,71189,2547],{},[1108,71191,14241],{},[1118,71193,71194,71201,71298,71306],{},[1105,71195,71196,71198],{},[1123,71197,66639],{},[1123,71199,71200],{},"Tần suất giảm dần, hòa thì theo alphabet",[1105,71202,71203,71206],{},[1123,71204,71205],{},"Top-K",[1123,71207,71208,71209,71211,71212],{},"Min-heap cỡ ",[992,71210,4022],{}," khi duyệt cây con, ",[1023,71213,71215,71245],{"className":71214},[1026],[1023,71216,71218],{"className":71217},[1030],[1032,71219,71220],{"xmlns":1034},[1036,71221,71222,71242],{},[1039,71223,71224,71226,71228,71230,71232,71234,71236,71238,71240],{},[1042,71225,1044],{},[1046,71227,1049],{"stretchy":1048},[1042,71229,15437],{},[1046,71231,21881],{},[1042,71233,41944],{},[1042,71235,8397],{},[1046,71237,8400],{},[1042,71239,4022],{},[1046,71241,1056],{"stretchy":1048},[1058,71243,71244],{"encoding":1060},"O(m + R \\log k)",[1023,71246,71248,71272],{"className":71247,"ariaHidden":1066},[1065],[1023,71249,71251,71254,71257,71260,71263,71266,71269],{"className":71250},[1070],[1023,71252],{"className":71253,"style":1075},[1074],[1023,71255,1044],{"className":71256,"style":1081},[1079,1080],[1023,71258,1049],{"className":71259},[1085],[1023,71261,15437],{"className":71262},[1079,1080],[1023,71264],{"className":71265,"style":13790},[2354],[1023,71267,21881],{"className":71268},[13794],[1023,71270],{"className":71271,"style":13790},[2354],[1023,71273,71275,71278,71281,71284,71289,71292,71295],{"className":71274},[1070],[1023,71276],{"className":71277,"style":1075},[1074],[1023,71279,41944],{"className":71280,"style":45389},[1079,1080],[1023,71282],{"className":71283,"style":8434},[2354],[1023,71285,8427,71287],{"className":71286},[8426],[1023,71288,7690],{"style":8430},[1023,71290],{"className":71291,"style":8434},[2354],[1023,71293,4022],{"className":71294,"style":4066},[1079,1080],[1023,71296,1056],{"className":71297},[1092],[1105,71299,71300,71303],{},[1123,71301,71302],{},"Chuẩn hóa",[1123,71304,71305],{},"Chữ thường, bỏ khoảng trắng đầu cuối. Hỗ trợ UTF-8 tiếng Việt",[1105,71307,71308,71311],{},[1123,71309,71310],{},"Prefix rỗng",[1123,71312,71313,71314,71316],{},"Trả top ",[992,71315,4022],{}," toàn bộ từ điển",[1352,71318,71321],{"className":71319,"code":71320,"language":2241,"meta":1357},[2239],"Từ điển: \"trie\"(50), \"tree\"(80), \"trick\"(20), \"try\"(80)\nsuggest(\"tr\", 3)  -> [(tree,80), (try,80), (trie,50)]\nsuggest(\"xyz\", 3) -> []\nrecordSelection(\"trick\") x 70 -> suggest(\"tri\", 1) = [(trick, 90)]\n",[992,71322,71320],{"__ignoreMap":1357},[981,71324,71326],{"id":71325},"bài-2-cache-và-tính-nhất-quán","Bài 2: Cache và tính nhất quán",[2273,71328,71329,71338,71351],{},[989,71330,71331,71332,71334,71335,1517],{},"Bọc ",[992,71333,27125],{}," bằng LRU 1024 mục, khóa là ",[992,71336,71337],{},"(prefix, k)",[989,71339,71340,71343,71344,71347,71348,71350],{},[992,71341,71342],{},"recordSelection(w)"," phải xóa cache của ",[1487,71345,71346],{},"mọi tiền tố"," của ",[992,71349,27557],{}," (không xóa toàn bộ cache).",[989,71352,9007,71353,1656,71356,1656,71359,1517],{},[992,71354,71355],{},"hits",[992,71357,71358],{},"misses",[992,71360,71361],{},"hitRate",[973,71363,71364],{},"Sinh 100.000 truy vấn theo phân bố Zipf trên 5000 tiền tố. Mục tiêu hit rate trên 70%.",[981,71366,71368],{"id":71367},"bài-3-giao-diện-và-đo-hiệu-năng-nâng-cao","Bài 3: Giao diện và đo hiệu năng (nâng cao)",[2273,71370,71371,71385,71388],{},[989,71372,71373,71374,16792,71377,71380,71381,71384],{},"CLI tương tác: gõ từng ký tự (hoặc cả tiền tố rồi Enter), in 5 gợi ý. Lệnh ",[992,71375,71376],{},":pick \u003Ctừ>",[992,71378,71379],{},"recordSelection",". Lệnh ",[992,71382,71383],{},":stats"," in hit rate.",[989,71386,71387],{},"Nạp từ điển 300.000 từ (có tần suất, ví dụ từ Wikipedia word frequency). In thời gian nạp và bộ nhớ.",[989,71389,71390,71391,71393],{},"Đo p50, p99 độ trễ ",[992,71392,27125],{}," có và không có cache.",[1352,71395,71398],{"className":71396,"code":71397,"language":2241,"meta":1357},[2239],"Mục tiêu: p99 \u003C 1 ms có cache, \u003C 5 ms không cache với 300.000 từ\n",[992,71399,71397],{"__ignoreMap":1357},[981,71401,2711],{"id":2710},[986,71403,71405,71411,71420,71426],{"className":71404},[2715],[989,71406,71408,71410],{"className":71407},[2719],[2721,71409],{"disabled":2723,"type":2724}," Test mẫu pass, gồm trường hợp hòa tần suất.",[989,71412,71414,71416,71417,71419],{"className":71413},[2719],[2721,71415],{"disabled":2723,"type":2724}," Cache không trả kết quả cũ sau ",[992,71418,71379],{}," (có test).",[989,71421,71423,71425],{"className":71422},[2719],[2721,71424],{"disabled":2723,"type":2724}," Hit rate trên 70% với dữ liệu Zipf.",[989,71427,71429,71431,71432,71434],{"className":71428},[2719],[2721,71430],{"disabled":2723,"type":2724}," Bảng p50\u002Fp99 và bộ nhớ có số thật. ",[992,71433,2513],{}," có hướng dẫn chạy.",[968,71436,2890],{"id":2889},[986,71438,71439,71442,71445,71448],{},[989,71440,71441],{},"Trie giúp tra prefix nhanh thế nào?",[989,71443,71444],{},"Heap giữ top-K theo điểm gì?",[989,71446,71447],{},"LRU cache tăng tốc prefix nóng ra sao?",[989,71449,71450],{},"Khi nào phải xóa cache cũ?",[3014,71452],{},[973,71454,71455],{},"🌕 Bạn đã hoàn thành ngày 126. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,71457,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":71459},[71460,71461,71466,71467,71473],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":71462},[71463,71464,71465],{"id":70864,"depth":73,"text":70865},{"id":70927,"depth":73,"text":70928},{"id":71010,"depth":73,"text":71011},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":71468},[71469,71470,71471,71472],{"id":71142,"depth":73,"text":71143},{"id":71325,"depth":73,"text":71326},{"id":71367,"depth":73,"text":71368},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app gợi ý từ khóa hoàn chỉnh: Trie lưu từ điển, heap xếp hạng theo tần suất, LRU cache tăng tốc prefix nóng, đo p95 dưới 50ms.",{},[3050,4669],{"title":685,"description":71474},[17502,27243,71479,71480,46182],"lru-cache","autocomplete","mluOvRDJt7Xe4qGOYsu47Yw_LB87LE_-WpNL3xFW6pM",{"id":71483,"title":690,"body":71484,"category":8797,"day":693,"description":71933,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":71934,"navigation":2723,"outcomes":3047,"path":691,"prerequisites":71935,"seo":71936,"stem":692,"tags":71937,"__hash__":71939},"challenges\u002Fchallenges\u002F127.app-search-engine.md",{"type":965,"value":71485,"toc":71917},[71486,71488,71491,71493,71497,71511,71515,71529,71533,71547,71549,71563,71565,71573,71577,71607,71665,71671,71675,71686,71690,71860,71862,71894,71896,71910,71912,71915],[968,71487,971],{"id":970},[973,71489,71490],{},"Bài này xây máy tìm kiếm mini cho văn bản. Gõ từ khóa là ra tài liệu đúng nhất.",[968,71492,979],{"id":978},[981,71494,71496],{"id":71495},"index-ngược-là-gì","Index ngược là gì",[986,71498,71499,71502,71505,71508],{},[989,71500,71501],{},"Index ngược ánh xạ từ từ tới danh sách tài liệu chứa nó.",[989,71503,71504],{},"Thay vì quét hết N tài liệu, chỉ tra vài posting list.",[989,71506,71507],{},"Ví dụ đời thường: mục lục sách chỉ trang nào có từ cần tìm.",[989,71509,71510],{},"Trie lưu từ, mỗi từ giữ danh sách doc-id và tần suất.",[981,71512,71514],{"id":71513},"tf-idf-chấm-điểm","TF-IDF chấm điểm",[986,71516,71517,71520,71523,71526],{},[989,71518,71519],{},"TF cao nghĩa là từ xuất hiện nhiều trong tài liệu đó.",[989,71521,71522],{},"IDF cao nghĩa là từ hiếm trong toàn tập nên quý.",[989,71524,71525],{},"Điểm = TF nhân IDF, tài liệu điểm cao xếp trước.",[989,71527,71528],{},"Ví dụ đời thường: từ lạ xuất hiện nhiều trong 1 bài thì bài đó rất liên quan.",[981,71530,71532],{"id":71531},"bloom-chặn-từ-rác","Bloom chặn từ rác",[986,71534,71535,71538,71541,71544],{},[989,71536,71537],{},"Bloom nhớ toàn bộ từ vựng đã index.",[989,71539,71540],{},"Từ chưa từng thấy bị chặn ngay, khỏi tra Trie.",[989,71542,71543],{},"Ví dụ đời thường: bảo vệ chặn khách không có tên trong danh sách.",[989,71545,71546],{},"Bloom không bao giờ bỏ sót từ có thật, chỉ nhầm nhẹ từ rác.",[968,71548,1433],{"id":1432},[986,71550,71551,71554,71557,71560],{},[989,71552,71553],{},"Input: query \"trie\". Output: tài liệu nhắc \"trie\" nhiều lần xếp trên nhắc 1 lần.",[989,71555,71556],{},"Giải thích: TF cao hơn nên điểm TF-IDF cao hơn.",[989,71558,71559],{},"Input: query \"trie cache\" kiểu AND. Output: chỉ tài liệu chứa cả 2 từ.",[989,71561,71562],{},"Giải thích: giao 2 posting list giữ lại doc chung.",[968,71564,1482],{"id":1481},[973,71566,1485,71567,71569,71570,1517],{},[1487,71568,13531],{}," (hoặc C++). Dùng lại TF-IDF ngày 57, Bloom ngày 30, Trie ngày 35. Nộp vào ",[992,71571,71572],{},"day-127-search\u002F",[981,71574,71576],{"id":71575},"bài-1-chỉ-mục-ngược","Bài 1: Chỉ mục ngược",[1352,71578,71580],{"className":3538,"code":71579,"language":3540,"meta":1357,"style":1357},"class SearchEngine:\n    def add_document(self, doc_id: str, title: str, body: str): ...\n    def build(self): ...                         # tính idf sau khi thêm hết\n    def search(self, query: str, k: int = 10) -> list[tuple[str, float]]: ...\n    def save(self, path); @classmethod def load(cls, path): ...\n",[992,71581,71582,71587,71592,71597,71602],{"__ignoreMap":1357},[1023,71583,71584],{"class":1362,"line":63},[1023,71585,71586],{},"class SearchEngine:\n",[1023,71588,71589],{"class":1362,"line":68},[1023,71590,71591],{},"    def add_document(self, doc_id: str, title: str, body: str): ...\n",[1023,71593,71594],{"class":1362,"line":73},[1023,71595,71596],{},"    def build(self): ...                         # tính idf sau khi thêm hết\n",[1023,71598,71599],{"class":1362,"line":78},[1023,71600,71601],{},"    def search(self, query: str, k: int = 10) -> list[tuple[str, float]]: ...\n",[1023,71603,71604],{"class":1362,"line":83},[1023,71605,71606],{},"    def save(self, path); @classmethod def load(cls, path): ...\n",[1099,71608,71609,71617],{},[1102,71610,71611],{},[1105,71612,71613,71615],{},[1108,71614,2544],{},[1108,71616,2547],{},[1118,71618,71619,71627,71641,71653],{},[1105,71620,71621,71624],{},[1123,71622,71623],{},"Tokenizer",[1123,71625,71626],{},"Chữ thường, bỏ dấu câu, bỏ từ dừng",[1105,71628,71629,71632],{},[1123,71630,71631],{},"Posting list",[1123,71633,71634,71637,71638],{},[992,71635,71636],{},"từ -> list[(doc_id, tf, vị trí)]",", sắp theo ",[992,71639,71640],{},"doc_id",[1105,71642,71643,71646],{},[1123,71644,71645],{},"Điểm",[1123,71647,71648,71649,71652],{},"TF-IDF, từ trong ",[992,71650,71651],{},"title"," nhân 2",[1105,71654,71655,71658],{},[1123,71656,71657],{},"Truy vấn nhiều từ",[1123,71659,71660,71661,71664],{},"Cộng điểm các từ. Hỗ trợ ",[992,71662,71663],{},"\"cụm từ chính xác\""," bằng vị trí",[1352,71666,71669],{"className":71667,"code":71668,"language":2241,"meta":1357},[2239],"Tài liệu nhắc \"trie\" 5 lần xếp trên tài liệu nhắc 1 lần\nQuery có từ không tồn tại  -> bỏ qua từ đó, không lỗi\nQuery \"\\\"binary search\\\"\" -> chỉ trả tài liệu có 2 từ liền nhau\n",[992,71670,71668],{"__ignoreMap":1357},[981,71672,71674],{"id":71673},"bài-2-bloom-chặn-từ-lạ-và-gợi-ý-sửa","Bài 2: Bloom chặn từ lạ và gợi ý sửa",[2273,71676,71677,71680,71683],{},[989,71678,71679],{},"Bloom filter chứa toàn bộ từ vựng. Từ Bloom báo \"không có\" thì không tra chỉ mục.",[989,71681,71682],{},"Từ không có thì gợi ý \"Có phải bạn muốn tìm\" bằng spell-check ngày 36 (khoảng cách tối đa 2).",[989,71684,71685],{},"Đếm số lần Bloom tiết kiệm được lượt tra chỉ mục trên 10.000 truy vấn có 30% từ gõ sai.",[981,71687,71689],{"id":71688},"bài-3-dữ-liệu-thật-và-đánh-giá-nâng-cao","Bài 3: Dữ liệu thật và đánh giá (nâng cao)",[2273,71691,71692,71695,71698,71707],{},[989,71693,71694],{},"Index 10.000 bài Wikipedia tiếng Việt (hoặc tiếng Anh) rút gọn.",[989,71696,71697],{},"Đo thời gian build, kích thước chỉ mục trên đĩa, thời gian truy vấn p50\u002Fp99.",[989,71699,71700,71701,1509,71704,1517],{},"Tự gán nhãn 10 truy vấn với 3-5 tài liệu liên quan mỗi truy vấn. Tính ",[1487,71702,71703],{},"precision@5",[1487,71705,71706],{},"MRR",[989,71708,71709,71710,18407,71713,1656,71807,71859],{},"Thay TF-IDF bằng ",[1487,71711,71712],{},"BM25",[1023,71714,71716,71739],{"className":71715},[1026],[1023,71717,71719],{"className":71718},[1030],[1032,71720,71721],{"xmlns":1034},[1036,71722,71723,71736],{},[1039,71724,71725,71731,71733],{},[17690,71726,71727,71729],{},[1042,71728,4022],{},[1051,71730,1053],{},[1046,71732,2325],{},[1051,71734,71735],{},"1.2",[1058,71737,71738],{"encoding":1060},"k_1 = 1.2",[1023,71740,71742,71798],{"className":71741,"ariaHidden":1066},[1065],[1023,71743,71745,71748,71789,71792,71795],{"className":71744},[1070],[1023,71746],{"className":71747,"style":59977},[1074],[1023,71749,71751,71754],{"className":71750},[1079],[1023,71752,4022],{"className":71753,"style":4066},[1079,1080],[1023,71755,71757],{"className":71756},[2383],[1023,71758,71760,71781],{"className":71759},[2387,17732],[1023,71761,71763,71778],{"className":71762},[2391],[1023,71764,71766],{"className":71765,"style":54019},[2395],[1023,71767,71769,71772],{"style":71768},"top:-2.55em;margin-left:-0.0315em;margin-right:0.05em;",[1023,71770],{"className":71771,"style":2403},[2402],[1023,71773,71775],{"className":71774},[2407,2408,2409,2410],[1023,71776,1053],{"className":71777},[1079,2410],[1023,71779,17797],{"className":71780},[17796],[1023,71782,71784],{"className":71783},[2391],[1023,71785,71787],{"className":71786,"style":17804},[2395],[1023,71788],{},[1023,71790],{"className":71791,"style":2355},[2354],[1023,71793,2325],{"className":71794},[2359],[1023,71796],{"className":71797,"style":2355},[2354],[1023,71799,71801,71804],{"className":71800},[1070],[1023,71802],{"className":71803,"style":10020},[1074],[1023,71805,71735],{"className":71806},[1079],[1023,71808,71810,71829],{"className":71809},[1026],[1023,71811,71813],{"className":71812},[1030],[1032,71814,71815],{"xmlns":1034},[1036,71816,71817,71826],{},[1039,71818,71819,71821,71823],{},[1042,71820,17703],{},[1046,71822,2325],{},[1051,71824,71825],{},"0.75",[1058,71827,71828],{"encoding":1060},"b = 0.75",[1023,71830,71832,71850],{"className":71831,"ariaHidden":1066},[1065],[1023,71833,71835,71838,71841,71844,71847],{"className":71834},[1070],[1023,71836],{"className":71837,"style":22079},[1074],[1023,71839,17703],{"className":71840},[1079,1080],[1023,71842],{"className":71843,"style":2355},[2354],[1023,71845,2325],{"className":71846},[2359],[1023,71848],{"className":71849,"style":2355},[2354],[1023,71851,71853,71856],{"className":71852},[1070],[1023,71854],{"className":71855,"style":10020},[1074],[1023,71857,71825],{"className":71858},[1079],"). So precision@5 và MRR.",[981,71861,2711],{"id":2710},[986,71863,71865,71871,71882,71888],{"className":71864},[2715],[989,71866,71868,71870],{"className":71867},[2719],[2721,71869],{"disabled":2723,"type":2724}," Test mẫu pass, gồm tìm cụm từ chính xác.",[989,71872,71874,2308,71876,2461,71878,71881],{"className":71873},[2719],[2721,71875],{"disabled":2723,"type":2724},[992,71877,26669],{},[992,71879,71880],{},"load"," cho cùng kết quả tìm.",[989,71883,71885,71887],{"className":71884},[2719],[2721,71886],{"disabled":2723,"type":2724}," Số liệu Bloom tiết kiệm lượt tra.",[989,71889,71891,71893],{"className":71890},[2719],[2721,71892],{"disabled":2723,"type":2724}," Bảng TF-IDF vs BM25 có precision@5 và MRR.",[968,71895,2890],{"id":2889},[986,71897,71898,71901,71904,71907],{},[989,71899,71900],{},"Index ngược biến quét toàn tập thành tra gì?",[989,71902,71903],{},"TF và IDF mỗi cái đo điều gì?",[989,71905,71906],{},"Bloom giúp bỏ qua query rác thế nào?",[989,71908,71909],{},"AND và OR kết hợp posting list khác nhau ra sao?",[3014,71911],{},[973,71913,71914],{},"🌕 Bạn đã hoàn thành ngày 127. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,71916,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":71918},[71919,71920,71925,71926,71932],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":71921},[71922,71923,71924],{"id":71495,"depth":73,"text":71496},{"id":71513,"depth":73,"text":71514},{"id":71531,"depth":73,"text":71532},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":71927},[71928,71929,71930,71931],{"id":71575,"depth":73,"text":71576},{"id":71673,"depth":73,"text":71674},{"id":71688,"depth":73,"text":71689},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây mini search engine: index ngược bằng Trie, chấm điểm TF-IDF, Bloom filter chặn từ vô nghĩa, benchmark truy vấn đa từ khóa.",{},[3050,14055],{"title":690,"description":71933},[17502,71938,27243,46182,24341],"search-engine","nB625VD-olltDiuj0gMxACxgsmsWzdiOcx_1mOrjQ4s",{"id":71941,"title":695,"body":71942,"category":3041,"day":698,"description":72337,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":72338,"navigation":2723,"outcomes":3047,"path":696,"prerequisites":72339,"seo":72340,"stem":697,"tags":72341,"__hash__":72344},"challenges\u002Fchallenges\u002F128.app-rate-limiter.md",{"type":965,"value":71943,"toc":72321},[71944,71946,71949,71951,71955,71969,71973,71987,71991,72005,72052,72054,72068,72070,72082,72086,72106,72174,72180,72186,72190,72238,72242,72269,72271,72298,72300,72314,72316,72319],[968,71945,971],{"id":970},[973,71947,71948],{},"Bài này xây bộ chặn spam request quá đà. Quá quota thì trả lỗi 429 chờ sau.",[968,71950,979],{"id":978},[981,71952,71954],{"id":71953},"_3-thuật-toán-giới-hạn","3 thuật toán giới hạn",[986,71956,71957,71960,71963,71966],{},[989,71958,71959],{},"Fixed window: đếm request trong cửa sổ cố định như mỗi phút.",[989,71961,71962],{},"Sliding window: lưu timestamp từng request, tỉa cái cũ.",[989,71964,71965],{},"Token bucket: thùng nạp token đều, có token mới cho qua.",[989,71967,71968],{},"Ví dụ đời thường: quán chỉ cho 5 khách vào mỗi 10 phút.",[981,71970,71972],{"id":71971},"lưu-trạng-thái-bằng-cache","Lưu trạng thái bằng cache",[986,71974,71975,71978,71981,71984],{},[989,71976,71977],{},"Mỗi key user hoặc IP có 1 bản ghi đếm riêng.",[989,71979,71980],{},"Key im lặng lâu tự bay nhờ TTL nên RAM không phình.",[989,71982,71983],{},"Khóa theo key để đếm đúng khi nhiều luồng cùng tới.",[989,71985,71986],{},"Ví dụ đời thường: mỗi khách có 1 thẻ đếm riêng, lâu không tới thì hủy thẻ.",[981,71988,71990],{"id":71989},"chọn-thuật-toán-theo-endpoint","Chọn thuật toán theo endpoint",[986,71992,71993,71996,71999,72002],{},[989,71994,71995],{},"Đăng nhập dùng sliding window cho nghiêm chống dò mật khẩu.",[989,71997,71998],{},"API đọc dùng token bucket cho thoáng, cho burst nhẹ.",[989,72000,72001],{},"Bị chặn trả 429 kèm Retry-After và header còn lại.",[989,72003,72004],{},"Nạp token kiểu lazy: tới lúc có request mới tính token mới.",[1099,72006,72007,72017],{},[1102,72008,72009],{},[1105,72010,72011,72013,72015],{},[1108,72012,9446],{},[1108,72014,27324],{},[1108,72016,35828],{},[1118,72018,72019,72030,72041],{},[1105,72020,72021,72024,72027],{},[1123,72022,72023],{},"Fixed window",[1123,72025,72026],{},"Rẻ, dễ code",[1123,72028,72029],{},"Tràn biên gấp đôi burst",[1105,72031,72032,72035,72038],{},[1123,72033,72034],{},"Sliding window",[1123,72036,72037],{},"Chính xác",[1123,72039,72040],{},"Tốn nhớ timestamp",[1105,72042,72043,72046,72049],{},[1123,72044,72045],{},"Token bucket",[1123,72047,72048],{},"Cho burst mượt",[1123,72050,72051],{},"Cần chỉnh tốc độ nạp",[968,72053,1433],{"id":1432},[986,72055,72056,72059,72062,72065],{},[989,72057,72058],{},"Input: rule 5 request mỗi phút, gửi 10 request dồn dập. Output: 5 qua, 5 bị chặn 429.",[989,72060,72061],{},"Giải thích: hết quota trong cửa sổ nên phải chờ.",[989,72063,72064],{},"Input: 50 luồng cùng key với quota 100. Output: đúng 100 request qua, không hơn.",[989,72066,72067],{},"Giải thích: khóa theo key giúp đếm không lệch khi chen nhau.",[968,72069,1482],{"id":1481},[973,72071,1485,72072,16234,72074,69839,72076,5599,72079,1517],{},[1487,72073,13531],{},[992,72075,40031],{},[1487,72077,72078],{},"Go",[992,72080,72081],{},"day-128-ratelimiter\u002F",[981,72083,72085],{"id":72084},"bài-1-ba-thuật-toán-giới-hạn","Bài 1: Ba thuật toán giới hạn",[1352,72087,72089],{"className":3538,"code":72088,"language":3540,"meta":1357,"style":1357},"class RateLimiter(Protocol):\n    def allow(self, key: str, now: float) -> tuple[bool, float]:\n        \"\"\"Trả (cho phép?, số giây phải chờ nếu bị chặn).\"\"\"\n",[992,72090,72091,72096,72101],{"__ignoreMap":1357},[1023,72092,72093],{"class":1362,"line":63},[1023,72094,72095],{},"class RateLimiter(Protocol):\n",[1023,72097,72098],{"class":1362,"line":68},[1023,72099,72100],{},"    def allow(self, key: str, now: float) -> tuple[bool, float]:\n",[1023,72102,72103],{"class":1362,"line":73},[1023,72104,72105],{},"        \"\"\"Trả (cho phép?, số giây phải chờ nếu bị chặn).\"\"\"\n",[1099,72107,72108,72119],{},[1102,72109,72110],{},[1105,72111,72112,72114,72116],{},[1108,72113,4881],{},[1108,72115,56648],{},[1108,72117,72118],{},"Cài đặt",[1118,72120,72121,72141,72157],{},[1105,72122,72123,72128,72135],{},[1123,72124,72125],{},[992,72126,72127],{},"FixedWindow",[1123,72129,72130,1656,72132],{},[992,72131,27103],{},[992,72133,72134],{},"window",[1123,72136,72137,72138],{},"Đếm theo ",[992,72139,72140],{},"floor(now \u002F window)",[1105,72142,72143,72148,72154],{},[1123,72144,72145],{},[992,72146,72147],{},"SlidingLog",[1123,72149,72150,1656,72152],{},[992,72151,27103],{},[992,72153,72134],{},[1123,72155,72156],{},"Deque timestamp mỗi key, tỉa cái cũ",[1105,72158,72159,72164,72171],{},[1123,72160,72161],{},[992,72162,72163],{},"TokenBucket",[1123,72165,72166,1656,72168],{},[992,72167,1000],{},[992,72169,72170],{},"refill_rate",[1123,72172,72173],{},"Nạp lười: tính token mới lúc có request",[973,72175,72176,72179],{},[992,72177,72178],{},"now"," được truyền vào để test bằng đồng hồ giả.",[1352,72181,72184],{"className":72182,"code":72183,"language":2241,"meta":1357},[2239],"FixedWindow(5, 60): 5 request lúc t=59, 5 request lúc t=60 -> 10 request trong 2 giây đều qua (điểm yếu biên cửa sổ)\nSlidingLog(5, 60): cùng kịch bản -> 5 request sau bị chặn\nTokenBucket(10, 1\u002Fs): 10 request dồn cùng lúc qua hết, request 11 bị chặn, chờ 1 giây\n",[992,72185,72183],{"__ignoreMap":1357},[981,72187,72189],{"id":72188},"bài-2-middleware-và-dọn-dẹp","Bài 2: Middleware và dọn dẹp",[2273,72191,72192,72216,72232,72235],{},[989,72193,72194,72195,5586,72198,72201,72202,2252,72205,72208,72209,2252,72212,72215],{},"Viết HTTP server nhỏ (",[992,72196,72197],{},"aiohttp",[992,72199,72200],{},"http.server",") với 2 route: ",[992,72203,72204],{},"\u002Flogin",[992,72206,72207],{},"SlidingLog(5, 60)"," theo IP, ",[992,72210,72211],{},"\u002Fapi\u002F*",[992,72213,72214],{},"TokenBucket(20, 5\u002Fs)"," theo API key.",[989,72217,72218,72219,72222,72223,1656,72226,1656,72229,1517],{},"Bị chặn trả ",[992,72220,72221],{},"429"," với header ",[992,72224,72225],{},"Retry-After",[992,72227,72228],{},"X-RateLimit-Limit",[992,72230,72231],{},"X-RateLimit-Remaining",[989,72233,72234],{},"Key im lặng quá 10 phút bị xóa (TTL). Chạy 1 triệu key ngẫu nhiên, kiểm tra bộ nhớ không phình mãi.",[989,72236,72237],{},"An toàn khi nhiều request đồng thời cùng key: dùng khóa theo key.",[981,72239,72241],{"id":72240},"bài-3-đo-và-giới-hạn-phân-tán-nâng-cao","Bài 3: Đo và giới hạn phân tán (nâng cao)",[2273,72243,72244,72256,72259],{},[989,72245,2699,72246,1656,72249,72252,72253,72255],{},[992,72247,72248],{},"wrk",[992,72250,72251],{},"hey"," hoặc script ",[992,72254,40031],{}," bắn 5000 request\u002Fgiây. Đo số request bị chặn đúng theo lý thuyết và độ trễ thêm do limiter.",[989,72257,72258],{},"Chạy 2 tiến trình server sau 1 load balancer giả (round robin). Chỉ ra limiter trong bộ nhớ bị vượt gấp đôi.",[989,72260,72261,72262,27888,72265,72268],{},"Chuyển trạng thái sang Redis (",[992,72263,72264],{},"INCR",[992,72266,72267],{},"EXPIRE"," cho fixed window, hoặc Lua script cho token bucket). Kiểm tra giới hạn đúng trên cả 2 tiến trình.",[981,72270,2711],{"id":2710},[986,72272,72274,72280,72286,72292],{"className":72273},[2715],[989,72275,72277,72279],{"className":72276},[2719],[2721,72278],{"disabled":2723,"type":2724}," Test 3 thuật toán bằng đồng hồ giả pass, có test điểm yếu biên cửa sổ.",[989,72281,72283,72285],{"className":72282},[2719],[2721,72284],{"disabled":2723,"type":2724}," Response 429 đủ 3 header.",[989,72287,72289,72291],{"className":72288},[2719],[2721,72290],{"disabled":2723,"type":2724}," Bộ nhớ ổn định với 1 triệu key.",[989,72293,72295,72297],{"className":72294},[2719],[2721,72296],{"disabled":2723,"type":2724}," Bài 3 cho thấy lỗi limiter cục bộ và bản Redis sửa được.",[968,72299,2890],{"id":2889},[986,72301,72302,72305,72308,72311],{},[989,72303,72304],{},"3 thuật toán giới hạn khác nhau ở điểm gì?",[989,72306,72307],{},"Vì sao cần khóa theo key?",[989,72309,72310],{},"TTL giúp cache limiter thế nào?",[989,72312,72313],{},"Khi nào dùng token bucket thay sliding window?",[3014,72315],{},[973,72317,72318],{},"🌕 Bạn đã hoàn thành ngày 128. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,72320,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":72322},[72323,72324,72329,72330,72336],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":72325},[72326,72327,72328],{"id":71953,"depth":73,"text":71954},{"id":71971,"depth":73,"text":71972},{"id":71989,"depth":73,"text":71990},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":72331},[72332,72333,72334,72335],{"id":72084,"depth":73,"text":72085},{"id":72188,"depth":73,"text":72189},{"id":72240,"depth":73,"text":72241},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây rate limiter đa thuật toán: fixed window, sliding window log, token bucket, lưu trạng thái bằng cache, test chịu tảiđồng thời.",{},[4669,14055],{"title":695,"description":72337},[17502,72342,29125,6437,72343],"rate-limiter","system-design","Pw4fSBgmFFf5NKhQfRJhaMrwtWykXwFsf9sDMQhFmkE",{"id":72346,"title":700,"body":72347,"category":8797,"day":703,"description":72943,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":72944,"navigation":2723,"outcomes":3047,"path":701,"prerequisites":72945,"seo":72946,"stem":702,"tags":72947,"__hash__":72949},"challenges\u002Fchallenges\u002F129.app-topk-stream.md",{"type":965,"value":72348,"toc":72927},[72349,72351,72354,72356,72360,72498,72502,72516,72520,72621,72651,72653,72667,72669,72677,72681,72706,72802,72808,72812,72844,72850,72854,72875,72877,72904,72906,72920,72922,72925],[968,72350,971],{"id":970},[973,72352,72353],{},"Bài này xây bảng trending như top hashtag. Dữ liệu chảy tới đâu, bảng xếp hạng cập nhật tới đó.",[968,72355,979],{"id":978},[981,72357,72359],{"id":72358},"min-heap-giữ-top-k","Min-heap giữ top-K",[986,72361,72362,72365,72492,72495],{},[989,72363,72364],{},"Min-heap cỡ K giữ K item điểm cao nhất.",[989,72366,72367,72368,72427,72428,1517],{},"Cập nhật tốn ",[1023,72369,72371,72397],{"className":72370},[1026],[1023,72372,72374],{"className":72373},[1030],[1032,72375,72376],{"xmlns":1034},[1036,72377,72378,72394],{},[1039,72379,72380,72382,72384,72386,72388,72390,72392],{},[1042,72381,1044],{},[1046,72383,1049],{"stretchy":1048},[1042,72385,7684],{},[1042,72387,7687],{},[1042,72389,7690],{},[1042,72391,20401],{},[1046,72393,1056],{"stretchy":1048},[1058,72395,72396],{"encoding":1060},"O(log K)",[1023,72398,72400],{"className":72399,"ariaHidden":1066},[1065],[1023,72401,72403,72406,72409,72412,72415,72418,72421,72424],{"className":72402},[1070],[1023,72404],{"className":72405,"style":1075},[1074],[1023,72407,1044],{"className":72408,"style":1081},[1079,1080],[1023,72410,1049],{"className":72411},[1085],[1023,72413,7684],{"className":72414,"style":7716},[1079,1080],[1023,72416,7687],{"className":72417},[1079,1080],[1023,72419,7690],{"className":72420,"style":7723},[1079,1080],[1023,72422,20401],{"className":72423,"style":20466},[1079,1080],[1023,72425,1056],{"className":72426},[1092]," thay vì sắp hết ",[1023,72429,72431,72459],{"className":72430},[1026],[1023,72432,72434],{"className":72433},[1030],[1032,72435,72436],{"xmlns":1034},[1036,72437,72438,72456],{},[1039,72439,72440,72442,72444,72446,72448,72450,72452,72454],{},[1042,72441,1044],{},[1046,72443,1049],{"stretchy":1048},[1042,72445,20421],{},[1042,72447,7684],{},[1042,72449,7687],{},[1042,72451,7690],{},[1042,72453,20421],{},[1046,72455,1056],{"stretchy":1048},[1058,72457,72458],{"encoding":1060},"O(N log N)",[1023,72460,72462],{"className":72461,"ariaHidden":1066},[1065],[1023,72463,72465,72468,72471,72474,72477,72480,72483,72486,72489],{"className":72464},[1070],[1023,72466],{"className":72467,"style":1075},[1074],[1023,72469,1044],{"className":72470,"style":1081},[1079,1080],[1023,72472,1049],{"className":72473},[1085],[1023,72475,20421],{"className":72476,"style":20451},[1079,1080],[1023,72478,7684],{"className":72479,"style":7716},[1079,1080],[1023,72481,7687],{"className":72482},[1079,1080],[1023,72484,7690],{"className":72485,"style":7723},[1079,1080],[1023,72487,20421],{"className":72488,"style":20451},[1079,1080],[1023,72490,1056],{"className":72491},[1092],[989,72493,72494],{},"Ví dụ đời thường: giữ khay 10 món bán chạy, món yếu bị đẩy ra.",[989,72496,72497],{},"Truy vấn mới đồng bộ heap từ bảng đếm.",[981,72499,72501],{"id":72500},"cửa-sổ-trượt-theo-thời-gian","Cửa sổ trượt theo thời gian",[986,72503,72504,72507,72510,72513],{},[989,72505,72506],{},"Chỉ đếm event trong cửa sổ W gần nhất như 1 giờ qua.",[989,72508,72509],{},"Event già hơn W bị trừ đếm và xóa khỏi hàng đợi.",[989,72511,72512],{},"Ví dụ đời thường: bảng trending hôm nay bỏ qua tin tuần trước.",[989,72514,72515],{},"Nhờ đó item hết hot tự rơi khỏi top.",[981,72517,72519],{"id":72518},"đếm-xấp-xỉ-khi-vượt-ram","Đếm xấp xỉ khi vượt RAM",[986,72521,72522,72525,72528,72531],{},[989,72523,72524],{},"Từ vựng vô hạn thì chuyển sang bộ đếm xác suất.",[989,72526,72527],{},"RAM cố định, chấp nhận sai số nhỏ có báo cáo.",[989,72529,72530],{},"Ví dụ đời thường: đếm lượt thả tim bằng máy bấm ước lượng.",[989,72532,72533,72534,72577,72578,1517],{},"Bảng băm cho đếm ",[1023,72535,72537,72556],{"className":72536},[1026],[1023,72538,72540],{"className":72539},[1030],[1032,72541,72542],{"xmlns":1034},[1036,72543,72544,72554],{},[1039,72545,72546,72548,72550,72552],{},[1042,72547,1044],{},[1046,72549,1049],{"stretchy":1048},[1051,72551,1053],{},[1046,72553,1056],{"stretchy":1048},[1058,72555,1061],{"encoding":1060},[1023,72557,72559],{"className":72558,"ariaHidden":1066},[1065],[1023,72560,72562,72565,72568,72571,72574],{"className":72561},[1070],[1023,72563],{"className":72564,"style":1075},[1074],[1023,72566,1044],{"className":72567,"style":1081},[1079,1080],[1023,72569,1049],{"className":72570},[1085],[1023,72572,1053],{"className":72573},[1079],[1023,72575,1056],{"className":72576},[1092],", deque cho trục xuất ",[1023,72579,72581,72600],{"className":72580},[1026],[1023,72582,72584],{"className":72583},[1030],[1032,72585,72586],{"xmlns":1034},[1036,72587,72588,72598],{},[1039,72589,72590,72592,72594,72596],{},[1042,72591,1044],{},[1046,72593,1049],{"stretchy":1048},[1051,72595,1053],{},[1046,72597,1056],{"stretchy":1048},[1058,72599,1061],{"encoding":1060},[1023,72601,72603],{"className":72602,"ariaHidden":1066},[1065],[1023,72604,72606,72609,72612,72615,72618],{"className":72605},[1070],[1023,72607],{"className":72608,"style":1075},[1074],[1023,72610,1044],{"className":72611,"style":1081},[1079,1080],[1023,72613,1049],{"className":72614},[1085],[1023,72616,1053],{"className":72617},[1079],[1023,72619,1056],{"className":72620},[1092],[1352,72622,72624],{"className":3538,"code":72623,"language":3540,"meta":1357,"style":1357},"# Cập nhật trending mỗi event\ndef on_event(item, now):\n    counts[item] += 1  # tăng đếm\n    queue.append((now, item))  # xếp hàng chờ trục xuất\n    evict_older_than(now - W)  # bỏ event quá cũ\n",[992,72625,72626,72631,72636,72641,72646],{"__ignoreMap":1357},[1023,72627,72628],{"class":1362,"line":63},[1023,72629,72630],{},"# Cập nhật trending mỗi event\n",[1023,72632,72633],{"class":1362,"line":68},[1023,72634,72635],{},"def on_event(item, now):\n",[1023,72637,72638],{"class":1362,"line":73},[1023,72639,72640],{},"    counts[item] += 1  # tăng đếm\n",[1023,72642,72643],{"class":1362,"line":78},[1023,72644,72645],{},"    queue.append((now, item))  # xếp hàng chờ trục xuất\n",[1023,72647,72648],{"class":1362,"line":83},[1023,72649,72650],{},"    evict_older_than(now - W)  # bỏ event quá cũ\n",[968,72652,1433],{"id":1432},[986,72654,72655,72658,72661,72664],{},[989,72656,72657],{},"Input: 100 nghìn event cố định, hỏi top-10. Output: khớp 100% với sắp xếp brute-force.",[989,72659,72660],{},"Giải thích: heap lazy vẫn giữ đúng K item điểm cao nhất.",[989,72662,72663],{},"Input: hashtag bùng nổ 5 phút rồi im 2 lần W. Output: lọt top-5 rồi tự rơi khỏi top.",[989,72665,72666],{},"Giải thích: hết cửa sổ thì đếm bị trừ về 0.",[968,72668,1482],{"id":1481},[973,72670,1485,72671,72673,72674,1517],{},[1487,72672,13531],{}," (hoặc C++). Dùng heap ngày 26. Nộp vào ",[992,72675,72676],{},"day-129-topk\u002F",[981,72678,72680],{"id":72679},"bài-1-top-k-chính-xác-trong-cửa-sổ-thời-gian","Bài 1: Top-K chính xác trong cửa sổ thời gian",[1352,72682,72684],{"className":3538,"code":72683,"language":3540,"meta":1357,"style":1357},"class TrendingTopK:\n    def __init__(self, k: int, window_sec: float): ...\n    def add(self, item: str, ts: float): ...           # ts tăng dần\n    def top(self, now: float) -> list[tuple[str, int]]: ...\n",[992,72685,72686,72691,72696,72701],{"__ignoreMap":1357},[1023,72687,72688],{"class":1362,"line":63},[1023,72689,72690],{},"class TrendingTopK:\n",[1023,72692,72693],{"class":1362,"line":68},[1023,72694,72695],{},"    def __init__(self, k: int, window_sec: float): ...\n",[1023,72697,72698],{"class":1362,"line":73},[1023,72699,72700],{},"    def add(self, item: str, ts: float): ...           # ts tăng dần\n",[1023,72702,72703],{"class":1362,"line":78},[1023,72704,72705],{},"    def top(self, now: float) -> list[tuple[str, int]]: ...\n",[1099,72707,72708,72716],{},[1102,72709,72710],{},[1105,72711,72712,72714],{},[1108,72713,2547],{},[1108,72715,14241],{},[1118,72717,72718,72771,72790],{},[1105,72719,72720,72723],{},[1123,72721,72722],{},"Đếm",[1123,72724,72725,54481,72728],{},[992,72726,72727],{},"dict[item, count]",[1023,72729,72731,72750],{"className":72730},[1026],[1023,72732,72734],{"className":72733},[1030],[1032,72735,72736],{"xmlns":1034},[1036,72737,72738,72748],{},[1039,72739,72740,72742,72744,72746],{},[1042,72741,1044],{},[1046,72743,1049],{"stretchy":1048},[1051,72745,1053],{},[1046,72747,1056],{"stretchy":1048},[1058,72749,1061],{"encoding":1060},[1023,72751,72753],{"className":72752,"ariaHidden":1066},[1065],[1023,72754,72756,72759,72762,72765,72768],{"className":72755},[1070],[1023,72757],{"className":72758,"style":1075},[1074],[1023,72760,1044],{"className":72761,"style":1081},[1079,1080],[1023,72763,1049],{"className":72764},[1085],[1023,72766,1053],{"className":72767},[1079],[1023,72769,1056],{"className":72770},[1092],[1105,72772,72773,72776],{},[1123,72774,72775],{},"Trục xuất",[1123,72777,72778,72781,72782,72785,72786,72789],{},[992,72779,72780],{},"deque"," các ",[992,72783,72784],{},"(ts, item)",", bỏ event cũ hơn ",[992,72787,72788],{},"now - window"," và giảm đếm",[1105,72791,72792,72796],{},[1123,72793,72794],{},[992,72795,19128],{},[1123,72797,72798,72801],{},[992,72799,72800],{},"heapq.nlargest"," trên bảng đếm, hòa thì theo alphabet",[1352,72803,72806],{"className":72804,"code":72805,"language":2241,"meta":1357},[2239],"k=2, window=60: a@0, b@10, a@20, c@30, c@40, c@50\ntop(55) -> [(c,3), (a,2)]\ntop(75) -> [(c,3), (a,1)]   (a@0 và b@10 đã hết hạn)\n",[992,72807,72805],{"__ignoreMap":1357},[981,72809,72811],{"id":72810},"bài-2-bộ-đếm-xác-suất-khi-từ-vựng-vô-hạn","Bài 2: Bộ đếm xác suất khi từ vựng vô hạn",[2273,72813,72814,72832,72841],{},[989,72815,6760,72816,18407,72819,1656,72822,72824,72825,1656,72828,72831],{},[1487,72817,72818],{},"Count-Min Sketch",[992,72820,72821],{},"width",[992,72823,8529],{},"): ",[992,72826,72827],{},"add(item)",[992,72829,72830],{},"estimate(item)",". Ước lượng không bao giờ thấp hơn thật.",[989,72833,6760,72834,72837,72838,72840],{},[1487,72835,72836],{},"Space-Saving"," (Misra-Gries biến thể) giữ đúng ",[992,72839,15437],{}," bộ đếm.",[989,72842,72843],{},"Luồng 10^7 hashtag theo Zipf, 10^6 hashtag khác nhau. So top 20 của 2 cách với top 20 chính xác:",[1352,72845,72848],{"className":72846,"code":72847,"language":2241,"meta":1357},[2239],"phương_pháp        bộ_nhớ     recall@20    sai_số_đếm_trung_bình\nchính xác          ...        1.0          0\nCount-Min + heap   ...        ...          ...\nSpace-Saving m=100 ...        ...          ...\n",[992,72849,72847],{"__ignoreMap":1357},[981,72851,72853],{"id":72852},"bài-3-dashboard-trending-nâng-cao","Bài 3: Dashboard trending (nâng cao)",[2273,72855,72856,72862,72865,72872],{},[989,72857,72858,72859,72861],{},"Đọc luồng từ file log lớn (hoặc sinh bằng ",[992,72860,40031],{},"), 10.000 event\u002Fgiây.",[989,72863,72864],{},"Mỗi giây in top 10 trong 5 phút gần nhất (dùng bản xác suất).",[989,72866,72867,72868,72871],{},"Phát hiện ",[1487,72869,72870],{},"đột biến",": item có đếm trong 1 phút gần nhất gấp 5 lần trung bình 1 phút của 30 phút trước. In cảnh báo.",[989,72873,72874],{},"Đo bộ nhớ và CPU khi chạy 10 phút.",[981,72876,2711],{"id":2710},[986,72878,72880,72886,72892,72898],{"className":72879},[2715],[989,72881,72883,72885],{"className":72882},[2719],[2721,72884],{"disabled":2723,"type":2724}," Test cửa sổ thời gian pass.",[989,72887,72889,72891],{"className":72888},[2719],[2721,72890],{"disabled":2723,"type":2724}," Count-Min không bao giờ ước lượng thấp (có test).",[989,72893,72895,72897],{"className":72894},[2719],[2721,72896],{"disabled":2723,"type":2724}," Bảng so sánh 3 cách có số thật.",[989,72899,72901,72903],{"className":72900},[2719],[2721,72902],{"disabled":2723,"type":2724}," Dashboard chạy 10 phút, bộ nhớ ổn định.",[968,72905,2890],{"id":2889},[986,72907,72908,72911,72914,72917],{},[989,72909,72910],{},"Min-heap giữ top-K rẻ hơn sắp hết ở điểm gì?",[989,72912,72913],{},"Cửa sổ trượt giúp trending tươi thế nào?",[989,72915,72916],{},"Khi nào phải chuyển sang đếm xấp xỉ?",[989,72918,72919],{},"Event tới trễ quá cũ xử lý ra sao?",[3014,72921],{},[973,72923,72924],{},"🌕 Bạn đã hoàn thành ngày 129. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,72926,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":72928},[72929,72930,72935,72936,72942],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":72931},[72932,72933,72934],{"id":72358,"depth":73,"text":72359},{"id":72500,"depth":73,"text":72501},{"id":72518,"depth":73,"text":72519},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":72937},[72938,72939,72940,72941],{"id":72679,"depth":73,"text":72680},{"id":72810,"depth":73,"text":72811},{"id":72852,"depth":73,"text":72853},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app top-K trending trên dòng dữ liệu chảy: min-heap K phần tử, cửa sổ trượt theo thời gian, xử lý tần suất xấp xỉ với bộ nhớ chặn trên.",{},[3050,14055],{"title":700,"description":72943},[17502,22230,19407,62455,72948],"trending","PswFW9wBhyzfW953ukZsjmcbQAr-QrrTIGwEPVD-8dw",{"id":72951,"title":705,"body":72952,"category":8797,"day":708,"description":73250,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":73251,"navigation":2723,"outcomes":3047,"path":706,"prerequisites":73252,"seo":73253,"stem":707,"tags":73254,"__hash__":73256},"challenges\u002Fchallenges\u002F130.app-fraud-pipeline.md",{"type":965,"value":72953,"toc":73234},[72954,72956,72959,72961,72965,72979,72983,72997,73001,73015,73017,73031,73033,73046,73050,73089,73093,73161,73166,73170,73184,73186,73213,73215,73229,73231],[968,72955,971],{"id":970},[973,72957,72958],{},"Bài này xây pipeline soi giao dịch đáng ngờ. Nhìn quan hệ chuyển tiền là thấy vòng gian lận.",[968,72960,979],{"id":978},[981,72962,72964],{"id":72963},"đồ-thị-giao-dịch-là-gì","Đồ thị giao dịch là gì",[986,72966,72967,72970,72973,72976],{},[989,72968,72969],{},"Mỗi tài khoản là 1 nút, mỗi chuyển tiền là 1 cạnh có hướng.",[989,72971,72972],{},"Cạnh giữ số tiền, thời gian và kênh giao dịch.",[989,72974,72975],{},"Ví dụ đời thường: vẽ sơ đồ ai chuyển cho ai để truy vết.",[989,72977,72978],{},"Xử lý được 1 triệu giao dịch là đạt.",[981,72980,72982],{"id":72981},"đặc-trưng-egonet-và-centrality","Đặc trưng egonet và centrality",[986,72984,72985,72988,72991,72994],{},[989,72986,72987],{},"Egonet là lân cận 1-2 hop quanh 1 tài khoản.",[989,72989,72990],{},"Bậc vào ra lệch mạnh là dấu hiệu gom hoặc quạt tiền.",[989,72992,72993],{},"PageRank lan độ đáng ngờ từ tài khoản xấu sang lân cận.",[989,72995,72996],{},"Ví dụ đời thường: ai chơi với nhiều kẻ xấu thì cũng đáng nghi.",[981,72998,73000],{"id":72999},"luật-watchtower-và-chấm-điểm","Luật watchtower và chấm điểm",[986,73002,73003,73006,73009,73012],{},[989,73004,73005],{},"Luật vòng tròn: A chuyển B chuyển C rồi về A trong thời gian ngắn.",[989,73007,73008],{},"Luật quạt tiền: 1 nguồn xả ra nhiều tài khoản mới.",[989,73010,73011],{},"Luật gom tiền: nhiều nguồn dồn về 1 đích.",[989,73013,73014],{},"Điểm rủi ro 0-100, cao thì đưa vào hàng đợi điều tra.",[968,73016,1433],{"id":1432},[986,73018,73019,73022,73025,73028],{},[989,73020,73021],{},"Input: vòng A-B-C-A trong 10 phút. Output: luật vòng tròn bắt, điểm trên 80.",[989,73023,73024],{},"Giải thích: tiền đi vòng khép kín là mẫu rửa tiền điển hình.",[989,73026,73027],{},"Input: tài khoản lương vào chi tiêu ra bình thường. Output: điểm dưới 20, không cảnh báo.",[989,73029,73030],{},"Giải thích: hành vi đều đặn không khớp mẫu gian lận nào.",[968,73032,1482],{"id":1481},[973,73034,1485,73035,7386,73037,26641,73039,73042,73043,1517],{},[1487,73036,13531],{},[992,73038,31660],{},[992,73040,73041],{},"igraph"," nếu cần nhanh), pandas. Dùng code ngày 44, 72, 73. Nộp vào ",[992,73044,73045],{},"day-130-fraud\u002F",[981,73047,73049],{"id":73048},"bài-1-nạp-dữ-liệu-và-dựng-đồ-thị","Bài 1: Nạp dữ liệu và dựng đồ thị",[2273,73051,73052,73079,73086],{},[989,73053,73054,73055,73058,73059],{},"Sinh 1.000.000 giao dịch trên 100.000 tài khoản ",[992,73056,73057],{},"(from, to, amount, ts, channel)",". Cài sẵn 3 kiểu gian lận có nhãn:\n",[986,73060,73061,73067,73073],{},[989,73062,73063,73066],{},[1487,73064,73065],{},"Vòng tròn:"," A -> B -> C -> A trong 1 giờ, số tiền gần bằng nhau.",[989,73068,73069,73072],{},[1487,73070,73071],{},"Quạt ra:"," 1 tài khoản chuyển cho 20 tài khoản mới mở trong 10 phút.",[989,73074,73075,73078],{},[1487,73076,73077],{},"Gom vào:"," 30 tài khoản chuyển về 1 đích trong 1 ngày.",[989,73080,73081,73082,73085],{},"Dựng đồ thị có hướng, cạnh gộp theo cặp ",[992,73083,73084],{},"(from, to)"," với tổng tiền và số lần.",[989,73087,73088],{},"In thời gian nạp và bộ nhớ. Mục tiêu: dưới 60 giây.",[981,73090,73092],{"id":73091},"bài-2-đặc-trưng-và-luật","Bài 2: Đặc trưng và luật",[1099,73094,73095,73105],{},[1102,73096,73097],{},[1105,73098,73099,73102],{},[1108,73100,73101],{},"Đặc trưng\u002FLuật",[1108,73103,73104],{},"Cách tính",[1118,73106,73107,73121,73131,73141,73151],{},[1105,73108,73109,73118],{},[1123,73110,73111,1656,73114,73117],{},[992,73112,73113],{},"in_degree",[992,73115,73116],{},"out_degree",", tỉ lệ vào\u002Fra",[1123,73119,73120],{},"Theo cửa sổ 24 giờ",[1105,73122,73123,73128],{},[1123,73124,73125],{},[992,73126,73127],{},"pagerank_suspicion",[1123,73129,73130],{},"Personalized PageRank từ 50 tài khoản đã biết xấu",[1105,73132,73133,73138],{},[1123,73134,73135],{},[992,73136,73137],{},"cycle_rule",[1123,73139,73140],{},"Tìm chu trình độ dài 3-4 trong 1 giờ (DFS giới hạn độ sâu)",[1105,73142,73143,73148],{},[1123,73144,73145],{},[992,73146,73147],{},"fan_out_rule",[1123,73149,73150],{},"Ra tới trên 15 tài khoản có tuổi dưới 7 ngày trong 10 phút",[1105,73152,73153,73158],{},[1123,73154,73155],{},[992,73156,73157],{},"fan_in_rule",[1123,73159,73160],{},"Trên 25 nguồn khác nhau trong 24 giờ",[973,73162,73163,73164,1517],{},"Điểm rủi ro 0-100: tổng có trọng số của luật và đặc trưng. Viết rõ trọng số và lý do trong ",[992,73165,2513],{},[981,73167,73169],{"id":73168},"bài-3-đánh-giá-và-điều-tra-nâng-cao","Bài 3: Đánh giá và điều tra (nâng cao)",[2273,73171,73172,73175,73178,73181],{},[989,73173,73174],{},"Precision, recall, F1 cho từng kiểu gian lận với ngưỡng điểm 70.",[989,73176,73177],{},"Vẽ đường precision-recall theo ngưỡng.",[989,73179,73180],{},"Với 5 tài khoản điểm cao nhất, xuất báo cáo điều tra: lý do (luật nào kích hoạt, số liệu), hình egonet 2 bước.",[989,73182,73183],{},"Đo thời gian chấm điểm 1 giao dịch mới (cập nhật tăng dần, không tính lại toàn bộ).",[981,73185,2711],{"id":2710},[986,73187,73189,73195,73201,73207],{"className":73188},[2715],[989,73190,73192,73194],{"className":73191},[2719],[2721,73193],{"disabled":2723,"type":2724}," Nạp 1 triệu giao dịch dưới 60 giây.",[989,73196,73198,73200],{"className":73197},[2719],[2721,73199],{"disabled":2723,"type":2724}," Mỗi luật có test với dữ liệu nhỏ cài sẵn.",[989,73202,73204,73206],{"className":73203},[2719],[2721,73205],{"disabled":2723,"type":2724}," Bảng precision\u002Frecall\u002FF1 theo kiểu gian lận.",[989,73208,73210,73212],{"className":73209},[2719],[2721,73211],{"disabled":2723,"type":2724}," 5 báo cáo điều tra có hình và lý do.",[968,73214,2890],{"id":2889},[986,73216,73217,73220,73223,73226],{},[989,73218,73219],{},"Đồ thị giao dịch dựng từ log thế nào?",[989,73221,73222],{},"Egonet quanh 1 tài khoản cho biết điều gì?",[989,73224,73225],{},"3 luật watchtower bắt mẫu hình nào?",[989,73227,73228],{},"Precision và recall đo chất lượng pipeline ra sao?",[3014,73230],{},[973,73232,73233],{},"🌕 Bạn đã hoàn thành ngày 130. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":73235},[73236,73237,73242,73243,73249],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":73238},[73239,73240,73241],{"id":72963,"depth":73,"text":72964},{"id":72981,"depth":73,"text":72982},{"id":72999,"depth":73,"text":73000},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":73244},[73245,73246,73247,73248],{"id":73048,"depth":73,"text":73049},{"id":73091,"depth":73,"text":73092},{"id":73168,"depth":73,"text":73169},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây pipeline chống gian lận: đồ thị giao dịch, đặc trưng egonet và centrality, luật watchtower, đánh giá precision recall trên dữ liệu gán nhãn.",{},[15144],{"title":705,"description":73250},[17502,73255,29786,32323,32322],"fraud-detection","6KojleoUkoVaHnLBe27puf4bTpZOIqXROpT-yQZgAXo",{"id":73258,"title":710,"body":73259,"category":8797,"day":713,"description":73579,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":73580,"navigation":2723,"outcomes":3047,"path":711,"prerequisites":73581,"seo":73582,"stem":712,"tags":73583,"__hash__":73586},"challenges\u002Fchallenges\u002F131.app-recsys-pipeline.md",{"type":965,"value":73260,"toc":73563},[73261,73263,73266,73268,73272,73286,73290,73304,73308,73322,73370,73372,73386,73388,73396,73400,73411,73415,73459,73479,73487,73491,73511,73513,73540,73542,73556,73558,73561],[968,73262,971],{"id":970},[973,73264,73265],{},"Bài này xây máy gợi ý phim và sản phẩm. Người cũ gợi theo gu, người mới gợi theo top phổ biến.",[968,73267,979],{"id":978},[981,73269,73271],{"id":73270},"content-based-theo-metadata","Content-based theo metadata",[986,73273,73274,73277,73280,73283],{},[989,73275,73276],{},"Vector hóa thể loại và mô tả bằng TF-IDF.",[989,73278,73279],{},"Profile user là trung bình vector các item đã thích.",[989,73281,73282],{},"Gợi ý bằng cosine giữa profile và item chưa xem.",[989,73284,73285],{},"Ví dụ đời thường: thích phim hành động thì gợi thêm phim hành động.",[981,73287,73289],{"id":73288},"collaborative-filtering-theo-đám-đông","Collaborative filtering theo đám đông",[986,73291,73292,73295,73298,73301],{},[989,73293,73294],{},"User-based: người giống bạn thích gì thì gợi nấy.",[989,73296,73297],{},"Item-based: ai thích món này cũng thích món kia.",[989,73299,73300],{},"Cần đủ rating chung mới tin, ít quá thì rất nhiễu.",[989,73302,73303],{},"Ví dụ đời thường: bạn cùng gu khen hay thì bạn cũng thấy hay.",[981,73305,73307],{"id":73306},"matrix-factorization-và-cold-start","Matrix factorization và cold start",[986,73309,73310,73313,73316,73319],{},[989,73311,73312],{},"Phân rã ma trận rating thành 2 ma trận latent user và item.",[989,73314,73315],{},"Dự đoán bằng tích vô hướng 2 vector latent.",[989,73317,73318],{},"User mới thì gợi phổ biến cộng theo thể loại đăng ký.",[989,73320,73321],{},"Item mới chỉ có metadata thì đi nhánh content-based.",[1099,73323,73324,73335],{},[1102,73325,73326],{},[1105,73327,73328,73330,73332],{},[1108,73329,41062],{},[1108,73331,39307],{},[1108,73333,73334],{},"Mạnh khi nào",[1118,73336,73337,73348,73359],{},[1105,73338,73339,73342,73345],{},[1123,73340,73341],{},"Content-based",[1123,73343,73344],{},"Metadata item",[1123,73346,73347],{},"Item mới, user ít lịch sử",[1105,73349,73350,73353,73356],{},[1123,73351,73352],{},"CF",[1123,73354,73355],{},"Rating chung",[1123,73357,73358],{},"User cũ đông",[1105,73360,73361,73364,73367],{},[1123,73362,73363],{},"Factorization",[1123,73365,73366],{},"Nhiều rating",[1123,73368,73369],{},"Gu ẩn phức tạp",[968,73371,1433],{"id":1432},[986,73373,73374,73377,73380,73383],{},[989,73375,73376],{},"Input: user mê hành động, hỏi top-10. Output: trên 60% phim hành động, không chứa phim đã xem.",[989,73378,73379],{},"Giải thích: cosine đẩy phim cùng thể loại lên đầu, bộ lọc bỏ phim đã xem.",[989,73381,73382],{},"Input: user mới tinh vừa đăng ký. Output: danh sách phổ biến theo thể loại đã chọn.",[989,73384,73385],{},"Giải thích: chưa có lịch sử nên đi nhánh cold start.",[968,73387,1482],{"id":1481},[973,73389,1485,73390,73392,73393,1517],{},[1487,73391,13531],{},". Dùng code ngày 58, 59, 91. Dữ liệu MovieLens 1M (hoặc 100K). Nộp vào ",[992,73394,73395],{},"day-131-recsys\u002F",[981,73397,73399],{"id":73398},"bài-1-pipeline-dữ-liệu","Bài 1: Pipeline dữ liệu",[2273,73401,73402,73405,73408],{},[989,73403,73404],{},"Nạp rating, phim, người dùng. Kiểm tra dữ liệu: rating ngoài 1-5, id trùng, phim thiếu thể loại.",[989,73406,73407],{},"Chia theo thời gian: mỗi user, 80% rating cũ là train, 20% mới là test.",[989,73409,73410],{},"Lưu dữ liệu đã xử lý ra Parquet. Pipeline chạy lại cho cùng kết quả.",[981,73412,73414],{"id":73413},"bài-2-ba-mô-hình-và-bộ-điều-phối","Bài 2: Ba mô hình và bộ điều phối",[1099,73416,73417,73425],{},[1102,73418,73419],{},[1105,73420,73421,73423],{},[1108,73422,41062],{},[1108,73424,23789],{},[1118,73426,73427,73437,73448],{},[1105,73428,73429,73434],{},[1123,73430,73431],{},[992,73432,73433],{},"PopularityModel",[1123,73435,73436],{},"User mới, 0 rating",[1105,73438,73439,73445],{},[1123,73440,73441,73444],{},[992,73442,73443],{},"ContentModel"," (ngày 58)",[1123,73446,73447],{},"User có 1-9 rating, hoặc phim mới chưa ai chấm",[1105,73449,73450,73456],{},[1123,73451,73452,73455],{},[992,73453,73454],{},"MFModel"," (ngày 91)",[1123,73457,73458],{},"User có từ 10 rating",[1352,73460,73462],{"className":3538,"code":73461,"language":3540,"meta":1357,"style":1357},"class Recommender:\n    def recommend(self, user_id: int, n: int = 10, exclude_seen: bool = True) -> list[tuple[int, float, str]]:\n        \"\"\"Trả (movie_id, score, lý_do). Lý do ví dụ: \"Vì bạn thích Toy Story\" hoặc \"Phổ biến tuần này\".\"\"\"\n",[992,73463,73464,73469,73474],{"__ignoreMap":1357},[1023,73465,73466],{"class":1362,"line":63},[1023,73467,73468],{},"class Recommender:\n",[1023,73470,73471],{"class":1362,"line":68},[1023,73472,73473],{},"    def recommend(self, user_id: int, n: int = 10, exclude_seen: bool = True) -> list[tuple[int, float, str]]:\n",[1023,73475,73476],{"class":1362,"line":73},[1023,73477,73478],{},"        \"\"\"Trả (movie_id, score, lý_do). Lý do ví dụ: \"Vì bạn thích Toy Story\" hoặc \"Phổ biến tuần này\".\"\"\"\n",[973,73480,73481,73483,73484,73486],{},[1487,73482,6076],{}," không gợi phim user đã xem. Luôn trả đủ ",[992,73485,1262],{}," phim (bù bằng phổ biến nếu thiếu).",[981,73488,73490],{"id":73489},"bài-3-đánh-giá-và-api-nâng-cao","Bài 3: Đánh giá và API (nâng cao)",[2273,73492,73493,73496,73499,73506],{},[989,73494,73495],{},"Tính cho từng nhóm user (0, 1-9, 10+ rating): precision@10, recall@10, NDCG@10, coverage (tỉ lệ phim từng được gợi ý), độ đa dạng thể loại.",[989,73497,73498],{},"So bộ điều phối với từng mô hình đơn lẻ.",[989,73500,73501,73502,73505],{},"Viết API ",[992,73503,73504],{},"GET \u002Frecommend?user_id=..&n=.."," bằng FastAPI. Độ trễ p99 dưới 50 ms (tính trước vector, dùng numpy cho tích vô hướng).",[989,73507,73508,73510],{},[992,73509,2513],{},": sơ đồ pipeline, cách chạy, bảng kết quả.",[981,73512,2711],{"id":2710},[986,73514,73516,73522,73528,73534],{"className":73515},[2715],[989,73517,73519,73521],{"className":73518},[2719],[2721,73520],{"disabled":2723,"type":2724}," Pipeline tất định, chạy lại cho cùng file Parquet.",[989,73523,73525,73527],{"className":73524},[2719],[2721,73526],{"disabled":2723,"type":2724}," User mới vẫn nhận đủ 10 gợi ý có lý do.",[989,73529,73531,73533],{"className":73530},[2719],[2721,73532],{"disabled":2723,"type":2724}," Bảng metric theo nhóm user có số thật.",[989,73535,73537,73539],{"className":73536},[2719],[2721,73538],{"disabled":2723,"type":2724}," API chạy, có số đo p99.",[968,73541,2890],{"id":2889},[986,73543,73544,73547,73550,73553],{},[989,73545,73546],{},"Content-based tính điểm gợi ý thế nào?",[989,73548,73549],{},"CF user-based khác item-based ở điểm gì?",[989,73551,73552],{},"Factorization học gu ẩn bằng cách nào?",[989,73554,73555],{},"Cold start xử lý user và item mới ra sao?",[3014,73557],{},[973,73559,73560],{},"🌕 Bạn đã hoàn thành ngày 131. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,73562,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":73564},[73565,73566,73571,73572,73578],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":73567},[73568,73569,73570],{"id":73270,"depth":73,"text":73271},{"id":73288,"depth":73,"text":73289},{"id":73306,"depth":73,"text":73307},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":73573},[73574,73575,73576,73577],{"id":73398,"depth":73,"text":73399},{"id":73413,"depth":73,"text":73414},{"id":73489,"depth":73,"text":73490},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây engine gợi ý hoàn chỉnh: content-based, collaborative filtering user và item, matrix factorization, xử lý cold start, đo precision và đa dạng.",{},[18469,14055],{"title":710,"description":73579},[17502,39582,73584,73585],"collaborative-filtering","matrix-factorization","Z_mcRbxj4aY1uKEuwr1wnkL4pnKGjsUBLKjCqFDi0fY",{"id":73588,"title":715,"body":73589,"category":8797,"day":718,"description":73862,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":73863,"navigation":2723,"outcomes":3047,"path":716,"prerequisites":73864,"seo":73865,"stem":717,"tags":73866,"__hash__":73867},"challenges\u002Fchallenges\u002F132.app-clustering-pipeline.md",{"type":965,"value":73590,"toc":73846},[73591,73593,73596,73598,73602,73616,73620,73634,73638,73652,73654,73668,73670,73678,73682,73697,73711,73715,73770,73776,73780,73796,73798,73825,73827,73841,73843],[968,73592,971],{"id":970},[973,73594,73595],{},"Bài này xây pipeline gom khách hàng thành nhóm. Mỗi nhóm có chân dung riêng để chăm sóc.",[968,73597,979],{"id":978},[981,73599,73601],{"id":73600},"chuẩn-hóa-trước-khi-cụm","Chuẩn hóa trước khi cụm",[986,73603,73604,73607,73610,73613],{},[989,73605,73606],{},"Chuẩn hóa z-score để tuổi và chi tiêu cùng thang đo.",[989,73608,73609],{},"Loại ngoại lệ cực đoan kẻo kéo centroid lệch.",[989,73611,73612],{},"Giảm chiều PCA để vẽ scatter 2D dễ nhìn.",[989,73614,73615],{},"Ví dụ đời thường: đổi hết tiền về cùng đơn vị rồi mới so.",[981,73617,73619],{"id":73618},"k-means-và-chọn-k","K-means và chọn K",[986,73621,73622,73625,73628,73631],{},[989,73623,73624],{},"K-means gom mỗi điểm về centroid gần nhất rồi cập nhật lại.",[989,73626,73627],{},"Khởi tạo k-means++ cộng nhiều restart để khỏi kẹt xấu.",[989,73629,73630],{},"Quét K từ 2 tới 10, chọn K có silhouette cao ổn định.",[989,73632,73633],{},"Ví dụ đời thường: chia lớp học thành K nhóm ngồi gần nhau.",[981,73635,73637],{"id":73636},"dbscan-và-optics-cho-hình-lạ","DBSCAN và OPTICS cho hình lạ",[986,73639,73640,73643,73646,73649],{},[989,73641,73642],{},"DBSCAN gom vùng dày điểm, điểm thưa đánh dấu nhiễu.",[989,73644,73645],{},"Xử lý cụm lưỡi liềm mà K-means cắt ngang bó tay.",[989,73647,73648],{},"OPTICS xử lý mật độ không đều và cho phân cấp nhiều mức.",[989,73650,73651],{},"Không có thuật toán vạn năng, phải so cả 3 họ.",[968,73653,1433],{"id":1432},[986,73655,73656,73659,73662,73665],{},[989,73657,73658],{},"Input: dữ liệu blob cầu rõ ràng. Output: K-means cho silhouette trên 0.6, khớp nhãn 90%.",[989,73660,73661],{},"Giải thích: cụm cầu đúng sở trường của K-means.",[989,73663,73664],{},"Input: dữ liệu 2 lưỡi liềm. Output: K-means cắt ngang, DBSCAN tách đúng 2 cụm nhiễu dưới 5%.",[989,73666,73667],{},"Giải thích: DBSCAN theo mật độ nên ôm được hình cong.",[968,73669,1482],{"id":1481},[973,73671,1485,73672,73674,73675,1517],{},[1487,73673,13531],{},". Dùng code ngày 47, 48, 49, 83, 84. Nộp vào ",[992,73676,73677],{},"day-132-clustering\u002F",[981,73679,73681],{"id":73680},"bài-1-tiền-xử-lý","Bài 1: Tiền xử lý",[973,73683,73684,73685,73688,73689,73692,73693,73696],{},"Dữ liệu: bộ khách hàng mua sắm (ví dụ Online Retail UCI) tính thành bảng RFM: ",[1487,73686,73687],{},"Recency"," (ngày từ lần mua cuối), ",[1487,73690,73691],{},"Frequency"," (số đơn), ",[1487,73694,73695],{},"Monetary"," (tổng chi).",[2273,73698,73699,73702,73705,73708],{},[989,73700,73701],{},"Làm sạch: bỏ đơn hủy, số lượng âm, khách không có id.",[989,73703,73704],{},"Log-transform cột lệch, chuẩn hóa z-score.",[989,73706,73707],{},"Loại ngoại lệ bằng IQR và ghi lại số dòng bị loại.",[989,73709,73710],{},"PCA 2D chỉ để vẽ.",[981,73712,73714],{"id":73713},"bài-2-so-3-họ-thuật-toán","Bài 2: So 3 họ thuật toán",[1099,73716,73717,73728],{},[1102,73718,73719],{},[1105,73720,73721,73723,73726],{},[1108,73722,9446],{},[1108,73724,73725],{},"Tham số cần chọn",[1108,73727,66606],{},[1118,73729,73730,73744,73757],{},[1105,73731,73732,73735,73739],{},[1123,73733,73734],{},"K-means (k-means++, 10 restart)",[1123,73736,73737],{},[992,73738,4022],{},[1123,73740,73741,73742],{},"Silhouette và elbow, ",[992,73743,35199],{},[1105,73745,73746,73748,73754],{},[1123,73747,34258],{},[1123,73749,73750,1656,73752],{},[992,73751,34552],{},[992,73753,34652],{},[1123,73755,73756],{},"k-distance plot",[1105,73758,73759,73762,73767],{},[1123,73760,73761],{},"OPTICS",[1123,73763,73764,73766],{},[992,73765,34652],{},", ngưỡng cắt",[1123,73768,73769],{},"Reachability plot",[973,73771,1505,73772,73775],{},[992,73773,73774],{},"run_all(X) -> pd.DataFrame"," trả bảng: thuật toán, tham số, số cụm, tỉ lệ nhiễu, silhouette, Davies-Bouldin, thời gian.",[981,73777,73779],{"id":73778},"bài-3-diễn-giải-và-báo-cáo-nâng-cao","Bài 3: Diễn giải và báo cáo (nâng cao)",[2273,73781,73782,73785,73788,73791],{},[989,73783,73784],{},"Với phân cụm được chọn, in bảng trung bình R, F, M mỗi cụm (theo giá trị gốc, không chuẩn hóa).",[989,73786,73787],{},"Đặt tên nghiệp vụ mỗi cụm (ví dụ \"khách VIP\", \"khách ngủ đông\") và 1 hành động marketing.",[989,73789,73790],{},"Kiểm tra độ ổn định: chạy lại trên 5 mẫu bootstrap 80%, đo Adjusted Rand Index giữa các lần.",[989,73792,73793,73795],{},[992,73794,17400],{},": hình scatter PCA tô màu theo cụm cho 3 thuật toán, bảng Bài 2, bảng cụm, lý do chọn.",[981,73797,2711],{"id":2710},[986,73799,73801,73807,73813,73819],{"className":73800},[2715],[989,73802,73804,73806],{"className":73803},[2719],[2721,73805],{"disabled":2723,"type":2724}," Pipeline tiền xử lý ghi rõ số dòng bị loại ở mỗi bước.",[989,73808,73810,73812],{"className":73809},[2719],[2721,73811],{"disabled":2723,"type":2724}," Bảng so sánh 3 thuật toán có số thật.",[989,73814,73816,73818],{"className":73815},[2719],[2721,73817],{"disabled":2723,"type":2724}," Mỗi cụm có tên nghiệp vụ và hành động.",[989,73820,73822,73824],{"className":73821},[2719],[2721,73823],{"disabled":2723,"type":2724}," Có chỉ số ổn định ARI.",[968,73826,2890],{"id":2889},[986,73828,73829,73832,73835,73838],{},[989,73830,73831],{},"Vì sao phải chuẩn hóa trước khi cụm?",[989,73833,73834],{},"Silhouette giúp chọn K thế nào?",[989,73836,73837],{},"DBSCAN thắng K-means ở dữ liệu nào?",[989,73839,73840],{},"Gán điểm mới vào cụm cũ bằng cách nào?",[3014,73842],{},[973,73844,73845],{},"🌕 Bạn đã hoàn thành ngày 132. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":73847},[73848,73849,73854,73855,73861],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":73850},[73851,73852,73853],{"id":73600,"depth":73,"text":73601},{"id":73618,"depth":73,"text":73619},{"id":73636,"depth":73,"text":73637},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":73856},[73857,73858,73859,73860],{"id":73680,"depth":73,"text":73681},{"id":73713,"depth":73,"text":73714},{"id":73778,"depth":73,"text":73779},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây pipeline phân cụm end-to-end: chuẩn hóa, chọn K bằng silhouette, so K-means DBSCAN OPTICS, báo cáo metric và diễn giải cụm.",{},[18469],{"title":715,"description":73862},[17502,34177,34178,34739,50952],"sJxKYF14at8ntEOhVYcTGNou-F5_nyoBCXt0xtTXsgQ",{"id":73869,"title":720,"body":73870,"category":8797,"day":723,"description":74174,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":74175,"navigation":2723,"outcomes":3047,"path":721,"prerequisites":74176,"seo":74177,"stem":722,"tags":74178,"__hash__":74180},"challenges\u002Fchallenges\u002F133.app-mapreduce-spark.md",{"type":965,"value":73871,"toc":74158},[73872,73874,73877,73879,73883,73897,73901,73915,73919,73933,73963,73965,73979,73981,73993,73997,74000,74039,74042,74046,74074,74078,74106,74108,74135,74137,74151,74153,74156],[968,73873,971],{"id":970},[973,73875,73876],{},"Bài này xây app đếm từ kiểu phân tán. Chia nhỏ văn bản cho nhiều worker cùng đếm.",[968,73878,979],{"id":978},[981,73880,73882],{"id":73881},"mapreduce-thủ-công-3-bước","MapReduce thủ công 3 bước",[986,73884,73885,73888,73891,73894],{},[989,73886,73887],{},"Map: mỗi worker đếm từ cục bộ trong chunk của mình.",[989,73889,73890],{},"Shuffle: gom cùng 1 từ về cùng 1 reducer theo hash.",[989,73892,73893],{},"Reduce: cộng tổng từng từ rồi ghi kết quả.",[989,73895,73896],{},"Ví dụ đời thường: chia xấp phiếu cho nhiều người đếm rồi cộng lại.",[981,73898,73900],{"id":73899},"spark-job-tương-đương","Spark job tương đương",[986,73902,73903,73906,73909,73912],{},[989,73904,73905],{},"TextFile chia văn bản thành nhiều partition.",[989,73907,73908],{},"FlatMap tách từ, map thành cặp từ-1, reduceByKey cộng.",[989,73910,73911],{},"Giữ dữ liệu trung gian trong RAM nên nhanh hơn ghi đĩa.",[989,73913,73914],{},"Lineage cho chịu lỗi: mất partition nào tính lại partition đó.",[981,73916,73918],{"id":73917},"combiner-và-skew","Combiner và skew",[986,73920,73921,73924,73927,73930],{},[989,73922,73923],{},"Combiner cộng cục bộ trước để giảm hàng gửi qua shuffle.",[989,73925,73926],{},"Skew là vài từ hot làm 1 reducer quá tải.",[989,73928,73929],{},"Xử lý skew bằng combiner mạnh hoặc salting.",[989,73931,73932],{},"MapReduce đơn giản chịu lỗi tốt, Spark nhanh nhờ RAM.",[1352,73934,73936],{"className":3538,"code":73935,"language":3540,"meta":1357,"style":1357},"# Spark wordcount gọn\nrdd = sc.textFile(\"data.txt\")  # chia partition\ncounts = rdd.flatMap(split_words)  # tách từ\n  .map(lambda w: (w, 1))  # cặp từ-1\n  .reduceByKey(add)  # cộng phân tán\n",[992,73937,73938,73943,73948,73953,73958],{"__ignoreMap":1357},[1023,73939,73940],{"class":1362,"line":63},[1023,73941,73942],{},"# Spark wordcount gọn\n",[1023,73944,73945],{"class":1362,"line":68},[1023,73946,73947],{},"rdd = sc.textFile(\"data.txt\")  # chia partition\n",[1023,73949,73950],{"class":1362,"line":73},[1023,73951,73952],{},"counts = rdd.flatMap(split_words)  # tách từ\n",[1023,73954,73955],{"class":1362,"line":78},[1023,73956,73957],{},"  .map(lambda w: (w, 1))  # cặp từ-1\n",[1023,73959,73960],{"class":1362,"line":83},[1023,73961,73962],{},"  .reduceByKey(add)  # cộng phân tán\n",[968,73964,1433],{"id":1432},[986,73966,73967,73970,73973,73976],{},[989,73968,73969],{},"Input: 100MB văn bản, chạy 2 engine. Output: top-10 từ khớp 100%, tổng từ bằng nhau.",[989,73971,73972],{},"Giải thích: 2 engine khác nhau nhưng cùng logic đếm nên kết quả khớp.",[989,73974,73975],{},"Input: tăng worker từ 2 lên 4. Output: thời gian giảm ít nhất 30%.",[989,73977,73978],{},"Giải thích: nhiều tay cùng đếm nên xong sớm hơn.",[968,73980,1482],{"id":1481},[973,73982,1485,73983,7386,73985,1509,73987,73989,73990,1517],{},[1487,73984,13531],{},[992,73986,35455],{},[1487,73988,63937],{},". Dùng khung ngày 50 và kiến thức ngày 109. Nộp vào ",[992,73991,73992],{},"day-133-wordcount\u002F",[981,73994,73996],{"id":73995},"bài-1-wordcount-3-cách","Bài 1: Wordcount 3 cách",[973,73998,73999],{},"Dữ liệu: 1 GB văn bản (ví dụ ghép nhiều file Wikipedia dump đã giải nén, hoặc lặp Gutenberg).",[1099,74001,74002,74010],{},[1102,74003,74004],{},[1105,74005,74006,74008],{},[1108,74007,14526],{},[1108,74009,2547],{},[1118,74011,74012,74023,74031],{},[1105,74013,74014,74017],{},[1123,74015,74016],{},"Tuần tự",[1123,74018,74019,74022],{},[992,74020,74021],{},"collections.Counter",", đọc từng dòng",[1105,74024,74025,74028],{},[1123,74026,74027],{},"MapReduce tự viết (ngày 50)",[1123,74029,74030],{},"Có combiner, 8 worker",[1105,74032,74033,74035],{},[1123,74034,63937],{},[1123,74036,74037],{},[992,74038,63963],{},[973,74040,74041],{},"Kiểm tra 3 kết quả giống hệt nhau (so top 1000 và tổng số từ). In thời gian mỗi cách.",[981,74043,74045],{"id":74044},"bài-2-shuffle-và-skew","Bài 2: Shuffle và skew",[2273,74047,74048,74061,74064],{},[989,74049,74050,74051,74054,74055,1509,74058,1517],{},"Đếm số cặp ",[992,74052,74053],{},"(từ, count)"," đi qua shuffle khi có và không có combiner (bản tự viết). Với Spark, đọc \"Shuffle Write\" trong Spark UI khi dùng ",[992,74056,74057],{},"groupByKey",[992,74059,74060],{},"reduceByKey",[989,74062,74063],{},"Tạo dữ liệu lệch: từ \"the\" chiếm 30% số từ. Quan sát reducer của \"the\" chạy lâu nhất.",[989,74065,74066,74067,10880,74070,74073],{},"Sửa bằng salting: ",[992,74068,74069],{},"the#0",[992,74071,74072],{},"the#9",", reduce 2 lần. So thời gian.",[981,74075,74077],{"id":74076},"bài-3-mở-rộng-job-nâng-cao","Bài 3: Mở rộng job (nâng cao)",[2273,74079,74080,74086,74092,74101],{},[989,74081,74082,74085],{},[1487,74083,74084],{},"Bigram"," phổ biến nhất (cặp 2 từ liền nhau).",[989,74087,74088,74091],{},[1487,74089,74090],{},"Chỉ mục ngược"," có số lần xuất hiện mỗi file.",[989,74093,74094,74097,74098,74100],{},[1487,74095,74096],{},"TF-IDF"," cho 10.000 tài liệu bằng Spark DataFrame. So với bản ",[992,74099,17633],{}," trên tập nhỏ để kiểm tra.",[989,74102,74103,74105],{},[992,74104,2513],{},": bảng thời gian, ảnh Spark UI, giải thích nơi nghẽn.",[981,74107,2711],{"id":2710},[986,74109,74111,74117,74123,74129],{"className":74110},[2715],[989,74112,74114,74116],{"className":74113},[2719],[2721,74115],{"disabled":2723,"type":2724}," 3 cách cho cùng kết quả.",[989,74118,74120,74122],{"className":74119},[2719],[2721,74121],{"disabled":2723,"type":2724}," Số liệu shuffle có và không có combiner.",[989,74124,74126,74128],{"className":74125},[2719],[2721,74127],{"disabled":2723,"type":2724}," Salting cải thiện thời gian với dữ liệu lệch.",[989,74130,74132,74134],{"className":74131},[2719],[2721,74133],{"disabled":2723,"type":2724}," TF-IDF Spark khớp sklearn trên tập nhỏ.",[968,74136,2890],{"id":2889},[986,74138,74139,74142,74145,74148],{},[989,74140,74141],{},"3 bước map, shuffle, reduce mỗi bước làm gì?",[989,74143,74144],{},"Combiner giúp giảm tải shuffle thế nào?",[989,74146,74147],{},"Spark nhanh hơn MapReduce đĩa nhờ gì?",[989,74149,74150],{},"Skew làm lệch tải reducer ra sao?",[3014,74152],{},[973,74154,74155],{},"🌕 Bạn đã hoàn thành ngày 133. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,74157,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":74159},[74160,74161,74166,74167,74173],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":74162},[74163,74164,74165],{"id":73881,"depth":73,"text":73882},{"id":73899,"depth":73,"text":73900},{"id":73917,"depth":73,"text":73918},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":74168},[74169,74170,74171,74172],{"id":73995,"depth":73,"text":73996},{"id":74044,"depth":73,"text":74045},{"id":74076,"depth":73,"text":74077},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app đếm từ phân tán: MapReduce thủ công đa tiến trình, Spark job tương đương, so sánh tốc độ, shuffle và fault tolerance.",{},[14055,17499],{"title":720,"description":74174},[17502,35747,64333,35749,74179],"wordcount","DT2VpbdXUpaHu_dm_vrJEfPhYAspTW2Xc1xkPToTWjA",{"id":74182,"title":725,"body":74183,"category":8797,"day":728,"description":74479,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":74480,"navigation":2723,"outcomes":3047,"path":726,"prerequisites":74481,"seo":74482,"stem":727,"tags":74483,"__hash__":74485},"challenges\u002Fchallenges\u002F134.app-delivery-routes.md",{"type":965,"value":74184,"toc":74463},[74185,74187,74190,74192,74196,74210,74214,74228,74232,74246,74291,74293,74307,74309,74317,74321,74340,74365,74371,74375,74390,74394,74411,74413,74440,74442,74456,74458,74461],[968,74186,971],{"id":970},[973,74188,74189],{},"Bài này xây app tìm đường giao hàng. So 3 thuật toán xem ai nhanh mà đường vẫn ngắn.",[968,74191,979],{"id":978},[981,74193,74195],{"id":74194},"_3-thuật-toán-tìm-đường","3 thuật toán tìm đường",[986,74197,74198,74201,74204,74207],{},[989,74199,74200],{},"BFS đi theo lớp, đúng khi mọi bước tốn bằng nhau.",[989,74202,74203],{},"Dijkstra luôn mở nút rẻ nhất nên đúng với trọng số không âm.",[989,74205,74206],{},"A* cộng thêm heuristic ước lượng về đích nên thăm ít nút hơn.",[989,74208,74209],{},"Ví dụ đời thường: BFS đi mò, Dijkstra cân giá xăng, A* có la bàn.",[981,74211,74213],{"id":74212},"heuristic-phải-admissible","Heuristic phải admissible",[986,74215,74216,74219,74222,74225],{},[989,74217,74218],{},"Admissible nghĩa là không bao giờ ước lượng cao hơn thật.",[989,74220,74221],{},"Manhattan trên lưới trống là admissible nên vẫn tối ưu.",[989,74223,74224],{},"Phóng đại heuristic gấp đôi sẽ cho đường dài hơn tối ưu.",[989,74226,74227],{},"Chọn sai heuristic thì A* có thể tệ hơn Dijkstra.",[981,74229,74231],{"id":74230},"đa-điểm-và-trực-quan","Đa điểm và trực quan",[986,74233,74234,74237,74240,74243],{},[989,74235,74236],{},"Đa điểm dùng tham lam: đi điểm gần nhất tiếp theo.",[989,74238,74239],{},"Tô vùng đã thăm mỗi thuật toán 1 màu để so.",[989,74241,74242],{},"Đầu cuối nằm trong chướng ngại phải báo lỗi rõ.",[989,74244,74245],{},"Mọi bản đồ lưu file để benchmark tái lập.",[1099,74247,74248,74260],{},[1102,74249,74250],{},[1105,74251,74252,74254,74257],{},[1108,74253,9446],{},[1108,74255,74256],{},"Khi nào đúng",[1108,74258,74259],{},"Số nút thăm",[1118,74261,74262,74271,74280],{},[1105,74263,74264,74266,74268],{},[1123,74265,29899],{},[1123,74267,30702],{},[1123,74269,74270],{},"Nhiều",[1105,74272,74273,74275,74278],{},[1123,74274,30672],{},[1123,74276,74277],{},"Trọng số không âm",[1123,74279,10667],{},[1105,74281,74282,74285,74288],{},[1123,74283,74284],{},"A* chuẩn",[1123,74286,74287],{},"Heuristic admissible",[1123,74289,74290],{},"Ít nhất",[968,74292,1433],{"id":1432},[986,74294,74295,74298,74301,74304],{},[989,74296,74297],{},"Input: lưới không trọng số, 20 cặp ngẫu nhiên. Output: BFS và Dijkstra cho cùng độ dài.",[989,74299,74300],{},"Giải thích: cạnh bằng nhau nên BFS đã tối ưu.",[989,74302,74303],{},"Input: đồ thị trọng số, 20 cặp. Output: A* cùng chi phí Dijkstra nhưng thăm ít hơn 30%.",[989,74305,74306],{},"Giải thích: heuristic hướng thẳng về đích nên bớt đi lạc.",[968,74308,1482],{"id":1481},[973,74310,1485,74311,74313,74314,1517],{},[1487,74312,13531],{}," với pygame hoặc matplotlib (hoặc C++ với SFML). Dùng code ngày 40, 42, 43. Nộp vào ",[992,74315,74316],{},"day-134-routes\u002F",[981,74318,74320],{"id":74319},"bài-1-bản-đồ-lưới-và-3-thuật-toán","Bài 1: Bản đồ lưới và 3 thuật toán",[973,74322,74323,74324,74326,74327,74329,74330,74332,74333,74335,74336,74339],{},"Bản đồ đọc từ file text: ",[992,74325,1517],{}," đường, ",[992,74328,15983],{}," tường, ",[992,74331,59588],{}," bùn (chi phí 5), ",[992,74334,4757],{}," kho, ",[992,74337,74338],{},"1..9"," điểm giao.",[1352,74341,74343],{"className":3538,"code":74342,"language":3540,"meta":1357,"style":1357},"def bfs(grid, s, t) -> Result: ...        # bỏ qua chi phí bùn\ndef dijkstra(grid, s, t) -> Result: ...\ndef astar(grid, s, t, h, weight=1.0) -> Result: ...   # f = g + weight * h\n# Result: path, cost, visited (tập ô đã mở), time_ms\n",[992,74344,74345,74350,74355,74360],{"__ignoreMap":1357},[1023,74346,74347],{"class":1362,"line":63},[1023,74348,74349],{},"def bfs(grid, s, t) -> Result: ...        # bỏ qua chi phí bùn\n",[1023,74351,74352],{"class":1362,"line":68},[1023,74353,74354],{},"def dijkstra(grid, s, t) -> Result: ...\n",[1023,74356,74357],{"class":1362,"line":73},[1023,74358,74359],{},"def astar(grid, s, t, h, weight=1.0) -> Result: ...   # f = g + weight * h\n",[1023,74361,74362],{"class":1362,"line":78},[1023,74363,74364],{},"# Result: path, cost, visited (tập ô đã mở), time_ms\n",[1352,74366,74369],{"className":74367,"code":74368,"language":2241,"meta":1357},[2239],"Bản đồ không bùn -> 3 thuật toán cùng cost\nBản đồ có bùn    -> BFS đi xuyên bùn (cost cao hơn), Dijkstra và A* vòng qua\nS hoặc đích nằm trong tường -> báo lỗi rõ ràng\n",[992,74370,74368],{"__ignoreMap":1357},[981,74372,74374],{"id":74373},"bài-2-trực-quan-hóa","Bài 2: Trực quan hóa",[2273,74376,74377,74380,74383],{},[989,74378,74379],{},"Vẽ bản đồ, tô ô đã mở của mỗi thuật toán một màu, vẽ đường đi.",[989,74381,74382],{},"Xuất 3 ảnh (hoặc 1 GIF quá trình mở ô).",[989,74384,74385,74386,74389],{},"A* với ",[992,74387,74388],{},"weight = 1, 1.5, 2, 5",": bảng số ô mở và cost. Chỉ ra từ weight nào đường không còn tối ưu.",[981,74391,74393],{"id":74392},"bài-3-giao-nhiều-điểm-nâng-cao","Bài 3: Giao nhiều điểm (nâng cao)",[2273,74395,74396,74402,74405,74408],{},[989,74397,74398,74399,74401],{},"Kho ",[992,74400,4757],{}," giao cho 9 điểm rồi quay về. Tính ma trận khoảng cách giữa 10 điểm bằng 10 lần Dijkstra.",[989,74403,74404],{},"Thứ tự giao: tham lam gần nhất, tham lam + 2-opt, Held-Karp (ngày 78, 10 điểm vẫn chạy được).",[989,74406,74407],{},"Vẽ tuyến cuối cùng trên bản đồ. In tổng chi phí 3 cách.",[989,74409,74410],{},"Thêm khung giờ: điểm 3 phải giao trước điểm 7. Sửa Held-Karp để tôn trọng ràng buộc.",[981,74412,2711],{"id":2710},[986,74414,74416,74422,74428,74434],{"className":74415},[2715],[989,74417,74419,74421],{"className":74418},[2719],[2721,74420],{"disabled":2723,"type":2724}," Test 3 kịch bản bản đồ pass.",[989,74423,74425,74427],{"className":74424},[2719],[2721,74426],{"disabled":2723,"type":2724}," Có ảnh so sánh vùng mở và bảng weight A*.",[989,74429,74431,74433],{"className":74430},[2719],[2721,74432],{"disabled":2723,"type":2724}," Bảng 3 cách xếp thứ tự giao có số thật.",[989,74435,74437,74439],{"className":74436},[2719],[2721,74438],{"disabled":2723,"type":2724}," Ràng buộc thứ tự được tôn trọng (có test).",[968,74441,2890],{"id":2889},[986,74443,74444,74447,74450,74453],{},[989,74445,74446],{},"BFS đúng trong trường hợp nào?",[989,74448,74449],{},"Dijkstra dùng heap để làm gì?",[989,74451,74452],{},"Heuristic admissible nghĩa là gì?",[989,74454,74455],{},"Khi nào không nên dùng A*?",[3014,74457],{},[973,74459,74460],{},"🌕 Bạn đã hoàn thành ngày 134. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,74462,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":74464},[74465,74466,74471,74472,74478],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":74467},[74468,74469,74470],{"id":74194,"depth":73,"text":74195},{"id":74212,"depth":73,"text":74213},{"id":74230,"depth":73,"text":74231},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":74473},[74474,74475,74476,74477],{"id":74319,"depth":73,"text":74320},{"id":74373,"depth":73,"text":74374},{"id":74392,"depth":73,"text":74393},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app tuyến giao hàng: bản đồ lưới và đồ thị thực, so BFS Dijkstra A*, đo số nút thăm và độ dài đường, trực quan 3 thuật toán.",{},[3050,17499],{"title":725,"description":74479},[17502,29787,49649,31500,74484],"routing","LLGSqJcpN3bRy9o2jcPtSnKoLdoq3QuDf5tOkaFJ0aI",{"id":74487,"title":730,"body":74488,"category":8797,"day":733,"description":74807,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":74808,"navigation":2723,"outcomes":3047,"path":731,"prerequisites":74809,"seo":74810,"stem":732,"tags":74811,"__hash__":74814},"challenges\u002Fchallenges\u002F135.app-mst-network.md",{"type":965,"value":74489,"toc":74791},[74490,74492,74495,74497,74501,74558,74562,74576,74580,74594,74641,74643,74657,74659,74667,74671,74674,74698,74702,74708,74711,74715,74738,74740,74770,74772,74786,74788],[968,74491,971],{"id":970},[973,74493,74494],{},"Bài này xây app đi dây cáp rẻ nhất nối mọi trạm. Hai thuật toán cùng cho tổng chi phí tối thiểu.",[968,74496,979],{"id":978},[981,74498,74500],{"id":74499},"kruskal-thêm-cạnh-rẻ-nhất","Kruskal thêm cạnh rẻ nhất",[986,74502,74503,74506,74509,74555],{},[989,74504,74505],{},"Sắp xếp mọi cạnh tăng dần rồi thêm dần.",[989,74507,74508],{},"Dùng Union-Find để bỏ cạnh tạo chu trình.",[989,74510,74511,74512,1517],{},"Union-Find có nén đường đi nên gần như ",[1023,74513,74515,74534],{"className":74514},[1026],[1023,74516,74518],{"className":74517},[1030],[1032,74519,74520],{"xmlns":1034},[1036,74521,74522,74532],{},[1039,74523,74524,74526,74528,74530],{},[1042,74525,1044],{},[1046,74527,1049],{"stretchy":1048},[1051,74529,1053],{},[1046,74531,1056],{"stretchy":1048},[1058,74533,1061],{"encoding":1060},[1023,74535,74537],{"className":74536,"ariaHidden":1066},[1065],[1023,74538,74540,74543,74546,74549,74552],{"className":74539},[1070],[1023,74541],{"className":74542,"style":1075},[1074],[1023,74544,1044],{"className":74545,"style":1081},[1079,1080],[1023,74547,1049],{"className":74548},[1085],[1023,74550,1053],{"className":74551},[1079],[1023,74553,1056],{"className":74554},[1092],[989,74556,74557],{},"Ví dụ đời thường: nối dây rẻ nhất mà không tạo vòng lặp.",[981,74559,74561],{"id":74560},"prim-mọc-cây-từ-1-nút","Prim mọc cây từ 1 nút",[986,74563,74564,74567,74570,74573],{},[989,74565,74566],{},"Bắt đầu từ 1 nút, luôn thêm cạnh rẻ nhất ra ngoài.",[989,74568,74569],{},"Dùng heap để lấy cạnh biên rẻ nhất.",[989,74571,74572],{},"Đồ thị rời thì cho rừng khung mỗi phần 1 cây.",[989,74574,74575],{},"Ví dụ đời thường: xây khu dân cư lan dần từ nhà đầu tiên.",[981,74577,74579],{"id":74578},"so-sánh-và-kiểm-đúng","So sánh và kiểm đúng",[986,74581,74582,74585,74588,74591],{},[989,74583,74584],{},"Kruskal thắng trên đồ thị thưa vì ít cạnh cần sắp.",[989,74586,74587],{},"Prim thắng trên đồ thị dày vì không sắp hết cạnh.",[989,74589,74590],{},"Cây đúng có V-1 cạnh, liên thông, tổng trọng số bằng nhau.",[989,74592,74593],{},"Cut property: cạnh rẻ nhất qua mọi lát cắt thuộc về MST.",[1099,74595,74596,74608],{},[1102,74597,74598],{},[1105,74599,74600,74603,74606],{},[1108,74601,74602],{},"Họ đồ thị",[1108,74604,74605],{},"Ai nhanh hơn",[1108,74607,55198],{},[1118,74609,74610,74620,74630],{},[1105,74611,74612,74614,74617],{},[1123,74613,54363],{},[1123,74615,74616],{},"Kruskal",[1123,74618,74619],{},"Ít cạnh cần sắp",[1105,74621,74622,74625,74627],{},[1123,74623,74624],{},"Dày",[1123,74626,31273],{},[1123,74628,74629],{},"Không sắp hết cạnh",[1105,74631,74632,74635,74638],{},[1123,74633,74634],{},"Rời rạc",[1123,74636,74637],{},"Cả 2",[1123,74639,74640],{},"Cho rừng khung",[968,74642,1433],{"id":1432},[986,74644,74645,74648,74651,74654],{},[989,74646,74647],{},"Input: đồ thị tay 8 nút tính tay trước. Output: 2 thuật toán cho cùng tổng trọng số.",[989,74649,74650],{},"Giải thích: cả 2 đều tối ưu nên tổng bằng nhau dù cây có thể khác.",[989,74652,74653],{},"Input: cấm 5 cạnh rẻ nhất rồi chạy lại. Output: tổng chi phí tăng vài phần trăm.",[989,74655,74656],{},"Giải thích: mất cạnh rẻ nên phải dùng cạnh đắt hơn.",[968,74658,1482],{"id":1481},[973,74660,1485,74661,74663,74664,1517],{},[1487,74662,1493],{}," (hoặc Python). Dùng code ngày 33, 43. Nộp vào ",[992,74665,74666],{},"day-135-network\u002F",[981,74668,74670],{"id":74669},"bài-1-thiết-kế-mạng-cáp-quang","Bài 1: Thiết kế mạng cáp quang",[973,74672,74673],{},"Dữ liệu: 200 tòa nhà có tọa độ. Chi phí kéo cáp giữa 2 tòa = khoảng cách Euclid x 1.2 triệu\u002Fkm. Có 30 cặp tòa không kéo trực tiếp được (qua sông).",[2273,74675,74676,74679,74685],{},[989,74677,74678],{},"Dựng đồ thị đầy đủ trừ 30 cặp cấm.",[989,74680,74681,74682,16014],{},"Chạy Kruskal và Prim. In tổng chi phí (phải bằng nhau) và số cạnh (",[992,74683,74684],{},"V - 1",[989,74686,1505,74687,74690,74691,74693,74694,74697],{},[992,74688,74689],{},"verifyMST(G, T)",": kiểm tra liên thông, đúng ",[992,74692,74684],{}," cạnh, và ",[1487,74695,74696],{},"cut property",": với mỗi cạnh ngoài cây, nó không rẻ hơn cạnh đắt nhất trên đường nối trong cây.",[981,74699,74701],{"id":74700},"bài-2-thưa-và-dày","Bài 2: Thưa và dày",[1352,74703,74706],{"className":74704,"code":74705,"language":2241,"meta":1357},[2239],"đồ_thị            V        E           Kruskal(ms)   Prim_heap(ms)   Prim_mảng O(V^2)(ms)\nthưa              10^5     3*10^5      ...\ndày               3000     ~4.5*10^6   ...\n",[992,74707,74705],{"__ignoreMap":1357},[973,74709,74710],{},"Kết luận: đồ thị nào hợp thuật toán nào.",[981,74712,74714],{"id":74713},"bài-3-yêu-cầu-thực-tế-nâng-cao","Bài 3: Yêu cầu thực tế (nâng cao)",[2273,74716,74717,74723,74729,74735],{},[989,74718,74719,74722],{},[1487,74720,74721],{},"Dự phòng:"," tìm cây khung nhỏ thứ hai (thay 1 cạnh). In chi phí tăng thêm.",[989,74724,74725,74728],{},[1487,74726,74727],{},"Bắt buộc:"," 5 cạnh đã có sẵn (chi phí 0) phải nằm trong mạng. Sửa Kruskal để dùng chúng trước.",[989,74730,74731,74734],{},[1487,74732,74733],{},"Giới hạn bậc:"," trạm trung tâm tối đa 4 kết nối. Viết heuristic và so chi phí với MST không giới hạn.",[989,74736,74737],{},"Vẽ mạng trên bản đồ tọa độ.",[981,74739,2711],{"id":2710},[986,74741,74743,74752,74758,74764],{"className":74742},[2715],[989,74744,74746,74748,74749,13981],{"className":74745},[2719],[2721,74747],{"disabled":2723,"type":2724}," Kruskal và Prim cùng tổng chi phí, ",[992,74750,74751],{},"verifyMST",[989,74753,74755,74757],{"className":74754},[2719],[2721,74756],{"disabled":2723,"type":2724}," Bảng thưa\u002Fdày có số thật.",[989,74759,74761,74763],{"className":74760},[2719],[2721,74762],{"disabled":2723,"type":2724}," 3 yêu cầu Bài 3 có kết quả và giải thích.",[989,74765,74767,74769],{"className":74766},[2719],[2721,74768],{"disabled":2723,"type":2724}," Có hình mạng.",[968,74771,2890],{"id":2889},[986,74773,74774,74777,74780,74783],{},[989,74775,74776],{},"Kruskal tránh chu trình bằng cấu trúc nào?",[989,74778,74779],{},"Prim chọn cạnh tiếp theo thế nào?",[989,74781,74782],{},"Đồ thị thưa nên dùng thuật toán nào?",[989,74784,74785],{},"Kiểm tra cây khung đúng bằng 3 dấu hiệu nào?",[3014,74787],{},[973,74789,74790],{},"🌕 Bạn đã hoàn thành ngày 135. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":74792},[74793,74794,74799,74800,74806],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":74795},[74796,74797,74798],{"id":74499,"depth":73,"text":74500},{"id":74560,"depth":73,"text":74561},{"id":74578,"depth":73,"text":74579},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":74801},[74802,74803,74804,74805],{"id":74669,"depth":73,"text":74670},{"id":74700,"depth":73,"text":74701},{"id":74713,"depth":73,"text":74714},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app thiết kế mạng cáp tối thiểu: cài Prim và Kruskal, so sánh trên đồ thị thưa và dày, kiểm tra tính đúng bằng cut property.",{},[3050],{"title":730,"description":74807},[17502,26309,31501,74812,74813],"kruskal","network-design","4hIBKrvTa-OOY5QasyqMwXS997yUP0iOnPj1vvhx36E",{"id":74816,"title":735,"body":74817,"category":8797,"day":738,"description":75085,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":75086,"navigation":2723,"outcomes":3047,"path":736,"prerequisites":75087,"seo":75088,"stem":737,"tags":75089,"__hash__":75092},"challenges\u002Fchallenges\u002F136.app-tsp-showdown.md",{"type":965,"value":74818,"toc":75069},[74819,74821,74824,74826,74830,74844,74848,74862,74866,74880,74882,74896,74898,74906,74910,74925,74978,74984,74988,74991,74997,75001,75017,75019,75046,75048,75062,75064,75067],[968,74820,971],{"id":970},[973,74822,74823],{},"Bài này cho 3 cách tìm tour ngắn đấu nhau. Cùng bản đồ và giờ đấu, ai ngắn hơn thì thắng.",[968,74825,979],{"id":978},[981,74827,74829],{"id":74828},"greedy-và-2-opt","Greedy và 2-opt",[986,74831,74832,74835,74838,74841],{},[989,74833,74834],{},"Greedy luôn đi thành phố gần nhất tiếp theo.",[989,74836,74837],{},"Nhanh nhưng thiển cận, dễ chọn sai sớm.",[989,74839,74840],{},"2-opt tháo 2 cạnh cắt nhau rồi nối lại cho ngắn hơn.",[989,74842,74843],{},"Ví dụ đời thường: đi chợ ghé sạp gần nhất rồi tối ưu lại vòng đi.",[981,74845,74847],{"id":74846},"sa-thoát-kẹt-bằng-nhiệt","SA thoát kẹt bằng nhiệt",[986,74849,74850,74853,74856,74859],{},[989,74851,74852],{},"SA bắt đầu từ tour ngẫu nhiên, đề xuất đổi 2-opt.",[989,74854,74855],{},"Tour tệ hơn vẫn nhận với xác suất giảm dần theo nhiệt.",[989,74857,74858],{},"Lịch mát hình học, kẹt lâu thì hâm nóng lại.",[989,74860,74861],{},"Ví dụ đời thường: leo lên dốc nhỏ để xuống thung lũng sâu hơn.",[981,74863,74865],{"id":74864},"ga-đấu-bằng-quần-thể","GA đấu bằng quần thể",[986,74867,74868,74871,74874,74877],{},[989,74869,74870],{},"GA giữ cả đàn tour, chọn cha mẹ bằng tournament.",[989,74872,74873],{},"Lai OX giữ thứ tự, đột biến swap giữ đa dạng.",[989,74875,74876],{},"Giữ tinh hoa elites sang thế hệ sau.",[989,74878,74879],{},"Cùng seed và ngân sách giờ để đấu công bằng.",[968,74881,1433],{"id":1432},[986,74883,74884,74887,74890,74893],{},[989,74885,74886],{},"Input: bản đồ 8 thành phố có optimum brute-force. Output: ít nhất 1 metaheuristic chạm optimum.",[989,74888,74889],{},"Giải thích: bản đồ nhỏ nên SA hoặc GA tìm được tour tốt nhất.",[989,74891,74892],{},"Input: 5 bản đồ 50 thành phố. Output: SA và GA ngắn hơn greedy ít nhất 5%.",[989,74894,74895],{},"Giải thích: greedy kẹt cực tiểu địa phương, 2 metaheuristic thoát được.",[968,74897,1482],{"id":1481},[973,74899,1485,74900,74902,74903,1517],{},[1487,74901,1493],{}," (khuyến nghị) hoặc Python có Numba. Dùng code ngày 78, 114, 115, 122. Nộp vào ",[992,74904,74905],{},"day-136-tsp\u002F",[981,74907,74909],{"id":74908},"bài-1-khung-thi-đấu-công-bằng","Bài 1: Khung thi đấu công bằng",[1352,74911,74913],{"className":1393,"code":74912,"language":1395,"meta":1357,"style":1357},"struct Solver { virtual std::string name() const = 0;\n                virtual std::vector\u003Cint> solve(const Matrix &d, uint64_t seed, double timeBudgetMs) = 0; };\n",[992,74914,74915,74920],{"__ignoreMap":1357},[1023,74916,74917],{"class":1362,"line":63},[1023,74918,74919],{},"struct Solver { virtual std::string name() const = 0;\n",[1023,74921,74922],{"class":1362,"line":68},[1023,74923,74924],{},"                virtual std::vector\u003Cint> solve(const Matrix &d, uint64_t seed, double timeBudgetMs) = 0; };\n",[1099,74926,74927,74936],{},[1102,74928,74929],{},[1105,74930,74931,74934],{},[1108,74932,74933],{},"Solver",[1108,74935,72118],{},[1118,74937,74938,74948,74958,74968],{},[1105,74939,74940,74945],{},[1123,74941,74942],{},[992,74943,74944],{},"Greedy",[1123,74946,74947],{},"Láng giềng gần nhất từ mọi điểm xuất phát, lấy tốt nhất",[1105,74949,74950,74955],{},[1123,74951,74952],{},[992,74953,74954],{},"Greedy2Opt",[1123,74956,74957],{},"Greedy rồi 2-opt tới khi không cải thiện",[1105,74959,74960,74965],{},[1123,74961,74962],{},[992,74963,74964],{},"SimulatedAnnealing",[1123,74966,74967],{},"Láng giềng 2-opt, lịch hình học, hâm nóng lại khi 10.000 bước không cải thiện",[1105,74969,74970,74975],{},[1123,74971,74972],{},[992,74973,74974],{},"GeneticAlgorithm",[1123,74976,74977],{},"Tournament, OX, đột biến đảo đoạn, elite 2, 10% đàn khởi tạo tham lam",[973,74979,74980,74983],{},[1487,74981,74982],{},"Ràng buộc công bằng:"," cùng ngân sách thời gian (ví dụ 2 giây), cùng 10 seed, cùng máy. Mọi tour trả về phải hợp lệ (kiểm tra là hoán vị).",[981,74985,74987],{"id":74986},"bài-2-bảng-đấu","Bài 2: Bảng đấu",[973,74989,74990],{},"Bộ dữ liệu: berlin52 (tối ưu 7542), kroA100 (tối ưu 21282), và 1000 điểm ngẫu nhiên.",[1352,74992,74995],{"className":74993,"code":74994,"language":2241,"meta":1357},[2239],"bộ          solver       best      trung_bình   độ_lệch   gap_so_tối_ưu\nberlin52    Greedy       ...\nberlin52    Greedy2Opt   ...\nberlin52    SA           ...\nberlin52    GA           ...\nkroA100     ...\nrandom1000  ...          (không có tối ưu, so với best tổng)\n",[992,74996,74994],{"__ignoreMap":1357},[981,74998,75000],{"id":74999},"bài-3-hội-tụ-theo-thời-gian-và-báo-cáo-nâng-cao","Bài 3: Hội tụ theo thời gian và báo cáo (nâng cao)",[2273,75002,75003,75006,75009,75012],{},[989,75004,75005],{},"Ghi độ dài tour tốt nhất theo thời gian cho SA và GA. Vẽ cả 2 đường trên cùng hình (trung vị 10 seed).",[989,75007,75008],{},"Thử ngân sách 0.1, 1, 10 giây. Solver nào thắng ở ngân sách ngắn, solver nào thắng ở ngân sách dài?",[989,75010,75011],{},"Vẽ tour tốt nhất của mỗi solver trên kroA100.",[989,75013,75014,75016],{},[992,75015,17400],{},": bảng, hình, khuyến nghị \"khi nào dùng solver nào\".",[981,75018,2711],{"id":2710},[986,75020,75022,75028,75034,75040],{"className":75021},[2715],[989,75023,75025,75027],{"className":75024},[2719],[2721,75026],{"disabled":2723,"type":2724}," Mọi tour hợp lệ, có kiểm tra tự động.",[989,75029,75031,75033],{"className":75030},[2719],[2721,75032],{"disabled":2723,"type":2724}," Bảng đấu 3 bộ x 4 solver x 10 seed.",[989,75035,75037,75039],{"className":75036},[2719],[2721,75038],{"disabled":2723,"type":2724}," Hình hội tụ theo thời gian.",[989,75041,75043,75045],{"className":75042},[2719],[2721,75044],{"disabled":2723,"type":2724}," Khuyến nghị gắn với số liệu.",[968,75047,2890],{"id":2889},[986,75049,75050,75053,75056,75059],{},[989,75051,75052],{},"Greedy nearest neighbor nhanh nhưng yếu ở điểm gì?",[989,75054,75055],{},"2-opt cải thiện tour bằng cách nào?",[989,75057,75058],{},"SA chấp nhận tour tệ để làm gì?",[989,75060,75061],{},"Vì sao đấu TSP phải cố định seed và giờ?",[3014,75063],{},[973,75065,75066],{},"🌕 Bạn đã hoàn thành ngày 136. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,75068,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":75070},[75071,75072,75077,75078,75084],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":75073},[75074,75075,75076],{"id":74828,"depth":73,"text":74829},{"id":74846,"depth":73,"text":74847},{"id":74864,"depth":73,"text":74865},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":75079},[75080,75081,75082,75083],{"id":74908,"depth":73,"text":74909},{"id":74986,"depth":73,"text":74987},{"id":74999,"depth":73,"text":75000},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây sàn đấu TSP: greedy nearest neighbor, simulated annealing với 2-opt, giải thuật di truyền, so chất lượng và thời gian trên cùng bản đồ.",{},[15143],{"title":735,"description":75085},[17502,48823,75090,75091,47532],"simulated-annealing","genetic-algorithm","E9Lr-mkVVUbYJoiDyjA85Rt5XZY2KfoURpxRs-VblzU",{"id":75094,"title":740,"body":75095,"category":8797,"day":743,"description":75740,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":75741,"navigation":2723,"outcomes":3047,"path":741,"prerequisites":75742,"seo":75743,"stem":742,"tags":75744,"__hash__":75748},"challenges\u002Fchallenges\u002F137.app-graph-embedding.md",{"type":965,"value":75096,"toc":75724},[75097,75099,75102,75104,75108,75122,75126,75140,75144,75158,75160,75174,75176,75187,75191,75281,75287,75291,75294,75298,75674,75676,75703,75705,75719,75721],[968,75098,971],{"id":970},[973,75100,75101],{},"Bài này học vẽ đồ thị bằng lực lò xo. Nút kề kéo nhau, nút xa đẩy nhau thành tranh thoáng.",[968,75103,979],{"id":978},[981,75105,75107],{"id":75106},"layout-force-directed-là-gì","Layout force-directed là gì",[986,75109,75110,75113,75116,75119],{},[989,75111,75112],{},"Đặt nút bừa rồi lặp lực đẩy và lực hút lò xo.",[989,75114,75115],{},"Lực đẩy tách mọi cặp nút, lực hút kéo nút kề lại.",[989,75117,75118],{},"Giới hạn bước dịch giảm dần như nhiệt độ nguội.",[989,75120,75121],{},"Ví dụ đời thường: thả bi nam châm tự giãn thành hình đều.",[981,75123,75125],{"id":75124},"sa-tinh-chỉnh-giảm-giao-cắt","SA tinh chỉnh giảm giao cắt",[986,75127,75128,75131,75134,75137],{},[989,75129,75130],{},"Năng lượng = số cạnh cắt nhau + độ lệch dài cạnh.",[989,75132,75133],{},"Đề xuất dịch bừa, đẹp lên thì giữ, xấu vẫn giữ theo nhiệt.",[989,75135,75136],{},"Giảm ít nhất 30% giao cắt so với đặt bừa.",[989,75138,75139],{},"Lưới 6x6 vẽ đúng phải về 0 giao cắt.",[981,75141,75143],{"id":75142},"embedding-học-vector-nút","Embedding học vector nút",[986,75145,75146,75149,75152,75155],{},[989,75147,75148],{},"Học 1 vector cho mỗi nút bằng gradient descent.",[989,75150,75151],{},"Nút kề nhau phải gần nhau trong không gian vector.",[989,75153,75154],{},"Chiếu xuống 2D để vẽ và so cụm với layout vật lý.",[989,75156,75157],{},"Nút kề có khoảng cách nhỏ hơn cặp ngẫu nhiên.",[968,75159,1433],{"id":1432},[986,75161,75162,75165,75168,75171],{},[989,75163,75164],{},"Input: lưới 6x6 đặt bừa rối tung. Output: sau layout hiện rõ ô lưới, 0 giao cắt.",[989,75166,75167],{},"Giải thích: lực lò xo duỗi thẳng từng ô lưới.",[989,75169,75170],{},"Input: đồ thị ngẫu nhiên 100 nút. Output: SA giảm giao cắt ít nhất 30%.",[989,75172,75173],{},"Giải thích: chấp nhận xấu tạm giúp thoát bố cục rối ban đầu.",[968,75175,1482],{"id":1481},[973,75177,1485,75178,75180,75181,75183,75184,1517],{},[1487,75179,13531],{}," với NumPy, ",[992,75182,31660],{},", matplotlib. Dùng code ngày 112, 121. Nộp vào ",[992,75185,75186],{},"day-137-graph-embed\u002F",[981,75188,75190],{"id":75189},"bài-1-force-directed-có-nguội","Bài 1: Force-directed có nguội",[2273,75192,75193,75199,75278],{},[989,75194,75195,75196,75198],{},"Cài lại Fruchterman-Reingold: lực đẩy mọi cặp, lực hút theo cạnh, bước dịch tối đa ",[992,75197,29580],{}," giảm dần mỗi vòng.",[989,75200,2699,75201,75204,75205,16014],{},[1487,75202,75203],{},"lưới ô"," để chỉ tính lực đẩy với đỉnh trong ô lân cận (giảm ",[1023,75206,75208,75231],{"className":75207},[1026],[1023,75209,75211],{"className":75210},[1030],[1032,75212,75213],{"xmlns":1034},[1036,75214,75215,75229],{},[1039,75216,75217,75219,75221,75227],{},[1042,75218,1044],{},[1046,75220,1049],{"stretchy":1048},[2327,75222,75223,75225],{},[1042,75224,1262],{},[1051,75226,2457],{},[1046,75228,1056],{"stretchy":1048},[1058,75230,2839],{"encoding":1060},[1023,75232,75234],{"className":75233,"ariaHidden":1066},[1065],[1023,75235,75237,75240,75243,75246,75275],{"className":75236},[1070],[1023,75238],{"className":75239,"style":2476},[1074],[1023,75241,1044],{"className":75242,"style":1081},[1079,1080],[1023,75244,1049],{"className":75245},[1085],[1023,75247,75249,75252],{"className":75248},[1079],[1023,75250,1262],{"className":75251},[1079,1080],[1023,75253,75255],{"className":75254},[2383],[1023,75256,75258],{"className":75257},[2387],[1023,75259,75261],{"className":75260},[2391],[1023,75262,75264],{"className":75263,"style":2369},[2395],[1023,75265,75266,75269],{"style":2398},[1023,75267],{"className":75268,"style":2403},[2402],[1023,75270,75272],{"className":75271},[2407,2408,2409,2410],[1023,75273,2457],{"className":75274},[1079,2410],[1023,75276,1056],{"className":75277},[1092],[989,75279,75280],{},"Chạy trên lưới 6x6: phải về 0 giao cắt. Chạy trên đồ thị 1000 đỉnh 3000 cạnh.",[1352,75282,75285],{"className":75283,"code":75284,"language":2241,"meta":1357},[2239],"Lưới 6x6 xáo trộn -> 0 giao cắt sau khi chạy\nĐồ thị ngẫu nhiên -> giao cắt giảm ít nhất 30% so với đặt ngẫu nhiên\n",[992,75286,75284],{"__ignoreMap":1357},[981,75288,75290],{"id":75289},"bài-2-sa-tinh-chỉnh","Bài 2: SA tinh chỉnh",[973,75292,75293],{},"Dùng SA ngày 121 bắt đầu từ kết quả force-directed, nhiệt độ thấp. So số giao cắt trước và sau. In thời gian.",[981,75295,75297],{"id":75296},"bài-3-graph-embedding-bằng-gradient-nâng-cao","Bài 3: Graph embedding bằng gradient (nâng cao)",[2273,75299,75300,75661,75664,75671],{},[989,75301,75302,75303,1517],{},"Học vector 16 chiều cho mỗi đỉnh bằng gradient descent: loss kéo cặp đỉnh kề gần nhau, đẩy cặp đỉnh lấy mẫu ngẫu nhiên (negative sampling) ra xa. ",[1023,75304,75306,75378],{"className":75305},[1026],[1023,75307,75309],{"className":75308},[1030],[1032,75310,75311],{"xmlns":1034},[1036,75312,75313,75375],{},[1039,75314,75315,75317,75319,75321,75323,75325,75327,75329,75335,75337,75343,75345,75347,75349,75351,75353,75355,75357,75359,75365,75367,75373],{},[1042,75316,4772],{},[1046,75318,2325],{},[1046,75320,17698],{},[1042,75322,8397],{},[1046,75324,8400],{},[1042,75326,59500],{},[1046,75328,1049],{"stretchy":1048},[17690,75330,75331,75333],{},[1042,75332,60120],{},[1042,75334,30390],{},[1046,75336,18118],{},[17690,75338,75339,75341],{},[1042,75340,60120],{},[1042,75342,30394],{},[1046,75344,1056],{"stretchy":1048},[1046,75346,17698],{},[1046,75348,17686],{},[1042,75350,8397],{},[1046,75352,8400],{},[1042,75354,59500],{},[1046,75356,1049],{"stretchy":1048},[1046,75358,17698],{},[17690,75360,75361,75363],{},[1042,75362,60120],{},[1042,75364,30390],{},[1046,75366,18118],{},[17690,75368,75369,75371],{},[1042,75370,60120],{},[1042,75372,1262],{},[1046,75374,1056],{"stretchy":1048},[1058,75376,75377],{"encoding":1060},"L = -\\log\\sigma(z_u \\cdot z_v) - \\sum \\log\\sigma(-z_u \\cdot z_n)",[1023,75379,75381,75399,75476,75534,75612],{"className":75380,"ariaHidden":1066},[1065],[1023,75382,75384,75387,75390,75393,75396],{"className":75383},[1070],[1023,75385],{"className":75386,"style":27414},[1074],[1023,75388,4772],{"className":75389},[1079,1080],[1023,75391],{"className":75392,"style":2355},[2354],[1023,75394,2325],{"className":75395},[2359],[1023,75397],{"className":75398,"style":2355},[2354],[1023,75400,75402,75405,75408,75411,75416,75419,75422,75425,75467,75470,75473],{"className":75401},[1070],[1023,75403],{"className":75404,"style":1075},[1074],[1023,75406,17698],{"className":75407},[1079],[1023,75409],{"className":75410,"style":8434},[2354],[1023,75412,8427,75414],{"className":75413},[8426],[1023,75415,7690],{"style":8430},[1023,75417],{"className":75418,"style":8434},[2354],[1023,75420,59500],{"className":75421,"style":7723},[1079,1080],[1023,75423,1049],{"className":75424},[1085],[1023,75426,75428,75431],{"className":75427},[1079],[1023,75429,60120],{"className":75430,"style":60150},[1079,1080],[1023,75432,75434],{"className":75433},[2383],[1023,75435,75437,75459],{"className":75436},[2387,17732],[1023,75438,75440,75456],{"className":75439},[2391],[1023,75441,75444],{"className":75442,"style":75443},[2395],"height:0.1514em;",[1023,75445,75447,75450],{"style":75446},"top:-2.55em;margin-left:-0.044em;margin-right:0.05em;",[1023,75448],{"className":75449,"style":2403},[2402],[1023,75451,75453],{"className":75452},[2407,2408,2409,2410],[1023,75454,30390],{"className":75455},[1079,1080,2410],[1023,75457,17797],{"className":75458},[17796],[1023,75460,75462],{"className":75461},[2391],[1023,75463,75465],{"className":75464,"style":17804},[2395],[1023,75466],{},[1023,75468],{"className":75469,"style":13790},[2354],[1023,75471,18118],{"className":75472},[13794],[1023,75474],{"className":75475,"style":13790},[2354],[1023,75477,75479,75482,75522,75525,75528,75531],{"className":75478},[1070],[1023,75480],{"className":75481,"style":1075},[1074],[1023,75483,75485,75488],{"className":75484},[1079],[1023,75486,60120],{"className":75487,"style":60150},[1079,1080],[1023,75489,75491],{"className":75490},[2383],[1023,75492,75494,75514],{"className":75493},[2387,17732],[1023,75495,75497,75511],{"className":75496},[2391],[1023,75498,75500],{"className":75499,"style":75443},[2395],[1023,75501,75502,75505],{"style":75446},[1023,75503],{"className":75504,"style":2403},[2402],[1023,75506,75508],{"className":75507},[2407,2408,2409,2410],[1023,75509,30394],{"className":75510,"style":7723},[1079,1080,2410],[1023,75512,17797],{"className":75513},[17796],[1023,75515,75517],{"className":75516},[2391],[1023,75518,75520],{"className":75519,"style":17804},[2395],[1023,75521],{},[1023,75523,1056],{"className":75524},[1092],[1023,75526],{"className":75527,"style":13790},[2354],[1023,75529,17698],{"className":75530},[13794],[1023,75532],{"className":75533,"style":13790},[2354],[1023,75535,75537,75540,75543,75546,75551,75554,75557,75560,75563,75603,75606,75609],{"className":75536},[1070],[1023,75538],{"className":75539,"style":1075},[1074],[1023,75541,17686],{"className":75542,"style":17758},[8426,17756,17757],[1023,75544],{"className":75545,"style":8434},[2354],[1023,75547,8427,75549],{"className":75548},[8426],[1023,75550,7690],{"style":8430},[1023,75552],{"className":75553,"style":8434},[2354],[1023,75555,59500],{"className":75556,"style":7723},[1079,1080],[1023,75558,1049],{"className":75559},[1085],[1023,75561,17698],{"className":75562},[1079],[1023,75564,75566,75569],{"className":75565},[1079],[1023,75567,60120],{"className":75568,"style":60150},[1079,1080],[1023,75570,75572],{"className":75571},[2383],[1023,75573,75575,75595],{"className":75574},[2387,17732],[1023,75576,75578,75592],{"className":75577},[2391],[1023,75579,75581],{"className":75580,"style":75443},[2395],[1023,75582,75583,75586],{"style":75446},[1023,75584],{"className":75585,"style":2403},[2402],[1023,75587,75589],{"className":75588},[2407,2408,2409,2410],[1023,75590,30390],{"className":75591},[1079,1080,2410],[1023,75593,17797],{"className":75594},[17796],[1023,75596,75598],{"className":75597},[2391],[1023,75599,75601],{"className":75600,"style":17804},[2395],[1023,75602],{},[1023,75604],{"className":75605,"style":13790},[2354],[1023,75607,18118],{"className":75608},[13794],[1023,75610],{"className":75611,"style":13790},[2354],[1023,75613,75615,75618,75658],{"className":75614},[1070],[1023,75616],{"className":75617,"style":1075},[1074],[1023,75619,75621,75624],{"className":75620},[1079],[1023,75622,60120],{"className":75623,"style":60150},[1079,1080],[1023,75625,75627],{"className":75626},[2383],[1023,75628,75630,75650],{"className":75629},[2387,17732],[1023,75631,75633,75647],{"className":75632},[2391],[1023,75634,75636],{"className":75635,"style":75443},[2395],[1023,75637,75638,75641],{"style":75446},[1023,75639],{"className":75640,"style":2403},[2402],[1023,75642,75644],{"className":75643},[2407,2408,2409,2410],[1023,75645,1262],{"className":75646},[1079,1080,2410],[1023,75648,17797],{"className":75649},[17796],[1023,75651,75653],{"className":75652},[2391],[1023,75654,75656],{"className":75655,"style":17804},[2395],[1023,75657],{},[1023,75659,1056],{"className":75660},[1092],[989,75662,75663],{},"Chạy trên đồ thị có 4 cộng đồng (stochastic block model). Chiếu xuống 2D bằng PCA (ngày 84). Tô màu theo cộng đồng thật.",[989,75665,75666,75667,75670],{},"Gom cụm embedding bằng K-means ",[992,75668,75669],{},"k = 4",". Tính ARI so với cộng đồng thật.",[989,75672,75673],{},"So hình 2D của embedding với layout force-directed.",[981,75675,2711],{"id":2710},[986,75677,75679,75685,75691,75697],{"className":75678},[2715],[989,75680,75682,75684],{"className":75681},[2719],[2721,75683],{"disabled":2723,"type":2724}," Lưới 6x6 về 0 giao cắt.",[989,75686,75688,75690],{"className":75687},[2719],[2721,75689],{"disabled":2723,"type":2724}," Bảng giao cắt: ngẫu nhiên, force, force + SA.",[989,75692,75694,75696],{"className":75693},[2719],[2721,75695],{"disabled":2723,"type":2724}," Embedding tách 4 cộng đồng, ARI trên 0.8.",[989,75698,75700,75702],{"className":75699},[2719],[2721,75701],{"disabled":2723,"type":2724}," Có hình so sánh embedding và layout.",[968,75704,2890],{"id":2889},[986,75706,75707,75710,75713,75716],{},[989,75708,75709],{},"Lực đẩy và lực hút mỗi cái giữ vai trò gì?",[989,75711,75712],{},"Năng lượng vẽ đồ thị gồm 2 số hạng nào?",[989,75714,75715],{},"Embedding khác layout vật lý ở mục tiêu nào?",[989,75717,75718],{},"Đo tranh đẹp bằng 2 metric nào?",[3014,75720],{},[973,75722,75723],{},"🌕 Bạn đã hoàn thành ngày 137. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":75725},[75726,75727,75732,75733,75739],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":75728},[75729,75730,75731],{"id":75106,"depth":73,"text":75107},{"id":75124,"depth":73,"text":75125},{"id":75142,"depth":73,"text":75143},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":75734},[75735,75736,75737,75738],{"id":75189,"depth":73,"text":75190},{"id":75289,"depth":73,"text":75290},{"id":75296,"depth":73,"text":75297},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app nhúng và vẽ đồ thị: layout lò xo Fruchterman-Reingold bằng SA, graph embedding bằng gradient, đo edge crossing và trực quan.",{},[15144],{"title":740,"description":75740},[17502,75745,75746,75090,75747],"graph-embedding","graph-drawing","visualization","6iobhmoytQGKX0DGgJ5wxwWzy7SeHPTh5U5Be_9AWUs",{"id":75750,"title":745,"body":75751,"category":8797,"day":748,"description":76049,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":76050,"navigation":2723,"outcomes":3047,"path":746,"prerequisites":76051,"seo":76052,"stem":747,"tags":76053,"__hash__":76055},"challenges\u002Fchallenges\u002F138.app-tuning.md",{"type":965,"value":75752,"toc":76033},[75753,75755,75758,75760,75764,75778,75782,75796,75800,75814,75849,75851,75865,75867,75876,75880,75895,75899,75924,75941,75947,75950,75954,75981,75983,76010,76012,76026,76028,76031],[968,75754,971],{"id":970},[973,75756,75757],{},"Bài này học chỉnh model cho vừa đẹp. Nhỏ quá thì dốt, lớn quá thì học vẹt.",[968,75759,979],{"id":978},[981,75761,75763],{"id":75762},"gradient-descent-học-tham-số","Gradient descent học tham số",[986,75765,75766,75769,75772,75775],{},[989,75767,75768],{},"Tham số là số trong model, học bằng bước ngược gradient.",[989,75770,75771],{},"Learning rate lớn quá thì phân kỳ, nhỏ quá thì lì.",[989,75773,75774],{},"Log loss mỗi epoch để vẽ đường cong học.",[989,75776,75777],{},"Ví dụ đời thường: xuống núi đi bước vừa chân, bước dài quá thì ngã.",[981,75779,75781],{"id":75780},"grid-và-random-search","Grid và random search",[986,75783,75784,75787,75790,75793],{},[989,75785,75786],{},"Siêu tham số là số ngoài model như độ sâu cây.",[989,75788,75789],{},"Grid search vét hết lưới, random search bốc ngẫu nhiên.",[989,75791,75792],{},"Cùng 20 trial thì random hay thắng vì ít siêu tham số quan trọng.",[989,75794,75795],{},"Mỗi trial chấm bằng cross-validation 3-fold cho chắc.",[981,75797,75799],{"id":75798},"chống-overfit-khi-eval","Chống overfit khi eval",[986,75801,75802,75805,75808,75811],{},[989,75803,75804],{},"Chia train, validation, test theo 60-20-20 có seed.",[989,75806,75807],{},"Chọn cấu hình trên validation, đo test đúng 1 lần cuối.",[989,75809,75810],{},"Train tốt mà validation tệ là overfit học vẹt.",[989,75812,75813],{},"Điểm train cao hơn hẳn validation là dấu hiệu overfit; khoảng cách nhỏ và ổn định qua các fold mới đáng tin.",[1352,75815,75817],{"className":3538,"code":75816,"language":3540,"meta":1357,"style":1357},"# Vòng tuning gọn\nfor params in search(20):  # grid hoặc random 20 trial\n    score = cross_val(params, train)  # chấm CV 3-fold\n    log(params, score)  # ghi nhật ký\nbest = pick_best()  # chốt trên validation\ntest_once(best)  # đo test đúng 1 lần\n",[992,75818,75819,75824,75829,75834,75839,75844],{"__ignoreMap":1357},[1023,75820,75821],{"class":1362,"line":63},[1023,75822,75823],{},"# Vòng tuning gọn\n",[1023,75825,75826],{"class":1362,"line":68},[1023,75827,75828],{},"for params in search(20):  # grid hoặc random 20 trial\n",[1023,75830,75831],{"class":1362,"line":73},[1023,75832,75833],{},"    score = cross_val(params, train)  # chấm CV 3-fold\n",[1023,75835,75836],{"class":1362,"line":78},[1023,75837,75838],{},"    log(params, score)  # ghi nhật ký\n",[1023,75840,75841],{"class":1362,"line":83},[1023,75842,75843],{},"best = pick_best()  # chốt trên validation\n",[1023,75845,75846],{"class":1362,"line":88},[1023,75847,75848],{},"test_once(best)  # đo test đúng 1 lần\n",[968,75850,1433],{"id":1432},[986,75852,75853,75856,75859,75862],{},[989,75854,75855],{},"Input: hồi quy tuyến tính với 3 learning rate. Output: rate vừa cho loss giảm đều, rate lớn gây phân kỳ.",[989,75857,75858],{},"Giải thích: bước quá dài nhảy qua đáy nên loss nổ tung.",[989,75860,75861],{},"Input: cây quá sâu. Output: train tốt, validation tệ, gap lớn.",[989,75863,75864],{},"Giải thích: cây nhớ vẹt từng điểm train nên không tổng quát.",[968,75866,1482],{"id":1481},[973,75868,1485,75869,7386,75871,5599,75873,1517],{},[1487,75870,13531],{},[992,75872,17633],{},[992,75874,75875],{},"day-138-tuning\u002F",[981,75877,75879],{"id":75878},"bài-1-đường-cong-học","Bài 1: Đường cong học",[2273,75881,75882,75889,75892],{},[989,75883,75884,75885,75888],{},"Dùng logistic regression tự cài (ngày 55) trên Breast Cancer. Quét ",[992,75886,75887],{},"lr = 1, 0.1, 0.01, 0.001",". Vẽ log-loss theo epoch cho cả 4.",[989,75890,75891],{},"Chia train\u002Fvalidation\u002Ftest 60\u002F20\u002F20 có seed. In loss train và validation mỗi epoch.",[989,75893,75894],{},"Chỉ ra lr phân kỳ, lr lì, lr tốt.",[981,75896,75898],{"id":75897},"bài-2-grid-search-và-random-search-tự-cài","Bài 2: Grid search và random search tự cài",[1352,75900,75902],{"className":3538,"code":75901,"language":3540,"meta":1357,"style":1357},"def grid_search(model_fn, param_grid: dict, X, y, cv=3, seed=0) -> list[dict]: ...\ndef random_search(model_fn, param_dist: dict, n_iter: int, X, y, cv=3, seed=0) -> list[dict]: ...\n# param_dist: giá trị là list (chọn đều) hoặc hàm sinh (ví dụ log-uniform)\n# Trả mọi trial: params, mean_score, std_score, time\n",[992,75903,75904,75909,75914,75919],{"__ignoreMap":1357},[1023,75905,75906],{"class":1362,"line":63},[1023,75907,75908],{},"def grid_search(model_fn, param_grid: dict, X, y, cv=3, seed=0) -> list[dict]: ...\n",[1023,75910,75911],{"class":1362,"line":68},[1023,75912,75913],{},"def random_search(model_fn, param_dist: dict, n_iter: int, X, y, cv=3, seed=0) -> list[dict]: ...\n",[1023,75915,75916],{"class":1362,"line":73},[1023,75917,75918],{},"# param_dist: giá trị là list (chọn đều) hoặc hàm sinh (ví dụ log-uniform)\n",[1023,75920,75921],{"class":1362,"line":78},[1023,75922,75923],{},"# Trả mọi trial: params, mean_score, std_score, time\n",[973,75925,2699,75926,75929,75930,1656,75933,1656,75935,1656,75938,1517],{},[992,75927,75928],{},"GradientBoostingClassifier"," trên bộ Adult Income với 4 siêu tham số: ",[992,75931,75932],{},"learning_rate",[992,75934,37082],{},[992,75936,75937],{},"n_estimators",[992,75939,75940],{},"subsample",[1352,75942,75945],{"className":75943,"code":75944,"language":2241,"meta":1357},[2239],"cách        số_trial   best_cv   test_score   thời_gian\ngrid        81         ...\nrandom      20         ...\nrandom      81         ...\n",[992,75946,75944],{"__ignoreMap":1357},[973,75948,75949],{},"Vẽ điểm CV theo từng siêu tham số (scatter). Chỉ ra siêu tham số nào quan trọng nhất.",[981,75951,75953],{"id":75952},"bài-3-tối-ưu-thông-minh-hơn-nâng-cao","Bài 3: Tối ưu thông minh hơn (nâng cao)",[2273,75955,75956,75962,75968,75978],{},[989,75957,2699,75958,75961],{},[992,75959,75960],{},"optuna"," (TPE) với 40 trial. So với random 40 trial.",[989,75963,5030,75964,75967],{},[1487,75965,75966],{},"pruning",": dừng sớm trial có điểm thấp ở fold đầu.",[989,75969,75970,75971,75974,75975,75977],{},"Chỉ đánh giá test ",[1487,75972,75973],{},"đúng 1 lần"," với cấu hình cuối cùng. Ghi rõ trong ",[992,75976,2513],{}," quy trình để không rò rỉ.",[989,75979,75980],{},"Chạy lại toàn bộ với seed khác. So cấu hình được chọn.",[981,75982,2711],{"id":2710},[986,75984,75986,75992,75998,76004],{"className":75985},[2715],[989,75987,75989,75991],{"className":75988},[2719],[2721,75990],{"disabled":2723,"type":2724}," Hình đường cong học 4 lr.",[989,75993,75995,75997],{"className":75994},[2719],[2721,75996],{"disabled":2723,"type":2724}," Grid và random tự cài, bảng so sánh có số thật.",[989,75999,76001,76003],{"className":76000},[2719],[2721,76002],{"disabled":2723,"type":2724}," Bảng random vs optuna.",[989,76005,76007,76009],{"className":76006},[2719],[2721,76008],{"disabled":2723,"type":2724}," Test chỉ chạm 1 lần, có ghi quy trình.",[968,76011,2890],{"id":2889},[986,76013,76014,76017,76020,76023],{},[989,76015,76016],{},"Learning rate lớn quá và nhỏ quá gây gì?",[989,76018,76019],{},"Random search thắng grid search khi nào?",[989,76021,76022],{},"Overfit lộ qua dấu hiệu nào?",[989,76024,76025],{},"Vì sao test chỉ đo 1 lần cuối?",[3014,76027],{},[973,76029,76030],{},"🌕 Bạn đã hoàn thành ngày 138. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,76032,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":76034},[76035,76036,76041,76042,76048],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":76037},[76038,76039,76040],{"id":75762,"depth":73,"text":75763},{"id":75780,"depth":73,"text":75781},{"id":75798,"depth":73,"text":75799},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":76043},[76044,76045,76046,76047],{"id":75878,"depth":73,"text":75879},{"id":75897,"depth":73,"text":75898},{"id":75952,"depth":73,"text":75953},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây pipeline tuning: gradient descent cho hồi quy, random và grid search siêu tham số, eval chống overfit, báo cáo đường cong học.",{},[18469,17499],{"title":745,"description":76049},[17502,76054,65006,35333,38887],"hyperparameter-tuning","4cZvu-RZV9c8FeQ9Tn7SOvIFvnNuJQDf54OHnxBienI",{"id":76057,"title":750,"body":76058,"category":8797,"day":753,"description":76348,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":76349,"navigation":2723,"outcomes":3047,"path":751,"prerequisites":76350,"seo":76351,"stem":752,"tags":76352,"__hash__":76355},"challenges\u002Fchallenges\u002F139.app-sentiment.md",{"type":965,"value":76059,"toc":76332},[76060,76062,76065,76067,76071,76085,76089,76103,76107,76121,76123,76137,76139,76147,76151,76229,76232,76238,76242,76253,76257,76278,76280,76311,76313,76327,76329],[968,76061,971],{"id":970},[973,76063,76064],{},"Bài này xây máy đọc review khen hay chê. Máy trả nhãn kèm từ khóa quyết định.",[968,76066,979],{"id":978},[981,76068,76070],{"id":76069},"tokenizer-và-vector-hóa","Tokenizer và vector hóa",[986,76072,76073,76076,76079,76082],{},[989,76074,76075],{},"Tokenizer tách từ, giữ emoticon và dấu cảm thán.",[989,76077,76078],{},"Từ vựng chỉ fit trên train, từ lạ ở test xử lý sau.",[989,76080,76081],{},"BoW đếm số lần xuất hiện, TF-IDF nhân thêm độ hiếm.",[989,76083,76084],{},"Ví dụ đời thường: bóc câu thành các mảnh từ để máy đếm.",[981,76086,76088],{"id":76087},"naive-bayes-tự-viết","Naive Bayes tự viết",[986,76090,76091,76094,76097,76100],{},[989,76092,76093],{},"Đếm xác suất mỗi lớp và mỗi từ trong lớp đó.",[989,76095,76096],{},"Cộng Laplace smoothing để từ chưa thấy không bị 0.",[989,76098,76099],{},"Dự đoán bằng log-probability, lớp nào cao hơn thì thắng.",[989,76101,76102],{},"Bigram kiểu không tốt giúp xử lý phủ định tốt hơn unigram.",[981,76104,76106],{"id":76105},"đánh-giá-bằng-confusion-matrix","Đánh giá bằng confusion matrix",[986,76108,76109,76112,76115,76118],{},[989,76110,76111],{},"Bảng 2x2 đếm đúng sai cho 2 lớp khen chê.",[989,76113,76114],{},"Precision đo nói khen có chuẩn không, recall đo sót khen không.",[989,76116,76117],{},"Gom lỗi phủ định, châm biếm, trung tính trá hình để sửa.",[989,76119,76120],{},"Luôn so với baseline đoán bừa để biết model có học thật.",[968,76122,1433],{"id":1432},[986,76124,76125,76128,76131,76134],{},[989,76126,76127],{},"Input: \"phim tuyệt vời, diễn xuất đỉnh\". Output: tích cực, top từ là tuyệt vời và đỉnh.",[989,76129,76130],{},"Giải thích: 2 từ này xuất hiện nhiều ở lớp tích cực train.",[989,76132,76133],{},"Input: \"không tốt chút nào\". Output: tiêu cực nhờ bigram không tốt.",[989,76135,76136],{},"Giải thích: unigram thuần thấy từ tốt dễ nhầm, bigram giữ được phủ định.",[968,76138,1482],{"id":1481},[973,76140,1485,76141,76143,76144,1517],{},[1487,76142,13531],{},". Dùng code ngày 54, 56, 57. Nộp vào ",[992,76145,76146],{},"day-139-sentiment\u002F",[981,76148,76150],{"id":76149},"bài-1-pipeline-từ-văn-bản-tới-nhãn","Bài 1: Pipeline từ văn bản tới nhãn",[1099,76152,76153,76161],{},[1102,76154,76155],{},[1105,76156,76157,76159],{},[1108,76158,36178],{},[1108,76160,2547],{},[1118,76162,76163,76187,76199,76211,76218],{},[1105,76164,76165,76167],{},[1123,76166,71623],{},[1123,76168,76169,76170,1656,76173,76176,76177,76179,76180,5586,76183,76186],{},"Chữ thường, giữ emoticon (",[992,76171,76172],{},":)",[992,76174,76175],{},":(","), giữ ",[992,76178,15001],{},", tách từ tiếng Việt bằng ",[992,76181,76182],{},"underthesea",[992,76184,76185],{},"pyvi"," nếu dữ liệu tiếng Việt",[1105,76188,76189,76192],{},[1123,76190,76191],{},"Phủ định",[1123,76193,76194,76195,76198],{},"Gắn tiền tố ",[992,76196,76197],{},"NOT_"," cho 3 từ sau \"không\", \"chẳng\", \"not\", \"never\"",[1105,76200,76201,76204],{},[1123,76202,76203],{},"Vector hóa",[1123,76205,76206,76207,76210],{},"BoW và TF-IDF, fit ",[1487,76208,76209],{},"chỉ"," trên train",[1105,76212,76213,76215],{},[1123,76214,41062],{},[1123,76216,76217],{},"Naive Bayes tự cài (ngày 54)",[1105,76219,76220,76223],{},[1123,76221,76222],{},"Lưu",[1123,76224,76225,76228],{},[992,76226,76227],{},"pickle"," toàn bộ pipeline, nạp lại cho cùng dự đoán",[973,76230,76231],{},"Dữ liệu: review sản phẩm tiếng Việt công khai (ví dụ trên Kaggle hoặc UIT-VSFC) hoặc IMDB.",[1352,76233,76236],{"className":76234,"code":76235,"language":2241,"meta":1357},[2239],"predict(\"Sản phẩm tốt, giao nhanh :)\")       -> khen\npredict(\"không tốt chút nào\")                -> chê (nhờ NOT_tốt)\n",[992,76237,76235],{"__ignoreMap":1357},[981,76239,76241],{"id":76240},"bài-2-đánh-giá-và-phân-tích-lỗi","Bài 2: Đánh giá và phân tích lỗi",[2273,76243,76244,76247,76250],{},[989,76245,76246],{},"In confusion matrix, precision, recall, F1 từng lớp.",[989,76248,76249],{},"So 4 cấu hình: unigram, unigram + bigram, có và không có xử lý phủ định.",[989,76251,76252],{},"Lấy 30 câu sai. Phân loại thủ công: phủ định, mỉa mai, trung tính, nhãn sai, khác. In bảng đếm.",[981,76254,76256],{"id":76255},"bài-3-dịch-vụ-nâng-cao","Bài 3: Dịch vụ (nâng cao)",[2273,76258,76259,76272,76275],{},[989,76260,76261,76262,5016,76265,21733,76268,76271],{},"API ",[992,76263,76264],{},"POST \u002Fsentiment",[992,76266,76267],{},"{\"text\": ...}",[992,76269,76270],{},"{\"label\", \"score\", \"top_words\"}"," (5 từ đóng góp nhiều nhất).",[989,76273,76274],{},"CLI: đọc file CSV, ghi thêm cột nhãn.",[989,76276,76277],{},"So với logistic regression và mô hình BERT ngày 103 trên cùng tập test. In thời gian dự đoán 1000 câu mỗi mô hình.",[981,76279,2711],{"id":2710},[986,76281,76283,76289,76295,76301],{"className":76282},[2715],[989,76284,76286,76288],{"className":76285},[2719],[2721,76287],{"disabled":2723,"type":2724}," Pipeline lưu và nạp lại cho cùng kết quả.",[989,76290,76292,76294],{"className":76291},[2719],[2721,76293],{"disabled":2723,"type":2724}," Bảng 4 cấu hình có số thật.",[989,76296,76298,76300],{"className":76297},[2719],[2721,76299],{"disabled":2723,"type":2724}," Bảng phân tích 30 lỗi.",[989,76302,76304,76306,76307,76310],{"className":76303},[2719],[2721,76305],{"disabled":2723,"type":2724}," API trả ",[992,76308,76309],{},"top_words"," giải thích được dự đoán.",[968,76312,2890],{"id":2889},[986,76314,76315,76318,76321,76324],{},[989,76316,76317],{},"Từ vựng fit trên train khác test ở điểm gì?",[989,76319,76320],{},"Laplace smoothing giải quyết từ lạ thế nào?",[989,76322,76323],{},"Bigram giúp câu phủ định ra sao?",[989,76325,76326],{},"Confusion matrix đọc thế nào?",[3014,76328],{},[973,76330,76331],{},"🌕 Bạn đã hoàn thành ngày 139. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":76333},[76334,76335,76340,76341,76347],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":76336},[76337,76338,76339],{"id":76069,"depth":73,"text":76070},{"id":76087,"depth":73,"text":76088},{"id":76105,"depth":73,"text":76106},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":76342},[76343,76344,76345,76346],{"id":76149,"depth":73,"text":76150},{"id":76240,"depth":73,"text":76241},{"id":76255,"depth":73,"text":76256},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app phân loại cảm xúc review: tokenizer, BoW TF-IDF, Naive Bayes tự viết, đánh giá confusion matrix, demo realtime.",{},[18469],{"title":750,"description":76348},[17502,76353,37979,37980,76354],"sentiment-analysis","tf-idf","r78m2G-JdZNXMAXiWsUI4GdIOSMe94UwP5h7_upeAAY",{"id":76357,"title":755,"body":76358,"category":8797,"day":758,"description":76630,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":76631,"navigation":2723,"outcomes":3047,"path":756,"prerequisites":76632,"seo":76633,"stem":757,"tags":76634,"__hash__":76636},"challenges\u002Fchallenges\u002F140.app-image-search.md",{"type":965,"value":76359,"toc":76614},[76360,76362,76365,76367,76371,76385,76389,76403,76407,76421,76423,76437,76439,76451,76455,76478,76482,76540,76546,76549,76553,76564,76566,76593,76595,76609,76611],[968,76361,971],{"id":970},[973,76363,76364],{},"Bài này xây app tìm ảnh giống nhau. Tải 1 ảnh mèo lên là ra thêm nhiều ảnh mèo.",[968,76366,979],{"id":978},[981,76368,76370],{"id":76369},"đặc-trưng-cnn-pretrained","Đặc trưng CNN pretrained",[986,76372,76373,76376,76379,76382],{},[989,76374,76375],{},"Dùng CNN có sẵn, cắt đầu phân loại lấy vector giữa.",[989,76377,76378],{},"Chuẩn hóa L2 để so cosine thành tích vô hướng.",[989,76380,76381],{},"Không cần huấn luyện lại từ đầu nên rất rẻ.",[989,76383,76384],{},"Ví dụ đời thường: mượn mắt thợ ảnh chuyên nghiệp để mô tả ảnh.",[981,76386,76388],{"id":76387},"_2-bản-index-nhanh-và-chuẩn","2 bản index nhanh và chuẩn",[986,76390,76391,76394,76397,76400],{},[989,76392,76393],{},"Brute-force so với hết mọi ảnh làm chuẩn đúng.",[989,76395,76396],{},"K-d tree chia không gian để tìm lân cận nhanh hơn.",[989,76398,76399],{},"Chiều rất cao 512+ thì k-d tree có thể thua brute-force.",[989,76401,76402],{},"Phải đo thực tế thay vì tin lý thuyết suông.",[981,76404,76406],{"id":76405},"đo-chất-lượng-tìm-kiếm","Đo chất lượng tìm kiếm",[986,76408,76409,76412,76415,76418],{},[989,76410,76411],{},"Precision at K: trong K ảnh trả về có mấy ảnh đúng lớp.",[989,76413,76414],{},"Recall: bản nhanh bắt được bao nhiêu so với bản chuẩn.",[989,76416,76417],{},"Ghi bảng theo từng lớp để lộ lớp khó dễ nhầm.",[989,76419,76420],{},"Mục tiêu mẫu: precision trên 0.7, recall trên 0.95.",[968,76422,1433],{"id":1432},[986,76424,76425,76428,76431,76434],{},[989,76426,76427],{},"Input: ảnh mèo hỏi top-10. Output: trên 7 ảnh mèo trong kết quả.",[989,76429,76430],{},"Giải thích: vector mèo gần nhau nên lân cận toàn mèo.",[989,76432,76433],{},"Input: 200 query so 2 index. Output: k-d tree recall trên 0.95, nhanh gấp 3 lần.",[989,76435,76436],{},"Giải thích: gần đúng bỏ chút chính xác để đổi tốc độ.",[968,76438,1482],{"id":1481},[973,76440,1485,76441,7386,76443,1656,76445,76447,76448,1517],{},[1487,76442,13531],{},[1487,76444,56749],{},[992,76446,57484],{},". Dùng code ngày 69 hoặc 119. Nộp vào ",[992,76449,76450],{},"day-140-image-search\u002F",[981,76452,76454],{"id":76453},"bài-1-trích-đặc-trưng","Bài 1: Trích đặc trưng",[2273,76456,76457,76466,76475],{},[989,76458,2699,76459,76461,76462,76465],{},[992,76460,57579],{}," pretrained, bỏ tầng ",[992,76463,76464],{},"fc",", lấy vector 512 chiều sau global average pooling.",[989,76467,76468,76469,1509,76472,1517],{},"Chạy trên 10.000 ảnh CIFAR-10 (hoặc thư mục ảnh của bạn). Chuẩn hóa L2. Lưu ra ",[992,76470,76471],{},"features.npy",[992,76473,76474],{},"labels.npy",[989,76476,76477],{},"Đo thời gian trích (ảnh\u002Fgiây) trên CPU và GPU nếu có.",[981,76479,76481],{"id":76480},"bài-2-ba-cách-tìm-kiếm","Bài 2: Ba cách tìm kiếm",[1099,76483,76484,76492],{},[1102,76485,76486],{},[1105,76487,76488,76490],{},[1108,76489,14526],{},[1108,76491,2547],{},[1118,76493,76494,76509,76519,76527],{},[1105,76495,76496,76499],{},[1123,76497,76498],{},"Brute-force",[1123,76500,76501,76502,76505,76506],{},"Tích vô hướng ",[992,76503,76504],{},"features @ q",", lấy top-k bằng ",[992,76507,76508],{},"argpartition",[1105,76510,76511,76513],{},[1123,76512,33279],{},[1123,76514,76515,76516,1056],{},"Bản ngày 69 (hoặc ",[992,76517,76518],{},"scipy.spatial.cKDTree",[1105,76520,76521,76524],{},[1123,76522,76523],{},"PCA + k-d tree",[1123,76525,76526],{},"Giảm còn 32 chiều rồi dựng cây",[1105,76528,76529,76532],{},[1123,76530,76531],{},"(Tùy chọn) FAISS",[1123,76533,76534,1509,76537],{},[992,76535,76536],{},"IndexFlatIP",[992,76538,76539],{},"IndexIVFFlat",[1352,76541,76544],{"className":76542,"code":76543,"language":2241,"meta":1357},[2239],"cách              thời_gian\u002Ftruy_vấn   precision@10   recall_so_brute_force\nbrute-force       ...                  ...            1.0\nkd-tree 512D      ...                  ...            1.0\npca32 + kd-tree   ...                  ...            ...\n",[992,76545,76543],{"__ignoreMap":1357},[973,76547,76548],{},"Precision@10: tỉ lệ ảnh trả về cùng lớp với ảnh truy vấn.",[981,76550,76552],{"id":76551},"bài-3-giao-diện-và-phân-tích-nâng-cao","Bài 3: Giao diện và phân tích (nâng cao)",[2273,76554,76555,76558,76561],{},[989,76556,76557],{},"Web nhỏ (Streamlit hoặc Gradio): tải ảnh lên, hiện 12 ảnh gần nhất kèm độ tương đồng.",[989,76559,76560],{},"Precision@10 theo từng lớp CIFAR. Chỉ ra 2 lớp hay bị nhầm với nhau và hiện ví dụ.",[989,76562,76563],{},"So với histogram màu ngày 119: precision@10 và 1 ví dụ trực quan cho thấy CNN hiểu \"nội dung\" tốt hơn.",[981,76565,2711],{"id":2710},[986,76567,76569,76575,76581,76587],{"className":76568},[2715],[989,76570,76572,76574],{"className":76571},[2719],[2721,76573],{"disabled":2723,"type":2724}," File đặc trưng lưu được, chuẩn hóa L2 đúng.",[989,76576,76578,76580],{"className":76577},[2719],[2721,76579],{"disabled":2723,"type":2724}," Bảng 3 cách có số thật, chỉ ra k-d tree ở 512 chiều không nhanh hơn brute-force.",[989,76582,76584,76586],{"className":76583},[2719],[2721,76585],{"disabled":2723,"type":2724}," Giao diện chạy được.",[989,76588,76590,76592],{"className":76589},[2719],[2721,76591],{"disabled":2723,"type":2724}," Bảng precision theo lớp và so sánh với histogram màu.",[968,76594,2890],{"id":2889},[986,76596,76597,76600,76603,76606],{},[989,76598,76599],{},"Vì sao dùng CNN pretrained thay vì train mới?",[989,76601,76602],{},"Chuẩn hóa L2 giúp so ảnh thế nào?",[989,76604,76605],{},"Brute-force làm chuẩn vàng để làm gì?",[989,76607,76608],{},"Precision at K và recall mỗi cái đo điều gì?",[3014,76610],{},[973,76612,76613],{},"🌕 Bạn đã hoàn thành ngày 140. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":76615},[76616,76617,76622,76623,76629],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":76618},[76619,76620,76621],{"id":76369,"depth":73,"text":76370},{"id":76387,"depth":73,"text":76388},{"id":76405,"depth":73,"text":76406},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":76624},[76625,76626,76627,76628],{"id":76453,"depth":73,"text":76454},{"id":76480,"depth":73,"text":76481},{"id":76551,"depth":73,"text":76552},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app tìm ảnh tương tự: trích đặc trưng CNN pretrained, index similarity bằng k-d tree và brute-force, đo recall và độ trễ.",{},[14055],{"title":755,"description":76630},[17502,76635,57316,68564,33130],"image-search","s6w75gSPJqxUSf9v9TbLqi_EHOcDWC-8FrWiDehfqT0",{"id":76638,"title":760,"body":76639,"category":8797,"day":763,"description":76887,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":76888,"navigation":2723,"outcomes":3047,"path":761,"prerequisites":76889,"seo":76890,"stem":762,"tags":76891,"__hash__":76894},"challenges\u002Fchallenges\u002F141.app-forecast.md",{"type":965,"value":76640,"toc":76871},[76641,76643,76646,76648,76652,76666,76670,76684,76688,76702,76704,76718,76720,76730,76734,76737,76752,76755,76759,76794,76797,76801,76821,76823,76850,76852,76866,76868],[968,76642,971],{"id":970},[973,76644,76645],{},"Bài này xây app dự báo như giá điện ngày mai. Dùng quá khứ 30 ngày để đoán ngày tiếp theo.",[968,76647,979],{"id":978},[981,76649,76651],{"id":76650},"cửa-sổ-trượt-và-baseline","Cửa sổ trượt và baseline",[986,76653,76654,76657,76660,76663],{},[989,76655,76656],{},"Cắt chuỗi thành cửa sổ input 30 bước đoán bước 31.",[989,76658,76659],{},"Baseline naive lặp giá trị cuối, trung bình trượt lấy trung bình.",[989,76661,76662],{},"Model học sâu phải vượt baseline mới tính là giỏi.",[989,76664,76665],{},"Ví dụ đời thường: đoán mai nắng vì 3 hôm nay đều nắng.",[981,76667,76669],{"id":76668},"rnn-và-bptt","RNN và BPTT",[986,76671,76672,76675,76678,76681],{},[989,76673,76674],{},"RNN lan truyền theo từng bước thời gian, nhớ quá khứ ngắn.",[989,76676,76677],{},"BPTT là lan truyền ngược trải ra theo thời gian.",[989,76679,76680],{},"Clip gradient để khỏi nổ số khi learning rate lớn.",[989,76682,76683],{},"Chia train test theo thời gian, cấm shuffle kẻo rò tương lai.",[981,76685,76687],{"id":76686},"lstm-giữ-nhớ-dài","LSTM giữ nhớ dài",[986,76689,76690,76693,76696,76699],{},[989,76691,76692],{},"LSTM thêm cell state và 3 cổng quên, vào, ra.",[989,76694,76695],{},"Cổng giữ gradient chảy xa nên nhớ phụ thuộc dài.",[989,76697,76698],{},"Dự báo nhiều bước kiểu đệ quy: lấy output làm input tiếp.",[989,76700,76701],{},"Chuỗi mùa vụ mạnh thì baseline mùa vụ đã rất khó vượt.",[968,76703,1433],{"id":1432},[986,76705,76706,76709,76712,76715],{},[989,76707,76708],{},"Input: chuỗi điện 1000 điểm, RNN dự báo 1 bước. Output: RMSE thấp hơn trung bình trượt 10%.",[989,76710,76711],{},"Giải thích: RNN bắt được quán tính ngắn hạn của chuỗi.",[989,76713,76714],{},"Input: dự báo 7 bước tiếp theo. Output: LSTM vượt RNN rõ rệt.",[989,76716,76717],{},"Giải thích: phụ thuộc dài cần cell state của LSTM mới giữ được.",[968,76719,1482],{"id":1481},[973,76721,1485,76722,7386,76724,76726,76727,1517],{},[1487,76723,13531],{},[1487,76725,56749],{},". Dùng code ngày 100, 101. Nộp vào ",[992,76728,76729],{},"day-141-forecast\u002F",[981,76731,76733],{"id":76732},"bài-1-dữ-liệu-và-baseline","Bài 1: Dữ liệu và baseline",[973,76735,76736],{},"Dữ liệu: điện tiêu thụ theo giờ, nhiệt độ theo ngày, hoặc số lượt truy cập website (dữ liệu công khai).",[2273,76738,76739,76746,76749],{},[989,76740,76741,76742,76745],{},"Chia theo thời gian 70\u002F15\u002F15, ",[1487,76743,76744],{},"không xáo trộn",". Chuẩn hóa bằng thống kê của train.",[989,76747,76748],{},"Cửa sổ 30 bước đoán bước 31.",[989,76750,76751],{},"3 baseline: naive (bằng giá trị cuối), trung bình trượt 7, seasonal naive (bằng giá trị cùng giờ hôm trước).",[973,76753,76754],{},"In MAE, RMSE, MAPE trên test cho 3 baseline.",[981,76756,76758],{"id":76757},"bài-2-rnn-và-lstm","Bài 2: RNN và LSTM",[1099,76760,76761,76769],{},[1102,76762,76763],{},[1105,76764,76765,76767],{},[1108,76766,41062],{},[1108,76768,40093],{},[1118,76770,76771,76779,76786],{},[1105,76772,76773,76776],{},[1123,76774,76775],{},"RNN",[1123,76777,76778],{},"1 tầng, hidden 64, clip gradient 1.0",[1105,76780,76781,76783],{},[1123,76782,59303],{},[1123,76784,76785],{},"1 tầng, hidden 64",[1105,76787,76788,76791],{},[1123,76789,76790],{},"LSTM + đặc trưng lịch",[1123,76792,76793],{},"Thêm giờ trong ngày, thứ trong tuần (mã hóa sin\u002Fcos)",[973,76795,76796],{},"Dừng sớm theo validation. In bảng metric so với baseline. Mô hình phải thắng seasonal naive mới tính là có ích.",[981,76798,76800],{"id":76799},"bài-3-dự-báo-nhiều-bước-nâng-cao","Bài 3: Dự báo nhiều bước (nâng cao)",[2273,76802,76803,76809,76815,76818],{},[989,76804,76805,76808],{},[1487,76806,76807],{},"Đệ quy:"," dự báo 1 bước, đưa kết quả vào làm input, lặp 24 bước.",[989,76810,76811,76814],{},[1487,76812,76813],{},"Trực tiếp:"," mô hình xuất 24 giá trị một lúc.",[989,76816,76817],{},"Vẽ MAE theo độ xa dự báo (bước 1 tới 24) cho 2 cách.",[989,76819,76820],{},"Vẽ 3 tuần cuối test: giá trị thật, dự báo 1 bước, dự báo 24 bước.",[981,76822,2711],{"id":2710},[986,76824,76826,76832,76838,76844],{"className":76825},[2715],[989,76827,76829,76831],{"className":76828},[2719],[2721,76830],{"disabled":2723,"type":2724}," Không rò rỉ: chuẩn hóa chỉ dùng train, không xáo trộn theo thời gian.",[989,76833,76835,76837],{"className":76834},[2719],[2721,76836],{"disabled":2723,"type":2724}," Bảng metric 3 baseline và 3 mô hình.",[989,76839,76841,76843],{"className":76840},[2719],[2721,76842],{"disabled":2723,"type":2724}," Hình MAE theo độ xa cho 2 cách dự báo nhiều bước.",[989,76845,76847,76849],{"className":76846},[2719],[2721,76848],{"disabled":2723,"type":2724}," Nhận xét khi nào mô hình học sâu không đáng dùng.",[968,76851,2890],{"id":2889},[986,76853,76854,76857,76860,76863],{},[989,76855,76856],{},"Cửa sổ trượt biến chuỗi thành bài toán gì?",[989,76858,76859],{},"BPTT khác backprop thường ở điểm gì?",[989,76861,76862],{},"3 cổng LSTM mỗi cổng giữ việc gì?",[989,76864,76865],{},"Vì sao chia chuỗi phải theo thời gian?",[3014,76867],{},[973,76869,76870],{},"🌕 Bạn đã hoàn thành ngày 141. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":76872},[76873,76874,76879,76880,76886],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":76875},[76876,76877,76878],{"id":76650,"depth":73,"text":76651},{"id":76668,"depth":73,"text":76669},{"id":76686,"depth":73,"text":76687},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":76881},[76882,76883,76884,76885],{"id":76732,"depth":73,"text":76733},{"id":76757,"depth":73,"text":76758},{"id":76799,"depth":73,"text":76800},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app dự báo chuỗi thời gian: baseline trung bình trượt, RNN tự viết với BPTT, LSTM cổng, so RMSE và vẽ dự báo nhiều bước.",{},[4669],{"title":760,"description":76887},[17502,76892,59287,59302,76893],"forecasting","time-series","-7JC2aqQPNel-WcrQBbxQ4J6wP61nSPovYvkASnSLSQ",{"id":76896,"title":765,"body":76897,"category":8797,"day":768,"description":77161,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":77162,"navigation":2723,"outcomes":3047,"path":766,"prerequisites":77163,"seo":77164,"stem":767,"tags":77165,"__hash__":77169},"challenges\u002Fchallenges\u002F142.app-secure-chat.md",{"type":965,"value":76898,"toc":77145},[76899,76901,76904,76906,76910,76924,76928,76942,76946,76960,76962,76976,76978,76995,77003,77007,77032,77038,77045,77049,77052,77066,77072,77076,77095,77097,77124,77126,77140,77142],[968,76900,971],{"id":970},[973,76902,76903],{},"Bài này xây app chat mã hóa như Zalo bảo mật. Kẻ nghe lén chỉ thấy ký tự rác.",[968,76905,979],{"id":978},[981,76907,76909],{"id":76908},"bắt-tay-tls-trao-khóa","Bắt tay TLS trao khóa",[986,76911,76912,76915,76918,76921],{},[989,76913,76914],{},"Client chào, server gửi chứng chỉ, client verify rồi trao khóa.",[989,76916,76917],{},"RSA mã hóa tiền khóa, ECDH cùng suy ra khóa phiên.",[989,76919,76920],{},"Xong handshake hai bên có chung 1 khóa phiên.",[989,76922,76923],{},"Ví dụ đời thường: 2 người thống nhất mật khẩu riêng giữa chợ đông.",[981,76925,76927],{"id":76926},"pki-xác-thực-danh-tính","PKI xác thực danh tính",[986,76929,76930,76933,76936,76939],{},[989,76931,76932],{},"CA gốc ký chứng chỉ gắn khóa công khai với tên miền.",[989,76934,76935],{},"Client verify chữ ký, tên miền và hạn sử dụng.",[989,76937,76938],{},"Chứng chỉ giả không do CA ký bị cắt ngay.",[989,76940,76941],{},"Bỏ qua verify là mở cửa cho kẻ giả mạo.",[981,76943,76945],{"id":76944},"kênh-chat-mã-hóa","Kênh chat mã hóa",[986,76947,76948,76951,76954,76957],{},[989,76949,76950],{},"Tin nhắn mã hóa đối xứng AES-GCM bằng khóa phiên.",[989,76952,76953],{},"Nonce tăng dần chống gửi lại bản mã cũ.",[989,76955,76956],{},"Tag chống sửa lén, sai tag thì vứt tin.",[989,76958,76959],{},"Server trung chuyển chỉ thấy bản mã, không đọc được.",[968,76961,1433],{"id":1432},[986,76963,76964,76967,76970,76973],{},[989,76965,76966],{},"Input: 2 client handshake rồi chat 20 tin. Output: nội dung đúng, server log toàn bản mã.",[989,76968,76969],{},"Giải thích: chỉ 2 đầu có khóa phiên nên chỉ họ giải được.",[989,76971,76972],{},"Input: kẻ MITM chen vào với chứng chỉ giả. Output: client từ chối, cắt trước tin đầu tiên.",[989,76974,76975],{},"Giải thích: chữ ký không về CA gốc nên verify thất bại.",[968,76977,1482],{"id":1481},[973,76979,1485,76980,7386,76982,1656,76985,2461,76988,1656,76990,5599,76992,1517],{},[1487,76981,13531],{},[992,76983,76984],{},"ssl",[992,76986,76987],{},"socket",[992,76989,40031],{},[992,76991,40796],{},[992,76993,76994],{},"day-142-secure-chat\u002F",[40801,76996,76997],{},[973,76998,76999,77000,16014],{},"Đây là bài học. Không tự thiết kế giao thức mật mã cho sản phẩm thật. Không commit khóa riêng vào repo (thêm vào ",[992,77001,77002],{},".gitignore",[981,77004,77006],{"id":77005},"bài-1-chat-qua-tls","Bài 1: Chat qua TLS",[2273,77008,77009,77015,77025],{},[989,77010,77011,77012,77014],{},"Tạo CA riêng, cấp chứng chỉ cho ",[992,77013,62752],{}," (dùng lại ngày 106).",[989,77016,77017,77018,77020,77021,77024],{},"Server ",[992,77019,40031],{}," nhận nhiều client, phát tin nhắn cho mọi người. Dùng ",[992,77022,77023],{},"ssl.SSLContext"," với TLS 1.3.",[989,77026,77027,77028,77031],{},"Client ",[1487,77029,77030],{},"bắt buộc"," kiểm tra chứng chỉ bằng CA riêng và kiểm tra hostname.",[1352,77033,77036],{"className":77034,"code":77035,"language":2241,"meta":1357},[2239],"Client dùng CA đúng           -> kết nối được, chat được\nServer dùng chứng chỉ tự ký khác -> client từ chối với lỗi CERTIFICATE_VERIFY_FAILED\nChứng chỉ hết hạn             -> client từ chối\n",[992,77037,77035],{"__ignoreMap":1357},[973,77039,77040,77041,77044],{},"Dùng Wireshark hoặc ",[992,77042,77043],{},"tcpdump"," bắt gói: chỉ ra nội dung tin nhắn không đọc được.",[981,77046,77048],{"id":77047},"bài-2-mã-hóa-đầu-cuối-giữa-2-người","Bài 2: Mã hóa đầu cuối giữa 2 người",[973,77050,77051],{},"TLS chỉ bảo vệ tới server. Thêm lớp mã hóa đầu cuối:",[2273,77053,77054,77057,77060,77063],{},[989,77055,77056],{},"Mỗi client sinh cặp khóa X25519. Server chỉ chuyển khóa công khai.",[989,77058,77059],{},"Hai client dùng ECDH suy ra khóa chung, qua HKDF thành khóa AES-256-GCM.",[989,77061,77062],{},"Nonce 12 byte = 4 byte ngẫu nhiên cố định mỗi phiên + 8 byte bộ đếm tăng dần.",[989,77064,77065],{},"Người nhận từ chối tin có bộ đếm không tăng (chống phát lại) và tin sai tag.",[1352,77067,77070],{"className":77068,"code":77069,"language":2241,"meta":1357},[2239],"Server in log tin nhắn -> chỉ thấy bản mã\nSửa 1 byte bản mã      -> người nhận vứt tin, báo \"sai tag\"\nGửi lại tin cũ         -> người nhận vứt tin, báo \"phát lại\"\n",[992,77071,77069],{"__ignoreMap":1357},[981,77073,77075],{"id":77074},"bài-3-tấn-công-mitm-nâng-cao","Bài 3: Tấn công MITM (nâng cao)",[2273,77077,77078,77088],{},[989,77079,77080,77081,77083,77084,77087],{},"Viết proxy MITM đứng giữa, tự tạo chứng chỉ giả cho ",[992,77082,62752],{},". Client kiểm tra đúng thì từ chối. Tắt kiểm tra (",[992,77085,77086],{},"verify_mode = CERT_NONE",") thì bị đọc lén. Ghi lại cả 2.",[989,77089,77090,77091,77094],{},"MITM ở lớp E2E: server độc hại tráo khóa công khai. Thêm ",[1487,77092,77093],{},"xác minh vân tay",": 2 người so 6 chữ số từ hash của 2 khóa công khai. Chỉ ra vân tay khác nhau khi bị tráo.",[981,77096,2711],{"id":2710},[986,77098,77100,77106,77112,77118],{"className":77099},[2715],[989,77101,77103,77105],{"className":77102},[2719],[2721,77104],{"disabled":2723,"type":2724}," 3 test chứng chỉ pass.",[989,77107,77109,77111],{"className":77108},[2719],[2721,77110],{"disabled":2723,"type":2724}," Có ảnh chụp gói tin mã hóa.",[989,77113,77115,77117],{"className":77114},[2719],[2721,77116],{"disabled":2723,"type":2724}," E2E chống sửa và chống phát lại, có test.",[989,77119,77121,77123],{"className":77120},[2719],[2721,77122],{"disabled":2723,"type":2724}," Bài 3 tái hiện được MITM khi tắt kiểm tra, và phát hiện tráo khóa bằng vân tay.",[968,77125,2890],{"id":2889},[986,77127,77128,77131,77134,77137],{},[989,77129,77130],{},"Handshake TLS 4 bước gồm những gì?",[989,77132,77133],{},"PKI gắn khóa công khai với danh tính thế nào?",[989,77135,77136],{},"Nonce chống tấn công gửi lại ra sao?",[989,77138,77139],{},"Vì sao verify chứng chỉ là bắt buộc?",[3014,77141],{},[973,77143,77144],{},"🌕 Bạn đã hoàn thành ngày 142. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":77146},[77147,77148,77153,77154,77160],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":77149},[77150,77151,77152],{"id":76908,"depth":73,"text":76909},{"id":76926,"depth":73,"text":76927},{"id":76944,"depth":73,"text":76945},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":77155},[77156,77157,77158,77159],{"id":77005,"depth":73,"text":77006},{"id":77047,"depth":73,"text":77048},{"id":77074,"depth":73,"text":77075},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app chat bảo mật: mô phỏng bắt tay TLS, mã hóa đối xứng phiên, chữ ký PKI, demo tấn công MITM bị chặn.",{},[15143,15144],{"title":765,"description":77161},[17502,40796,77166,77167,77168],"tls","pki","secure-chat","nGFqW3o5XrSFPVEFsq-WTyLbGI1P6Vj39UKy10OkgrQ",{"id":77171,"title":770,"body":77172,"category":8797,"day":773,"description":77415,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":77416,"navigation":2723,"outcomes":3047,"path":771,"prerequisites":77417,"seo":77418,"stem":772,"tags":77419,"__hash__":77423},"challenges\u002Fchallenges\u002F143.app-data-pipeline.md",{"type":965,"value":77173,"toc":77399},[77174,77176,77179,77181,77185,77199,77203,77217,77221,77235,77237,77251,77253,77261,77265,77271,77288,77292,77310,77316,77320,77323,77347,77349,77378,77380,77394,77396],[968,77175,971],{"id":970},[973,77177,77178],{},"Bài này xây pipeline đếm doanh thu 2 nhánh. Nhánh nhanh báo liền, nhánh chậm chốt số chuẩn.",[968,77180,979],{"id":978},[981,77182,77184],{"id":77183},"batch-đúng-dần","Batch đúng dần",[986,77186,77187,77190,77193,77196],{},[989,77188,77189],{},"Batch quét toàn bộ log ngày rồi tính lại từ đầu.",[989,77191,77192],{},"Chạy định kỳ, idempotent chạy lại vẫn ra 1 kết quả.",[989,77194,77195],{},"Throughput cao, chính xác nhưng trễ cả ngày.",[989,77197,77198],{},"Ví dụ đời thường: cuối ngày cộng lại sổ thu chi cả ngày.",[981,77200,77202],{"id":77201},"stream-realtime","Stream realtime",[986,77204,77205,77208,77211,77214],{},[989,77206,77207],{},"Stream cập nhật mỗi phút theo event chảy tới.",[989,77209,77210],{},"Dùng cửa sổ và watermark để chờ event trễ.",[989,77212,77213],{},"Event trễ quá watermark ghi riêng rồi hiệu chỉnh sau.",[989,77215,77216],{},"Event time chống sai khi xử lý chậm hơn thực tế.",[981,77218,77220],{"id":77219},"cap-khi-node-chết","CAP khi node chết",[986,77222,77223,77226,77229,77232],{},[989,77224,77225],{},"CAP: khi chia mạng phải chọn trả lời hay chọn đúng.",[989,77227,77228],{},"Giết 1 trong 3 node mà stream vẫn trả lời là chọn A.",[989,77230,77231],{},"Chia mạng mà bên thiểu số từ chối ghi là chọn C.",[989,77233,77234],{},"Ngày thường không chia mạng thì vẫn có cả 2.",[968,77236,1433],{"id":1432},[986,77238,77239,77242,77245,77248],{},[989,77240,77241],{},"Input: không trễ không trùng. Output: stream khớp batch 100% cuối kỳ.",[989,77243,77244],{},"Giải thích: không sự cố thì nhánh nhanh và nhánh chuẩn trùng nhau.",[989,77246,77247],{},"Input: trễ 5% event. Output: stream sai tạm rồi đuổi kịp batch, sai cuối dưới 1%.",[989,77249,77250],{},"Giải thích: event trễ tới muộn được hiệu chỉnh bổ sung sau.",[968,77252,1482],{"id":1481},[973,77254,1485,77255,77257,77258,1517],{},[1487,77256,13531],{},". Dùng code ngày 60, 105. Nộp vào ",[992,77259,77260],{},"day-143-pipeline\u002F",[981,77262,77264],{"id":77263},"bài-1-pipeline-batch","Bài 1: Pipeline batch",[973,77266,77267,77268,1517],{},"Dữ liệu: log truy cập web 7 ngày (sinh giả, 10^6 dòng\u002Fngày) ",[992,77269,77270],{},"ts, user_id, url, status, bytes",[2273,77272,77273,77279,77285],{},[989,77274,77275,77276,1517],{},"Job batch tính mỗi ngày: số user duy nhất, top 10 URL, tỉ lệ lỗi 5xx theo giờ. Ghi Parquet theo phân vùng ",[992,77277,77278],{},"date=YYYY-MM-DD",[989,77280,77281,77284],{},[1487,77282,77283],{},"Idempotent:"," chạy lại job 1 ngày ghi đè đúng phân vùng đó, kết quả giống hệt. Có test.",[989,77286,77287],{},"Chạy lại lịch sử (backfill) 7 ngày bằng 1 lệnh.",[981,77289,77291],{"id":77290},"bài-2-pipeline-stream","Bài 2: Pipeline stream",[2273,77293,77294,77300,77307],{},[989,77295,77296,77297,1517],{},"Cùng các chỉ số nhưng cập nhật mỗi phút, cửa sổ tumbling 1 phút theo ",[1487,77298,77299],{},"thời gian sự kiện",[989,77301,77302,77303,77306],{},"5% event đến trễ 1-10 phút. Watermark 3 phút. Event trễ hơn watermark ghi vào ",[992,77304,77305],{},"late\u002F"," rồi job batch cuối ngày hiệu chỉnh.",[989,77308,77309],{},"So kết quả stream (sau hiệu chỉnh) với batch của cùng ngày. Phải khớp.",[1352,77311,77314],{"className":77312,"code":77313,"language":2241,"meta":1357},[2239],"Tổng request ngày D: stream_realtime + late_corrections == batch\n",[992,77315,77313],{"__ignoreMap":1357},[981,77317,77319],{"id":77318},"bài-3-cap-trên-cụm-3-node-nâng-cao","Bài 3: CAP trên cụm 3 node (nâng cao)",[973,77321,77322],{},"Dùng kho nhân bản ngày 60 làm nơi lưu bộ đếm stream.",[2273,77324,77325,77332,77335,77342],{},[989,77326,77327,77328,77331],{},"Giết 1 node giữa chừng. Stream vẫn ghi được với ",[992,77329,77330],{},"W = 2",". Ghi lại.",[989,77333,77334],{},"Chia mạng 1 | 2. Bên thiểu số từ chối ghi (chọn C). Bên đa số vẫn chạy.",[989,77336,77337,77338,77341],{},"Chuyển sang chế độ AP: cả 2 bên ghi, sau khi nối lại gộp bộ đếm bằng ",[1487,77339,77340],{},"G-Counter"," (CRDT): mỗi node giữ đếm riêng, giá trị = tổng, gộp bằng max từng node. Chứng minh không mất đếm.",[989,77343,77344,77346],{},[992,77345,2513],{},": sơ đồ pipeline, bảng batch vs stream (độ trễ, độ chính xác, chi phí), lựa chọn CAP cho từng chỉ số.",[981,77348,2711],{"id":2710},[986,77350,77352,77358,77364,77370],{"className":77351},[2715],[989,77353,77355,77357],{"className":77354},[2719],[2721,77356],{"disabled":2723,"type":2724}," Job batch idempotent, có test chạy lại.",[989,77359,77361,77363],{"className":77360},[2719],[2721,77362],{"disabled":2723,"type":2724}," Stream sau hiệu chỉnh khớp batch.",[989,77365,77367,77369],{"className":77366},[2719],[2721,77368],{"disabled":2723,"type":2724}," G-Counter gộp đúng sau chia mạng.",[989,77371,77373,2308,77375,77377],{"className":77372},[2719],[2721,77374],{"disabled":2723,"type":2724},[992,77376,2513],{}," có sơ đồ và bảng so sánh.",[968,77379,2890],{"id":2889},[986,77381,77382,77385,77388,77391],{},[989,77383,77384],{},"Batch và stream mỗi nhánh mạnh điều gì?",[989,77386,77387],{},"Watermark giúp xử lý event trễ thế nào?",[989,77389,77390],{},"Trùng event khử bằng cách nào?",[989,77392,77393],{},"CAP buộc chọn A hay C khi nào?",[3014,77395],{},[973,77397,77398],{},"🌕 Bạn đã hoàn thành ngày 143. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":77400},[77401,77402,77407,77408,77414],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":77403},[77404,77405,77406],{"id":77183,"depth":73,"text":77184},{"id":77201,"depth":73,"text":77202},{"id":77219,"depth":73,"text":77220},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":77409},[77410,77411,77412,77413],{"id":77263,"depth":73,"text":77264},{"id":77290,"depth":73,"text":77291},{"id":77318,"depth":73,"text":77319},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây pipeline dữ liệu kép: batch đúng dần, stream realtime, đối chiếu chênh lệch, phân tích đánh đổi CAP khi node chết.",{},[14055],{"title":770,"description":77415},[17502,77420,77421,62455,77422],"data-pipeline","batch","cap-theorem","9CElUix2FGkbZ38fDsW8XZeJv9i6kPR5s97jJDfoQrk",{"id":77425,"title":775,"body":77426,"category":3041,"day":778,"description":77693,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":77694,"navigation":2723,"outcomes":3047,"path":776,"prerequisites":77695,"seo":77696,"stem":777,"tags":77697,"__hash__":77700},"challenges\u002Fchallenges\u002F144.app-cache-system.md",{"type":965,"value":77427,"toc":77677},[77428,77430,77433,77435,77439,77453,77457,77471,77475,77489,77491,77505,77507,77519,77523,77529,77568,77572,77578,77609,77613,77616,77627,77629,77656,77658,77672,77674],[968,77429,971],{"id":970},[973,77431,77432],{},"Bài này xây kho nhớ tạm cho app nhanh. Trúng cache trả vài ms, trượt phải chờ DB 50ms.",[968,77434,979],{"id":978},[981,77436,77438],{"id":77437},"lru-và-lfu-đuổi-gì","LRU và LFU đuổi gì",[986,77440,77441,77444,77447,77450],{},[989,77442,77443],{},"LRU đuổi món ít dùng gần đây nhất.",[989,77445,77446],{},"LFU đuổi món ít dùng nhất theo tần suất có aging.",[989,77448,77449],{},"Gu ổn định thì LFU thắng, gu trượt nhanh thì LRU thắng.",[989,77451,77452],{},"Ví dụ đời thường: dọn tủ lạnh bỏ món lâu không ăn hoặc ít ăn.",[981,77454,77456],{"id":77455},"ttl-và-refresh-nền","TTL và refresh nền",[986,77458,77459,77462,77465,77468],{},[989,77460,77461],{},"TTL là hạn tươi của mỗi entry, quá hạn thành cũ.",[989,77463,77464],{},"Stale-while-revalidate trả cũ ngay đồng thời refresh nền.",[989,77466,77467],{},"Async load giúp reader không bị chặn khi tải lại.",[989,77469,77470],{},"Nhờ đó p99 không vọt mỗi lần key hot hết hạn.",[981,77472,77474],{"id":77473},"singleflight-chống-dogpile","Singleflight chống dogpile",[986,77476,77477,77480,77483,77486],{},[989,77478,77479],{},"Dogpile là chục request cùng miss 1 key đổ xuống DB.",[989,77481,77482],{},"Singleflight gom waiter, chỉ 1 request xuống DB thật.",[989,77484,77485],{},"9 người còn lại chờ ké kết quả rồi cùng về.",[989,77487,77488],{},"Khóa theo key để đúng mà không khóa cả cache.",[968,77490,1433],{"id":1432},[986,77492,77493,77496,77499,77502],{},[989,77494,77495],{},"Input: 50 luồng cùng miss 1 key hết hạn. Output: DB chỉ bị gọi đúng 1 lần.",[989,77497,77498],{},"Giải thích: singleflight gom 50 waiter thành 1 lượt tải duy nhất.",[989,77500,77501],{},"Input: tải Zipf gu ổn định. Output: LFU hit-rate hơn LRU ít nhất 5 điểm.",[989,77503,77504],{},"Giải thích: tần suất tích lũy bắt đúng hot set ổn định.",[968,77506,1482],{"id":1481},[973,77508,1485,77509,5586,77511,5586,77513,77515,77516,1517],{},[1487,77510,72078],{},[1487,77512,4800],{},[1487,77514,64499],{}," (asyncio). Dùng code ngày 39, 66. Nộp vào ",[992,77517,77518],{},"day-144-cache\u002F",[981,77520,77522],{"id":77521},"bài-1-thư-viện-cache","Bài 1: Thư viện cache",[1352,77524,77527],{"className":77525,"code":77526,"language":2241,"meta":1357},[2239],"Cache(capacity, policy = LRU | LFU, default_ttl)\n  get(key) -> (value, found)\n  set(key, value, ttl)\n  delete(key)\n  stats() -> hits, misses, evictions, size\n",[992,77528,77526],{"__ignoreMap":1357},[1099,77530,77531,77539],{},[1102,77532,77533],{},[1105,77534,77535,77537],{},[1108,77536,2547],{},[1108,77538,14241],{},[1118,77540,77541,77549,77560],{},[1105,77542,77543,77546],{},[1123,77544,77545],{},"Chính sách",[1123,77547,77548],{},"LRU và LFU có aging, chọn khi khởi tạo",[1105,77550,77551,77554],{},[1123,77552,77553],{},"TTL",[1123,77555,77556,77557,77559],{},"Hết hạn lười khi ",[992,77558,28507],{},", cộng 1 tác vụ nền dọn mỗi giây",[1105,77561,77562,77565],{},[1123,77563,77564],{},"An toàn luồng",[1123,77566,77567],{},"Sharded 16 mảnh, mỗi mảnh 1 khóa",[981,77569,77571],{"id":77570},"bài-2-loader-singleflight-và-stale-while-revalidate","Bài 2: Loader, singleflight và stale-while-revalidate",[1352,77573,77576],{"className":77574,"code":77575,"language":2241,"meta":1357},[2239],"get_or_load(key, loader, ttl, stale_ttl)\n",[992,77577,77575],{"__ignoreMap":1357},[2273,77579,77580,77590,77604],{},[989,77581,77582,77585,77586,77589],{},[1487,77583,77584],{},"Singleflight:"," 100 goroutine\u002Fluồng cùng miss 1 key -> ",[992,77587,77588],{},"loader"," chỉ chạy 1 lần. Có test đếm số lần gọi.",[989,77591,77592,77595,77596,77599,77600,77603],{},[1487,77593,77594],{},"Stale-while-revalidate:"," key hết ",[992,77597,77598],{},"ttl"," nhưng còn trong ",[992,77601,77602],{},"stale_ttl"," -> trả giá trị cũ ngay, tải lại ở nền. Có test bằng đồng hồ giả.",[989,77605,77606,77608],{},[992,77607,77588],{}," lỗi -> không lưu lỗi vào cache, trả lỗi cho mọi người đang chờ.",[981,77610,77612],{"id":77611},"bài-3-benchmark-trước-kho-chậm-nâng-cao","Bài 3: Benchmark trước kho chậm (nâng cao)",[973,77614,77615],{},"Kho giả lập: mỗi lần đọc 20 ms, tối đa 50 truy vấn đồng thời.",[2273,77617,77618,77621,77624],{},[989,77619,77620],{},"10.000 request\u002Fgiây theo Zipf trên 100.000 key trong 60 giây.",[989,77622,77623],{},"So 4 cấu hình: không cache, LRU, LFU, LRU + singleflight + SWR. In hit rate, p50, p99, số truy vấn xuống kho.",[989,77625,77626],{},"Kịch bản \"key nóng hết hạn\": 1 key nhận 30% lưu lượng, TTL 5 giây. Vẽ p99 theo thời gian có và không có SWR.",[981,77628,2711],{"id":2710},[986,77630,77632,77638,77644,77650],{"className":77631},[2715],[989,77633,77635,77637],{"className":77634},[2719],[2721,77636],{"disabled":2723,"type":2724}," Test singleflight, SWR, loader lỗi pass.",[989,77639,77641,77643],{"className":77640},[2719],[2721,77642],{"disabled":2723,"type":2724}," Không data race (race detector của Go, TSan, hoặc test đồng thời).",[989,77645,77647,77649],{"className":77646},[2719],[2721,77648],{"disabled":2723,"type":2724}," Bảng benchmark 4 cấu hình có số thật.",[989,77651,77653,77655],{"className":77652},[2719],[2721,77654],{"disabled":2723,"type":2724}," Hình p99 theo thời gian cho kịch bản key nóng.",[968,77657,2890],{"id":2889},[986,77659,77660,77663,77666,77669],{},[989,77661,77662],{},"LRU và LFU mỗi cái đuổi entry nào?",[989,77664,77665],{},"TTL và stale-while-revalidate giúp gì cho p99?",[989,77667,77668],{},"Dogpile giết DB lúc nào?",[989,77670,77671],{},"Singleflight gom request trùng thế nào?",[3014,77673],{},[973,77675,77676],{},"🌕 Bạn đã hoàn thành ngày 144. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":77678},[77679,77680,77685,77686,77692],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":77681},[77682,77683,77684],{"id":77437,"depth":73,"text":77438},{"id":77455,"depth":73,"text":77456},{"id":77473,"depth":73,"text":77474},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":77687},[77688,77689,77690,77691],{"id":77521,"depth":73,"text":77522},{"id":77570,"depth":73,"text":77571},{"id":77611,"depth":73,"text":77612},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây hệ thống cache đa chiến lược: LRU, LFU, TTL freshness, async load, khóa chống dogpile, benchmark hit-rate và p99.",{},[4669,17499],{"title":775,"description":77693},[17502,29125,77698,77699,42561],"lru","lfu","uRtMb5AOHyo8fcvoxOBGKlRm6nr1c93XbNwD59kI_Vc",{"id":77702,"title":780,"body":77703,"category":3041,"day":785,"description":78073,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":78074,"navigation":2723,"outcomes":3047,"path":781,"prerequisites":78075,"seo":78076,"stem":782,"tags":78077,"__hash__":78081},"challenges\u002Fchallenges\u002F145.app-db-index.md",{"type":965,"value":77704,"toc":78057},[77705,77707,77710,77712,77716,77730,77734,77791,77795,77809,77811,77825,77827,77835,77839,77891,77897,77903,77907,77913,77967,77973,77977,78003,78005,78034,78036,78050,78052,78055],[968,77706,971],{"id":970},[973,77708,77709],{},"Bài này xây mục lục cho database mini. Tìm 1 dòng thì dùng hash, tìm 1 đoạn thì dùng cây.",[968,77711,979],{"id":978},[981,77713,77715],{"id":77714},"b-tree-cho-range-query","B-tree cho range query",[986,77717,77718,77721,77724,77727],{},[989,77719,77720],{},"B-tree giữ key có thứ tự, lá nối nhau thành chuỗi.",[989,77722,77723],{},"Insert đầy nút thì split lan lên trên.",[989,77725,77726],{},"Range scan tìm lá đầu rồi quét ngang tới hết khoảng.",[989,77728,77729],{},"Fanout lớn giữ cây rất thấp: fanout 100 thì 3 tầng đã chứa cỡ 1 triệu khóa, 4 tầng cỡ 100 triệu.",[981,77731,77733],{"id":77732},"hash-cho-point-lookup","Hash cho point lookup",[986,77735,77736,77782,77785,77788],{},[989,77737,77738,77739,1517],{},"Hash ánh xạ key tới offset bản ghi trong ",[1023,77740,77742,77761],{"className":77741},[1026],[1023,77743,77745],{"className":77744},[1030],[1032,77746,77747],{"xmlns":1034},[1036,77748,77749,77759],{},[1039,77750,77751,77753,77755,77757],{},[1042,77752,1044],{},[1046,77754,1049],{"stretchy":1048},[1051,77756,1053],{},[1046,77758,1056],{"stretchy":1048},[1058,77760,1061],{"encoding":1060},[1023,77762,77764],{"className":77763,"ariaHidden":1066},[1065],[1023,77765,77767,77770,77773,77776,77779],{"className":77766},[1070],[1023,77768],{"className":77769,"style":1075},[1074],[1023,77771,1044],{"className":77772,"style":1081},[1079,1080],[1023,77774,1049],{"className":77775},[1085],[1023,77777,1053],{"className":77778},[1079],[1023,77780,1056],{"className":77781},[1092],[989,77783,77784],{},"Nhanh nhất cho hỏi bằng như tìm mã đơn hàng.",[989,77786,77787],{},"Không phục vụ được hỏi khoảng vì mất thứ tự.",[989,77789,77790],{},"Ví dụ đời thường: tra từ điển bằng số trang đánh dấu sẵn.",[981,77792,77794],{"id":77793},"bloom-chặn-key-vắng","Bloom chặn key vắng",[986,77796,77797,77800,77803,77806],{},[989,77798,77799],{},"Bloom nhớ toàn bộ key đã có.",[989,77801,77802],{},"Key vắng bị chặn trước khi chạm index đắt.",[989,77804,77805],{},"Phủ định là chắc chắn vắng, khẳng định mới cần verify.",[989,77807,77808],{},"Planner: Bloom trước, hash cho bằng, B-tree cho khoảng.",[968,77810,1433],{"id":1432},[986,77812,77813,77816,77819,77822],{},[989,77814,77815],{},"Input: point query 50 nghìn key. Output: đúng 100% value so với quét file.",[989,77817,77818],{},"Giải thích: hash trỏ đúng offset nên đọc đúng bản ghi.",[989,77820,77821],{},"Input: range 1000 key liên tiếp. Output: trả đủ có thứ tự, hash bó tay.",[989,77823,77824],{},"Giải thích: chỉ B-tree giữ thứ tự để quét đoạn.",[968,77826,1482],{"id":1481},[973,77828,1485,77829,77831,77832,1517],{},[1487,77830,4800],{},". Dùng Bloom ngày 30, hash map ngày 38. Nộp vào ",[992,77833,77834],{},"day-145-index\u002F",[981,77836,77838],{"id":77837},"bài-1-b-tree-trong-bộ-nhớ","Bài 1: B+ tree trong bộ nhớ",[1352,77840,77842],{"className":1393,"code":77841,"language":1395,"meta":1357,"style":1357},"template \u003Cclass K, class V, int ORDER = 32>\nclass BPlusTree {\n public:\n  void insert(const K &k, const V &v);          \u002F\u002F khóa trùng thì ghi đè\n  std::optional\u003CV> find(const K &k) const;\n  bool erase(const K &k);                        \u002F\u002F mượn hoặc gộp nút khi thiếu\n  std::vector\u003Cstd::pair\u003CK, V>> range(const K &lo, const K &hi) const;   \u002F\u002F lá nối nhau\n  int height() const;\n  bool check() const;   \u002F\u002F lá cùng độ sâu, khóa có thứ tự, số khóa mỗi nút đúng giới hạn\n};\n",[992,77843,77844,77849,77854,77858,77863,77868,77873,77878,77882,77887],{"__ignoreMap":1357},[1023,77845,77846],{"class":1362,"line":63},[1023,77847,77848],{},"template \u003Cclass K, class V, int ORDER = 32>\n",[1023,77850,77851],{"class":1362,"line":68},[1023,77852,77853],{},"class BPlusTree {\n",[1023,77855,77856],{"class":1362,"line":73},[1023,77857,4836],{},[1023,77859,77860],{"class":1362,"line":78},[1023,77861,77862],{},"  void insert(const K &k, const V &v);          \u002F\u002F khóa trùng thì ghi đè\n",[1023,77864,77865],{"class":1362,"line":83},[1023,77866,77867],{},"  std::optional\u003CV> find(const K &k) const;\n",[1023,77869,77870],{"class":1362,"line":88},[1023,77871,77872],{},"  bool erase(const K &k);                        \u002F\u002F mượn hoặc gộp nút khi thiếu\n",[1023,77874,77875],{"class":1362,"line":93},[1023,77876,77877],{},"  std::vector\u003Cstd::pair\u003CK, V>> range(const K &lo, const K &hi) const;   \u002F\u002F lá nối nhau\n",[1023,77879,77880],{"class":1362,"line":98},[1023,77881,44171],{},[1023,77883,77884],{"class":1362,"line":103},[1023,77885,77886],{},"  bool check() const;   \u002F\u002F lá cùng độ sâu, khóa có thứ tự, số khóa mỗi nút đúng giới hạn\n",[1023,77888,77889],{"class":1362,"line":108},[1023,77890,4866],{},[1352,77892,77895],{"className":77893,"code":77894,"language":2241,"meta":1357},[2239],"insert 1..10^6 -> height không quá 5 với ORDER = 32; check = true\nrange(100, 200) -> 101 cặp theo thứ tự\nerase mọi số chẵn -> check = true, find(2) = nullopt\n",[992,77896,77894],{"__ignoreMap":1357},[973,77898,77899,77900,77902],{},"Test ngẫu nhiên so với ",[992,77901,28600],{}," sau 10^5 thao tác trộn.",[981,77904,77906],{"id":77905},"bài-2-ba-loại-index-trên-1-bảng","Bài 2: Ba loại index trên 1 bảng",[973,77908,47713,77909,77912],{},[992,77910,77911],{},"orders(id, customer_id, created_at, amount)"," 10^6 dòng lưu trong file nhị phân, mỗi dòng cố định 32 byte.",[1099,77914,77915,77925],{},[1102,77916,77917],{},[1105,77918,77919,77922],{},[1108,77920,77921],{},"Index",[1108,77923,77924],{},"Trả lời truy vấn",[1118,77926,77927,77940,77953],{},[1105,77928,77929,77935],{},[1123,77930,77931,77932],{},"Hash index trên ",[992,77933,77934],{},"id",[1123,77936,77937],{},[992,77938,77939],{},"WHERE id = ?",[1105,77941,77942,77948],{},[1123,77943,77944,77945],{},"B+ tree trên ",[992,77946,77947],{},"created_at",[1123,77949,77950],{},[992,77951,77952],{},"WHERE created_at BETWEEN ? AND ?",[1105,77954,77955,77961],{},[1123,77956,77957,77958],{},"Bloom trên ",[992,77959,77960],{},"customer_id",[1123,77962,77963,77964,77966],{},"Loại nhanh ",[992,77965,77960],{}," không tồn tại trước khi quét",[1352,77968,77971],{"className":77969,"code":77970,"language":2241,"meta":1357},[2239],"truy_vấn                 quét_toàn_bảng(ms)   có_index(ms)   số_dòng_đọc\nid = 123456              ...\ncreated_at trong 1 ngày  ...\ncustomer_id vắng mặt     ...\n",[992,77972,77970],{"__ignoreMap":1357},[981,77974,77976],{"id":77975},"bài-3-b-tree-trên-đĩa-nâng-cao","Bài 3: B+ tree trên đĩa (nâng cao)",[2273,77978,77979,77988,77994,77997],{},[989,77980,77981,77982,2461,77985,1517],{},"Mỗi nút là 1 trang 4096 byte trong file. Đọc ghi trang bằng ",[992,77983,77984],{},"pread",[992,77986,77987],{},"pwrite",[989,77989,5030,77990,77993],{},[1487,77991,77992],{},"buffer pool"," LRU 256 trang. Đếm số lần đọc đĩa thật.",[989,77995,77996],{},"So số lần đọc đĩa cho 10.000 truy vấn điểm với buffer pool 0, 64, 256, 1024 trang.",[989,77998,77999,78000,78002],{},"Đóng chương trình, mở lại: dữ liệu vẫn còn, ",[992,78001,44248],{}," đúng.",[981,78004,2711],{"id":2710},[986,78006,78008,78016,78022,78028],{"className":78007},[2715],[989,78009,78011,78013,78014,1517],{"className":78010},[2719],[2721,78012],{"disabled":2723,"type":2724}," B+ tree pass test ngẫu nhiên so với ",[992,78015,28600],{},[989,78017,78019,78021],{"className":78018},[2719],[2721,78020],{"disabled":2723,"type":2724}," Bảng 3 truy vấn có và không có index.",[989,78023,78025,78027],{"className":78024},[2719],[2721,78026],{"disabled":2723,"type":2724}," Bản trên đĩa mở lại vẫn đúng.",[989,78029,78031,78033],{"className":78030},[2719],[2721,78032],{"disabled":2723,"type":2724}," Bảng số lần đọc đĩa theo kích thước buffer pool.",[968,78035,2890],{"id":2889},[986,78037,78038,78041,78044,78047],{},[989,78039,78040],{},"B-tree phục vụ range query bằng cách nào?",[989,78042,78043],{},"Hash nhanh cho point nhưng bó tay với gì?",[989,78045,78046],{},"Bloom chặn key vắng trước index để làm gì?",[989,78048,78049],{},"Planner chọn index theo loại query ra sao?",[3014,78051],{},[973,78053,78054],{},"🌕 Bạn đã hoàn thành ngày 145. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,78056,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":78058},[78059,78060,78065,78066,78072],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":78061},[78062,78063,78064],{"id":77714,"depth":73,"text":77715},{"id":77732,"depth":73,"text":77733},{"id":77793,"depth":73,"text":77794},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":78067},[78068,78069,78070,78071],{"id":77837,"depth":73,"text":77838},{"id":77905,"depth":73,"text":77906},{"id":77975,"depth":73,"text":77976},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây engine index mini: B-tree cho range query, hash cho point lookup, Bloom chặn key vắng, so độ trễ đọc ghi.",{},[3050,17499],{"title":780,"description":78073},[17502,78078,78079,78080,24341],"db-index","b-tree","hash-index","f0HIxFFGy2AOyiqlnxnHv6eElzoO-s--VrH55zpGe1w",{"id":78083,"title":787,"body":78084,"category":8797,"day":790,"description":78465,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":78466,"navigation":2723,"outcomes":3047,"path":788,"prerequisites":78467,"seo":78468,"stem":789,"tags":78469,"__hash__":78472},"challenges\u002Fchallenges\u002F146.app-spell-checker.md",{"type":965,"value":78085,"toc":78449},[78086,78088,78091,78093,78097,78154,78158,78172,78176,78190,78192,78206,78208,78216,78220,78258,78303,78309,78313,78316,78360,78363,78367,78397,78399,78426,78428,78442,78444,78447],[968,78087,971],{"id":970},[973,78089,78090],{},"Bài này xây app sửa lỗi gõ sai. Gõ sai 1 chữ là máy gợi ý đúng ngay.",[968,78092,979],{"id":978},[981,78094,78096],{"id":78095},"trie-làm-từ-điển","Trie làm từ điển",[986,78098,78099,78145,78148,78151],{},[989,78100,78101,78102,1517],{},"Trie lưu 100 nghìn từ, kiểm tra tồn tại tốn ",[1023,78103,78105,78124],{"className":78104},[1026],[1023,78106,78108],{"className":78107},[1030],[1032,78109,78110],{"xmlns":1034},[1036,78111,78112,78122],{},[1039,78113,78114,78116,78118,78120],{},[1042,78115,1044],{},[1046,78117,1049],{"stretchy":1048},[1042,78119,15437],{},[1046,78121,1056],{"stretchy":1048},[1058,78123,70902],{"encoding":1060},[1023,78125,78127],{"className":78126,"ariaHidden":1066},[1065],[1023,78128,78130,78133,78136,78139,78142],{"className":78129},[1070],[1023,78131],{"className":78132,"style":1075},[1074],[1023,78134,1044],{"className":78135,"style":1081},[1079,1080],[1023,78137,1049],{"className":78138},[1085],[1023,78140,15437],{"className":78141},[1079,1080],[1023,78143,1056],{"className":78144},[1092],[989,78146,78147],{},"Từ vắng trong Trie thì đánh dấu sai kèm vị trí.",[989,78149,78150],{},"Ví dụ đời thường: dò từ điển xem từ này có thật không.",[989,78152,78153],{},"Từ đúng hiếm có trong từ điển thì không báo sai.",[981,78155,78157],{"id":78156},"edit-distance-sinh-ứng-viên","Edit distance sinh ứng viên",[986,78159,78160,78163,78166,78169],{},[989,78161,78162],{},"Edit distance đếm số lần sửa để biến từ sai thành đúng.",[989,78164,78165],{},"4 phép sửa: xóa, chèn, thay, hoán vị 2 chữ.",[989,78167,78168],{},"80% lỗi gõ cách đáp án đúng 1 edit nên tối ưu đường này trước.",[989,78170,78171],{},"Ví dụ đời thường: komputer sửa 1 chữ thành computer.",[981,78173,78175],{"id":78174},"xếp-hạng-bằng-khoảng-cách-và-tần-suất","Xếp hạng bằng khoảng cách và tần suất",[986,78177,78178,78181,78184,78187],{},[989,78179,78180],{},"Điểm gồm khoảng cách nhỏ và tần suất cao.",[989,78182,78183],{},"Từ hay dùng thắng khi nhiều ứng viên cùng khoảng cách.",[989,78185,78186],{},"Giữ top-3 bằng heap cho rẻ.",[989,78188,78189],{},"Người dùng chọn từ nào thì tăng tần suất từ đó.",[968,78191,1433],{"id":1432},[986,78193,78194,78197,78200,78203],{},[989,78195,78196],{},"Input: từ sai komputer. Output: gợi ý hạng 1 là computer.",[989,78198,78199],{},"Giải thích: cách đúng 1 edit và tần suất rất cao.",[989,78201,78202],{},"Input: văn bản 200 từ có 10 lỗi cài sẵn. Output: bắt đúng 10 vị trí, không báo oan từ đúng.",[989,78204,78205],{},"Giải thích: Trie kiểm tra từng từ nên chỉ từ vắng mới bị gắn cờ.",[968,78207,1482],{"id":1481},[973,78209,1485,78210,78212,78213,1517],{},[1487,78211,4800],{}," (hoặc Python). Dùng Trie ngày 35, edit distance ngày 77, spell-check ngày 36. Nộp vào ",[992,78214,78215],{},"day-146-spell\u002F",[981,78217,78219],{"id":78218},"bài-1-kiểm-tra-chính-tả-văn-bản","Bài 1: Kiểm tra chính tả văn bản",[1352,78221,78223],{"className":1393,"code":78222,"language":1395,"meta":1357,"style":1357},"struct Misspelling { std::string word; size_t line, col; std::vector\u003Cstd::string> suggestions; };\nclass SpellChecker {\n public:\n  static SpellChecker fromFile(const std::string &dictPath);   \u002F\u002F \"từ\u003CTAB>tần_suất\"\n  std::vector\u003CMisspelling> check(const std::string &text, int topK = 3) const;\n  void learn(const std::string &word);                          \u002F\u002F người dùng chọn\u002Fthêm từ\n};\n",[992,78224,78225,78230,78235,78239,78244,78249,78254],{"__ignoreMap":1357},[1023,78226,78227],{"class":1362,"line":63},[1023,78228,78229],{},"struct Misspelling { std::string word; size_t line, col; std::vector\u003Cstd::string> suggestions; };\n",[1023,78231,78232],{"class":1362,"line":68},[1023,78233,78234],{},"class SpellChecker {\n",[1023,78236,78237],{"class":1362,"line":73},[1023,78238,4836],{},[1023,78240,78241],{"class":1362,"line":78},[1023,78242,78243],{},"  static SpellChecker fromFile(const std::string &dictPath);   \u002F\u002F \"từ\u003CTAB>tần_suất\"\n",[1023,78245,78246],{"class":1362,"line":83},[1023,78247,78248],{},"  std::vector\u003CMisspelling> check(const std::string &text, int topK = 3) const;\n",[1023,78250,78251],{"class":1362,"line":88},[1023,78252,78253],{},"  void learn(const std::string &word);                          \u002F\u002F người dùng chọn\u002Fthêm từ\n",[1023,78255,78256],{"class":1362,"line":93},[1023,78257,4866],{},[1099,78259,78260,78268],{},[1102,78261,78262],{},[1105,78263,78264,78266],{},[1108,78265,2547],{},[1108,78267,14241],{},[1118,78269,78270,78278,78286,78294],{},[1105,78271,78272,78275],{},[1123,78273,78274],{},"Tách từ",[1123,78276,78277],{},"Bỏ số, URL, email, từ viết hoa toàn bộ (tên riêng viết tắt)",[1105,78279,78280,78283],{},[1123,78281,78282],{},"Vị trí",[1123,78284,78285],{},"Dòng và cột tính từ 1",[1105,78287,78288,78291],{},[1123,78289,78290],{},"Gợi ý",[1123,78292,78293],{},"Khoảng cách Damerau-Levenshtein (có hoán vị 2 chữ kề) tối đa 2. Xếp theo khoảng cách tăng, rồi tần suất giảm",[1105,78295,78296,78298],{},[1123,78297,71205],{},[1123,78299,78300,78301],{},"Heap cỡ ",[992,78302,4022],{},[1352,78304,78307],{"className":78305,"code":78306,"language":2241,"meta":1357},[2239],"\"teh cat\" -> teh ở (1,1), gợi ý [the, ten, tea]\n\"recieve\" -> gợi ý đầu tiên \"receive\" (hoán vị ie -> ei)\n\"COVID https:\u002F\u002Fx.com a@b.vn 2024\" -> không báo lỗi\n",[992,78308,78306],{"__ignoreMap":1357},[981,78310,78312],{"id":78311},"bài-2-sinh-ứng-viên-nhanh","Bài 2: Sinh ứng viên nhanh",[973,78314,78315],{},"So 3 cách sinh ứng viên cho từ sai:",[1099,78317,78318,78326],{},[1102,78319,78320],{},[1105,78321,78322,78324],{},[1108,78323,14526],{},[1108,78325,8303],{},[1118,78327,78328,78336,78344,78352],{},[1105,78329,78330,78333],{},[1123,78331,78332],{},"Quét hết",[1123,78334,78335],{},"Tính khoảng cách với mọi từ trong từ điển",[1105,78337,78338,78341],{},[1123,78339,78340],{},"Sinh biến thể",[1123,78342,78343],{},"Sinh mọi chuỗi cách 1 và 2 phép sửa, tra trong hash set (kiểu Norvig)",[1105,78345,78346,78349],{},[1123,78347,78348],{},"Duyệt Trie có cắt nhánh",[1123,78350,78351],{},"Như ngày 36",[1105,78353,78354,78357],{},[1123,78355,78356],{},"SymSpell (tùy chọn)",[1123,78358,78359],{},"Tiền xử lý các biến thể xóa ký tự",[973,78361,78362],{},"Từ điển 100.000 từ, 1000 từ sai. In thời gian trung bình mỗi từ và kiểm tra 3 cách cho cùng danh sách gợi ý.",[981,78364,78366],{"id":78365},"bài-3-đánh-giá-và-học-nâng-cao","Bài 3: Đánh giá và học (nâng cao)",[2273,78368,78369,78378,78381,78387],{},[989,78370,78371,78372,1509,78375,1517],{},"Dùng bộ lỗi chính tả có đáp án (ví dụ Birkbeck spelling corpus, hoặc tự tạo 500 cặp bằng cách chèn lỗi ngẫu nhiên vào từ đúng). Tính ",[1487,78373,78374],{},"accuracy@1",[1487,78376,78377],{},"accuracy@3",[989,78379,78380],{},"Thêm mô hình lỗi bàn phím: thay thế giữa 2 phím kề nhau có chi phí 0.5. So lại accuracy.",[989,78382,78383,78386],{},[992,78384,78385],{},"learn(word)"," tăng tần suất. Chứng minh sau khi học, gợi ý thay đổi đúng.",[989,78388,78389,78390,78393,78394,1517],{},"CLI: ",[992,78391,78392],{},"spell check file.txt"," in lỗi dạng ",[992,78395,78396],{},"file.txt:3:15: \"teh\" -> the, ten, tea",[981,78398,2711],{"id":2710},[986,78400,78402,78408,78414,78420],{"className":78401},[2715],[989,78403,78405,78407],{"className":78404},[2719],[2721,78406],{"disabled":2723,"type":2724}," Test mẫu pass, gồm hoán vị và các chuỗi bị bỏ qua.",[989,78409,78411,78413],{"className":78410},[2719],[2721,78412],{"disabled":2723,"type":2724}," Bảng thời gian 3 cách, cùng kết quả.",[989,78415,78417,78419],{"className":78416},[2719],[2721,78418],{"disabled":2723,"type":2724}," Bảng accuracy@1, @3 có và không có mô hình bàn phím.",[989,78421,78423,78425],{"className":78422},[2719],[2721,78424],{"disabled":2723,"type":2724}," CLI in đúng định dạng.",[968,78427,2890],{"id":2889},[986,78429,78430,78433,78436,78439],{},[989,78431,78432],{},"Trie kiểm tra từ tồn tại thế nào?",[989,78434,78435],{},"4 phép sửa trong edit distance là gì?",[989,78437,78438],{},"Vì sao tối ưu đường 1-edit trước?",[989,78440,78441],{},"Tần suất giúp chọn gợi ý ra sao?",[3014,78443],{},[973,78445,78446],{},"🌕 Bạn đã hoàn thành ngày 146. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,78448,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":78450},[78451,78452,78457,78458,78464],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":78453},[78454,78455,78456],{"id":78095,"depth":73,"text":78096},{"id":78156,"depth":73,"text":78157},{"id":78174,"depth":73,"text":78175},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":78459},[78460,78461,78462,78463],{"id":78218,"depth":73,"text":78219},{"id":78311,"depth":73,"text":78312},{"id":78365,"depth":73,"text":78366},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây app sửa chính tả: Trie từ điển, edit distance, gợi ý xếp hạng, đo precision trên lỗi gõ mẫu.",{},[3050],{"title":787,"description":78465},[17502,78470,27243,78471,37980],"spell-checker","edit-distance","pI03BQsSDegpF9c-lPzxvqteS_4og5Z4iUP8m5G2W3I",{"id":78474,"title":792,"body":78475,"category":5189,"day":795,"description":78795,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":78796,"navigation":2723,"outcomes":3047,"path":793,"prerequisites":78797,"seo":78798,"stem":794,"tags":78799,"__hash__":78804},"challenges\u002Fchallenges\u002F147.app-game-ai.md",{"type":965,"value":78476,"toc":78779},[78477,78479,78482,78484,78488,78502,78506,78520,78524,78538,78540,78554,78556,78564,78568,78577,78586,78631,78640,78644,78687,78694,78700,78704,78725,78727,78756,78758,78772,78774,78777],[968,78478,971],{"id":970},[973,78480,78481],{},"Bài này xây máy bán kẹo có thưởng. Đổi chính sách thưởng là đổi doanh thu ngay.",[968,78483,979],{"id":978},[981,78485,78487],{"id":78486},"state-quản-vòng-đời-máy","State quản vòng đời máy",[986,78489,78490,78493,78496,78499],{},[989,78491,78492],{},"5 trạng thái: chờ xu, có xu, đang nhả, hết kẹo, trúng thưởng.",[989,78494,78495],{},"Mỗi trạng thái là 1 lớp xử lý 4 việc bỏ xu, nhả xu, quay, nhả kẹo.",[989,78497,78498],{},"Máy chỉ ủy thác cho trạng thái hiện tại nên gọn if-else.",[989,78500,78501],{},"Ví dụ đời thường: máy hết kẹo thì nuốt quay và trả xu.",[981,78503,78505],{"id":78504},"strategy-đổi-chính-sách-thưởng","Strategy đổi chính sách thưởng",[986,78507,78508,78511,78514,78517],{},[989,78509,78510],{},"RandomWinner trúng tỉ lệ cố định như 10%.",[989,78512,78513],{},"PityWinner tăng tỉ lệ khi lâu chưa trúng để giữ khách.",[989,78515,78516],{},"ProfitGuard giảm tỉ lệ khi tồn kho thấp để giữ lãi.",[989,78518,78519],{},"Ví dụ đời thường: quán cho voucher nhiều hơn khi khách sắp bỏ đi.",[981,78521,78523],{"id":78522},"mô-phỏng-ngàn-ván","Mô phỏng ngàn ván",[986,78525,78526,78529,78532,78535],{},[989,78527,78528],{},"3 kiểu khách: bừa, dễ bỏ cuộc, chơi tới cùng.",[989,78530,78531],{},"Cùng seed chạy qua 3 chính sách để so công bằng.",[989,78533,78534],{},"Ghi doanh thu, kẹo phát, tỉ lệ trúng mỗi phiên.",[989,78536,78537],{},"Thêm trạng thái mới không sửa code cũ.",[968,78539,1433],{"id":1432},[986,78541,78542,78545,78548,78551],{},[989,78543,78544],{},"Input: quay khi máy hết kẹo. Output: báo hết và trả xu, không kẹt.",[989,78546,78547],{},"Giải thích: trạng thái hết kẹo chặn nhả và hoàn xu.",[989,78549,78550],{},"Input: cùng seed chạy 3 chính sách 1000 ván. Output: 3 bảng số khác nhau, tổng ván bằng nhau.",[989,78552,78553],{},"Giải thích: cùng khách cùng ván nên so lãi là công bằng.",[968,78555,1482],{"id":1481},[973,78557,1485,78558,78560,78561,1517],{},[1487,78559,4800],{}," (hoặc Java\u002FPython). Dùng máy kẹo ngày 85, 86. Nộp vào ",[992,78562,78563],{},"day-147-gumball-ai\u002F",[981,78565,78567],{"id":78566},"bài-1-máy-kẹo-với-chính-sách-thưởng-thay-được","Bài 1: Máy kẹo với chính sách thưởng thay được",[973,78569,78570,78572,78573,78576],{},[992,78571,51550],{}," có 5 trạng thái (State pattern) và giữ ",[992,78574,78575],{},"WinnerPolicy"," (Strategy pattern).",[1352,78578,78580],{"className":1393,"code":78579,"language":1395,"meta":1357,"style":1357},"struct WinnerPolicy { virtual bool isWinner(const MachineStats &s, Rng &rng) = 0; virtual std::string name() const = 0; };\n",[992,78581,78582],{"__ignoreMap":1357},[1023,78583,78584],{"class":1362,"line":63},[1023,78585,78579],{},[1099,78587,78588,78596],{},[1102,78589,78590],{},[1105,78591,78592,78594],{},[1108,78593,77545],{},[1108,78595,23340],{},[1118,78597,78598,78611,78621],{},[1105,78599,78600,78605],{},[1123,78601,78602],{},[992,78603,78604],{},"RandomWinner(p)",[1123,78606,78607,78608],{},"Trúng với xác suất ",[992,78609,78610],{},"p = 0.1",[1105,78612,78613,78618],{},[1123,78614,78615],{},[992,78616,78617],{},"PityWinner",[1123,78619,78620],{},"Bắt đầu 5%, mỗi lượt không trúng cộng thêm 2%, trúng thì về 5%",[1105,78622,78623,78628],{},[1123,78624,78625],{},[992,78626,78627],{},"ProfitGuard",[1123,78629,78630],{},"10% khi tồn kho trên 50%, 3% khi dưới 50%, 0% khi dưới 10 viên",[973,78632,78633,78635,78636,78639],{},[1487,78634,6076],{}," đổi chính sách lúc chạy bằng ",[992,78637,78638],{},"setPolicy",". Thêm chính sách mới không sửa trạng thái nào.",[981,78641,78643],{"id":78642},"bài-2-mô-phỏng-khách-hàng","Bài 2: Mô phỏng khách hàng",[1099,78645,78646,78655],{},[1102,78647,78648],{},[1105,78649,78650,78653],{},[1108,78651,78652],{},"Kiểu khách",[1108,78654,4292],{},[1118,78656,78657,78667,78677],{},[1105,78658,78659,78664],{},[1123,78660,78661],{},[992,78662,78663],{},"RandomPlayer",[1123,78665,78666],{},"Mỗi lượt 50% mua tiếp, 50% rời đi",[1105,78668,78669,78674],{},[1123,78670,78671],{},[992,78672,78673],{},"QuitterPlayer",[1123,78675,78676],{},"Rời đi sau 3 lượt liên tiếp không trúng",[1105,78678,78679,78684],{},[1123,78680,78681],{},[992,78682,78683],{},"GrinderPlayer",[1123,78685,78686],{},"Chơi tới khi trúng hoặc hết 20 xu",[973,78688,78689,78690,78693],{},"Chạy 10.000 phiên với mỗi tổ hợp 3 chính sách x 3 kiểu khách, ",[1487,78691,78692],{},"cùng seed"," cho từng tổ hợp. Mỗi xu 5.000đ, giá vốn mỗi viên 2.000đ.",[1352,78695,78698],{"className":78696,"code":78697,"language":2241,"meta":1357},[2239],"chính_sách     kiểu_khách   doanh_thu   kẹo_phát   tỉ_lệ_trúng   lượt_chơi_trung_bình   lãi\nRandomWinner   Random       ...\n...\n",[992,78699,78697],{"__ignoreMap":1357},[981,78701,78703],{"id":78702},"bài-3-thêm-trạng-thái-và-báo-cáo-nâng-cao","Bài 3: Thêm trạng thái và báo cáo (nâng cao)",[2273,78705,78706,78717,78720],{},[989,78707,78708,78709,78712,78713,78716],{},"Thêm trạng thái ",[992,78710,78711],{},"Maintenance",": sau 500 lượt quay, máy khóa tới khi gọi ",[992,78714,78715],{},"service()",". Chỉ thêm 1 lớp và 1 chỗ chuyển trạng thái.",[989,78718,78719],{},"Vẽ sơ đồ trạng thái đầy đủ (Mermaid).",[989,78721,78722,78724],{},[992,78723,17400],{},": chính sách nào tối ưu lãi, chính sách nào giữ khách lâu nhất, khuyến nghị cho chủ máy. Mọi kết luận gắn với số trong bảng.",[981,78726,2711],{"id":2710},[986,78728,78730,78736,78742,78750],{"className":78729},[2715],[989,78731,78733,78735],{"className":78732},[2719],[2721,78734],{"disabled":2723,"type":2724}," 3 chính sách có test riêng với rng giả.",[989,78737,78739,78741],{"className":78738},[2719],[2721,78740],{"disabled":2723,"type":2724}," Bảng 9 tổ hợp có số thật, tái lập được với cùng seed.",[989,78743,78745,11992,78747,78749],{"className":78744},[2719],[2721,78746],{"disabled":2723,"type":2724},[992,78748,78711],{}," không sửa trạng thái khác ngoài 1 chỗ chuyển.",[989,78751,78753,78755],{"className":78752},[2719],[2721,78754],{"disabled":2723,"type":2724}," Sơ đồ trạng thái và báo cáo khuyến nghị.",[968,78757,2890],{"id":2889},[986,78759,78760,78763,78766,78769],{},[989,78761,78762],{},"5 trạng thái máy kẹo mỗi cái làm gì?",[989,78764,78765],{},"3 chính sách thưởng khác nhau ở điểm gì?",[989,78767,78768],{},"Vì sao mô phỏng phải cố định seed?",[989,78770,78771],{},"State và Strategy khác nhau ở mục đích nào?",[3014,78773],{},[973,78775,78776],{},"🌕 Bạn đã hoàn thành ngày 147. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,78778,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":78780},[78781,78782,78787,78788,78794],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":78783},[78784,78785,78786],{"id":78486,"depth":73,"text":78487},{"id":78504,"depth":73,"text":78505},{"id":78522,"depth":73,"text":78523},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":78789},[78790,78791,78792,78793],{"id":78566,"depth":73,"text":78567},{"id":78642,"depth":73,"text":78643},{"id":78702,"depth":73,"text":78703},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây game máy bán kẹo có AI: State quản lý vòng đời, Strategy đổi chính sách thưởng, mô phỏng ngàn ván đo doanh thu.",{},[5194],{"title":792,"description":78795},[17502,78800,78801,78802,78803],"state-pattern","strategy-pattern","game-ai","simulation","8yyJ375gw_fN3IjVXpdkWdYhvnGQW3P7q313nAklka8",{"id":78806,"title":797,"body":78807,"category":5189,"day":800,"description":79131,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":79132,"navigation":2723,"outcomes":3047,"path":798,"prerequisites":79133,"seo":79134,"stem":799,"tags":79135,"__hash__":79140},"challenges\u002Fchallenges\u002F148.app-text-editor.md",{"type":965,"value":78808,"toc":79115},[78809,78811,78814,78816,78820,78834,78838,78852,78856,78870,78872,78886,78888,78896,78900,78943,78989,79002,79006,79012,79028,79032,79063,79065,79092,79094,79108,79110,79113],[968,78810,971],{"id":970},[973,78812,78813],{},"Bài này xây editor có undo redo. Gõ sai bấm undo là quay lại ngay.",[968,78815,979],{"id":978},[981,78817,78819],{"id":78818},"command-gói-thao-tác","Command gói thao tác",[986,78821,78822,78825,78828,78831],{},[989,78823,78824],{},"Mỗi thao tác là 1 lệnh có execute và unexecute.",[989,78826,78827],{},"Insert lưu chữ đã chèn, Delete lưu chữ đã xóa.",[989,78829,78830],{},"Ví dụ đời thường: mỗi bước đi ghi vào sổ để xóa được.",[989,78832,78833],{},"Lệnh mới sau undo sẽ xóa sạch redo.",[981,78835,78837],{"id":78836},"_2-stack-undo-redo","2 stack undo redo",[986,78839,78840,78843,78846,78849],{},[989,78841,78842],{},"Execute đẩy vào stack undo và xóa stack redo.",[989,78844,78845],{},"Undo pop ra đảo ngược rồi đẩy sang redo.",[989,78847,78848],{},"Redo pop ra làm lại rồi đẩy về undo.",[989,78850,78851],{},"Giới hạn 500 entry để RAM không phình.",[981,78853,78855],{"id":78854},"memento-và-macro","Memento và macro",[986,78857,78858,78861,78864,78867],{},[989,78859,78860],{},"Memento chụp ảnh toàn văn cho thao tác lớn như paste 5000 chữ.",[989,78862,78863],{},"Undo việc lớn chỉ cần khôi phục ảnh 1 bước.",[989,78865,78866],{},"Macro gom 5 thao tác thành 1 lệnh undo 1 lần.",[989,78868,78869],{},"Delta nhỏ tiết kiệm RAM, snapshot lớn tiện 1 bước.",[968,78871,1433],{"id":1432},[986,78873,78874,78877,78880,78883],{},[989,78875,78876],{},"Input: gõ hello rồi xóa 2 chữ. Output: còn hel, undo về hello, redo về hel.",[989,78878,78879],{},"Giải thích: mỗi lệnh nhớ đủ delta để đi tới lui.",[989,78881,78882],{},"Input: paste 5000 chữ rồi undo. Output: về đúng văn bản cũ chỉ 1 bước.",[989,78884,78885],{},"Giải thích: snapshot lưu ảnh trước paste nên khôi phục 1 lần.",[968,78887,1482],{"id":1481},[973,78889,1485,78890,78892,78893,1517],{},[1487,78891,4800],{}," (hoặc Python). Dùng Command ngày 81, Memento ngày 95. Nộp vào ",[992,78894,78895],{},"day-148-editor\u002F",[981,78897,78899],{"id":78898},"bài-1-văn-bản-và-lệnh","Bài 1: Văn bản và lệnh",[1352,78901,78903],{"className":1393,"code":78902,"language":1395,"meta":1357,"style":1357},"class Document {\n public:\n  void insert(size_t pos, const std::string &s);\n  std::string erase(size_t pos, size_t len);   \u002F\u002F trả phần đã xóa\n  const std::string &text() const; size_t cursor() const; void setCursor(size_t);\n};\nstruct EditCommand { virtual void execute(Document&) = 0; virtual void undo(Document&) = 0;\n                     virtual bool mergeWith(const EditCommand &next) { return false; } };\n",[992,78904,78905,78910,78914,78919,78924,78929,78933,78938],{"__ignoreMap":1357},[1023,78906,78907],{"class":1362,"line":63},[1023,78908,78909],{},"class Document {\n",[1023,78911,78912],{"class":1362,"line":68},[1023,78913,4836],{},[1023,78915,78916],{"class":1362,"line":73},[1023,78917,78918],{},"  void insert(size_t pos, const std::string &s);\n",[1023,78920,78921],{"class":1362,"line":78},[1023,78922,78923],{},"  std::string erase(size_t pos, size_t len);   \u002F\u002F trả phần đã xóa\n",[1023,78925,78926],{"class":1362,"line":83},[1023,78927,78928],{},"  const std::string &text() const; size_t cursor() const; void setCursor(size_t);\n",[1023,78930,78931],{"class":1362,"line":88},[1023,78932,4866],{},[1023,78934,78935],{"class":1362,"line":93},[1023,78936,78937],{},"struct EditCommand { virtual void execute(Document&) = 0; virtual void undo(Document&) = 0;\n",[1023,78939,78940],{"class":1362,"line":98},[1023,78941,78942],{},"                     virtual bool mergeWith(const EditCommand &next) { return false; } };\n",[1099,78944,78945,78955],{},[1102,78946,78947],{},[1105,78948,78949,78952],{},[1108,78950,78951],{},"Lệnh",[1108,78953,78954],{},"Lưu gì để undo",[1118,78956,78957,78967,78979],{},[1105,78958,78959,78964],{},[1123,78960,78961],{},[992,78962,78963],{},"InsertCommand(pos, text)",[1123,78965,78966],{},"Vị trí và chuỗi đã chèn",[1105,78968,78969,78974],{},[1123,78970,78971],{},[992,78972,78973],{},"DeleteCommand(pos, len)",[1123,78975,78976,78977,1056],{},"Chuỗi đã xóa (lấy lúc ",[992,78978,49947],{},[1105,78980,78981,78986],{},[1123,78982,78983],{},[992,78984,78985],{},"ReplaceCommand(pos, len, text)",[1123,78987,78988],{},"Chuỗi cũ và chuỗi mới",[973,78990,78991,78994,78995,78998,78999,1517],{},[1487,78992,78993],{},"Gộp gõ phím:"," 10 lần gõ từng ký tự liền nhau (cùng vị trí nối tiếp, cách nhau dưới 1 giây) gộp thành 1 ",[992,78996,78997],{},"InsertCommand",". Dùng ",[992,79000,79001],{},"mergeWith",[981,79003,79005],{"id":79004},"bài-2-lịch-sử-undoredo","Bài 2: Lịch sử undo\u002Fredo",[1352,79007,79010],{"className":79008,"code":79009,"language":2241,"meta":1357},[2239],"type \"Hello\"; type \" World\"; undo -> \"Hello\"; redo -> \"Hello World\"\nundo; type \"!\"; redo -> không làm gì, văn bản \"Hello!\"\nLịch sử giới hạn 500 mục, mục cũ nhất bị bỏ\nUndo khi lịch sử rỗng -> không làm gì\n",[992,79011,79009],{"__ignoreMap":1357},[2273,79013,79014,79019,79025],{},[989,79015,79016,79018],{},[992,79017,70712],{},": \"Tìm và thay tất cả\" là 1 macro, undo 1 lần là hoàn tác toàn bộ.",[989,79020,79021,79022,79024],{},"Paste đoạn trên 5000 ký tự: lưu ",[1487,79023,56167],{}," (ảnh toàn văn bản) thay vì lệnh. Undo khôi phục ảnh.",[989,79026,79027],{},"In bộ nhớ lịch sử ước lượng sau 10.000 thao tác.",[981,79029,79031],{"id":79030},"bài-3-giao-diện-dòng-lệnh-nâng-cao","Bài 3: Giao diện dòng lệnh (nâng cao)",[2273,79033,79034,79057,79060],{},[989,79035,79036,79037,1656,79040,1656,79043,1656,79046,1656,79048,79050,79051,79053,79054,79056],{},"REPL với lệnh: ",[992,79038,79039],{},"i \u003Cpos> \u003Ctext>",[992,79041,79042],{},"d \u003Cpos> \u003Clen>",[992,79044,79045],{},"r \u003Cfind> \u003Creplace>",[992,79047,30390],{},[992,79049,32887],{}," (redo), ",[992,79052,973],{}," (in), ",[992,79055,7908],{}," (in lịch sử, đánh dấu vị trí hiện tại).",[989,79058,79059],{},"Lưu và mở file. Đánh dấu \"đã sửa\" khi lịch sử khác điểm lưu gần nhất (undo về đúng điểm lưu thì hết dấu).",[989,79061,79062],{},"Test tính chất: chuỗi 1000 thao tác ngẫu nhiên, rồi undo hết phải về văn bản ban đầu, rồi redo hết phải về văn bản cuối.",[981,79064,2711],{"id":2710},[986,79066,79068,79074,79080,79086],{"className":79067},[2715],[989,79069,79071,79073],{"className":79070},[2719],[2721,79072],{"disabled":2723,"type":2724}," Test mẫu undo\u002Fredo pass.",[989,79075,79077,79079],{"className":79076},[2719],[2721,79078],{"disabled":2723,"type":2724}," Gõ phím liền nhau gộp thành 1 bước undo.",[989,79081,79083,79085],{"className":79082},[2719],[2721,79084],{"disabled":2723,"type":2724}," Test tính chất 1000 thao tác ngẫu nhiên pass.",[989,79087,79089,79091],{"className":79088},[2719],[2721,79090],{"disabled":2723,"type":2724}," Dấu \"đã sửa\" đúng khi undo về điểm lưu.",[968,79093,2890],{"id":2889},[986,79095,79096,79099,79102,79105],{},[989,79097,79098],{},"Command cần lưu gì để đảo ngược được?",[989,79100,79101],{},"2 stack undo redo chuyển lệnh cho nhau thế nào?",[989,79103,79104],{},"Memento dùng cho thao tác nào?",[989,79106,79107],{},"Macro gom nhiều lệnh để làm gì?",[3014,79109],{},[973,79111,79112],{},"🌕 Bạn đã hoàn thành ngày 148. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,79114,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":79116},[79117,79118,79123,79124,79130],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":79119},[79120,79121,79122],{"id":78818,"depth":73,"text":78819},{"id":78836,"depth":73,"text":78837},{"id":78854,"depth":73,"text":78855},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":79125},[79126,79127,79128,79129],{"id":78898,"depth":73,"text":78899},{"id":79004,"depth":73,"text":79005},{"id":79030,"depth":73,"text":79031},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây text editor có undo redo: Command đóng gói thao tác, Memento snapshot, stack lịch sử, macro và benchmark bộ nhớ.",{},[5194],{"title":797,"description":79131},[17502,79136,79137,79138,79139],"command-pattern","memento-pattern","undo-redo","text-editor","RIjalvEc-40O7WDw1wIUDhOyZ73EYjP5POkjoaNkWDk",{"id":79142,"title":802,"body":79143,"category":5189,"day":805,"description":79457,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":79458,"navigation":2723,"outcomes":3047,"path":803,"prerequisites":79459,"seo":79460,"stem":804,"tags":79461,"__hash__":79465},"challenges\u002Fchallenges\u002F149.app-notification.md",{"type":965,"value":79144,"toc":79441},[79145,79147,79150,79152,79156,79170,79174,79188,79192,79206,79208,79222,79224,79234,79238,79263,79269,79273,79342,79364,79368,79388,79390,79418,79420,79434,79436,79439],[968,79146,971],{"id":970},[973,79148,79149],{},"Bài này xây hệ thống gửi thông báo đa kênh. 1 sự kiện bắn ra là email SMS push cùng chạy.",[968,79151,979],{"id":978},[981,79153,79155],{"id":79154},"observer-pub-sub-là-gì","Observer pub-sub là gì",[986,79157,79158,79161,79164,79167],{},[989,79159,79160],{},"Publisher bắn event vào bus, không biết ai nghe.",[989,79162,79163],{},"Subscriber đăng ký theo chủ đề như đơn hàng hay khuyến mãi.",[989,79165,79166],{},"Hủy đăng ký thì ngừng nhận ngay.",[989,79168,79169],{},"Ví dụ đời thường: loa phường phát, ai mở cửa mới nghe.",[981,79171,79173],{"id":79172},"hàng-đợi-và-retry","Hàng đợi và retry",[986,79175,79176,79179,79182,79185],{},[989,79177,79178],{},"Event vào queue bền nên burst 5000 tin không mất.",[989,79180,79181],{},"Worker lấy tin gửi dần, lỗi thì retry với backoff mũ.",[989,79183,79184],{},"Hỏng N lần thì chuyển dead-letter chờ xử lý tay.",[989,79186,79187],{},"Digest gom 10 tin cùng user thành 1 tin tổng hợp.",[981,79189,79191],{"id":79190},"kênh-gửi-dạng-strategy","Kênh gửi dạng Strategy",[986,79193,79194,79197,79200,79203],{},[989,79195,79196],{},"3 kênh email SMS push cùng 1 interface send.",[989,79198,79199],{},"Mỗi kênh có giới hạn tốc độ và tỉ lệ lỗi riêng.",[989,79201,79202],{},"Thêm kênh webhook mới không sửa bus cũ.",[989,79204,79205],{},"Đo tỉ lệ thành công và p95 độ trễ mỗi kênh.",[968,79207,1433],{"id":1432},[986,79209,79210,79213,79216,79219],{},[989,79211,79212],{},"Input: subscriber A đăng ký cảnh báo, B đăng ký khuyến mãi. Output: mỗi người chỉ nhận đúng chủ đề mình.",[989,79214,79215],{},"Giải thích: bus lọc theo chủ đề trước khi đẩy vào queue.",[989,79217,79218],{},"Input: kênh lỗi 30%, gửi 200 tin có retry. Output: thành công cuối trên 95%, còn lại vào dead-letter.",[989,79220,79221],{},"Giải thích: retry vớt được lỗi tạm thời, lỗi vĩnh viễn gom riêng.",[968,79223,1482],{"id":1481},[973,79225,1485,79226,7386,79228,79230,79231,1517],{},[1487,79227,13531],{},[992,79229,40031],{}," (hoặc Go). Dùng Observer ngày 9, rate limiter ngày 128. Nộp vào ",[992,79232,79233],{},"day-149-notify\u002F",[981,79235,79237],{"id":79236},"bài-1-event-bus","Bài 1: Event bus",[1352,79239,79241],{"className":3538,"code":79240,"language":3540,"meta":1357,"style":1357},"class EventBus:\n    def subscribe(self, topic: str, handler: Callable[[Event], Awaitable[None]]) -> str: ...  # trả subscription id\n    def unsubscribe(self, sub_id: str): ...\n    async def publish(self, event: Event): ...    # topic hỗ trợ ký tự đại diện: \"order.*\"\n",[992,79242,79243,79248,79253,79258],{"__ignoreMap":1357},[1023,79244,79245],{"class":1362,"line":63},[1023,79246,79247],{},"class EventBus:\n",[1023,79249,79250],{"class":1362,"line":68},[1023,79251,79252],{},"    def subscribe(self, topic: str, handler: Callable[[Event], Awaitable[None]]) -> str: ...  # trả subscription id\n",[1023,79254,79255],{"class":1362,"line":73},[1023,79256,79257],{},"    def unsubscribe(self, sub_id: str): ...\n",[1023,79259,79260],{"class":1362,"line":78},[1023,79261,79262],{},"    async def publish(self, event: Event): ...    # topic hỗ trợ ký tự đại diện: \"order.*\"\n",[1352,79264,79267],{"className":79265,"code":79266,"language":2241,"meta":1357},[2239],"subscribe(\"order.*\"), publish(\"order.paid\") -> nhận\nsubscribe(\"order.paid\"), publish(\"order.shipped\") -> không nhận\nunsubscribe rồi publish -> không nhận\n1 handler lỗi -> các handler khác vẫn nhận\n",[992,79268,79266],{"__ignoreMap":1357},[981,79270,79272],{"id":79271},"bài-2-hàng-đợi-bền-retry-và-dead-letter","Bài 2: Hàng đợi bền, retry và dead-letter",[1099,79274,79275,79283],{},[1102,79276,79277],{},[1105,79278,79279,79281],{},[1108,79280,2544],{},[1108,79282,2547],{},[1118,79284,79285,79296,79307,79318,79330],{},[1105,79286,79287,79289],{},[1123,79288,30692],{},[1123,79290,79291,79292,79295],{},"SQLite (bảng ",[992,79293,79294],{},"jobs",": id, payload, attempts, next_run_at, status). Khởi động lại không mất việc",[1105,79297,79298,79301],{},[1123,79299,79300],{},"Worker",[1123,79302,79303,79304],{},"N worker lấy việc có ",[992,79305,79306],{},"next_run_at \u003C= now",[1105,79308,79309,79312],{},[1123,79310,79311],{},"Retry",[1123,79313,79314,79315,62314],{},"Backoff mũ có jitter: ",[992,79316,79317],{},"min(60, 2^attempt) * random(0.5, 1.5)",[1105,79319,79320,79323],{},[1123,79321,79322],{},"Dead-letter",[1123,79324,79325,79326,79329],{},"Sau 5 lần lỗi chuyển ",[992,79327,79328],{},"status = dead",". Có lệnh chạy lại việc chết",[1105,79331,79332,79335],{},[1123,79333,79334],{},"Idempotency",[1123,79336,79337,79338,79341],{},"Mỗi thông báo có ",[992,79339,79340],{},"idempotency_key",", gửi trùng thì bỏ qua",[973,79343,79344,79345,13568,79348,79351,79352,79355,79356,79359,79360,79363],{},"3 kênh cùng interface ",[992,79346,79347],{},"Channel.send(user, message)",[992,79349,79350],{},"EmailChannel"," (lỗi ngẫu nhiên 5%), ",[992,79353,79354],{},"SmsChannel"," (giới hạn 10 tin\u002Fgiây), ",[992,79357,79358],{},"PushChannel"," (lỗi 20%). Thêm ",[992,79361,79362],{},"WebhookChannel"," không sửa bus hay worker.",[981,79365,79367],{"id":79366},"bài-3-bùng-nổ-và-gom-tin-nâng-cao","Bài 3: Bùng nổ và gom tin (nâng cao)",[2273,79369,79370,79373,79379,79385],{},[989,79371,79372],{},"Bắn 5000 sự kiện trong 1 giây. Không mất tin nào: số tin gửi thành công + dead-letter = 5000.",[989,79374,79375,79378],{},[1487,79376,79377],{},"Digest:"," 1 user nhận trên 3 thông báo khuyến mãi trong 10 phút thì gom thành 1 tin tổng hợp.",[989,79380,79381,79384],{},[1487,79382,79383],{},"Tùy chọn người dùng:"," mỗi user chọn kênh cho từng loại thông báo và giờ yên lặng (22h-7h, trừ thông báo bảo mật).",[989,79386,79387],{},"Dashboard dòng lệnh: số việc chờ, đang chạy, thành công, chết, theo kênh.",[981,79389,2711],{"id":2710},[986,79391,79393,79399,79405,79411],{"className":79392},[2715],[989,79394,79396,79398],{"className":79395},[2719],[2721,79397],{"disabled":2723,"type":2724}," Test event bus 4 kịch bản pass.",[989,79400,79402,79404],{"className":79401},[2719],[2721,79403],{"disabled":2723,"type":2724}," Giết tiến trình giữa chừng, khởi động lại không mất việc.",[989,79406,79408,79410],{"className":79407},[2719],[2721,79409],{"disabled":2723,"type":2724}," Bài 3: 5000 sự kiện đếm đủ, có digest và giờ yên lặng.",[989,79412,79414,11992,79416,9194],{"className":79413},[2719],[2721,79415],{"disabled":2723,"type":2724},[992,79417,79362],{},[968,79419,2890],{"id":2889},[986,79421,79422,79425,79428,79431],{},[989,79423,79424],{},"Publisher và subscriber tách nhau qua bus thế nào?",[989,79426,79427],{},"Queue giúp burst lớn không mất tin ra sao?",[989,79429,79430],{},"Retry backoff và dead-letter mỗi cái xử lý lỗi nào?",[989,79432,79433],{},"Thêm kênh mới vì sao không cần sửa bus?",[3014,79435],{},[973,79437,79438],{},"🌕 Bạn đã hoàn thành ngày 149. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,79440,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":79442},[79443,79444,79449,79450,79456],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":79445},[79446,79447,79448],{"id":79154,"depth":73,"text":79155},{"id":79172,"depth":73,"text":79173},{"id":79190,"depth":73,"text":79191},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":79451},[79452,79453,79454,79455],{"id":79236,"depth":73,"text":79237},{"id":79271,"depth":73,"text":79272},{"id":79366,"depth":73,"text":79367},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây hệ thống thông báo đa kênh: Observer pub-sub, hàng đợi retry, template Strategy, đo tỉ lệ gửi và độ trễ.",{},[5194,14055],{"title":802,"description":79457},[17502,79462,79463,6437,79464],"observer-pattern","notification","pub-sub","Oapmi4VezmU-bzAodlXUSLoADoTisbfthqJdNzuBOZc",{"id":79467,"title":807,"body":79468,"category":8797,"day":810,"description":79767,"difficulty":5191,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":79768,"navigation":2723,"outcomes":3047,"path":808,"prerequisites":79769,"seo":79770,"stem":809,"tags":79771,"__hash__":79776},"challenges\u002Fchallenges\u002F150.on-tap-tong-hop.md",{"type":965,"value":79469,"toc":79751},[79470,79472,79475,79477,79481,79495,79499,79513,79517,79531,79580,79582,79596,79598,79604,79608,79617,79641,79647,79651,79674,79678,79695,79697,79730,79732,79746,79748],[968,79471,971],{"id":970},[973,79473,79474],{},"Bài này rà soát 24 app đã build. Vá lỗi cũ rồi mới bước vào 5 capstone lớn.",[968,79476,979],{"id":978},[981,79478,79480],{"id":79479},"chia-24-app-thành-4-cụm","Chia 24 app thành 4 cụm",[986,79482,79483,79486,79489,79492],{},[989,79484,79485],{},"Cụm tìm kiếm gợi ý: autocomplete, search, spell, recsys.",[989,79487,79488],{},"Cụm hạ tầng: limiter, top-K, cache, index, mapreduce, pipeline.",[989,79490,79491],{},"Cụm đồ thị tối ưu: fraud, routing, MST, TSP, embedding.",[989,79493,79494],{},"Ví dụ đời thường: tổng vệ sinh 4 phòng trước khi đón khách.",[981,79496,79498],{"id":79497},"checklist-rà-mỗi-app","Checklist rà mỗi app",[986,79500,79501,79504,79507,79510],{},[989,79502,79503],{},"App còn chạy 1 lệnh không.",[989,79505,79506],{},"Benchmark còn tái lập không.",[989,79508,79509],{},"README có metric và cạm bẫy không.",[989,79511,79512],{},"Test có chứng minh đúng không.",[981,79514,79516],{"id":79515},"vá-lỗi-và-chốt-portfolio","Vá lỗi và chốt portfolio",[986,79518,79519,79522,79525,79528],{},[989,79520,79521],{},"App đỏ thì ghi thẻ lỗi gồm triệu chứng và mức ưu tiên.",[989,79523,79524],{},"Vá ít nhất 3 thẻ quan trọng nhất trong ngày.",[989,79526,79527],{},"Chọn 3 app mạnh nhất mang đi phỏng vấn.",[989,79529,79530],{},"Mỗi app viết pitch 5 câu nêu khó kỹ thuật và metric.",[1099,79532,79533,79546],{},[1102,79534,79535],{},[1105,79536,79537,79540,79543],{},[1108,79538,79539],{},"Cột kiểm tra",[1108,79541,79542],{},"Xanh",[1108,79544,79545],{},"Đỏ",[1118,79547,79548,79559,79570],{},[1105,79549,79550,79553,79556],{},[1123,79551,79552],{},"Chạy được",[1123,79554,79555],{},"1 lệnh lên ngay",[1123,79557,79558],{},"Lỗi không rõ",[1105,79560,79561,79564,79567],{},[1123,79562,79563],{},"Benchmark",[1123,79565,79566],{},"Tái lập chênh dưới 15%",[1123,79568,79569],{},"Thiếu số liệu",[1105,79571,79572,79574,79577],{},[1123,79573,8306],{},[1123,79575,79576],{},"Trước đỏ sau xanh",[1123,79578,79579],{},"Không có test",[968,79581,1433],{"id":1432},[986,79583,79584,79587,79590,79593],{},[989,79585,79586],{},"Input: chạy smoke test 24 app. Output: bảng 24 hàng ghi rõ app nào xanh đỏ.",[989,79588,79589],{},"Giải thích: không app nào ở trạng thái không biết chạy hay hỏng.",[989,79591,79592],{},"Input: benchmark lại 8 metric lõi. Output: chênh dưới 15% so với lần đầu.",[989,79594,79595],{},"Giải thích: metric ổn định chứng tỏ app tái lập được.",[968,79597,1482],{"id":1481},[973,79599,79600,79601,1517],{},"Không có kiến thức mới. Hôm nay rà soát toàn bộ app ngày 126-149. Nộp vào ",[992,79602,79603],{},"day-150-review\u002F",[981,79605,79607],{"id":79606},"bài-1-kiểm-kê","Bài 1: Kiểm kê",[973,79609,16860,79610,79613,79614,79616],{},[992,79611,79612],{},"inventory.md"," với 1 bảng cho ",[1487,79615,46509],{}," app đã làm (ngày 126 tới 149):",[1099,79618,79619],{},[1102,79620,79621],{},[1105,79622,79623,79626,79629,79632,79635,79638],{},[1108,79624,79625],{},"App",[1108,79627,79628],{},"Chạy bằng 1 lệnh?",[1108,79630,79631],{},"Test pass?",[1108,79633,79634],{},"Benchmark tái lập?",[1108,79636,79637],{},"README có metric?",[1108,79639,79640],{},"Trạng thái",[973,79642,79643,79644,79646],{},"Với mỗi app, clone repo sang thư mục mới, làm theo đúng ",[992,79645,2513],{},". Ghi lại mọi chỗ phải làm thêm ngoài hướng dẫn. Trạng thái: xanh (ổn), vàng (chạy nhưng thiếu), đỏ (hỏng).",[981,79648,79650],{"id":79649},"bài-2-thẻ-lỗi-và-sửa","Bài 2: Thẻ lỗi và sửa",[2273,79652,79653,79660,79667],{},[989,79654,79655,79656,79659],{},"Mỗi vấn đề là 1 thẻ trong ",[992,79657,79658],{},"issues.md",": tiêu đề, triệu chứng, cách tái hiện, mức ưu tiên (P0 hỏng, P1 sai số liệu, P2 thiếu tài liệu).",[989,79661,79662,79663,79666],{},"Sửa ít nhất ",[1487,79664,79665],{},"3 thẻ P0 hoặc P1",". Mỗi bản sửa là 1 commit có tham chiếu thẻ.",[989,79668,79669,79670,79673],{},"Thêm 1 script ",[992,79671,79672],{},"run_all_tests.sh"," chạy test của mọi app, in bảng tổng hợp.",[981,79675,79677],{"id":79676},"bài-3-ôn-tập-chủ-động-nâng-cao","Bài 3: Ôn tập chủ động (nâng cao)",[2273,79679,79680,79683,79689],{},[989,79681,79682],{},"Không nhìn code, viết lại từ đầu trong 60 phút: LRU cache, Dijkstra với heap, và Union-Find. Chạy test cũ trên bản mới.",[989,79684,79685,79686,1517],{},"Ghi lại chỗ bí, chỗ sai, thời gian mỗi bài vào ",[992,79687,79688],{},"recall.md",[989,79690,53934,79691,79694],{},[1487,79692,79693],{},"3 app mạnh nhất"," để mang đi phỏng vấn. Với mỗi app viết 5 dòng: vấn đề, kiến trúc, con số ấn tượng nhất, đánh đổi lớn nhất, việc sẽ làm tiếp.",[981,79696,2711],{"id":2710},[986,79698,79700,79708,79714,79722],{"className":79699},[2715],[989,79701,79703,2308,79705,79707],{"className":79702},[2719],[2721,79704],{"disabled":2723,"type":2724},[992,79706,79612],{}," đủ mọi app, có trạng thái.",[989,79709,79711,79713],{"className":79710},[2719],[2721,79712],{"disabled":2723,"type":2724}," Ít nhất 3 thẻ P0\u002FP1 được sửa, commit có tham chiếu.",[989,79715,79717,2308,79719,79721],{"className":79716},[2719],[2721,79718],{"disabled":2723,"type":2724},[992,79720,79672],{}," chạy được.",[989,79723,79725,79727,79728,1517],{"className":79724},[2719],[2721,79726],{"disabled":2723,"type":2724}," 3 bài viết lại pass test cũ, có ",[992,79729,79688],{},[968,79731,2890],{"id":2889},[986,79733,79734,79737,79740,79743],{},[989,79735,79736],{},"24 app chia 4 cụm gồm những cụm nào?",[989,79738,79739],{},"Checklist rà mỗi app có 4 mục gì?",[989,79741,79742],{},"Bản vá đạt cần có gì kèm theo?",[989,79744,79745],{},"Portfolio 3 app chọn theo tiêu chí nào?",[3014,79747],{},[973,79749,79750],{},"🌕 Bạn đã hoàn thành ngày 150. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":79752},[79753,79754,79759,79760,79766],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":79755},[79756,79757,79758],{"id":79479,"depth":73,"text":79480},{"id":79497,"depth":73,"text":79498},{"id":79515,"depth":73,"text":79516},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":79761},[79762,79763,79764,79765],{"id":79606,"depth":73,"text":79607},{"id":79649,"depth":73,"text":79650},{"id":79676,"depth":73,"text":79677},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Checkpoint giữa chặng app: rà soát 24 app đã build, vá lỗ hổng, benchmark lại, chuẩn bị nền cho 5 capstone lớn.",{},[3050,15144],{"title":807,"description":79767},[79772,79773,79774,79775],"review","checkpoint","benchmark","portfolio","F2neWbaVocPmA_EoP11wSc_gZnw_fokem4BvFD2apm0",{"id":79778,"title":812,"body":79779,"category":8797,"day":815,"description":80854,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":80855,"navigation":2723,"outcomes":3047,"path":813,"prerequisites":80856,"seo":80857,"stem":814,"tags":80858,"__hash__":80861},"challenges\u002Fchallenges\u002F151.capstone-sort-graph.md",{"type":965,"value":79780,"toc":80837},[79781,79783,79786,79788,79928,80078,80108,80110,80124,80128,80142,80594,80596,80612,80614,80622,80626,80629,80635,80657,80661,80679,80683,80688,80709,80711,80740,80742,80830,80832,80835],[968,79782,971],{"id":970},[973,79784,79785],{},"Bạn đo tốc độ sắp xếp và duyệt đồ thị. Kết quả giúp bạn chọn thuật toán đúng.",[968,79787,979],{"id":978},[981,79789,79791,79792,1509,79865],{"id":79790},"sắp-xếp-on2on2on2-và-onlognon-log-nonlogn","Sắp xếp ",[1023,79793,79795,79818],{"className":79794},[1026],[1023,79796,79798],{"className":79797},[1030],[1032,79799,79800],{"xmlns":1034},[1036,79801,79802,79816],{},[1039,79803,79804,79806,79808,79814],{},[1042,79805,1044],{},[1046,79807,1049],{"stretchy":1048},[2327,79809,79810,79812],{},[1042,79811,1262],{},[1051,79813,2457],{},[1046,79815,1056],{"stretchy":1048},[1058,79817,2839],{"encoding":1060},[1023,79819,79821],{"className":79820,"ariaHidden":1066},[1065],[1023,79822,79824,79827,79830,79833,79862],{"className":79823},[1070],[1023,79825],{"className":79826,"style":2476},[1074],[1023,79828,1044],{"className":79829,"style":1081},[1079,1080],[1023,79831,1049],{"className":79832},[1085],[1023,79834,79836,79839],{"className":79835},[1079],[1023,79837,1262],{"className":79838},[1079,1080],[1023,79840,79842],{"className":79841},[2383],[1023,79843,79845],{"className":79844},[2387],[1023,79846,79848],{"className":79847},[2391],[1023,79849,79851],{"className":79850,"style":2369},[2395],[1023,79852,79853,79856],{"style":2398},[1023,79854],{"className":79855,"style":2403},[2402],[1023,79857,79859],{"className":79858},[2407,2408,2409,2410],[1023,79860,2457],{"className":79861},[1079,2410],[1023,79863,1056],{"className":79864},[1092],[1023,79866,79868,79895],{"className":79867},[1026],[1023,79869,79871],{"className":79870},[1030],[1032,79872,79873],{"xmlns":1034},[1036,79874,79875,79893],{},[1039,79876,79877,79879,79881,79883,79885,79887,79889,79891],{},[1042,79878,1044],{},[1046,79880,1049],{"stretchy":1048},[1042,79882,1262],{},[1042,79884,7684],{},[1042,79886,7687],{},[1042,79888,7690],{},[1042,79890,1262],{},[1046,79892,1056],{"stretchy":1048},[1058,79894,10248],{"encoding":1060},[1023,79896,79898],{"className":79897,"ariaHidden":1066},[1065],[1023,79899,79901,79904,79907,79910,79913,79916,79919,79922,79925],{"className":79900},[1070],[1023,79902],{"className":79903,"style":1075},[1074],[1023,79905,1044],{"className":79906,"style":1081},[1079,1080],[1023,79908,1049],{"className":79909},[1085],[1023,79911,1262],{"className":79912},[1079,1080],[1023,79914,7684],{"className":79915,"style":7716},[1079,1080],[1023,79917,7687],{"className":79918},[1079,1080],[1023,79920,7690],{"className":79921,"style":7723},[1079,1080],[1023,79923,1262],{"className":79924},[1079,1080],[1023,79926,1056],{"className":79927},[1092],[986,79929,79930,80006,80072,80075],{},[989,79931,79791,79932,80005],{},[1023,79933,79935,79958],{"className":79934},[1026],[1023,79936,79938],{"className":79937},[1030],[1032,79939,79940],{"xmlns":1034},[1036,79941,79942,79956],{},[1039,79943,79944,79946,79948,79954],{},[1042,79945,1044],{},[1046,79947,1049],{"stretchy":1048},[2327,79949,79950,79952],{},[1042,79951,1262],{},[1051,79953,2457],{},[1046,79955,1056],{"stretchy":1048},[1058,79957,2839],{"encoding":1060},[1023,79959,79961],{"className":79960,"ariaHidden":1066},[1065],[1023,79962,79964,79967,79970,79973,80002],{"className":79963},[1070],[1023,79965],{"className":79966,"style":2476},[1074],[1023,79968,1044],{"className":79969,"style":1081},[1079,1080],[1023,79971,1049],{"className":79972},[1085],[1023,79974,79976,79979],{"className":79975},[1079],[1023,79977,1262],{"className":79978},[1079,1080],[1023,79980,79982],{"className":79981},[2383],[1023,79983,79985],{"className":79984},[2387],[1023,79986,79988],{"className":79987},[2391],[1023,79989,79991],{"className":79990,"style":2369},[2395],[1023,79992,79993,79996],{"style":2398},[1023,79994],{"className":79995,"style":2403},[2402],[1023,79997,79999],{"className":79998},[2407,2408,2409,2410],[1023,80000,2457],{"className":80001},[1079,2410],[1023,80003,1056],{"className":80004},[1092]," đơn giản, hợp với mảng nhỏ.",[989,80007,79791,80008,80071],{},[1023,80009,80011,80038],{"className":80010},[1026],[1023,80012,80014],{"className":80013},[1030],[1032,80015,80016],{"xmlns":1034},[1036,80017,80018,80036],{},[1039,80019,80020,80022,80024,80026,80028,80030,80032,80034],{},[1042,80021,1044],{},[1046,80023,1049],{"stretchy":1048},[1042,80025,1262],{},[1042,80027,7684],{},[1042,80029,7687],{},[1042,80031,7690],{},[1042,80033,1262],{},[1046,80035,1056],{"stretchy":1048},[1058,80037,10248],{"encoding":1060},[1023,80039,80041],{"className":80040,"ariaHidden":1066},[1065],[1023,80042,80044,80047,80050,80053,80056,80059,80062,80065,80068],{"className":80043},[1070],[1023,80045],{"className":80046,"style":1075},[1074],[1023,80048,1044],{"className":80049,"style":1081},[1079,1080],[1023,80051,1049],{"className":80052},[1085],[1023,80054,1262],{"className":80055},[1079,1080],[1023,80057,7684],{"className":80058,"style":7716},[1079,1080],[1023,80060,7687],{"className":80061},[1079,1080],[1023,80063,7690],{"className":80064,"style":7723},[1079,1080],[1023,80066,1262],{"className":80067},[1079,1080],[1023,80069,1056],{"className":80070},[1092]," nhanh hơn nhiều khi n lớn.",[989,80073,80074],{},"Ví dụ đời thường: xếp 10 quyển sách tay nhanh, xếp 10.000 cần máy.",[989,80076,80077],{},"Luôn đo trên cùng máy và cùng dữ liệu.",[1352,80079,80081],{"className":3538,"code":80080,"language":3540,"meta":1357,"style":1357},"# đo thời gian sắp xếp (giây)\nimport time\nt = time.time()  # bắt đầu bấm giờ\na = sorted([3, 1, 2])  # sắp xếp mẫu\nprint(time.time() - t)  # in thời gian chạy\n",[992,80082,80083,80088,80093,80098,80103],{"__ignoreMap":1357},[1023,80084,80085],{"class":1362,"line":63},[1023,80086,80087],{},"# đo thời gian sắp xếp (giây)\n",[1023,80089,80090],{"class":1362,"line":68},[1023,80091,80092],{},"import time\n",[1023,80094,80095],{"class":1362,"line":73},[1023,80096,80097],{},"t = time.time()  # bắt đầu bấm giờ\n",[1023,80099,80100],{"class":1362,"line":78},[1023,80101,80102],{},"a = sorted([3, 1, 2])  # sắp xếp mẫu\n",[1023,80104,80105],{"class":1362,"line":83},[1023,80106,80107],{},"print(time.time() - t)  # in thời gian chạy\n",[981,80109,49361],{"id":49360},[986,80111,80112,80115,80118,80121],{},[989,80113,80114],{},"BFS đi theo lớp, tìm đường ngắn nhất khi không trọng số.",[989,80116,80117],{},"DFS đi sâu một nhánh trước, hợp kiểm tra liên thông.",[989,80119,80120],{},"Ví dụ đời thường: BFS như loang nước, DFS như đi mê cung.",[989,80122,80123],{},"Cả hai đều thăm mỗi đỉnh đúng một lần.",[981,80125,80127],{"id":80126},"dijkstra-cơ-bản","Dijkstra cơ bản",[986,80129,80130,80133,80136,80139],{},[989,80131,80132],{},"Dijkstra tìm đường rẻ nhất khi cạnh không âm.",[989,80134,80135],{},"Định nghĩa: luôn mở đỉnh có khoảng cách nhỏ nhất trước.",[989,80137,80138],{},"Ví dụ đời thường: giống chọn đường đi xe rẻ nhất.",[989,80140,80141],{},"Dùng heap để lấy đỉnh nhanh.",[1099,80143,80144,80154],{},[1102,80145,80146],{},[1105,80147,80148,80150,80152],{},[1108,80149,9446],{},[1108,80151,10673],{},[1108,80153,1113],{},[1118,80155,80156,80312,80447,80521],{},[1105,80157,80158,80234,80237],{},[1123,80159,80160,80161],{},"Sort ",[1023,80162,80164,80187],{"className":80163},[1026],[1023,80165,80167],{"className":80166},[1030],[1032,80168,80169],{"xmlns":1034},[1036,80170,80171,80185],{},[1039,80172,80173,80175,80177,80183],{},[1042,80174,1044],{},[1046,80176,1049],{"stretchy":1048},[2327,80178,80179,80181],{},[1042,80180,1262],{},[1051,80182,2457],{},[1046,80184,1056],{"stretchy":1048},[1058,80186,2839],{"encoding":1060},[1023,80188,80190],{"className":80189,"ariaHidden":1066},[1065],[1023,80191,80193,80196,80199,80202,80231],{"className":80192},[1070],[1023,80194],{"className":80195,"style":2476},[1074],[1023,80197,1044],{"className":80198,"style":1081},[1079,1080],[1023,80200,1049],{"className":80201},[1085],[1023,80203,80205,80208],{"className":80204},[1079],[1023,80206,1262],{"className":80207},[1079,1080],[1023,80209,80211],{"className":80210},[2383],[1023,80212,80214],{"className":80213},[2387],[1023,80215,80217],{"className":80216},[2391],[1023,80218,80220],{"className":80219,"style":2369},[2395],[1023,80221,80222,80225],{"style":2398},[1023,80223],{"className":80224,"style":2403},[2402],[1023,80226,80228],{"className":80227},[2407,2408,2409,2410],[1023,80229,2457],{"className":80230},[1079,2410],[1023,80232,1056],{"className":80233},[1092],[1123,80235,80236],{},"n nhỏ",[1123,80238,80239],{},[1023,80240,80242,80265],{"className":80241},[1026],[1023,80243,80245],{"className":80244},[1030],[1032,80246,80247],{"xmlns":1034},[1036,80248,80249,80263],{},[1039,80250,80251,80253,80255,80261],{},[1042,80252,1044],{},[1046,80254,1049],{"stretchy":1048},[2327,80256,80257,80259],{},[1042,80258,1262],{},[1051,80260,2457],{},[1046,80262,1056],{"stretchy":1048},[1058,80264,2839],{"encoding":1060},[1023,80266,80268],{"className":80267,"ariaHidden":1066},[1065],[1023,80269,80271,80274,80277,80280,80309],{"className":80270},[1070],[1023,80272],{"className":80273,"style":2476},[1074],[1023,80275,1044],{"className":80276,"style":1081},[1079,1080],[1023,80278,1049],{"className":80279},[1085],[1023,80281,80283,80286],{"className":80282},[1079],[1023,80284,1262],{"className":80285},[1079,1080],[1023,80287,80289],{"className":80288},[2383],[1023,80290,80292],{"className":80291},[2387],[1023,80293,80295],{"className":80294},[2391],[1023,80296,80298],{"className":80297,"style":2369},[2395],[1023,80299,80300,80303],{"style":2398},[1023,80301],{"className":80302,"style":2403},[2402],[1023,80304,80306],{"className":80305},[2407,2408,2409,2410],[1023,80307,2457],{"className":80308},[1079,2410],[1023,80310,1056],{"className":80311},[1092],[1105,80313,80314,80379,80382],{},[1123,80315,80160,80316],{},[1023,80317,80319,80346],{"className":80318},[1026],[1023,80320,80322],{"className":80321},[1030],[1032,80323,80324],{"xmlns":1034},[1036,80325,80326,80344],{},[1039,80327,80328,80330,80332,80334,80336,80338,80340,80342],{},[1042,80329,1044],{},[1046,80331,1049],{"stretchy":1048},[1042,80333,1262],{},[1042,80335,7684],{},[1042,80337,7687],{},[1042,80339,7690],{},[1042,80341,1262],{},[1046,80343,1056],{"stretchy":1048},[1058,80345,10248],{"encoding":1060},[1023,80347,80349],{"className":80348,"ariaHidden":1066},[1065],[1023,80350,80352,80355,80358,80361,80364,80367,80370,80373,80376],{"className":80351},[1070],[1023,80353],{"className":80354,"style":1075},[1074],[1023,80356,1044],{"className":80357,"style":1081},[1079,1080],[1023,80359,1049],{"className":80360},[1085],[1023,80362,1262],{"className":80363},[1079,1080],[1023,80365,7684],{"className":80366,"style":7716},[1079,1080],[1023,80368,7687],{"className":80369},[1079,1080],[1023,80371,7690],{"className":80372,"style":7723},[1079,1080],[1023,80374,1262],{"className":80375},[1079,1080],[1023,80377,1056],{"className":80378},[1092],[1123,80380,80381],{},"n lớn",[1123,80383,80384],{},[1023,80385,80387,80414],{"className":80386},[1026],[1023,80388,80390],{"className":80389},[1030],[1032,80391,80392],{"xmlns":1034},[1036,80393,80394,80412],{},[1039,80395,80396,80398,80400,80402,80404,80406,80408,80410],{},[1042,80397,1044],{},[1046,80399,1049],{"stretchy":1048},[1042,80401,1262],{},[1042,80403,7684],{},[1042,80405,7687],{},[1042,80407,7690],{},[1042,80409,1262],{},[1046,80411,1056],{"stretchy":1048},[1058,80413,10248],{"encoding":1060},[1023,80415,80417],{"className":80416,"ariaHidden":1066},[1065],[1023,80418,80420,80423,80426,80429,80432,80435,80438,80441,80444],{"className":80419},[1070],[1023,80421],{"className":80422,"style":1075},[1074],[1023,80424,1044],{"className":80425,"style":1081},[1079,1080],[1023,80427,1049],{"className":80428},[1085],[1023,80430,1262],{"className":80431},[1079,1080],[1023,80433,7684],{"className":80434,"style":7716},[1079,1080],[1023,80436,7687],{"className":80437},[1079,1080],[1023,80439,7690],{"className":80440,"style":7723},[1079,1080],[1023,80442,1262],{"className":80443},[1079,1080],[1023,80445,1056],{"className":80446},[1092],[1105,80448,80449,80451,80454],{},[1123,80450,29899],{},[1123,80452,80453],{},"Đồ thị không trọng số",[1123,80455,80456],{},[1023,80457,80459,80482],{"className":80458},[1026],[1023,80460,80462],{"className":80461},[1030],[1032,80463,80464],{"xmlns":1034},[1036,80465,80466,80480],{},[1039,80467,80468,80470,80472,80474,80476,80478],{},[1042,80469,1044],{},[1046,80471,1049],{"stretchy":1048},[1042,80473,29619],{},[1046,80475,21881],{},[1042,80477,26217],{},[1046,80479,1056],{"stretchy":1048},[1058,80481,29628],{"encoding":1060},[1023,80483,80485,80509],{"className":80484,"ariaHidden":1066},[1065],[1023,80486,80488,80491,80494,80497,80500,80503,80506],{"className":80487},[1070],[1023,80489],{"className":80490,"style":1075},[1074],[1023,80492,1044],{"className":80493,"style":1081},[1079,1080],[1023,80495,1049],{"className":80496},[1085],[1023,80498,29619],{"className":80499,"style":13790},[1079,1080],[1023,80501],{"className":80502,"style":13790},[2354],[1023,80504,21881],{"className":80505},[13794],[1023,80507],{"className":80508,"style":13790},[2354],[1023,80510,80512,80515,80518],{"className":80511},[1070],[1023,80513],{"className":80514,"style":1075},[1074],[1023,80516,26217],{"className":80517,"style":26247},[1079,1080],[1023,80519,1056],{"className":80520},[1092],[1105,80522,80523,80525,80528],{},[1123,80524,30672],{},[1123,80526,80527],{},"Cạnh không âm",[1123,80529,80530],{},[1023,80531,80533,80561],{"className":80532},[1026],[1023,80534,80536],{"className":80535},[1030],[1032,80537,80538],{"xmlns":1034},[1036,80539,80540,80558],{},[1039,80541,80542,80544,80546,80548,80550,80552,80554,80556],{},[1042,80543,1044],{},[1046,80545,1049],{"stretchy":1048},[1042,80547,26217],{},[1042,80549,7684],{},[1042,80551,7687],{},[1042,80553,7690],{},[1042,80555,29619],{},[1046,80557,1056],{"stretchy":1048},[1058,80559,80560],{"encoding":1060},"O(E log V)",[1023,80562,80564],{"className":80563,"ariaHidden":1066},[1065],[1023,80565,80567,80570,80573,80576,80579,80582,80585,80588,80591],{"className":80566},[1070],[1023,80568],{"className":80569,"style":1075},[1074],[1023,80571,1044],{"className":80572,"style":1081},[1079,1080],[1023,80574,1049],{"className":80575},[1085],[1023,80577,26217],{"className":80578,"style":26247},[1079,1080],[1023,80580,7684],{"className":80581,"style":7716},[1079,1080],[1023,80583,7687],{"className":80584},[1079,1080],[1023,80586,7690],{"className":80587,"style":7723},[1079,1080],[1023,80589,29619],{"className":80590,"style":13790},[1079,1080],[1023,80592,1056],{"className":80593},[1092],[968,80595,1433],{"id":1432},[986,80597,80598,80609],{},[989,80599,80600,80601,80604,80605,80608],{},"Input ",[992,80602,80603],{},"[3, 1, 2]"," -> output ",[992,80606,80607],{},"[1, 2, 3]"," vì sắp xếp tăng dần.",[989,80610,80611],{},"Đồ thị A-B-C thẳng hàng, BFS từ A thăm theo thứ tự A, B, C.",[968,80613,1482],{"id":1481},[973,80615,1485,80616,80618,80619,1517],{},[1487,80617,1493],{}," (hoặc ngôn ngữ chính của bạn). Gom code ngày 10, 11, 21, 40-43, 80. Nộp vào ",[992,80620,80621],{},"day-151-capstone\u002F",[981,80623,80625],{"id":80624},"bài-1-thư-viện-gộp","Bài 1: Thư viện gộp",[973,80627,80628],{},"Gom thành 1 thư viện có cấu trúc rõ:",[1352,80630,80633],{"className":80631,"code":80632,"language":2241,"meta":1357},[2239],"algo\u002F\n  sort\u002F      bubble, insertion, merge, quick (3 biến thể), shell, heap\n  graph\u002F     Graph, bfs, dfs, dijkstra, astar, topoSort, components\n  bench\u002F     makeData, timeMs, CSV writer\ntests\u002F       mọi test cũ + test mới\n",[992,80634,80632],{"__ignoreMap":1357},[2273,80636,80637,80644,80650],{},[989,80638,80639,80640,80643],{},"Build bằng CMake (hoặc Makefile), 1 lệnh ",[992,80641,80642],{},"make test"," chạy toàn bộ test.",[989,80645,80646,80647,1517],{},"Mọi thuật toán sắp xếp dùng chung interface ",[992,80648,80649],{},"template\u003Cclass It, class Cmp> void sort(It first, It last, Cmp cmp)",[989,80651,80652,80653,80656],{},"Bật ",[992,80654,80655],{},"-Wall -Wextra -Werror"," và sanitizer trong chế độ test.",[981,80658,80660],{"id":80659},"bài-2-benchmark-tái-lập","Bài 2: Benchmark tái lập",[2273,80662,80663,80670,80673,80676],{},[989,80664,80665,80666,80669],{},"Script ",[992,80667,80668],{},"bench.sh"," chạy benchmark sắp xếp (6 thuật toán x 5 loại dữ liệu x 4 cỡ) và đồ thị (BFS, DFS, Dijkstra, A* trên lưới 1000x1000 và đồ thị ngẫu nhiên 10^6 cạnh).",[989,80671,80672],{},"Ghi CSV có thông tin máy (CPU, RAM, compiler, cờ build).",[989,80674,80675],{},"Script Python vẽ biểu đồ từ CSV.",[989,80677,80678],{},"Chạy 2 lần: kết quả chênh không quá 10%.",[981,80680,80682],{"id":80681},"bài-3-báo-cáo-capstone-nâng-cao","Bài 3: Báo cáo capstone (nâng cao)",[973,80684,80685,80687],{},[992,80686,17400],{}," 2-3 trang:",[2273,80689,80690,80693,80696,80706],{},[989,80691,80692],{},"Bảng và biểu đồ.",[989,80694,80695],{},"Đối chiếu từng kết quả với Big-O. Chỉ ra ít nhất 2 chỗ lệch và giải thích (cache, hằng số, dữ liệu).",[989,80697,37059,80698,1509,80700,26641,80703,80705],{},[992,80699,9956],{},[992,80701,80702],{},"boost::graph",[992,80704,31660],{},"). Bạn chậm hơn bao nhiêu lần, vì sao.",[989,80707,80708],{},"Mục \"Bài học\": 5 điều bạn hiểu sâu hơn so với ngày 10.",[981,80710,2711],{"id":2710},[986,80712,80714,80722,80728,80734],{"className":80713},[2715],[989,80715,80717,2308,80719,80721],{"className":80716},[2719],[2721,80718],{"disabled":2723,"type":2724},[992,80720,80642],{}," chạy toàn bộ, sanitizer sạch.",[989,80723,80725,80727],{"className":80724},[2719],[2721,80726],{"disabled":2723,"type":2724}," Benchmark tái lập được, chênh dưới 10%.",[989,80729,80731,80733],{"className":80730},[2719],[2721,80732],{"disabled":2723,"type":2724}," Báo cáo có đối chiếu Big-O và so thư viện chuẩn.",[989,80735,80737,80739],{"className":80736},[2719],[2721,80738],{"disabled":2723,"type":2724}," Repo có CI (GitHub Actions) chạy test mỗi lần push.",[968,80741,2890],{"id":2889},[2273,80743,80744,80821,80824,80827],{},[989,80745,80746,80747,80820],{},"Khi nào ",[1023,80748,80750,80773],{"className":80749},[1026],[1023,80751,80753],{"className":80752},[1030],[1032,80754,80755],{"xmlns":1034},[1036,80756,80757,80771],{},[1039,80758,80759,80761,80763,80769],{},[1042,80760,1044],{},[1046,80762,1049],{"stretchy":1048},[2327,80764,80765,80767],{},[1042,80766,1262],{},[1051,80768,2457],{},[1046,80770,1056],{"stretchy":1048},[1058,80772,2839],{"encoding":1060},[1023,80774,80776],{"className":80775,"ariaHidden":1066},[1065],[1023,80777,80779,80782,80785,80788,80817],{"className":80778},[1070],[1023,80780],{"className":80781,"style":2476},[1074],[1023,80783,1044],{"className":80784,"style":1081},[1079,1080],[1023,80786,1049],{"className":80787},[1085],[1023,80789,80791,80794],{"className":80790},[1079],[1023,80792,1262],{"className":80793},[1079,1080],[1023,80795,80797],{"className":80796},[2383],[1023,80798,80800],{"className":80799},[2387],[1023,80801,80803],{"className":80802},[2391],[1023,80804,80806],{"className":80805,"style":2369},[2395],[1023,80807,80808,80811],{"style":2398},[1023,80809],{"className":80810,"style":2403},[2402],[1023,80812,80814],{"className":80813},[2407,2408,2409,2410],[1023,80815,2457],{"className":80816},[1079,2410],[1023,80818,1056],{"className":80819},[1092]," vẫn ổn?",[989,80822,80823],{},"BFS khác DFS ở điểm nào?",[989,80825,80826],{},"Dijkstra cấm loại cạnh nào?",[989,80828,80829],{},"Vì sao phải đo trên cùng máy?",[3014,80831],{},[973,80833,80834],{},"🌕 Bạn đã hoàn thành ngày 151. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,80836,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":80838},[80839,80840,80846,80847,80853],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":80841},[80842,80844,80845],{"id":79790,"depth":73,"text":80843},"Sắp xếp O(n2)O(n^2)O(n2) và O(nlogn)O(n log n)O(nlogn)",{"id":49360,"depth":73,"text":49361},{"id":80126,"depth":73,"text":80127},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":80848},[80849,80850,80851,80852],{"id":80624,"depth":73,"text":80625},{"id":80659,"depth":73,"text":80660},{"id":80681,"depth":73,"text":80682},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Capstone 1: benchmark freedoms sắp xếp O(n²) vs O(n log n) và BFS DFS Dijkstra trên cùng hạ tầng đo, báo cáo chọn thuật toán.",{},[3050,17499],{"title":812,"description":80854},[17502,80859,80860,29787,49649],"sorting-benchmark","graph-traversal","n53ig0vwze3SGkhPrWHosbL7hnaF1DMh-gtNhUlmaY0",{"id":80863,"title":817,"body":80864,"category":8797,"day":820,"description":81143,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":81144,"navigation":2723,"outcomes":3047,"path":818,"prerequisites":81145,"seo":81146,"stem":819,"tags":81147,"__hash__":81148},"challenges\u002Fchallenges\u002F152.capstone-cache-trie.md",{"type":965,"value":80865,"toc":81127},[80866,80868,80871,80873,80877,80891,80895,80909,80913,80927,80972,80974,80991,80993,81001,81005,81008,81014,81020,81024,81027,81035,81039,81075,81077,81104,81106,81120,81122,81125],[968,80867,971],{"id":970},[973,80869,80870],{},"Bạn nâng gợi ý từ khóa nhanh hơn. Cache giúp câu hỏi lặp trả lời ngay.",[968,80872,979],{"id":978},[981,80874,80876],{"id":80875},"trie-và-radix-trie","Trie và radix trie",[986,80878,80879,80882,80885,80888],{},[989,80880,80881],{},"Trie là cây tiền tố, tìm gợi ý theo từng ký tự.",[989,80883,80884],{},"Radix trie nén chuỗi chung, tiết kiệm bộ nhớ hơn.",[989,80886,80887],{},"Ví dụ đời thường: giống mục lục từ điển theo vần.",[989,80889,80890],{},"Tìm kiếm mỗi từ tốn theo độ dài từ.",[981,80892,80894],{"id":80893},"lru-và-lfu","LRU và LFU",[986,80896,80897,80900,80903,80906],{},[989,80898,80899],{},"LRU đuổi mục lâu chưa dùng nhất.",[989,80901,80902],{},"LFU đuổi mục ít dùng nhất.",[989,80904,80905],{},"Ví dụ đời thường: LRU như dọn đồ lâu không đụng, LFU như bỏ đồ ít dùng.",[989,80907,80908],{},"Chọn LRU khi thói quen mới, LFU khi thói quen ổn định.",[981,80910,80912],{"id":80911},"cache-và-slo-p95","Cache và SLO p95",[986,80914,80915,80918,80921,80924],{},[989,80916,80917],{},"Cache lưu kết quả cũ để trả lời nhanh.",[989,80919,80920],{},"Định nghĩa p95: 95% request nhanh hơn ngưỡng này.",[989,80922,80923],{},"Ví dụ đời thường: p95 như cam kết 95 đơn giao đúng giờ.",[989,80925,80926],{},"Đo p95 thay vì chỉ đo trung bình.",[1352,80928,80930],{"className":3538,"code":80929,"language":3540,"meta":1357,"style":1357},"# cache đơn giản bằng dict\ncache = {}  # nơi lưu kết quả cũ\ndef goi_y(tu):\n    if tu in cache:  # đã hỏi rồi\n        return cache[tu]  # trả ngay\n    kq = [\"gợi ý 1\"]  # tính mới ở đây\n    cache[tu] = kq  # lưu lại\n    return kq\n",[992,80931,80932,80937,80942,80947,80952,80957,80962,80967],{"__ignoreMap":1357},[1023,80933,80934],{"class":1362,"line":63},[1023,80935,80936],{},"# cache đơn giản bằng dict\n",[1023,80938,80939],{"class":1362,"line":68},[1023,80940,80941],{},"cache = {}  # nơi lưu kết quả cũ\n",[1023,80943,80944],{"class":1362,"line":73},[1023,80945,80946],{},"def goi_y(tu):\n",[1023,80948,80949],{"class":1362,"line":78},[1023,80950,80951],{},"    if tu in cache:  # đã hỏi rồi\n",[1023,80953,80954],{"class":1362,"line":83},[1023,80955,80956],{},"        return cache[tu]  # trả ngay\n",[1023,80958,80959],{"class":1362,"line":88},[1023,80960,80961],{},"    kq = [\"gợi ý 1\"]  # tính mới ở đây\n",[1023,80963,80964],{"class":1362,"line":93},[1023,80965,80966],{},"    cache[tu] = kq  # lưu lại\n",[1023,80968,80969],{"class":1362,"line":98},[1023,80970,80971],{},"    return kq\n",[968,80973,1433],{"id":1432},[986,80975,80976,80985],{},[989,80977,80600,80978,80604,80981,80984],{},[992,80979,80980],{},"\"app\"",[992,80982,80983],{},"[\"apple\", \"app\"]"," vì cùng tiền tố.",[989,80986,80987,80988,80990],{},"Hỏi ",[992,80989,80980],{}," lần hai trả ngay từ cache.",[968,80992,1482],{"id":1481},[973,80994,1485,80995,80997,80998,1517],{},[1487,80996,4800],{}," (hoặc ngôn ngữ app ngày 126). Gom code ngày 35, 36, 39, 66, 126. Nộp vào ",[992,80999,81000],{},"day-152-capstone\u002F",[981,81002,81004],{"id":81003},"bài-1-so-trie-và-radix-trie","Bài 1: So Trie và Radix trie",[973,81006,81007],{},"Cùng từ điển 300.000 từ có tần suất:",[1352,81009,81012],{"className":81010,"code":81011,"language":2241,"meta":1357},[2239],"cấu_trúc     số_nút    bộ_nhớ(MB)   nạp(ms)   suggest_p50(µs)   suggest_p95(µs)\nTrie         ...\nRadixTrie    ...\nsorted vector + lower_bound ...\n",[992,81013,81011],{"__ignoreMap":1357},[973,81015,81016,81017,1517],{},"Autocomplete dùng được với cả 3 qua 1 interface ",[992,81018,81019],{},"PrefixIndex",[981,81021,81023],{"id":81022},"bài-2-so-lru-và-lfu-trước-autocomplete","Bài 2: So LRU và LFU trước autocomplete",[973,81025,81026],{},"Sinh 3 luồng truy vấn 10^6 tiền tố: Zipf ổn định, Zipf đổi chủ đề mỗi 10^5, và luồng thật (log gõ phím nếu có, hoặc tách từ bài báo thành các tiền tố gõ dần).",[2273,81028,81029,81032],{},[989,81030,81031],{},"Cache 1024 mục. In hit rate và p95 cho LRU, LFU có aging, và không cache.",[989,81033,81034],{},"Chọn chính sách mặc định và ghi lý do.",[981,81036,81038],{"id":81037},"bài-3-dịch-vụ-hoàn-chỉnh-nâng-cao","Bài 3: Dịch vụ hoàn chỉnh (nâng cao)",[2273,81040,81041,81052,81060,81070],{},[989,81042,81043,81044,81047,81048,81051],{},"HTTP server ",[992,81045,81046],{},"GET \u002Fsuggest?q=...&k=..."," trả JSON. ",[992,81049,81050],{},"POST \u002Fselect"," ghi nhận lựa chọn.",[989,81053,81054,81055,5586,81057,81059],{},"Test tải bằng ",[992,81056,72248],{},[992,81058,72251],{},": 2000 request\u002Fgiây, 60 giây. In p50, p95, p99, lỗi.",[989,81061,81062,81063,26641,81066,81069],{},"Mục tiêu p95 dưới 2 ms. Nếu chưa đạt, profile bằng ",[992,81064,81065],{},"perf",[992,81067,81068],{},"py-spy",") và sửa điểm nóng nhất. Ghi lại trước và sau.",[989,81071,81072,81074],{},[992,81073,17400],{},": bảng Bài 1, 2, 3, ảnh flame graph, quyết định thiết kế.",[981,81076,2711],{"id":2710},[986,81078,81080,81086,81092,81098],{"className":81079},[2715],[989,81081,81083,81085],{"className":81082},[2719],[2721,81084],{"disabled":2723,"type":2724}," Bảng Trie vs Radix vs vector có số thật.",[989,81087,81089,81091],{"className":81088},[2719],[2721,81090],{"disabled":2723,"type":2724}," Bảng cache 3 luồng x 3 cấu hình.",[989,81093,81095,81097],{"className":81094},[2719],[2721,81096],{"disabled":2723,"type":2724}," Test tải có p95, có flame graph.",[989,81099,81101,81103],{"className":81100},[2719],[2721,81102],{"disabled":2723,"type":2724}," Mỗi quyết định thiết kế gắn với số liệu.",[968,81105,2890],{"id":2889},[2273,81107,81108,81111,81114,81117],{},[989,81109,81110],{},"Trie tìm theo đơn vị nào?",[989,81112,81113],{},"LRU khác LFU ở điểm nào?",[989,81115,81116],{},"p95 nghĩa là gì?",[989,81118,81119],{},"Khi nào cache gây sai?",[3014,81121],{},[973,81123,81124],{},"🌕 Bạn đã hoàn thành ngày 152. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,81126,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":81128},[81129,81130,81135,81136,81142],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":81131},[81132,81133,81134],{"id":80875,"depth":73,"text":80876},{"id":80893,"depth":73,"text":80894},{"id":80911,"depth":73,"text":80912},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":81137},[81138,81139,81140,81141],{"id":81003,"depth":73,"text":81004},{"id":81022,"depth":73,"text":81023},{"id":81037,"depth":73,"text":81038},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Capstone 2: nâng autocomplete ngày 126 lên radix trie, LFU so LRU, singleflightđồng thời, SLO p95 và báo cáo production-ready.",{},[4669],{"title":817,"description":81143},[17502,71480,27648,71479,77699],"CoG7rXPzq7LGQRk6ThchgCVT1BpWNkXexXIJ93iFciM",{"id":81150,"title":822,"body":81151,"category":8797,"day":825,"description":81400,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":81401,"navigation":2723,"outcomes":3047,"path":823,"prerequisites":81402,"seo":81403,"stem":824,"tags":81404,"__hash__":81406},"challenges\u002Fchallenges\u002F153.capstone-clustering.md",{"type":965,"value":81152,"toc":81383},[81153,81155,81158,81160,81164,81178,81182,81196,81200,81214,81239,81241,81253,81255,81263,81270,81276,81286,81290,81301,81308,81312,81317,81331,81333,81360,81362,81376,81378,81381],[968,81154,971],{"id":970},[973,81156,81157],{},"Bạn gom khách hàng thành nhóm giống nhau. Mỗi nhóm cần một cách bán riêng.",[968,81159,979],{"id":978},[981,81161,81163],{"id":81162},"phân-cụm-là-gì","Phân cụm là gì",[986,81165,81166,81169,81172,81175],{},[989,81167,81168],{},"Phân cụm gom điểm gần nhau vào một nhóm.",[989,81170,81171],{},"Định nghĩa: không có nhãn trước, máy tự tìm nhóm.",[989,81173,81174],{},"Ví dụ đời thường: giống xếp khách vào bàn theo sở thích.",[989,81176,81177],{},"Số nhóm k thường phải chọn trước.",[981,81179,81181],{"id":81180},"k-means-cơ-bản","K-means cơ bản",[986,81183,81184,81187,81190,81193],{},[989,81185,81186],{},"K-means lặp hai bước: gán nhóm rồi dời tâm.",[989,81188,81189],{},"Ví dụ đời thường: giống chia lớp rồi chọn lớp trưởng mới.",[989,81191,81192],{},"Dễ làm nhưng nhạy với tâm ban đầu.",[989,81194,81195],{},"Chạy nhiều lần rồi chọn lần tốt nhất.",[981,81197,81199],{"id":81198},"đo-chất-lượng-và-scale","Đo chất lượng và scale",[986,81201,81202,81205,81208,81211],{},[989,81203,81204],{},"Silhouette đo điểm có hợp với nhóm mình không.",[989,81206,81207],{},"Điểm càng gần 1 càng tốt.",[989,81209,81210],{},"Ví dụ đời thường: giống chấm khách có ngồi đúng bàn không.",[989,81212,81213],{},"Dữ liệu lớn thì chia nhỏ với MapReduce.",[1352,81215,81217],{"className":3538,"code":81216,"language":3540,"meta":1357,"style":1357},"# gán điểm vào tâm gần nhất\ndef gan_nhom(diem, tams):\n    xa = [abs(diem - t) for t in tams]  # khoảng cách tới mỗi tâm\n    return xa.index(min(xa))  # chọn tâm gần nhất\n",[992,81218,81219,81224,81229,81234],{"__ignoreMap":1357},[1023,81220,81221],{"class":1362,"line":63},[1023,81222,81223],{},"# gán điểm vào tâm gần nhất\n",[1023,81225,81226],{"class":1362,"line":68},[1023,81227,81228],{},"def gan_nhom(diem, tams):\n",[1023,81230,81231],{"class":1362,"line":73},[1023,81232,81233],{},"    xa = [abs(diem - t) for t in tams]  # khoảng cách tới mỗi tâm\n",[1023,81235,81236],{"class":1362,"line":78},[1023,81237,81238],{},"    return xa.index(min(xa))  # chọn tâm gần nhất\n",[968,81240,1433],{"id":1432},[986,81242,81243,81250],{},[989,81244,81245,81246,81249],{},"Input điểm ",[992,81247,81248],{},"[1, 2, 10, 11]"," với k = 2 -> hai nhóm quanh 1 và 10.",[989,81251,81252],{},"Silhouette cao nghĩa là nhóm tách rõ.",[968,81254,1482],{"id":1481},[973,81256,1485,81257,81259,81260,1517],{},[1487,81258,13531],{},". Gom code ngày 47-49, 83, 84, 87, 88, 132. Nộp vào ",[992,81261,81262],{},"day-153-capstone\u002F",[981,81264,81266,81267],{"id":81265},"bài-1-gói-clusterkit","Bài 1: Gói ",[992,81268,81269],{},"clusterkit",[1352,81271,81274],{"className":81272,"code":81273,"language":2241,"meta":1357},[2239],"clusterkit\u002F\n  preprocess.py   scale, log_transform, remove_outliers, pca\n  models.py       KMeans, DBSCAN, OPTICS, Agglomerative (tự cài, cùng API fit\u002Fpredict\u002Flabels_)\n  metrics.py      silhouette, davies_bouldin, adjusted_rand\n  distributed.py  kmeans_mapreduce, dbscan_partitioned\n  report.py       tạo báo cáo HTML\u002FMarkdown có hình\ntests\u002F\n",[992,81275,81273],{"__ignoreMap":1357},[973,81277,81278,81279,81282,81283,81285],{},"Cài được bằng ",[992,81280,81281],{},"pip install -e .",". Có test cho từng module. Kết quả khớp ",[992,81284,17633],{}," trên 3 bộ dữ liệu chuẩn (sai số hoặc ARI ghi trong test).",[981,81287,81289],{"id":81288},"bài-2-chạy-trên-3-bộ-dữ-liệu","Bài 2: Chạy trên 3 bộ dữ liệu",[2273,81291,81292,81295,81298],{},[989,81293,81294],{},"Iris (có nhãn thật).",[989,81296,81297],{},"RFM khách hàng ngày 132.",[989,81299,81300],{},"10^6 điểm tổng hợp 2D có 8 cụm mật độ khác nhau cộng 5% nhiễu.",[973,81302,81303,81304,81307],{},"Với mỗi bộ, ",[992,81305,81306],{},"report.py"," sinh báo cáo: bảng metric mọi thuật toán, hình scatter, thời gian. Bộ 3 dùng bản phân tán cho K-means và DBSCAN.",[981,81309,81311],{"id":81310},"bài-3-kết-luận-nâng-cao","Bài 3: Kết luận (nâng cao)",[973,81313,81314,81316],{},[992,81315,17400],{}," tổng hợp:",[2273,81318,81319,81322,81325,81328],{},[989,81320,81321],{},"Bảng \"thuật toán nào thắng trên dữ liệu nào\" với lý do.",[989,81323,81324],{},"Ảnh hưởng của tiền xử lý: chạy lại Iris và RFM không chuẩn hóa, không loại ngoại lệ. So metric.",[989,81326,81327],{},"Tốc độ bản phân tán theo số worker.",[989,81329,81330],{},"Giới hạn: khi nào silhouette đánh giá sai (ví dụ từ ngày 49).",[981,81332,2711],{"id":2710},[986,81334,81336,81342,81348,81354],{"className":81335},[2715],[989,81337,81339,81341],{"className":81338},[2719],[2721,81340],{"disabled":2723,"type":2724}," Gói cài được, test pass, khớp sklearn.",[989,81343,81345,81347],{"className":81344},[2719],[2721,81346],{"disabled":2723,"type":2724}," 3 báo cáo tự sinh cho 3 bộ dữ liệu.",[989,81349,81351,81353],{"className":81350},[2719],[2721,81352],{"disabled":2723,"type":2724}," Bảng ảnh hưởng tiền xử lý.",[989,81355,81357,81359],{"className":81356},[2719],[2721,81358],{"disabled":2723,"type":2724}," Bản phân tán chạy được 10^6 điểm.",[968,81361,2890],{"id":2889},[2273,81363,81364,81367,81370,81373],{},[989,81365,81366],{},"Phân cụm khác phân loại ở đâu?",[989,81368,81369],{},"Hai bước lặp của K-means là gì?",[989,81371,81372],{},"Silhouette cao nghĩa là gì?",[989,81374,81375],{},"Vì sao chạy K-means nhiều lần?",[3014,81377],{},[973,81379,81380],{},"🌕 Bạn đã hoàn thành ngày 153. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,81382,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":81384},[81385,81386,81391,81392,81399],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":81387},[81388,81389,81390],{"id":81162,"depth":73,"text":81163},{"id":81180,"depth":73,"text":81181},{"id":81198,"depth":73,"text":81199},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":81393},[81394,81396,81397,81398],{"id":81265,"depth":73,"text":81395},"Bài 1: Gói clusterkit",{"id":81288,"depth":73,"text":81289},{"id":81310,"depth":73,"text":81311},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Capstone 3: pipeline clustering production trên dữ liệu khách hàng thật mô phỏng, MapReduce scale, báo cáo metric và diễn giải kinh doanh.",{},[18469],{"title":822,"description":81400},[17502,34177,35747,35334,81405],"customer-segmentation","c2zDGDBQw41V4KtUN1RgFo_bey2H-jQE-JLhBOcpPwY",{"id":81408,"title":827,"body":81409,"category":8797,"day":830,"description":82091,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":82092,"navigation":2723,"outcomes":3047,"path":828,"prerequisites":82093,"seo":82094,"stem":829,"tags":82095,"__hash__":82099},"challenges\u002Fchallenges\u002F154.capstone-recsys.md",{"type":965,"value":81410,"toc":82075},[81411,81413,81416,81418,81422,81436,81440,81454,81458,81472,81497,81499,81507,81509,81517,81521,81532,81539,81543,81551,81555,81953,81955,82052,82054,82068,82070,82073],[968,81412,971],{"id":970},[973,81414,81415],{},"Bạn gợi ý phim và hàng cho người dùng. Người mới cần cách gợi ý riêng.",[968,81417,979],{"id":978},[981,81419,81421],{"id":81420},"gợi-ý-cộng-tác","Gợi ý cộng tác",[986,81423,81424,81427,81430,81433],{},[989,81425,81426],{},"Gợi ý cộng tác dựa vào người giống bạn.",[989,81428,81429],{},"Ví dụ đời thường: bạn thích gì thì rủ người giống bạn.",[989,81431,81432],{},"Cần đủ lịch sử chung mới so được.",[989,81434,81435],{},"Ít dữ liệu thì gợi ý kém.",[981,81437,81439],{"id":81438},"cold-start-và-sparsity","Cold start và sparsity",[986,81441,81442,81445,81448,81451],{},[989,81443,81444],{},"Cold start là người mới hoặc món mới chưa có dữ liệu.",[989,81446,81447],{},"Sparsity là bảng đánh giá nhiều ô trống.",[989,81449,81450],{},"Ví dụ đời thường: khách mới vào quán chưa biết thích gì.",[989,81452,81453],{},"Cách xử lý: dùng món phổ biến hoặc theo nội dung.",[981,81455,81457],{"id":81456},"a-b-test-và-blend","A-B test và blend",[986,81459,81460,81463,81466,81469],{},[989,81461,81462],{},"A-B test chia người dùng làm hai nhóm so sánh.",[989,81464,81465],{},"Blend là trộn nhiều cách gợi ý theo tỉ lệ.",[989,81467,81468],{},"Ví dụ đời thường: blend như pha hai vị nước theo tỉ lệ.",[989,81470,81471],{},"Người mới thì tăng tỉ trọng gợi ý phổ biến.",[1352,81473,81475],{"className":3538,"code":81474,"language":3540,"meta":1357,"style":1357},"# trộn gợi ý phổ biến và cá nhân\ndef blend(pho_bien, ca_nhan, do_am):\n    w = min(do_am, 1.0)  # càng nhiều dữ liệu càng tin cá nhân\n    return w * ca_nhan + (1 - w) * pho_bien  # điểm trộn\n",[992,81476,81477,81482,81487,81492],{"__ignoreMap":1357},[1023,81478,81479],{"class":1362,"line":63},[1023,81480,81481],{},"# trộn gợi ý phổ biến và cá nhân\n",[1023,81483,81484],{"class":1362,"line":68},[1023,81485,81486],{},"def blend(pho_bien, ca_nhan, do_am):\n",[1023,81488,81489],{"class":1362,"line":73},[1023,81490,81491],{},"    w = min(do_am, 1.0)  # càng nhiều dữ liệu càng tin cá nhân\n",[1023,81493,81494],{"class":1362,"line":78},[1023,81495,81496],{},"    return w * ca_nhan + (1 - w) * pho_bien  # điểm trộn\n",[968,81498,1433],{"id":1432},[986,81500,81501,81504],{},[989,81502,81503],{},"Người mới chưa đánh giá gì -> gợi ý top phổ biến.",[989,81505,81506],{},"Người cũ nhiều đánh giá -> gợi ý theo sở thích riêng.",[968,81508,1482],{"id":1481},[973,81510,1485,81511,81513,81514,1517],{},[1487,81512,13531],{},". Gom code ngày 58, 59, 91, 131. Dữ liệu MovieLens 1M. Nộp vào ",[992,81515,81516],{},"day-154-capstone\u002F",[981,81518,81520],{"id":81519},"bài-1-đo-cold-start","Bài 1: Đo cold start",[2273,81522,81523,81526,81529],{},[989,81524,81525],{},"Chọn 500 user có ít nhất 50 rating. Giả làm user mới: giữ lại 0, 1, 3, 5, 10, 20 rating trong train.",[989,81527,81528],{},"Đo precision@10 và NDCG@10 cho 4 mô hình (phổ biến, content, item-CF, MF) ở mỗi mức.",[989,81530,81531],{},"Vẽ đường NDCG theo số rating cho 4 mô hình. Chỉ ra điểm giao nhau: từ bao nhiêu rating thì MF bắt đầu thắng.",[973,81533,81534,81535,81538],{},"Làm tương tự cho ",[1487,81536,81537],{},"phim mới",": giấu toàn bộ rating của 200 phim, rồi thêm lại dần.",[981,81540,81542],{"id":81541},"bài-2-đo-sparsity","Bài 2: Đo sparsity",[2273,81544,81545,81548],{},[989,81546,81547],{},"Xóa ngẫu nhiên 0%, 30%, 60%, 90% rating train. In RMSE và NDCG@10 của item-CF và MF.",[989,81549,81550],{},"Tính mật độ ma trận mỗi mức. Viết 3 câu vì sao MF chịu thưa tốt hơn.",[981,81552,81554],{"id":81553},"bài-3-blend-và-ab-test-giả-lập-nâng-cao","Bài 3: Blend và A\u002FB test giả lập (nâng cao)",[2273,81556,81557,81942,81945,81948],{},[989,81558,81559,81560,81692,81693,35207,81872,22123],{},"Blend theo số rating của user: ",[1023,81561,81563,81601],{"className":81562},[1026],[1023,81564,81566],{"className":81565},[1030],[1032,81567,81568],{"xmlns":1034},[1036,81569,81570,81598],{},[1039,81571,81572,81574,81576,81578,81580,81582,81584,81586,81588,81590,81596],{},[1042,81573,27557],{},[1046,81575,2325],{},[1042,81577,22184],{},[1046,81579,8400],{},[1046,81581,1049],{"stretchy":1048},[1051,81583,1053],{},[1046,81585,13897],{"separator":1066},[1042,81587,1262],{},[1042,81589,2461],{"mathvariant":2460},[17690,81591,81592,81594],{},[1042,81593,1262],{},[1051,81595,2379],{},[1046,81597,1056],{"stretchy":1048},[1058,81599,81600],{"encoding":1060},"w = \\min(1, n \u002F n_0)",[1023,81602,81604,81622],{"className":81603,"ariaHidden":1066},[1065],[1023,81605,81607,81610,81613,81616,81619],{"className":81606},[1070],[1023,81608],{"className":81609,"style":2347},[1074],[1023,81611,27557],{"className":81612,"style":37436},[1079,1080],[1023,81614],{"className":81615,"style":2355},[2354],[1023,81617,2325],{"className":81618},[2359],[1023,81620],{"className":81621,"style":2355},[2354],[1023,81623,81625,81628,81631,81634,81637,81640,81643,81646,81649,81689],{"className":81624},[1070],[1023,81626],{"className":81627,"style":1075},[1074],[1023,81629,22184],{"className":81630},[8426],[1023,81632,1049],{"className":81633},[1085],[1023,81635,1053],{"className":81636},[1079],[1023,81638,13897],{"className":81639},[13943],[1023,81641],{"className":81642,"style":8434},[2354],[1023,81644,1262],{"className":81645},[1079,1080],[1023,81647,2461],{"className":81648},[1079],[1023,81650,81652,81655],{"className":81651},[1079],[1023,81653,1262],{"className":81654},[1079,1080],[1023,81656,81658],{"className":81657},[2383],[1023,81659,81661,81681],{"className":81660},[2387,17732],[1023,81662,81664,81678],{"className":81663},[2391],[1023,81665,81667],{"className":81666,"style":54019},[2395],[1023,81668,81669,81672],{"style":17783},[1023,81670],{"className":81671,"style":2403},[2402],[1023,81673,81675],{"className":81674},[2407,2408,2409,2410],[1023,81676,2379],{"className":81677},[1079,2410],[1023,81679,17797],{"className":81680},[17796],[1023,81682,81684],{"className":81683},[2391],[1023,81685,81687],{"className":81686,"style":17804},[2395],[1023,81688],{},[1023,81690,1056],{"className":81691},[1092],", điểm = ",[1023,81694,81696,81750],{"className":81695},[1026],[1023,81697,81699],{"className":81698},[1030],[1032,81700,81701],{"xmlns":1034},[1036,81702,81703,81747],{},[1039,81704,81705,81707,81709,81711,81713,81715,81717,81719,81721,81723,81725,81727,81729,81731,81733,81735,81737,81739,81741,81743,81745],{},[1042,81706,27557],{},[1046,81708,18118],{},[1042,81710,44268],{},[1042,81712,29697],{},[1046,81714,21881],{},[1046,81716,1049],{"stretchy":1048},[1051,81718,1053],{},[1046,81720,17698],{},[1042,81722,27557],{},[1046,81724,1056],{"stretchy":1048},[1046,81726,18118],{},[1042,81728,973],{},[1042,81730,7687],{},[1042,81732,973],{},[1042,81734,30390],{},[1042,81736,7684],{},[1042,81738,6207],{},[1042,81740,12970],{},[1042,81742,1837],{},[1042,81744,29580],{},[1042,81746,32887],{},[1058,81748,81749],{"encoding":1060},"w \\cdot MF + (1 - w) \\cdot popularity",[1023,81751,81753,81772,81794,81815,81836],{"className":81752,"ariaHidden":1066},[1065],[1023,81754,81756,81760,81763,81766,81769],{"className":81755},[1070],[1023,81757],{"className":81758,"style":81759},[1074],"height:0.4445em;",[1023,81761,27557],{"className":81762,"style":37436},[1079,1080],[1023,81764],{"className":81765,"style":13790},[2354],[1023,81767,18118],{"className":81768},[13794],[1023,81770],{"className":81771,"style":13790},[2354],[1023,81773,81775,81779,81782,81785,81788,81791],{"className":81774},[1070],[1023,81776],{"className":81777,"style":81778},[1074],"height:0.7667em;vertical-align:-0.0833em;",[1023,81780,44268],{"className":81781,"style":20451},[1079,1080],[1023,81783,29697],{"className":81784,"style":37429},[1079,1080],[1023,81786],{"className":81787,"style":13790},[2354],[1023,81789,21881],{"className":81790},[13794],[1023,81792],{"className":81793,"style":13790},[2354],[1023,81795,81797,81800,81803,81806,81809,81812],{"className":81796},[1070],[1023,81798],{"className":81799,"style":1075},[1074],[1023,81801,1049],{"className":81802},[1085],[1023,81804,1053],{"className":81805},[1079],[1023,81807],{"className":81808,"style":13790},[2354],[1023,81810,17698],{"className":81811},[13794],[1023,81813],{"className":81814,"style":13790},[2354],[1023,81816,81818,81821,81824,81827,81830,81833],{"className":81817},[1070],[1023,81819],{"className":81820,"style":1075},[1074],[1023,81822,27557],{"className":81823,"style":37436},[1079,1080],[1023,81825,1056],{"className":81826},[1092],[1023,81828],{"className":81829,"style":13790},[2354],[1023,81831,18118],{"className":81832},[13794],[1023,81834],{"className":81835,"style":13790},[2354],[1023,81837,81839,81842,81845,81848,81851,81854,81857,81860,81863,81866,81869],{"className":81838},[1070],[1023,81840],{"className":81841,"style":59519},[1074],[1023,81843,973],{"className":81844},[1079,1080],[1023,81846,7687],{"className":81847},[1079,1080],[1023,81849,973],{"className":81850},[1079,1080],[1023,81852,30390],{"className":81853},[1079,1080],[1023,81855,7684],{"className":81856,"style":7716},[1079,1080],[1023,81858,6207],{"className":81859},[1079,1080],[1023,81861,12970],{"className":81862,"style":1081},[1079,1080],[1023,81864,1837],{"className":81865},[1079,1080],[1023,81867,29580],{"className":81868},[1079,1080],[1023,81870,32887],{"className":81871,"style":7723},[1079,1080],[1023,81873,81875,81893],{"className":81874},[1026],[1023,81876,81878],{"className":81877},[1030],[1032,81879,81880],{"xmlns":1034},[1036,81881,81882,81890],{},[1039,81883,81884],{},[17690,81885,81886,81888],{},[1042,81887,1262],{},[1051,81889,2379],{},[1058,81891,81892],{"encoding":1060},"n_0",[1023,81894,81896],{"className":81895,"ariaHidden":1066},[1065],[1023,81897,81899,81902],{"className":81898},[1070],[1023,81900],{"className":81901,"style":54000},[1074],[1023,81903,81905,81908],{"className":81904},[1079],[1023,81906,1262],{"className":81907},[1079,1080],[1023,81909,81911],{"className":81910},[2383],[1023,81912,81914,81934],{"className":81913},[2387,17732],[1023,81915,81917,81931],{"className":81916},[2391],[1023,81918,81920],{"className":81919,"style":54019},[2395],[1023,81921,81922,81925],{"style":17783},[1023,81923],{"className":81924,"style":2403},[2402],[1023,81926,81928],{"className":81927},[2407,2408,2409,2410],[1023,81929,2379],{"className":81930},[1079,2410],[1023,81932,17797],{"className":81933},[17796],[1023,81935,81937],{"className":81936},[2391],[1023,81938,81940],{"className":81939,"style":17804},[2395],[1023,81941],{},[989,81943,81944],{},"A\u002FB test giả lập: chia 6000 user ngẫu nhiên 2 nhóm. Nhóm A dùng MF, nhóm B dùng blend. \"Click\" là phim trong top 10 được user chấm ≥ 4 ở tập test.",[989,81946,81947],{},"Tính tỉ lệ click 2 nhóm, khoảng tin cậy 95% và p-value (kiểm định 2 tỉ lệ). Kết luận có ý nghĩa thống kê không.",[989,81949,81950,81952],{},[992,81951,17400],{}," tổng hợp 3 phần.",[981,81954,2711],{"id":2710},[986,81956,81958,81964,81970,82046],{"className":81957},[2715],[989,81959,81961,81963],{"className":81960},[2719],[2721,81962],{"disabled":2723,"type":2724}," Hình NDCG theo số rating cho user mới và phim mới.",[989,81965,81967,81969],{"className":81966},[2719],[2721,81968],{"disabled":2723,"type":2724}," Bảng sparsity có số thật.",[989,81971,81973,81975,81976,82045],{"className":81972},[2719],[2721,81974],{"disabled":2723,"type":2724}," Blend có ",[1023,81977,81979,81996],{"className":81978},[1026],[1023,81980,81982],{"className":81981},[1030],[1032,81983,81984],{"xmlns":1034},[1036,81985,81986,81994],{},[1039,81987,81988],{},[17690,81989,81990,81992],{},[1042,81991,1262],{},[1051,81993,2379],{},[1058,81995,81892],{"encoding":1060},[1023,81997,81999],{"className":81998,"ariaHidden":1066},[1065],[1023,82000,82002,82005],{"className":82001},[1070],[1023,82003],{"className":82004,"style":54000},[1074],[1023,82006,82008,82011],{"className":82007},[1079],[1023,82009,1262],{"className":82010},[1079,1080],[1023,82012,82014],{"className":82013},[2383],[1023,82015,82017,82037],{"className":82016},[2387,17732],[1023,82018,82020,82034],{"className":82019},[2391],[1023,82021,82023],{"className":82022,"style":54019},[2395],[1023,82024,82025,82028],{"style":17783},[1023,82026],{"className":82027,"style":2403},[2402],[1023,82029,82031],{"className":82030},[2407,2408,2409,2410],[1023,82032,2379],{"className":82033},[1079,2410],[1023,82035,17797],{"className":82036},[17796],[1023,82038,82040],{"className":82039},[2391],[1023,82041,82043],{"className":82042,"style":17804},[2395],[1023,82044],{}," chọn bằng validation.",[989,82047,82049,82051],{"className":82048},[2719],[2721,82050],{"disabled":2723,"type":2724}," A\u002FB test có khoảng tin cậy và p-value.",[968,82053,2890],{"id":2889},[2273,82055,82056,82059,82062,82065],{},[989,82057,82058],{},"Cold start là gì?",[989,82060,82061],{},"Sparsity cao gây khó gì?",[989,82063,82064],{},"A-B test chia nhóm thế nào?",[989,82066,82067],{},"Blend nghĩa là gì?",[3014,82069],{},[973,82071,82072],{},"🌕 Bạn đã hoàn thành ngày 154. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,82074,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":82076},[82077,82078,82083,82084,82090],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":82079},[82080,82081,82082],{"id":81420,"depth":73,"text":81421},{"id":81438,"depth":73,"text":81439},{"id":81456,"depth":73,"text":81457},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":82085},[82086,82087,82088,82089],{"id":81519,"depth":73,"text":81520},{"id":81541,"depth":73,"text":81542},{"id":81553,"depth":73,"text":81554},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Capstone 4: nâng recsys ngày 131 lên A-B test, đo cold start và sparsity, blend theo độ ấm, báo cáo business metric.",{},[14055],{"title":827,"description":82091},[17502,39582,82096,82097,82098],"cold-start","ab-testing","sparsity","Z5JDCjx012O2Hkn-oxmsxSpWdeq6qym0eWwbCxmNI04",{"id":82101,"title":832,"body":82102,"category":8797,"day":835,"description":82462,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":82463,"navigation":2723,"outcomes":3047,"path":833,"prerequisites":82464,"seo":82465,"stem":834,"tags":82466,"__hash__":82468},"challenges\u002Fchallenges\u002F155.capstone-crypto-scale.md",{"type":965,"value":82103,"toc":82446},[82104,82106,82109,82111,82115,82129,82133,82147,82151,82165,82205,82207,82215,82217,82225,82234,82238,82244,82311,82315,82328,82332,82335,82385,82390,82392,82423,82425,82439,82441,82444],[968,82105,971],{"id":970},[973,82107,82108],{},"Bạn xây pipeline xử lý liên tục có mã hóa. Dữ liệu chạy qua mà không lộ.",[968,82110,979],{"id":978},[981,82112,82114],{"id":82113},"streaming-pipeline","Streaming pipeline",[986,82116,82117,82120,82123,82126],{},[989,82118,82119],{},"Streaming xử lý từng mẩu dữ liệu ngay khi tới.",[989,82121,82122],{},"Ví dụ đời thường: giống băng chuyền sushi ra món nào ăn món đó.",[989,82124,82125],{},"Khác batch gom đủ mẻ mới xử lý.",[989,82127,82128],{},"Cần chịu được khi một nút bị hỏng.",[981,82130,82132],{"id":82131},"mã-hóa-e2e","Mã hóa E2E",[986,82134,82135,82138,82141,82144],{},[989,82136,82137],{},"Mã hóa E2E là chỉ người gửi và nhận đọc được.",[989,82139,82140],{},"Định nghĩa: máy chủ trung gian chỉ thấy chữ đã mã hóa.",[989,82142,82143],{},"Ví dụ đời thường: giống thư niêm phong chỉ người nhận mở được.",[989,82145,82146],{},"Không bao giờ ghi khóa cùng chỗ với dữ liệu.",[981,82148,82150],{"id":82149},"bloom-filter-và-chaos-test","Bloom filter và chaos test",[986,82152,82153,82156,82159,82162],{},[989,82154,82155],{},"Bloom filter kiểm tra nhanh món đồ có thể đã thấy.",[989,82157,82158],{},"Ví dụ đời thường: giống danh sách đen ghi nháp, có thể nhầm.",[989,82160,82161],{},"Nó có thể báo nhầm có, không bao giờ báo nhầm không.",[989,82163,82164],{},"Chaos test là cố tình phá một phần để tập chịu đựng.",[1352,82166,82168],{"className":3538,"code":82167,"language":3540,"meta":1357,"style":1357},"# kiểm tra trùng bằng tập đã thấy\nda_thay = set()  # nơi nhớ món đã qua\ndef la_trung(mon):\n    if mon in da_thay:  # đã gặp rồi\n        return True\n    da_thay.add(mon)  # nhớ lại\n    return False\n",[992,82169,82170,82175,82180,82185,82190,82195,82200],{"__ignoreMap":1357},[1023,82171,82172],{"class":1362,"line":63},[1023,82173,82174],{},"# kiểm tra trùng bằng tập đã thấy\n",[1023,82176,82177],{"class":1362,"line":68},[1023,82178,82179],{},"da_thay = set()  # nơi nhớ món đã qua\n",[1023,82181,82182],{"class":1362,"line":73},[1023,82183,82184],{},"def la_trung(mon):\n",[1023,82186,82187],{"class":1362,"line":78},[1023,82188,82189],{},"    if mon in da_thay:  # đã gặp rồi\n",[1023,82191,82192],{"class":1362,"line":83},[1023,82193,82194],{},"        return True\n",[1023,82196,82197],{"class":1362,"line":88},[1023,82198,82199],{},"    da_thay.add(mon)  # nhớ lại\n",[1023,82201,82202],{"class":1362,"line":93},[1023,82203,82204],{},"    return False\n",[968,82206,1433],{"id":1432},[986,82208,82209,82212],{},[989,82210,82211],{},"Tin nhắn mã hóa -> máy chủ chỉ thấy ký tự lạ.",[989,82213,82214],{},"Link độc đã biết -> Bloom chặn trước khi hiển thị.",[968,82216,1482],{"id":1481},[973,82218,1485,82219,82221,82222,1517],{},[1487,82220,13531],{}," (hoặc Go). Gom code ngày 30, 105, 106, 142, 143. Nộp vào ",[992,82223,82224],{},"day-155-capstone\u002F",[40801,82226,82227],{},[973,82228,82229,82230,82233],{},"Khóa bí mật chỉ nằm trong biến môi trường hoặc file ngoài repo. Kiểm tra bằng ",[992,82231,82232],{},"git grep"," trước khi push.",[981,82235,82237],{"id":82236},"bài-1-hệ-thống-nhận-sự-kiện-có-mã-hóa","Bài 1: Hệ thống nhận sự kiện có mã hóa",[1352,82239,82242],{"className":82240,"code":82241,"language":2241,"meta":1357},[2239],"producer (N tiến trình) --TLS--> gateway --> hàng đợi --> consumer --> kho lưu\n",[992,82243,82241],{"__ignoreMap":1357},[1099,82245,82246,82254],{},[1102,82247,82248],{},[1105,82249,82250,82252],{},[1108,82251,2544],{},[1108,82253,2547],{},[1118,82255,82256,82271,82281,82292,82300],{},[1105,82257,82258,82261],{},[1123,82259,82260],{},"Producer",[1123,82262,82263,82264,1838,82267,82270],{},"Mỗi sự kiện ",[992,82265,82266],{},"{id, ts, payload}",[992,82268,82269],{},"payload"," mã hóa đầu cuối bằng AES-GCM, khóa chỉ producer và consumer biết",[1105,82272,82273,82276],{},[1123,82274,82275],{},"Gateway",[1123,82277,82278,82279],{},"Nhận qua TLS, kiểm tra chữ ký HMAC, không giải mã ",[992,82280,82269],{},[1105,82282,82283,82286],{},[1123,82284,82285],{},"Khử trùng",[1123,82287,82288,82289,82291],{},"Bloom filter theo ",[992,82290,77934],{}," ở gateway, trúng Bloom thì kiểm lại trong kho (không bỏ nhầm)",[1105,82293,82294,82297],{},[1123,82295,82296],{},"Consumer",[1123,82298,82299],{},"Giải mã, xử lý cửa sổ 1 phút, ghi kết quả",[1105,82301,82302,82305],{},[1123,82303,82304],{},"Kho",[1123,82306,82307,82308,82310],{},"Khóa mã hóa ",[1487,82309,41587],{}," lưu cùng chỗ với dữ liệu",[981,82312,82314],{"id":82313},"bài-2-tải-và-trùng-lặp","Bài 2: Tải và trùng lặp",[2273,82316,82317,82320,82323],{},[989,82318,82319],{},"20 producer, tổng 20.000 sự kiện\u002Fgiây trong 5 phút. 3% sự kiện gửi trùng.",[989,82321,82322],{},"In: thông lượng, độ trễ đầu cuối p50\u002Fp99, số trùng bị loại, số lần Bloom báo nhầm.",[989,82324,82325,82326,16014],{},"Kiểm tra: không mất sự kiện nào, không xử lý trùng sự kiện nào (đếm theo ",[992,82327,77934],{},[981,82329,82331],{"id":82330},"bài-3-chaos-test-nâng-cao","Bài 3: Chaos test (nâng cao)",[973,82333,82334],{},"Viết script gây lỗi và ghi lại hành vi hệ thống:",[1099,82336,82337,82345],{},[1102,82338,82339],{},[1105,82340,82341,82343],{},[1108,82342,54979],{},[1108,82344,8573],{},[1118,82346,82347,82355,82363,82377],{},[1105,82348,82349,82352],{},[1123,82350,82351],{},"Giết consumer 30 giây",[1123,82353,82354],{},"Hàng đợi tăng, consumer lên lại xử lý hết, không mất",[1105,82356,82357,82360],{},[1123,82358,82359],{},"Gateway chậm 500 ms",[1123,82361,82362],{},"Producer retry có backoff, không bão request",[1105,82364,82365,82371],{},[1123,82366,82367,82368,82370],{},"Sửa 1 byte ",[992,82369,82269],{}," trên đường",[1123,82372,82373,82374],{},"Consumer phát hiện sai tag, ghi vào ",[992,82375,82376],{},"rejected\u002F",[1105,82378,82379,82382],{},[1123,82380,82381],{},"Chứng chỉ gateway hết hạn",[1123,82383,82384],{},"Producer từ chối kết nối, báo lỗi rõ",[973,82386,82387,82389],{},[992,82388,17400],{},": sơ đồ, bảng số liệu, bảng chaos, 3 điểm yếu còn lại.",[981,82391,2711],{"id":2710},[986,82393,82395,82403,82409,82415],{"className":82394},[2715],[989,82396,82398,82400,82401,71419],{"className":82397},[2719],[2721,82399],{"disabled":2723,"type":2724}," Gateway không đọc được ",[992,82402,82269],{},[989,82404,82406,82408],{"className":82405},[2719],[2721,82407],{"disabled":2723,"type":2724}," Không mất, không trùng dưới tải 20.000 sự kiện\u002Fgiây.",[989,82410,82412,82414],{"className":82411},[2719],[2721,82413],{"disabled":2723,"type":2724}," Bảng chaos 4 kịch bản có kết quả thật.",[989,82416,82418,2308,82420,82422],{"className":82417},[2719],[2721,82419],{"disabled":2723,"type":2724},[992,82421,82232],{}," không tìm thấy khóa trong repo.",[968,82424,2890],{"id":2889},[2273,82426,82427,82430,82433,82436],{},[989,82428,82429],{},"Streaming khác batch ở đâu?",[989,82431,82432],{},"E2E nghĩa là ai đọc được?",[989,82434,82435],{},"Bloom filter nhầm theo hướng nào?",[989,82437,82438],{},"Chaos test để làm gì?",[3014,82440],{},[973,82442,82443],{},"🌕 Bạn đã hoàn thành ngày 155. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,82445,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":82447},[82448,82449,82454,82455,82461],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":82450},[82451,82452,82453],{"id":82113,"depth":73,"text":82114},{"id":82131,"depth":73,"text":82132},{"id":82149,"depth":73,"text":82150},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":82456},[82457,82458,82459,82460],{"id":82236,"depth":73,"text":82237},{"id":82313,"depth":73,"text":82314},{"id":82330,"depth":73,"text":82331},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Capstone 5: tổng hợp lớn nhất — pipeline streaming mã hóa E2E, cache phân tán, index Bloom, chaos test, báo cáo kiến trúc hệ thống.",{},[14055,15144],{"title":832,"description":82462},[17502,82467,62455,40796,72343],"distributed-systems","eFR1zMEWEzMXUTj8ratbM-4f0ymApq4Z9YjNY7dk0Rk",{"id":82470,"title":837,"body":82471,"category":8797,"day":840,"description":82734,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":82735,"navigation":2723,"outcomes":3047,"path":838,"prerequisites":82736,"seo":82737,"stem":839,"tags":82738,"__hash__":82739},"challenges\u002Fchallenges\u002F156.capstone-optimization.md",{"type":965,"value":82472,"toc":82718},[82473,82475,82478,82480,82484,82498,82502,82516,82520,82534,82579,82581,82589,82591,82602,82606,82612,82617,82619,82636,82640,82643,82649,82653,82666,82668,82695,82697,82711,82713,82716],[968,82474,971],{"id":970},[973,82476,82477],{},"Bạn tìm đường thăm mọi thành phố ngắn nhất. Thử nhiều cách rồi so kết quả.",[968,82479,979],{"id":978},[981,82481,82483],{"id":82482},"tsp-là-gì","TSP là gì",[986,82485,82486,82489,82492,82495],{},[989,82487,82488],{},"TSP là đi qua mọi thành phố rồi về chỗ cũ.",[989,82490,82491],{},"Định nghĩa: tìm tour ngắn nhất, bài toán khó nổi tiếng.",[989,82493,82494],{},"Ví dụ đời thường: giống shipper đi mọi điểm rồi về kho.",[989,82496,82497],{},"Thử mọi cách chỉ hợp khi thành phố ít.",[981,82499,82501],{"id":82500},"brute-force-greedy-và-dp","Brute-force, greedy và DP",[986,82503,82504,82507,82510,82513],{},[989,82505,82506],{},"Brute-force thử mọi tour, đúng nhưng rất chậm.",[989,82508,82509],{},"Greedy mỗi bước đi tới thành phố gần nhất.",[989,82511,82512],{},"Ví dụ đời thường: greedy như luôn chọn quán gần nhất.",[989,82514,82515],{},"DP nhớ kết quả con nên nhanh hơn brute-force.",[981,82517,82519],{"id":82518},"heuristic-và-2-opt","Heuristic và 2-opt",[986,82521,82522,82525,82528,82531],{},[989,82523,82524],{},"Heuristic là cách gần đúng, nhanh nhưng không chắc tốt nhất.",[989,82526,82527],{},"2-opt gỡ hai đoạn chéo nhau để tour ngắn lại.",[989,82529,82530],{},"Ví dụ đời thường: 2-opt như gỡ dây rối cho gọn.",[989,82532,82533],{},"Vẽ ít giao cắt giúp nhìn tour rõ hơn.",[1352,82535,82537],{"className":3538,"code":82536,"language":3540,"meta":1357,"style":1357},"# độ dài một tour\ndef do_dai(tour, xa):\n    tong = 0  # cộng dồn quãng đường\n    for i in range(len(tour)):\n        a = tour[i]  # điểm hiện tại\n        b = tour[(i + 1) % len(tour)]  # điểm tiếp theo\n        tong += xa[a][b]  # cộng đoạn này\n    return tong\n",[992,82538,82539,82544,82549,82554,82559,82564,82569,82574],{"__ignoreMap":1357},[1023,82540,82541],{"class":1362,"line":63},[1023,82542,82543],{},"# độ dài một tour\n",[1023,82545,82546],{"class":1362,"line":68},[1023,82547,82548],{},"def do_dai(tour, xa):\n",[1023,82550,82551],{"class":1362,"line":73},[1023,82552,82553],{},"    tong = 0  # cộng dồn quãng đường\n",[1023,82555,82556],{"class":1362,"line":78},[1023,82557,82558],{},"    for i in range(len(tour)):\n",[1023,82560,82561],{"class":1362,"line":83},[1023,82562,82563],{},"        a = tour[i]  # điểm hiện tại\n",[1023,82565,82566],{"class":1362,"line":88},[1023,82567,82568],{},"        b = tour[(i + 1) % len(tour)]  # điểm tiếp theo\n",[1023,82570,82571],{"class":1362,"line":93},[1023,82572,82573],{},"        tong += xa[a][b]  # cộng đoạn này\n",[1023,82575,82576],{"class":1362,"line":98},[1023,82577,82578],{},"    return tong\n",[968,82580,1433],{"id":1432},[986,82582,82583,82586],{},[989,82584,82585],{},"Input 4 thành phố -> brute-force thử mọi tour rồi chọn ngắn nhất.",[989,82587,82588],{},"Tour bị chéo nhau -> 2-opt gỡ chéo cho ngắn lại.",[968,82590,1482],{"id":1481},[973,82592,1485,82593,82595,82596,82598,82599,1517],{},[1487,82594,1493],{}," cho TSP, ",[1487,82597,64499],{}," cho vẽ. Gom code ngày 16, 78, 114, 115, 121, 136. Nộp vào ",[992,82600,82601],{},"day-156-capstone\u002F",[981,82603,82605],{"id":82604},"bài-1-thư-viện-tsp-thống-nhất","Bài 1: Thư viện TSP thống nhất",[1352,82607,82610],{"className":82608,"code":82609,"language":2241,"meta":1357},[2239],"tsp\u002F\n  io.hpp          đọc TSPLIB (EUC_2D), đọc\u002Fghi tour\n  exact.hpp       bruteForce (n \u003C= 10), heldKarp (n \u003C= 20)\n  heuristic.hpp   nearestNeighbor, twoOpt, orOpt\n  meta.hpp        simulatedAnnealing, geneticAlgorithm\n  verify.hpp      isValidTour, tourLength\n",[992,82611,82609],{"__ignoreMap":1357},[973,82613,78389,82614,1517],{},[992,82615,82616],{},"tsp solve --algo sa --time 5 --seed 1 berlin52.tsp > tour.txt",[973,82618,11283],{},[986,82620,82621,82627,82630],{},[989,82622,82623,82624,82626],{},"Held-Karp khớp brute-force với mọi ",[992,82625,48537],{}," (100 bộ ngẫu nhiên).",[989,82628,82629],{},"Mọi thuật toán trả tour hợp lệ.",[989,82631,82632,82635],{},[992,82633,82634],{},"twoOpt"," không bao giờ làm tour dài hơn.",[981,82637,82639],{"id":82638},"bài-2-bảng-so-sánh-cuối-cùng","Bài 2: Bảng so sánh cuối cùng",[973,82641,82642],{},"Chạy mọi thuật toán phù hợp trên: 10 điểm, 20 điểm (có tối ưu từ Held-Karp), berlin52, kroA100, 1000 điểm ngẫu nhiên.",[1352,82644,82647],{"className":82645,"code":82646,"language":2241,"meta":1357},[2239],"bộ        n      thuật_toán    độ_dài   gap(%)   thời_gian\ntiny10    10     brute         ...      0\ntiny10    10     heldKarp      ...      0\n...\n",[992,82648,82646],{"__ignoreMap":1357},[981,82650,82652],{"id":82651},"bài-3-trực-quan-hóa-ít-giao-cắt-nâng-cao","Bài 3: Trực quan hóa ít giao cắt (nâng cao)",[2273,82654,82655,82658,82661],{},[989,82656,82657],{},"Vẽ tour tốt nhất cho mỗi bộ. Đếm số cạnh cắt nhau trong tour (hàm ngày 120). Tour sau 2-opt phải có 0 giao cắt: chứng minh bằng số.",[989,82659,82660],{},"Tạo GIF quá trình SA cải thiện tour trên kroA100 (mỗi 5% tiến trình 1 khung).",[989,82662,82663,82665],{},[992,82664,17400],{},": bảng, hình, giải thích vì sao tour tối ưu Euclid không có giao cắt.",[981,82667,2711],{"id":2710},[986,82669,82671,82677,82683,82689],{"className":82670},[2715],[989,82672,82674,82676],{"className":82673},[2719],[2721,82675],{"disabled":2723,"type":2724}," 3 nhóm test bắt buộc pass.",[989,82678,82680,82682],{"className":82679},[2719],[2721,82681],{"disabled":2723,"type":2724}," CLI chạy được mọi thuật toán.",[989,82684,82686,82688],{"className":82685},[2719],[2721,82687],{"disabled":2723,"type":2724}," Bảng so sánh 5 bộ dữ liệu.",[989,82690,82692,82694],{"className":82691},[2719],[2721,82693],{"disabled":2723,"type":2724}," Có GIF và chứng minh 0 giao cắt sau 2-opt.",[968,82696,2890],{"id":2889},[2273,82698,82699,82702,82705,82708],{},[989,82700,82701],{},"TSP yêu cầu tour thế nào?",[989,82703,82704],{},"Greedy chọn bước tiếp theo ra sao?",[989,82706,82707],{},"2-opt làm gì?",[989,82709,82710],{},"Vì sao không brute-force khi n lớn?",[3014,82712],{},[973,82714,82715],{},"🌕 Bạn đã hoàn thành ngày 156. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,82717,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":82719},[82720,82721,82726,82727,82733],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":82722},[82723,82724,82725],{"id":82482,"depth":73,"text":82483},{"id":82500,"depth":73,"text":82501},{"id":82518,"depth":73,"text":82519},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":82728},[82729,82730,82731,82732],{"id":82604,"depth":73,"text":82605},{"id":82638,"depth":73,"text":82639},{"id":82651,"depth":73,"text":82652},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"So găng brute-force, greedy, DP, simulated annealing và di truyền trên cùng bộ TSP, cải thiện tour bằng 2-opt và vẽ mạng lưới ít giao cắt.",{},[15143],{"title":837,"description":82734},[17502,48823,47532],"CiiQVQ_oJmhP4jPiuF2Vk_G9U9N7VhIn5J_JTNAxvX0",{"id":82741,"title":842,"body":82742,"category":5189,"day":845,"description":83082,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":83083,"navigation":2723,"outcomes":3047,"path":843,"prerequisites":83084,"seo":83085,"stem":844,"tags":83086,"__hash__":83087},"challenges\u002Fchallenges\u002F157.capstone-patterns-duck.md",{"type":965,"value":82743,"toc":83066},[82744,82746,82749,82751,82753,82767,82771,82785,82789,82803,82853,82855,82863,82865,82873,82877,82880,82951,82954,82958,82963,82989,82992,82996,83013,83015,83044,83046,83059,83061,83064],[968,82745,971],{"id":970},[973,82747,82748],{},"Bạn sửa đàn vịt bị rối code. Mỗi hành vi thành khối riêng dễ thay.",[968,82750,979],{"id":978},[981,82752,7052],{"id":7051},[986,82754,82755,82758,82761,82764],{},[989,82756,82757],{},"Strategy gói mỗi cách làm thành một khối riêng.",[989,82759,82760],{},"Định nghĩa: vịt giữ hành vi, muốn đổi thì thay khối.",[989,82762,82763],{},"Ví dụ đời thường: giống thay đầu tuốc-nơ-vít cho một cán.",[989,82765,82766],{},"Thêm kiểu bay mới không cần sửa code vịt cũ.",[981,82768,82770],{"id":82769},"observer-là-gì","Observer là gì",[986,82772,82773,82776,82779,82782],{},[989,82774,82775],{},"Observer là một bên đổi, nhiều bên tự biết.",[989,82777,82778],{},"Ví dụ đời thường: giống nhóm chat, một tin cả nhóm thấy.",[989,82780,82781],{},"Vịt đăng ký theo dõi rồi nhận tin tự động.",[989,82783,82784],{},"Nhớ hủy đăng ký khi không cần nữa.",[981,82786,82788],{"id":82787},"refactor-an-toàn","Refactor an toàn",[986,82790,82791,82794,82797,82800],{},[989,82792,82793],{},"Refactor là sửa cấu trúc mà giữ nguyên cách chạy.",[989,82795,82796],{},"Ví dụ đời thường: giống sắp lại tủ mà đồ vẫn đủ.",[989,82798,82799],{},"Mỗi bước nhỏ xong phải chạy lại kiểm thử.",[989,82801,82802],{},"Yêu cầu đổi phút chót thì chỉ thay khối hành vi.",[1352,82804,82806],{"className":3538,"code":82805,"language":3540,"meta":1357,"style":1357},"# strategy bay đơn giản\nclass BayCanh:  # khối bay bằng cánh\n    def bay(self):\n        return \"vỗ cánh\"  # cách bay này\nclass Vit:\n    def __init__(self, cach_bay):\n        self.cach_bay = cach_bay  # cắm khối bay vào\n    def thuc_hien_bay(self):\n        return self.cach_bay.bay()  # dùng khối đã cắm\n",[992,82807,82808,82813,82818,82823,82828,82833,82838,82843,82848],{"__ignoreMap":1357},[1023,82809,82810],{"class":1362,"line":63},[1023,82811,82812],{},"# strategy bay đơn giản\n",[1023,82814,82815],{"class":1362,"line":68},[1023,82816,82817],{},"class BayCanh:  # khối bay bằng cánh\n",[1023,82819,82820],{"class":1362,"line":73},[1023,82821,82822],{},"    def bay(self):\n",[1023,82824,82825],{"class":1362,"line":78},[1023,82826,82827],{},"        return \"vỗ cánh\"  # cách bay này\n",[1023,82829,82830],{"class":1362,"line":83},[1023,82831,82832],{},"class Vit:\n",[1023,82834,82835],{"class":1362,"line":88},[1023,82836,82837],{},"    def __init__(self, cach_bay):\n",[1023,82839,82840],{"class":1362,"line":93},[1023,82841,82842],{},"        self.cach_bay = cach_bay  # cắm khối bay vào\n",[1023,82844,82845],{"class":1362,"line":98},[1023,82846,82847],{},"    def thuc_hien_bay(self):\n",[1023,82849,82850],{"class":1362,"line":103},[1023,82851,82852],{},"        return self.cach_bay.bay()  # dùng khối đã cắm\n",[968,82854,1433],{"id":1432},[986,82856,82857,82860],{},[989,82858,82859],{},"Vịt cao su không bay -> cắm khối bay \"không bay\".",[989,82861,82862],{},"Muốn bay tên lửa -> chỉ thay khối bay mới.",[968,82864,1482],{"id":1481},[973,82866,1485,82867,82869,82870,1517],{},[1487,82868,4800],{}," (hoặc Java). Dùng code ngày 6, 9, 108, 116. Nộp vào ",[992,82871,82872],{},"day-157-capstone\u002F",[981,82874,82876],{"id":82875},"bài-1-simuduck-hoàn-chỉnh","Bài 1: SimUDuck hoàn chỉnh",[973,82878,82879],{},"Gộp mọi phần về vịt đã làm thành 1 codebase:",[1099,82881,82882,82890],{},[1102,82883,82884],{},[1105,82885,82886,82888],{},[1108,82887,41388],{},[1108,82889,60961],{},[1118,82891,82892,82903,82910,82918,82929,82940],{},[1105,82893,82894,82896],{},[1123,82895,7137],{},[1123,82897,82898,1656,82900,82902],{},[992,82899,67186],{},[992,82901,67189],{},", đổi lúc chạy",[1105,82904,82905,82907],{},[1123,82906,8903],{},[1123,82908,82909],{},"Nhà nghiên cứu, bảng đếm nghe tiếng kêu",[1105,82911,82912,82914],{},[1123,82913,63398],{},[1123,82915,82916],{},[992,82917,63571],{},[1105,82919,82920,82922],{},[1123,82921,46261],{},[1123,82923,82924,1656,82927],{},[992,82925,82926],{},"DuckFactory",[992,82928,63591],{},[1105,82930,82931,82933],{},[1123,82932,24469],{},[1123,82934,82935,1656,82937],{},[992,82936,63559],{},[992,82938,82939],{},"PigeonAdapter",[1105,82941,82942,82945],{},[1123,82943,82944],{},"Composite + Iterator",[1123,82946,82947,82950],{},[992,82948,82949],{},"Flock"," lồng nhau",[973,82952,82953],{},"Có test cho từng pattern. Độ phủ test (gcov\u002Flcov hoặc JaCoCo) trên 85%.",[981,82955,82957],{"id":82956},"bài-2-yêu-cầu-đổi-phút-chót","Bài 2: Yêu cầu đổi phút chót",[973,82959,82960,82961,4437],{},"Thực hiện 4 yêu cầu, mỗi yêu cầu 1 commit, ghi ",[992,82962,14320],{},[2273,82964,82965,82977,82980,82983],{},[989,82966,82967,82968,82971,82972,15881,82975,1517],{},"Thêm vịt ",[992,82969,82970],{},"SolarDuck",": chỉ bay được khi ",[992,82973,82974],{},"SunSensor::isDay()",[992,82976,1066],{},[989,82978,82979],{},"Nhà nghiên cứu chỉ muốn nghe vịt thuộc đàn \"Hồ Tây\".",[989,82981,82982],{},"Đếm riêng tiếng kêu theo loại vịt.",[989,82984,82985,82986,82988],{},"Bay bằng tên lửa tiêu tốn nhiên liệu: hết nhiên liệu thì chuyển sang ",[992,82987,7258],{}," tự động.",[973,82990,82991],{},"Mỗi yêu cầu chỉ thêm file mới hoặc sửa tối đa 1 file cũ. Nếu phải sửa nhiều hơn, ghi lý do và đề xuất cải thiện thiết kế.",[981,82993,82995],{"id":82994},"bài-3-review-và-tài-liệu-nâng-cao","Bài 3: Review và tài liệu (nâng cao)",[2273,82997,82998,83001,83010],{},[989,82999,83000],{},"Nhờ 1 người (bạn học, đồng nghiệp) review code, hoặc tự review sau 1 ngày. Ghi lại 5 góp ý và cách xử lý.",[989,83002,83003,83006,83007,83009],{},[992,83004,83005],{},"DESIGN.md",": sơ đồ lớp đầy đủ, bảng pattern, 3 chỗ bạn cố tình ",[1487,83008,41587],{}," dùng pattern và vì sao.",[989,83011,83012],{},"So số dòng code và số lớp với bản ngày 6. Giải thích phần tăng thêm mua được gì.",[981,83014,2711],{"id":2710},[986,83016,83018,83024,83030,83038],{"className":83017},[2715],[989,83019,83021,83023],{"className":83020},[2719],[2721,83022],{"disabled":2723,"type":2724}," Độ phủ test trên 85%.",[989,83025,83027,83029],{"className":83026},[2719],[2721,83028],{"disabled":2723,"type":2724}," 4 yêu cầu đổi, mỗi cái sửa tối đa 1 file cũ (hoặc có giải thích).",[989,83031,83033,2308,83035,83037],{"className":83032},[2719],[2721,83034],{"disabled":2723,"type":2724},[992,83036,83005],{}," có mục \"không dùng pattern\".",[989,83039,83041,83043],{"className":83040},[2719],[2721,83042],{"disabled":2723,"type":2724}," Có 5 góp ý review và cách xử lý.",[968,83045,2890],{"id":2889},[2273,83047,83048,83050,83053,83056],{},[989,83049,67315],{},[989,83051,83052],{},"Observer báo tin cho ai?",[989,83054,83055],{},"Refactor khác viết mới ở đâu?",[989,83057,83058],{},"Thêm hành vi mới sửa chỗ nào?",[3014,83060],{},[973,83062,83063],{},"🌕 Bạn đã hoàn thành ngày 157. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,83065,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":83067},[83068,83069,83074,83075,83081],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":83070},[83071,83072,83073],{"id":7051,"depth":73,"text":7052},{"id":82769,"depth":73,"text":82770},{"id":82787,"depth":73,"text":82788},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":83076},[83077,83078,83079,83080],{"id":82875,"depth":73,"text":82876},{"id":82956,"depth":73,"text":82957},{"id":82994,"depth":73,"text":82995},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Refactor đàn vịt bằng Strategy và Observer, thêm hành vi bay mới lúc chạy và thử thách khách hàng đổi yêu cầu phút chót.",{},[5194],{"title":842,"description":83082},[17502,7552,9251],"ZHinTA8uAy-V0RD-x0UL-lPtvmrkPS7NtJVqjAKac_E",{"id":83089,"title":847,"body":83090,"category":5189,"day":850,"description":83381,"difficulty":42171,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":83382,"navigation":2723,"outcomes":3047,"path":848,"prerequisites":83383,"seo":83384,"stem":849,"tags":83385,"__hash__":83386},"challenges\u002Fchallenges\u002F158.capstone-patterns-pizza.md",{"type":965,"value":83091,"toc":83365},[83092,83094,83097,83099,83101,83115,83117,83131,83135,83149,83198,83200,83208,83210,83218,83222,83225,83247,83250,83254,83285,83291,83295,83311,83313,83342,83344,83358,83360,83363],[968,83093,971],{"id":970},[973,83095,83096],{},"Bạn mở tiệm pizza nhiều vùng. Mỗi vùng có công thức riêng nhưng gọi chung một cách.",[968,83098,979],{"id":978},[981,83100,20694],{"id":21058},[986,83102,83103,83106,83109,83112],{},[989,83104,83105],{},"Factory Method gom việc tạo bánh vào một chỗ.",[989,83107,83108],{},"Định nghĩa: code gọi chung, lớp con quyết định loại bánh.",[989,83110,83111],{},"Ví dụ đời thường: giống quầy gọi món chung cho nhiều bếp.",[989,83113,83114],{},"Thêm vùng mới thì thêm lớp mới, không sửa chỗ gọi.",[981,83116,46261],{"id":46642},[986,83118,83119,83122,83125,83128],{},[989,83120,83121],{},"Abstract Factory tạo cả bộ nguyên liệu hợp nhau.",[989,83123,83124],{},"Ví dụ đời thường: giống combo bếp vùng nào đồ vùng đó.",[989,83126,83127],{},"Bảo đảm phô mai và sốt cùng một vùng.",[989,83129,83130],{},"Đổi vùng là đổi cả bộ một lần.",[981,83132,83134],{"id":83133},"decorator-và-giá","Decorator và giá",[986,83136,83137,83140,83143,83146],{},[989,83138,83139],{},"Decorator chồng thêm topping mà không sửa bánh gốc.",[989,83141,83142],{},"Ví dụ đời thường: giống thêm topping lên bánh có sẵn.",[989,83144,83145],{},"Mỗi lớp topping cộng thêm tiền của nó.",[989,83147,83148],{},"Giá cuối bằng giá bánh cộng mọi topping.",[1352,83150,83152],{"className":3538,"code":83151,"language":3540,"meta":1357,"style":1357},"# decorator cộng giá topping\nclass Banh:  # bánh gốc\n    def gia(self):\n        return 100  # giá gốc\nclass ThemPhomai:  # lớp topping bọc ngoài\n    def __init__(self, banh):\n        self.banh = banh  # giữ bánh gốc\n    def gia(self):\n        return self.banh.gia() + 20  # cộng thêm tiền\n",[992,83153,83154,83159,83164,83169,83174,83179,83184,83189,83193],{"__ignoreMap":1357},[1023,83155,83156],{"class":1362,"line":63},[1023,83157,83158],{},"# decorator cộng giá topping\n",[1023,83160,83161],{"class":1362,"line":68},[1023,83162,83163],{},"class Banh:  # bánh gốc\n",[1023,83165,83166],{"class":1362,"line":73},[1023,83167,83168],{},"    def gia(self):\n",[1023,83170,83171],{"class":1362,"line":78},[1023,83172,83173],{},"        return 100  # giá gốc\n",[1023,83175,83176],{"class":1362,"line":83},[1023,83177,83178],{},"class ThemPhomai:  # lớp topping bọc ngoài\n",[1023,83180,83181],{"class":1362,"line":88},[1023,83182,83183],{},"    def __init__(self, banh):\n",[1023,83185,83186],{"class":1362,"line":93},[1023,83187,83188],{},"        self.banh = banh  # giữ bánh gốc\n",[1023,83190,83191],{"class":1362,"line":98},[1023,83192,83168],{},[1023,83194,83195],{"class":1362,"line":103},[1023,83196,83197],{},"        return self.banh.gia() + 20  # cộng thêm tiền\n",[968,83199,1433],{"id":1432},[986,83201,83202,83205],{},[989,83203,83204],{},"Bánh 100 + phô mai 20 -> giá 120.",[989,83206,83207],{},"Đổi vùng Hà Nội sang Sài Gòn -> cả bộ nguyên liệu đổi theo.",[968,83209,1482],{"id":1481},[973,83211,1485,83212,83214,83215,1517],{},[1487,83213,4800],{}," (hoặc Java). Dùng code ngày 117. Nộp vào ",[992,83216,83217],{},"day-158-capstone\u002F",[981,83219,83221],{"id":83220},"bài-1-pizza-store-đa-vùng","Bài 1: Pizza Store đa vùng",[973,83223,83224],{},"Mở rộng project ngày 117 thành 4 vùng: NY, Chicago, California, Hà Nội.",[1099,83226,83227,83237],{},[1102,83228,83229],{},[1105,83230,83231,83234],{},[1108,83232,83233],{},"Vùng",[1108,83235,83236],{},"Đặc trưng nguyên liệu",[1118,83238,83239],{},[1105,83240,83241,83244],{},[1123,83242,83243],{},"Hà Nội",[1123,83245,83246],{},"Bột mỏng, sốt cà chua, phô mai mozzarella, thêm rau thơm",[973,83248,83249],{},"Mỗi vùng có 4 loại pizza. Test: mọi pizza của mọi vùng chỉ chứa nguyên liệu vùng đó (test sinh tự động cho 16 tổ hợp).",[981,83251,83253],{"id":83252},"bài-2-topping-combo-và-khuyến-mãi","Bài 2: Topping, combo và khuyến mãi",[2273,83255,83256,83259,83266,83282],{},[989,83257,83258],{},"8 topping (Decorator). Giới hạn tối đa 5 topping mỗi pizza: topping thứ 6 ném lỗi.",[989,83260,83261,83262,83265],{},"Combo: pizza + nước + khoai là ",[992,83263,83264],{},"ComboItem"," (Composite), giá combo giảm 10% tổng.",[989,83267,83268,83269,1656,83272,83275,83276,1656,83279,1517],{},"Khuyến mãi là Strategy: ",[992,83270,83271],{},"NoPromo",[992,83273,83274],{},"BuyTwoGetOne"," (rẻ nhất miễn phí), ",[992,83277,83278],{},"WeekdayDiscount(15%)",[992,83280,83281],{},"CouponCode(code, amount)",[989,83283,83284],{},"Hóa đơn in từng dòng, topping thụt lề, dòng giảm giá, tổng.",[1352,83286,83289],{"className":83287,"code":83288,"language":2241,"meta":1357},[2239],"Đơn: NY cheese + ExtraCheese, Chicago veggie, Hà Nội pepperoni + 2 topping; khuyến mãi BuyTwoGetOne\n-> pizza rẻ nhất miễn phí, in đúng hóa đơn\n",[992,83290,83288],{"__ignoreMap":1357},[981,83292,83294],{"id":83293},"bài-3-chỉ-số-thiết-kế-nâng-cao","Bài 3: Chỉ số thiết kế (nâng cao)",[2273,83296,83297,83300,83306],{},[989,83298,83299],{},"Đếm số lớp, số dòng, độ sâu kế thừa lớn nhất.",[989,83301,83302,83303,83305],{},"Thực hiện 3 thay đổi: thêm vùng Đà Nẵng, thêm topping trứng muối, thêm khuyến mãi \"sinh nhật giảm 50% 1 pizza\". Ghi ",[992,83304,14320],{}," từng cái.",[989,83307,83308,83310],{},[992,83309,83005],{},": sơ đồ, bảng pattern (Factory Method, Abstract Factory, Decorator, Composite, Strategy), chỗ thiết kế còn cứng.",[981,83312,2711],{"id":2710},[986,83314,83316,83322,83328,83334],{"className":83315},[2715],[989,83317,83319,83321],{"className":83318},[2719],[2721,83320],{"disabled":2723,"type":2724}," 16 tổ hợp vùng x loại pass test nguyên liệu.",[989,83323,83325,83327],{"className":83324},[2719],[2721,83326],{"disabled":2723,"type":2724}," Giới hạn topping và combo có test.",[989,83329,83331,83333],{"className":83330},[2719],[2721,83332],{"disabled":2723,"type":2724}," 4 khuyến mãi có test với số tiền cụ thể.",[989,83335,83337,83339,83340,1517],{"className":83336},[2719],[2721,83338],{"disabled":2723,"type":2724}," 3 thay đổi có số liệu ",[992,83341,14320],{},[968,83343,2890],{"id":2889},[2273,83345,83346,83349,83352,83355],{},[989,83347,83348],{},"Factory gom việc gì vào một chỗ?",[989,83350,83351],{},"Abstract Factory tạo mấy món một lần?",[989,83353,83354],{},"Decorator có sửa bánh gốc không?",[989,83356,83357],{},"Giá cuối tính thế nào?",[3014,83359],{},[973,83361,83362],{},"🌕 Bạn đã hoàn thành ngày 158. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,83364,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":83366},[83367,83368,83373,83374,83380],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":83369},[83370,83371,83372],{"id":21058,"depth":73,"text":20694},{"id":46642,"depth":73,"text":46261},{"id":83133,"depth":73,"text":83134},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":83375},[83376,83377,83378,83379],{"id":83220,"depth":73,"text":83221},{"id":83252,"depth":73,"text":83253},{"id":83293,"depth":73,"text":83294},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây Pizza Store nhiều vùng bằng Factory Method và Abstract Factory, chồng topping bằng Decorator và chốt bảng giá chính xác.",{},[5194],{"title":847,"description":83381},[17502,16071,12056],"ccJqda_efCLhOtbiH5CWLQs3UrsWFhF7RRBjYtwSj2c",{"id":83388,"title":852,"body":83389,"category":5189,"day":855,"description":83680,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":83681,"navigation":2723,"outcomes":3047,"path":853,"prerequisites":83682,"seo":83683,"stem":854,"tags":83684,"__hash__":83685},"challenges\u002Fchallenges\u002F159.capstone-patterns-home.md",{"type":965,"value":83390,"toc":83664},[83391,83393,83396,83398,83400,83414,83418,83432,83436,83450,83500,83502,83510,83512,83520,83524,83527,83558,83562,83583,83589,83593,83612,83614,83641,83643,83657,83659,83662],[968,83392,971],{"id":970},[973,83394,83395],{},"Bạn gom dàn máy rạp hát sau một nút. Một nút bấm là phim chạy.",[968,83397,979],{"id":978},[981,83399,24357],{"id":24356},[986,83401,83402,83405,83408,83411],{},[989,83403,83404],{},"Facade là một mặt tiền đơn giản che dàn máy phức tạp.",[989,83406,83407],{},"Định nghĩa: một hàm duy nhất gọi đúng thứ tự nhiều máy.",[989,83409,83410],{},"Ví dụ đời thường: giống nút \"xem phim\" trên remote.",[989,83412,83413],{},"Muốn xem phim không cần nhớ thứ tự 6 máy.",[981,83415,83417],{"id":83416},"command-và-macro","Command và macro",[986,83419,83420,83423,83426,83429],{},[989,83421,83422],{},"Command gói mỗi thao tác thành một lệnh riêng.",[989,83424,83425],{},"Macro là chuỗi lệnh chạy liền một lần.",[989,83427,83428],{},"Ví dụ đời thường: macro như danh sách việc phát một lần.",[989,83430,83431],{},"Mỗi lệnh biết cách undo của chính nó.",[981,83433,83435],{"id":83434},"undo-và-lỗi-giữa-chừng","Undo và lỗi giữa chừng",[986,83437,83438,83441,83444,83447],{},[989,83439,83440],{},"Undo đưa mọi máy về đúng trạng thái trước đó.",[989,83442,83443],{},"Ví dụ đời thường: giống nút hoàn tác trong Word.",[989,83445,83446],{},"Máy lỗi giữa macro thì dừng và báo rõ máy nào.",[989,83448,83449],{},"Ghi nhật ký để mất điện vẫn chạy lại được.",[1352,83451,83453],{"className":3538,"code":83452,"language":3540,"meta":1357,"style":1357},"# lệnh có undo đơn giản\nclass LenBatDen:  # một lệnh cụ thể\n    def chay(self):\n        print(\"tắt đèn\")  # làm việc\n    def undo(self):\n        print(\"bật đèn lại\")  # hoàn tác\nmacro = [LenBatDen()]  # chuỗi lệnh xem phim\nfor lenh in macro:\n    lenh.chay()  # chạy từng lệnh\n",[992,83454,83455,83460,83465,83470,83475,83480,83485,83490,83495],{"__ignoreMap":1357},[1023,83456,83457],{"class":1362,"line":63},[1023,83458,83459],{},"# lệnh có undo đơn giản\n",[1023,83461,83462],{"class":1362,"line":68},[1023,83463,83464],{},"class LenBatDen:  # một lệnh cụ thể\n",[1023,83466,83467],{"class":1362,"line":73},[1023,83468,83469],{},"    def chay(self):\n",[1023,83471,83472],{"class":1362,"line":78},[1023,83473,83474],{},"        print(\"tắt đèn\")  # làm việc\n",[1023,83476,83477],{"class":1362,"line":83},[1023,83478,83479],{},"    def undo(self):\n",[1023,83481,83482],{"class":1362,"line":88},[1023,83483,83484],{},"        print(\"bật đèn lại\")  # hoàn tác\n",[1023,83486,83487],{"class":1362,"line":93},[1023,83488,83489],{},"macro = [LenBatDen()]  # chuỗi lệnh xem phim\n",[1023,83491,83492],{"class":1362,"line":98},[1023,83493,83494],{},"for lenh in macro:\n",[1023,83496,83497],{"class":1362,"line":103},[1023,83498,83499],{},"    lenh.chay()  # chạy từng lệnh\n",[968,83501,1433],{"id":1432},[986,83503,83504,83507],{},[989,83505,83506],{},"Một nút xem phim -> 6 máy về đúng trạng thái chiếu.",[989,83508,83509],{},"Undo macro -> mọi máy về trạng thái ban đầu.",[968,83511,1482],{"id":1481},[973,83513,1485,83514,83516,83517,1517],{},[1487,83515,4800],{}," (hoặc Java). Dùng code ngày 125. Nộp vào ",[992,83518,83519],{},"day-159-capstone\u002F",[981,83521,83523],{"id":83522},"bài-1-hoàn-thiện-rạp-hát","Bài 1: Hoàn thiện rạp hát",[973,83525,83526],{},"Mở rộng project ngày 125:",[2273,83528,83529,83540,83551],{},[989,83530,83531,83532,83535,83536,83539],{},"Thêm 2 thiết bị: ",[992,83533,83534],{},"SmartBlinds"," (rèm, mở theo %), ",[992,83537,83538],{},"Thermostat"," (nhiệt độ).",[989,83541,83542,83543,1656,83545,1656,83547,83550],{},"Facade có 3 chế độ: ",[992,83544,70725],{},[992,83546,70729],{},[992,83548,83549],{},"gaming",". Chuyển giữa các chế độ chỉ bật\u002Ftắt phần khác biệt.",[989,83552,83553,83554,83557],{},"Mọi thiết bị có thể lỗi (",[992,83555,83556],{},"DeviceError",") với xác suất cấu hình được.",[981,83559,83561],{"id":83560},"bài-2-macro-an-toàn","Bài 2: Macro an toàn",[2273,83563,83564,83567,83577],{},[989,83565,83566],{},"Macro lỗi giữa chừng: dừng, hoàn tác các lệnh đã chạy, báo rõ thiết bị lỗi và bước lỗi.",[989,83568,83569,83572,83573,83576],{},[1487,83570,83571],{},"Nhật ký bền:"," mỗi lệnh ghi vào ",[992,83574,83575],{},"journal.log"," trước khi chạy. Mất điện (giết tiến trình) giữa macro: khởi động lại đọc nhật ký, đưa mọi thiết bị về trạng thái nhất quán (hoàn tác nửa macro dở).",[989,83578,83579,83580,83582],{},"Test tính chất: 1000 chuỗi lệnh ngẫu nhiên với lỗi ngẫu nhiên, sau khi hoàn tác hết thì ",[992,83581,70761],{}," bằng trạng thái ban đầu.",[1352,83584,83587],{"className":83585,"code":83586,"language":2241,"meta":1357},[2239],"partyOn, thiết bị thứ 3 lỗi -> 2 thiết bị đầu được hoàn tác, báo \"Amplifier lỗi ở bước 3\u002F5\"\n",[992,83588,83586],{"__ignoreMap":1357},[981,83590,83592],{"id":83591},"bài-3-lịch-và-remote-từ-xa-nâng-cao","Bài 3: Lịch và remote từ xa (nâng cao)",[2273,83594,83595,83604,83607],{},[989,83596,83597,83600,83601,83603],{},[992,83598,83599],{},"Scheduler",": đặt lệnh chạy lúc giờ cụ thể (ví dụ ",[992,83602,70725],{}," lúc 20:00). Dùng đồng hồ giả để test.",[989,83605,83606],{},"Remote từ xa: server TCP nhận lệnh dạng text, chạy qua Command. Gọi được từ 2 client cùng lúc mà không hỏng trạng thái.",[989,83608,83609,83611],{},[992,83610,83005],{},": sơ đồ, vai trò Facade, Command, Memento nếu dùng, cơ chế nhật ký.",[981,83613,2711],{"id":2710},[986,83615,83617,83623,83629,83635],{"className":83616},[2715],[989,83618,83620,83622],{"className":83619},[2719],[2721,83621],{"disabled":2723,"type":2724}," Macro lỗi giữa chừng hoàn tác đúng.",[989,83624,83626,83628],{"className":83625},[2719],[2721,83627],{"disabled":2723,"type":2724}," Giết tiến trình giữa macro, khởi động lại về trạng thái nhất quán.",[989,83630,83632,83634],{"className":83631},[2719],[2721,83633],{"disabled":2723,"type":2724}," Test tính chất 1000 chuỗi pass.",[989,83636,83638,83640],{"className":83637},[2719],[2721,83639],{"disabled":2723,"type":2724}," Scheduler test bằng đồng hồ giả.",[968,83642,2890],{"id":2889},[2273,83644,83645,83648,83651,83654],{},[989,83646,83647],{},"Facade che cái gì?",[989,83649,83650],{},"Macro gồm những gì?",[989,83652,83653],{},"Undo phải đưa máy về đâu?",[989,83655,83656],{},"Nhật ký lệnh để làm gì?",[3014,83658],{},[973,83660,83661],{},"🌕 Bạn đã hoàn thành ngày 159. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,83663,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":83665},[83666,83667,83672,83673,83679],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":83668},[83669,83670,83671],{"id":24356,"depth":73,"text":24357},{"id":83416,"depth":73,"text":83417},{"id":83434,"depth":73,"text":83435},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":83674},[83675,83676,83677,83678],{"id":83522,"depth":73,"text":83523},{"id":83560,"depth":73,"text":83561},{"id":83591,"depth":73,"text":83592},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Gom dàn máy rạp hát sau một nút bấm Facade, lập trình macro xem phim bằng Command có undo và xử lý lỗi từng thiết bị.",{},[5194],{"title":852,"description":83680},[17502,24848,23084],"-YmkCTpNjViF-MTbnmFGDQNUvdG6nXD7BJio6_cOKrI",{"id":83687,"title":857,"body":83688,"category":8797,"day":860,"description":84022,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":84023,"navigation":2723,"outcomes":3047,"path":858,"prerequisites":84024,"seo":84025,"stem":859,"tags":84026,"__hash__":84028},"challenges\u002Fchallenges\u002F160.capstone-social.md",{"type":965,"value":83689,"toc":84006},[83690,83692,83695,83697,83701,83715,83719,83733,83737,83751,83786,83788,83796,83798,83806,83810,83855,83858,83862,83914,83920,83924,83949,83951,83983,83985,83999,84001,84004],[968,83691,971],{"id":970},[973,83693,83694],{},"Bạn dựng mạng xã hội mini chạy được. Có gợi ý bạn và bảng tin.",[968,83696,979],{"id":978},[981,83698,83700],{"id":83699},"đồ-thị-theo-dõi","Đồ thị theo dõi",[986,83702,83703,83706,83709,83712],{},[989,83704,83705],{},"Mỗi người là một đỉnh, theo dõi là một mũi tên.",[989,83707,83708],{},"Ví dụ đời thường: giống sơ đồ ai theo dõi ai.",[989,83710,83711],{},"Cần hỏi nhanh: đang theo dõi ai, ai theo dõi mình.",[989,83713,83714],{},"Bạn chung là người cả hai cùng theo dõi.",[981,83716,83718],{"id":83717},"gợi-ý-bạn-bằng-bfs","Gợi ý bạn bằng BFS",[986,83720,83721,83724,83727,83730],{},[989,83722,83723],{},"BFS lan hai tầng từ bạn để tìm ứng viên.",[989,83725,83726],{},"Chấm điểm bằng số bạn chung và tương tác.",[989,83728,83729],{},"Ví dụ đời thường: giống giới thiệu bạn của bạn.",[989,83731,83732],{},"Trả top 10 kèm lý do gợi ý.",[981,83734,83736],{"id":83735},"bảng-tin-và-chống-spam","Bảng tin và chống spam",[986,83738,83739,83742,83745,83748],{},[989,83740,83741],{},"Bảng tin gom bài của người đang theo dõi.",[989,83743,83744],{},"Chấm mỗi bài bằng độ mới và tương tác.",[989,83746,83747],{},"Ví dụ đời thường: giống chọn tin hot lên đầu.",[989,83749,83750],{},"Bloom filter chặn link độc trước khi đăng.",[1352,83752,83754],{"className":3538,"code":83753,"language":3540,"meta":1357,"style":1357},"# tìm bạn chung đơn giản\ndef ban_chung(a, b):\n    return a & b  # giao hai tập theo dõi\nme = {\"An\", \"Binh\"}\nban = {\"Binh\", \"Chi\"}\nprint(ban_chung(me, ban))  # ra {'Binh'}\n",[992,83755,83756,83761,83766,83771,83776,83781],{"__ignoreMap":1357},[1023,83757,83758],{"class":1362,"line":63},[1023,83759,83760],{},"# tìm bạn chung đơn giản\n",[1023,83762,83763],{"class":1362,"line":68},[1023,83764,83765],{},"def ban_chung(a, b):\n",[1023,83767,83768],{"class":1362,"line":73},[1023,83769,83770],{},"    return a & b  # giao hai tập theo dõi\n",[1023,83772,83773],{"class":1362,"line":78},[1023,83774,83775],{},"me = {\"An\", \"Binh\"}\n",[1023,83777,83778],{"class":1362,"line":83},[1023,83779,83780],{},"ban = {\"Binh\", \"Chi\"}\n",[1023,83782,83783],{"class":1362,"line":88},[1023,83784,83785],{},"print(ban_chung(me, ban))  # ra {'Binh'}\n",[968,83787,1433],{"id":1432},[986,83789,83790,83793],{},[989,83791,83792],{},"A theo dõi B, B theo dõi C -> gợi ý C cho A.",[989,83794,83795],{},"Bài mới nhiều like -> xếp hạng cao hơn.",[968,83797,1482],{"id":1481},[973,83799,1485,83800,83802,83803,1517],{},[1487,83801,13531],{}," (hoặc Go). Dùng code đồ thị, heap, Bloom, cache các ngày trước. Nộp vào ",[992,83804,83805],{},"day-160-capstone\u002F",[981,83807,83809],{"id":83808},"bài-1-mô-hình-dữ-liệu-và-api","Bài 1: Mô hình dữ liệu và API",[1352,83811,83813],{"className":3538,"code":83812,"language":3540,"meta":1357,"style":1357},"class SocialGraph:\n    def follow(self, a: int, b: int): ...\n    def unfollow(self, a: int, b: int): ...\n    def following(self, a: int) -> set[int]: ...\n    def followers(self, a: int) -> set[int]: ...\n    def mutuals(self, a: int, b: int) -> set[int]: ...   # cùng theo dõi\n    def post(self, user: int, text: str, ts: float) -> int: ...\n    def like(self, user: int, post_id: int): ...\n",[992,83814,83815,83820,83825,83830,83835,83840,83845,83850],{"__ignoreMap":1357},[1023,83816,83817],{"class":1362,"line":63},[1023,83818,83819],{},"class SocialGraph:\n",[1023,83821,83822],{"class":1362,"line":68},[1023,83823,83824],{},"    def follow(self, a: int, b: int): ...\n",[1023,83826,83827],{"class":1362,"line":73},[1023,83828,83829],{},"    def unfollow(self, a: int, b: int): ...\n",[1023,83831,83832],{"class":1362,"line":78},[1023,83833,83834],{},"    def following(self, a: int) -> set[int]: ...\n",[1023,83836,83837],{"class":1362,"line":83},[1023,83838,83839],{},"    def followers(self, a: int) -> set[int]: ...\n",[1023,83841,83842],{"class":1362,"line":88},[1023,83843,83844],{},"    def mutuals(self, a: int, b: int) -> set[int]: ...   # cùng theo dõi\n",[1023,83846,83847],{"class":1362,"line":93},[1023,83848,83849],{},"    def post(self, user: int, text: str, ts: float) -> int: ...\n",[1023,83851,83852],{"class":1362,"line":98},[1023,83853,83854],{},"    def like(self, user: int, post_id: int): ...\n",[973,83856,83857],{},"Sinh dữ liệu: 100.000 user, phân bố theo dõi theo luật lũy thừa (vài người rất nổi tiếng), 10^6 bài.",[981,83859,83861],{"id":83860},"bài-2-gợi-ý-theo-dõi-và-bảng-tin","Bài 2: Gợi ý theo dõi và bảng tin",[1099,83863,83864,83873],{},[1102,83865,83866],{},[1105,83867,83868,83871],{},[1108,83869,83870],{},"Tính năng",[1108,83872,2547],{},[1118,83874,83875,83885,83898],{},[1105,83876,83877,83882],{},[1123,83878,83879],{},[992,83880,83881],{},"suggest(a, k=10)",[1123,83883,83884],{},"BFS 2 tầng. Điểm = số bạn chung + 0.1 x log(followers). Không gợi người đã theo dõi. Trả lý do \"3 bạn chung: X, Y, Z\"",[1105,83886,83887,83892],{},[1123,83888,83889],{},[992,83890,83891],{},"feed(a, k=20)",[1123,83893,83894,83895,83897],{},"Bài của người ",[992,83896,6207],{}," theo dõi. Điểm = like \u002F (giờ + 2)^1.5. Gộp K danh sách bằng heap",[1105,83899,83900,83903],{},[1123,83901,83902],{},"Người nổi tiếng",[1123,83904,83905,83906,83909,83910,83913],{},"Bài của người trên 10.000 follower ",[1487,83907,83908],{},"kéo"," lúc đọc, còn lại ",[1487,83911,83912],{},"đẩy"," vào hộp thư lúc đăng (fan-out on write)",[1352,83915,83918],{"className":83916,"code":83917,"language":2241,"meta":1357},[2239],"suggest cho user mới 0 theo dõi -> trả người nổi tiếng nhất\nfeed không chứa bài của người đã unfollow\n",[992,83919,83917],{"__ignoreMap":1357},[981,83921,83923],{"id":83922},"bài-3-chống-spam-và-đo-nâng-cao","Bài 3: Chống spam và đo (nâng cao)",[2273,83925,83926,83929,83936,83944],{},[989,83927,83928],{},"Bloom filter 10^6 link độc. Bài chứa link độc bị chặn khi đăng.",[989,83930,83931,83932,83935],{},"Cache LRU cho ",[992,83933,83934],{},"feed"," 60 giây, xóa khi người mình theo dõi đăng bài.",[989,83937,83938,83939,1509,83941,83943],{},"Đo p50\u002Fp99 của ",[992,83940,27125],{},[992,83942,83934],{}," với 1000 truy vấn ngẫu nhiên. So fan-out on write và on read cho người nổi tiếng: bộ nhớ và độ trễ.",[989,83945,83946,83948],{},[992,83947,17400],{},": sơ đồ, bảng số liệu, đánh đổi push\u002Fpull.",[981,83950,2711],{"id":2710},[986,83952,83954,83960,83971,83977],{"className":83953},[2715],[989,83955,83957,83959],{"className":83956},[2719],[2721,83958],{"disabled":2723,"type":2724}," API có test cho follow\u002Funfollow\u002Fmutuals.",[989,83961,83963,2308,83965,83967,83968,83970],{"className":83962},[2719],[2721,83964],{"disabled":2723,"type":2724},[992,83966,27125],{}," có lý do, ",[992,83969,83934],{}," đúng thứ tự điểm.",[989,83972,83974,83976],{"className":83973},[2719],[2721,83975],{"disabled":2723,"type":2724}," Bảng push vs pull có số thật.",[989,83978,83980,83982],{"className":83979},[2719],[2721,83981],{"disabled":2723,"type":2724}," Link độc bị chặn, có test.",[968,83984,2890],{"id":2889},[2273,83986,83987,83990,83993,83996],{},[989,83988,83989],{},"Mũi tên theo dõi chỉ hướng nào?",[989,83991,83992],{},"BFS gợi ý bạn đi mấy tầng?",[989,83994,83995],{},"Bảng tin chấm bài bằng gì?",[989,83997,83998],{},"Bloom filter đặt ở đâu?",[3014,84000],{},[973,84002,84003],{},"🌕 Bạn đã hoàn thành ngày 160. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,84005,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":84007},[84008,84009,84014,84015,84021],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":84010},[84011,84012,84013],{"id":83699,"depth":73,"text":83700},{"id":83717,"depth":73,"text":83718},{"id":83735,"depth":73,"text":83736},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":84016},[84017,84018,84019,84020],{"id":83808,"depth":73,"text":83809},{"id":83860,"depth":73,"text":83861},{"id":83922,"depth":73,"text":83923},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Dựng mạng xã hội mini: đồ thị theo dõi, gợi ý bạn bằng BFS, bảng tin xếp hạng và chống spam bằng Bloom filter.",{},[14055,15144],{"title":857,"description":84022},[17502,29786,84027],"social","5caojmkQm79WjK-yMT8zFnbftIzWvXyW0DevvTBVJf8",{"id":84030,"title":862,"body":84031,"category":8797,"day":865,"description":84602,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":84603,"navigation":2723,"outcomes":3047,"path":863,"prerequisites":84604,"seo":84605,"stem":864,"tags":84606,"__hash__":84608},"challenges\u002Fchallenges\u002F161.phong-van-algo-1.md",{"type":965,"value":84032,"toc":84586},[84033,84035,84038,84040,84044,84058,84062,84076,84080,84094,84154,84156,84170,84172,84183,84186,84190,84449,84455,84459,84503,84509,84513,84534,84536,84563,84565,84579,84581,84584],[968,84034,971],{"id":970},[973,84036,84037],{},"Bạn luyện bài mảng chuỗi hay gặp nhất. Nói to suy nghĩ khi làm bài.",[968,84039,979],{"id":978},[981,84041,84043],{"id":84042},"two-pointers-đối-đầu","Two pointers đối đầu",[986,84045,84046,84049,84052,84055],{},[989,84047,84048],{},"Hai con trỏ đi từ hai đầu vào giữa.",[989,84050,84051],{},"Hợp mảng đã sắp như tìm cặp tổng.",[989,84053,84054],{},"Ví dụ đời thường: giống hai người đi từ hai đầu cầu.",[989,84056,84057],{},"Gặp trùng thì bỏ qua để tránh đáp án lặp.",[981,84059,84061],{"id":84060},"two-pointers-đồng-hướng","Two pointers đồng hướng",[986,84063,84064,84067,84070,84073],{},[989,84065,84066],{},"Hai con trỏ cùng đi một chiều, một nhanh một chậm.",[989,84068,84069],{},"Hợp dồn số 0 về cuối hoặc xóa tại chỗ.",[989,84071,84072],{},"Ví dụ đời thường: giống hai người chạy cùng đường.",[989,84074,84075],{},"Chỉ dùng bộ nhớ phụ hằng số.",[981,84077,84079],{"id":84078},"sliding-window-và-chuỗi","Sliding window và chuỗi",[986,84081,84082,84085,84088,84091],{},[989,84083,84084],{},"Sliding window là cửa sổ trượt trên mảng.",[989,84086,84087],{},"Cửa cố định hợp đoạn dài k, cửa co giãn hợp ràng buộc.",[989,84089,84090],{},"Ví dụ đời thường: giống khung nhìn trượt trên thước.",[989,84092,84093],{},"Chuỗi hay gặp: đảo từ, đối xứng, tiền tố chung.",[1352,84095,84097],{"className":3538,"code":84096,"language":3540,"meta":1357,"style":1357},"# hai con trỏ tìm cặp tổng\ndef cap_tong(a, k):\n    t, p = 0, len(a) - 1  # hai đầu mảng\n    while t \u003C p:  # chưa gặp nhau\n        s = a[t] + a[p]  # tổng hiện tại\n        if s == k:  # trúng mục tiêu\n            return (t, p)\n        if s \u003C k:  # tổng nhỏ, tăng trái\n            t += 1\n        else:  # tổng lớn, giảm phải\n            p -= 1\n",[992,84098,84099,84104,84109,84114,84119,84124,84129,84134,84139,84144,84149],{"__ignoreMap":1357},[1023,84100,84101],{"class":1362,"line":63},[1023,84102,84103],{},"# hai con trỏ tìm cặp tổng\n",[1023,84105,84106],{"class":1362,"line":68},[1023,84107,84108],{},"def cap_tong(a, k):\n",[1023,84110,84111],{"class":1362,"line":73},[1023,84112,84113],{},"    t, p = 0, len(a) - 1  # hai đầu mảng\n",[1023,84115,84116],{"class":1362,"line":78},[1023,84117,84118],{},"    while t \u003C p:  # chưa gặp nhau\n",[1023,84120,84121],{"class":1362,"line":83},[1023,84122,84123],{},"        s = a[t] + a[p]  # tổng hiện tại\n",[1023,84125,84126],{"class":1362,"line":88},[1023,84127,84128],{},"        if s == k:  # trúng mục tiêu\n",[1023,84130,84131],{"class":1362,"line":93},[1023,84132,84133],{},"            return (t, p)\n",[1023,84135,84136],{"class":1362,"line":98},[1023,84137,84138],{},"        if s \u003C k:  # tổng nhỏ, tăng trái\n",[1023,84140,84141],{"class":1362,"line":103},[1023,84142,84143],{},"            t += 1\n",[1023,84145,84146],{"class":1362,"line":108},[1023,84147,84148],{},"        else:  # tổng lớn, giảm phải\n",[1023,84150,84151],{"class":1362,"line":113},[1023,84152,84153],{},"            p -= 1\n",[968,84155,1433],{"id":1432},[986,84157,84158,84164],{},[989,84159,80600,84160,84163],{},[992,84161,84162],{},"[1, 2, 3, 4]",", k = 5 -> cặp (1, 3) vì 1 + 4 = 5.",[989,84165,80600,84166,84169],{},[992,84167,84168],{},"\"hello\""," đảo từ đơn -> vẫn rõ từng từ.",[968,84171,1482],{"id":1481},[973,84173,84174,84175,84178,84179,84182],{},"Luyện phỏng vấn: mỗi bài ",[1487,84176,84177],{},"tự bấm giờ 25 phút",", viết bằng ngôn ngữ bạn định dùng khi phỏng vấn. Nộp vào ",[992,84180,84181],{},"day-161\u002F",", mỗi bài 1 file có test.",[973,84184,84185],{},"Với mỗi bài, trước khi code, viết comment 3 dòng: ý tưởng, độ phức tạp thời gian, độ phức tạp bộ nhớ.",[981,84187,84189],{"id":84188},"bài-1-hai-con-trỏ","Bài 1: Hai con trỏ",[1099,84191,84192,84204],{},[1102,84193,84194],{},[1105,84195,84196,84199,84202],{},[1108,84197,84198],{},"Bài",[1108,84200,84201],{},"Đề",[1108,84203,2194],{},[1118,84205,84206,84289,84385,84396],{},[1105,84207,84208,84211,84214],{},[1123,84209,84210],{},"1a",[1123,84212,84213],{},"Mảng đã sắp, tìm mọi bộ 3 số có tổng 0, không trùng",[1123,84215,84216],{},[1023,84217,84219,84242],{"className":84218},[1026],[1023,84220,84222],{"className":84221},[1030],[1032,84223,84224],{"xmlns":1034},[1036,84225,84226,84240],{},[1039,84227,84228,84230,84232,84238],{},[1042,84229,1044],{},[1046,84231,1049],{"stretchy":1048},[2327,84233,84234,84236],{},[1042,84235,1262],{},[1051,84237,2457],{},[1046,84239,1056],{"stretchy":1048},[1058,84241,2839],{"encoding":1060},[1023,84243,84245],{"className":84244,"ariaHidden":1066},[1065],[1023,84246,84248,84251,84254,84257,84286],{"className":84247},[1070],[1023,84249],{"className":84250,"style":2476},[1074],[1023,84252,1044],{"className":84253,"style":1081},[1079,1080],[1023,84255,1049],{"className":84256},[1085],[1023,84258,84260,84263],{"className":84259},[1079],[1023,84261,1262],{"className":84262},[1079,1080],[1023,84264,84266],{"className":84265},[2383],[1023,84267,84269],{"className":84268},[2387],[1023,84270,84272],{"className":84271},[2391],[1023,84273,84275],{"className":84274,"style":2369},[2395],[1023,84276,84277,84280],{"style":2398},[1023,84278],{"className":84279,"style":2403},[2402],[1023,84281,84283],{"className":84282},[2407,2408,2409,2410],[1023,84284,2457],{"className":84285},[1079,2410],[1023,84287,1056],{"className":84288},[1092],[1105,84290,84291,84294,84297],{},[1123,84292,84293],{},"1b",[1123,84295,84296],{},"Chuỗi, kiểm tra đối xứng khi chỉ xét chữ và số, bỏ qua hoa thường",[1123,84298,84299,1656,84342,8695],{},[1023,84300,84302,84321],{"className":84301},[1026],[1023,84303,84305],{"className":84304},[1030],[1032,84306,84307],{"xmlns":1034},[1036,84308,84309,84319],{},[1039,84310,84311,84313,84315,84317],{},[1042,84312,1044],{},[1046,84314,1049],{"stretchy":1048},[1042,84316,1262],{},[1046,84318,1056],{"stretchy":1048},[1058,84320,1267],{"encoding":1060},[1023,84322,84324],{"className":84323,"ariaHidden":1066},[1065],[1023,84325,84327,84330,84333,84336,84339],{"className":84326},[1070],[1023,84328],{"className":84329,"style":1075},[1074],[1023,84331,1044],{"className":84332,"style":1081},[1079,1080],[1023,84334,1049],{"className":84335},[1085],[1023,84337,1262],{"className":84338},[1079,1080],[1023,84340,1056],{"className":84341},[1092],[1023,84343,84345,84364],{"className":84344},[1026],[1023,84346,84348],{"className":84347},[1030],[1032,84349,84350],{"xmlns":1034},[1036,84351,84352,84362],{},[1039,84353,84354,84356,84358,84360],{},[1042,84355,1044],{},[1046,84357,1049],{"stretchy":1048},[1051,84359,1053],{},[1046,84361,1056],{"stretchy":1048},[1058,84363,1061],{"encoding":1060},[1023,84365,84367],{"className":84366,"ariaHidden":1066},[1065],[1023,84368,84370,84373,84376,84379,84382],{"className":84369},[1070],[1023,84371],{"className":84372,"style":1075},[1074],[1023,84374,1044],{"className":84375,"style":1081},[1079,1080],[1023,84377,1049],{"className":84378},[1085],[1023,84380,1053],{"className":84381},[1079],[1023,84383,1056],{"className":84384},[1092],[1105,84386,84387,84390,84393],{},[1123,84388,84389],{},"1c",[1123,84391,84392],{},"Mảng, dồn mọi số 0 về cuối, giữ thứ tự các số khác",[1123,84394,84395],{},"Tại chỗ",[1105,84397,84398,84401,84404],{},[1123,84399,84400],{},"1d",[1123,84402,84403],{},"Mảng chiều cao cột, tìm 2 cột chứa nhiều nước nhất",[1123,84405,84406],{},[1023,84407,84409,84428],{"className":84408},[1026],[1023,84410,84412],{"className":84411},[1030],[1032,84413,84414],{"xmlns":1034},[1036,84415,84416,84426],{},[1039,84417,84418,84420,84422,84424],{},[1042,84419,1044],{},[1046,84421,1049],{"stretchy":1048},[1042,84423,1262],{},[1046,84425,1056],{"stretchy":1048},[1058,84427,1267],{"encoding":1060},[1023,84429,84431],{"className":84430,"ariaHidden":1066},[1065],[1023,84432,84434,84437,84440,84443,84446],{"className":84433},[1070],[1023,84435],{"className":84436,"style":1075},[1074],[1023,84438,1044],{"className":84439,"style":1081},[1079,1080],[1023,84441,1049],{"className":84442},[1085],[1023,84444,1262],{"className":84445},[1079,1080],[1023,84447,1056],{"className":84448},[1092],[1352,84450,84453],{"className":84451,"code":84452,"language":2241,"meta":1357},[2239],"1a: [-1,0,1,2,-1,-4] -> [[-1,-1,2], [-1,0,1]]\n1b: \"A man, a plan, a canal: Panama\" -> true\n1c: [0,1,0,3,12] -> [1,3,12,0,0]\n1d: [1,8,6,2,5,4,8,3,7] -> 49\n",[992,84454,84452],{"__ignoreMap":1357},[981,84456,84458],{"id":84457},"bài-2-cửa-sổ-trượt","Bài 2: Cửa sổ trượt",[1099,84460,84461,84469],{},[1102,84462,84463],{},[1105,84464,84465,84467],{},[1108,84466,84198],{},[1108,84468,84201],{},[1118,84470,84471,84479,84490],{},[1105,84472,84473,84476],{},[1123,84474,84475],{},"2a",[1123,84477,84478],{},"Chuỗi con dài nhất không lặp ký tự",[1105,84480,84481,84484],{},[1123,84482,84483],{},"2b",[1123,84485,84486,84487],{},"Mảng dương, đoạn con ngắn nhất có tổng ≥ ",[992,84488,84489],{},"target",[1105,84491,84492,84495],{},[1123,84493,84494],{},"2c",[1123,84496,84497,84498,84500,84501],{},"Mọi vị trí bắt đầu của hoán vị chuỗi ",[992,84499,973],{}," trong chuỗi ",[992,84502,29577],{},[1352,84504,84507],{"className":84505,"code":84506,"language":2241,"meta":1357},[2239],"2a: \"abcabcbb\" -> 3\n2b: target=7, [2,3,1,2,4,3] -> 2\n2c: s=\"cbaebabacd\", p=\"abc\" -> [0, 6]\n",[992,84508,84506],{"__ignoreMap":1357},[981,84510,84512],{"id":84511},"bài-3-chuỗi-và-mô-phỏng-phỏng-vấn-nâng-cao","Bài 3: Chuỗi và mô phỏng phỏng vấn (nâng cao)",[2273,84514,84515,84525,84528,84531],{},[989,84516,84517,84518,84521,84522,1517],{},"Đảo thứ tự từ trong câu, bỏ khoảng trắng thừa: ",[992,84519,84520],{},"\"  the sky  is blue \""," -> ",[992,84523,84524],{},"\"blue is sky the\"",[989,84526,84527],{},"Tiền tố chung dài nhất của mảng chuỗi.",[989,84529,84530],{},"Nhóm các từ là hoán vị của nhau.",[989,84532,84533],{},"Nhờ 1 người đóng vai người phỏng vấn cho 1 bài bất kỳ (hoặc tự ghi âm và nói to suy nghĩ). Ghi lại: thời gian, có hỏi làm rõ đề không, có tự kiểm tra biên không.",[981,84535,2711],{"id":2710},[986,84537,84539,84545,84551,84557],{"className":84538},[2715],[989,84540,84542,84544],{"className":84541},[2719],[2721,84543],{"disabled":2723,"type":2724}," 10 bài có test gồm ca biên (rỗng, 1 phần tử, toàn trùng).",[989,84546,84548,84550],{"className":84547},[2719],[2721,84549],{"disabled":2723,"type":2724}," Mỗi bài có comment độ phức tạp.",[989,84552,84554,84556],{"className":84553},[2719],[2721,84555],{"disabled":2723,"type":2724}," Bảng thời gian thực tế mỗi bài so với 25 phút.",[989,84558,84560,84562],{"className":84559},[2719],[2721,84561],{"disabled":2723,"type":2724}," Có ghi chú buổi phỏng vấn thử.",[968,84564,2890],{"id":2889},[2273,84566,84567,84570,84573,84576],{},[989,84568,84569],{},"Two pointers đối đầu hợp mảng nào?",[989,84571,84572],{},"Đồng hướng dùng mấy chiều đi?",[989,84574,84575],{},"Cửa sổ co giãn dùng khi nào?",[989,84577,84578],{},"Think-aloud gồm mấy lượt?",[3014,84580],{},[973,84582,84583],{},"🌕 Bạn đã hoàn thành ngày 161. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,84585,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":84587},[84588,84589,84594,84595,84601],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":84590},[84591,84592,84593],{"id":84042,"depth":73,"text":84043},{"id":84060,"depth":73,"text":84061},{"id":84078,"depth":73,"text":84079},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":84596},[84597,84598,84599,84600],{"id":84188,"depth":73,"text":84189},{"id":84457,"depth":73,"text":84458},{"id":84511,"depth":73,"text":84512},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện phỏng vấn mảng và chuỗi: two pointers, sliding window, tiền tố, trình bày think-aloud và phân tích độ phức tạp.",{},[3050,4669],{"title":862,"description":84602},[68137,3053,84607],"string","wMAZcHbCGxq1gMow7Xx75c-Rtx_g8V9PSprvIWylbGs",{"id":84610,"title":867,"body":84611,"category":8797,"day":870,"description":85493,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":85494,"navigation":2723,"outcomes":3047,"path":868,"prerequisites":85495,"seo":85496,"stem":869,"tags":85497,"__hash__":85498},"challenges\u002Fchallenges\u002F162.phong-van-algo-2.md",{"type":965,"value":84612,"toc":85477},[84613,84615,84618,84620,84624,84638,84642,84656,84660,84717,84767,84769,84777,84779,84789,84793,85009,85015,85019,85186,85192,85196,85422,85424,85454,85456,85470,85472,85475],[968,84614,971],{"id":970},[973,84616,84617],{},"Bạn luyện bài cây và heap. Vẽ hình heap khi dry-run.",[968,84619,979],{"id":978},[981,84621,84623],{"id":84622},"duyệt-và-biến-đổi-bst","Duyệt và biến đổi BST",[986,84625,84626,84629,84632,84635],{},[989,84627,84628],{},"BST là trái nhỏ hơn gốc, phải lớn hơn gốc.",[989,84630,84631],{},"Hay gặp: liệt kê trong khoảng, tìm tổ tiên chung.",[989,84633,84634],{},"Ví dụ đời thường: giống tìm sách trong kệ xếp theo tên.",[989,84636,84637],{},"Cắt tỉa bỏ nhánh ngoài khoảng cho nhanh.",[981,84639,84641],{"id":84640},"kiểm-tra-bst-hợp-lệ","Kiểm tra BST hợp lệ",[986,84643,84644,84647,84650,84653],{},[989,84645,84646],{},"So cha con thôi là chưa đủ.",[989,84648,84649],{},"Phải dùng khoảng chặn từ gốc truyền xuống.",[989,84651,84652],{},"Ví dụ đời thường: giống kiểm tra cả dòng họ, không chỉ cha con.",[989,84654,84655],{},"Nút sai ở tầng sâu dễ lọt nếu chỉ so gần.",[981,84657,84659],{"id":84658},"heap-và-top-k","Heap và top-k",[986,84661,84662,84665,84711,84714],{},[989,84663,84664],{},"Heap lấy lớn nhất hoặc nhỏ nhất rất nhanh.",[989,84666,84667,84668,1517],{},"Heapify biến mảng thành heap trong ",[1023,84669,84671,84690],{"className":84670},[1026],[1023,84672,84674],{"className":84673},[1030],[1032,84675,84676],{"xmlns":1034},[1036,84677,84678,84688],{},[1039,84679,84680,84682,84684,84686],{},[1042,84681,1044],{},[1046,84683,1049],{"stretchy":1048},[1042,84685,1262],{},[1046,84687,1056],{"stretchy":1048},[1058,84689,1267],{"encoding":1060},[1023,84691,84693],{"className":84692,"ariaHidden":1066},[1065],[1023,84694,84696,84699,84702,84705,84708],{"className":84695},[1070],[1023,84697],{"className":84698,"style":1075},[1074],[1023,84700,1044],{"className":84701,"style":1081},[1079,1080],[1023,84703,1049],{"className":84704},[1085],[1023,84706,1262],{"className":84707},[1079,1080],[1023,84709,1056],{"className":84710},[1092],[989,84712,84713],{},"Ví dụ đời thường: heap như xếp hàng ưu tiên.",[989,84715,84716],{},"Top-k trên stream chỉ giữ k món, không giữ hết.",[1352,84718,84720],{"className":3538,"code":84719,"language":3540,"meta":1357,"style":1357},"# top-k nhỏ nhất bằng heap\nimport heapq  # thư viện heap sẵn\ndef topk(a, k):\n    h = []  # heap giữ k món\n    for x in a:  # duyệt từng món\n        heapq.heappush(h, x)  # đẩy vào heap\n        if len(h) > k:  # quá k món\n            heapq.heappop(h)  # bỏ món nhỏ nhất\n    return sorted(h)  # trả k món lớn nhất\n",[992,84721,84722,84727,84732,84737,84742,84747,84752,84757,84762],{"__ignoreMap":1357},[1023,84723,84724],{"class":1362,"line":63},[1023,84725,84726],{},"# top-k nhỏ nhất bằng heap\n",[1023,84728,84729],{"class":1362,"line":68},[1023,84730,84731],{},"import heapq  # thư viện heap sẵn\n",[1023,84733,84734],{"class":1362,"line":73},[1023,84735,84736],{},"def topk(a, k):\n",[1023,84738,84739],{"class":1362,"line":78},[1023,84740,84741],{},"    h = []  # heap giữ k món\n",[1023,84743,84744],{"class":1362,"line":83},[1023,84745,84746],{},"    for x in a:  # duyệt từng món\n",[1023,84748,84749],{"class":1362,"line":88},[1023,84750,84751],{},"        heapq.heappush(h, x)  # đẩy vào heap\n",[1023,84753,84754],{"class":1362,"line":93},[1023,84755,84756],{},"        if len(h) > k:  # quá k món\n",[1023,84758,84759],{"class":1362,"line":98},[1023,84760,84761],{},"            heapq.heappop(h)  # bỏ món nhỏ nhất\n",[1023,84763,84764],{"class":1362,"line":103},[1023,84765,84766],{},"    return sorted(h)  # trả k món lớn nhất\n",[968,84768,1433],{"id":1432},[986,84770,84771,84774],{},[989,84772,84773],{},"Cây 7 nút, khoảng hẹp trúng 2 -> chỉ thăm đường cần thiết.",[989,84775,84776],{},"Stream 100 số, k = 3 -> chỉ giữ 3 số lớn nhất.",[968,84778,1482],{"id":1481},[973,84780,84781,84782,5599,84785,84788],{},"Luyện phỏng vấn, mỗi bài ",[1487,84783,84784],{},"25 phút",[992,84786,84787],{},"day-162\u002F",", mỗi bài 1 file có test và comment độ phức tạp.",[981,84790,84792],{"id":84791},"bài-1-bst","Bài 1: BST",[1099,84794,84795,84805],{},[1102,84796,84797],{},[1105,84798,84799,84801,84803],{},[1108,84800,84198],{},[1108,84802,84201],{},[1108,84804,2194],{},[1118,84806,84807,84860,84935,84987,84999],{},[1105,84808,84809,84811,84814],{},[1123,84810,84210],{},[1123,84812,84813],{},"Kiểm tra cây có phải BST hợp lệ",[1123,84815,84816,84817],{},"Dùng khoảng chặn, ",[1023,84818,84820,84839],{"className":84819},[1026],[1023,84821,84823],{"className":84822},[1030],[1032,84824,84825],{"xmlns":1034},[1036,84826,84827,84837],{},[1039,84828,84829,84831,84833,84835],{},[1042,84830,1044],{},[1046,84832,1049],{"stretchy":1048},[1042,84834,1262],{},[1046,84836,1056],{"stretchy":1048},[1058,84838,1267],{"encoding":1060},[1023,84840,84842],{"className":84841,"ariaHidden":1066},[1065],[1023,84843,84845,84848,84851,84854,84857],{"className":84844},[1070],[1023,84846],{"className":84847,"style":1075},[1074],[1023,84849,1044],{"className":84850,"style":1081},[1079,1080],[1023,84852,1049],{"className":84853},[1085],[1023,84855,1262],{"className":84856},[1079,1080],[1023,84858,1056],{"className":84859},[1092],[1105,84861,84862,84864,84867],{},[1123,84863,84293],{},[1123,84865,84866],{},"Phần tử nhỏ thứ k trong BST",[1123,84868,84869],{},[1023,84870,84872,84896],{"className":84871},[1026],[1023,84873,84875],{"className":84874},[1030],[1032,84876,84877],{"xmlns":1034},[1036,84878,84879,84893],{},[1039,84880,84881,84883,84885,84887,84889,84891],{},[1042,84882,1044],{},[1046,84884,1049],{"stretchy":1048},[1042,84886,7908],{},[1046,84888,21881],{},[1042,84890,4022],{},[1046,84892,1056],{"stretchy":1048},[1058,84894,84895],{"encoding":1060},"O(h + k)",[1023,84897,84899,84923],{"className":84898,"ariaHidden":1066},[1065],[1023,84900,84902,84905,84908,84911,84914,84917,84920],{"className":84901},[1070],[1023,84903],{"className":84904,"style":1075},[1074],[1023,84906,1044],{"className":84907,"style":1081},[1079,1080],[1023,84909,1049],{"className":84910},[1085],[1023,84912,7908],{"className":84913},[1079,1080],[1023,84915],{"className":84916,"style":13790},[2354],[1023,84918,21881],{"className":84919},[13794],[1023,84921],{"className":84922,"style":13790},[2354],[1023,84924,84926,84929,84932],{"className":84925},[1070],[1023,84927],{"className":84928,"style":1075},[1074],[1023,84930,4022],{"className":84931,"style":4066},[1079,1080],[1023,84933,1056],{"className":84934},[1092],[1105,84936,84937,84939,84942],{},[1123,84938,84389],{},[1123,84940,84941],{},"Tổ tiên chung thấp nhất của 2 nút trong BST",[1123,84943,84944],{},[1023,84945,84947,84966],{"className":84946},[1026],[1023,84948,84950],{"className":84949},[1030],[1032,84951,84952],{"xmlns":1034},[1036,84953,84954,84964],{},[1039,84955,84956,84958,84960,84962],{},[1042,84957,1044],{},[1046,84959,1049],{"stretchy":1048},[1042,84961,7908],{},[1046,84963,1056],{"stretchy":1048},[1058,84965,7913],{"encoding":1060},[1023,84967,84969],{"className":84968,"ariaHidden":1066},[1065],[1023,84970,84972,84975,84978,84981,84984],{"className":84971},[1070],[1023,84973],{"className":84974,"style":1075},[1074],[1023,84976,1044],{"className":84977,"style":1081},[1079,1080],[1023,84979,1049],{"className":84980},[1085],[1023,84982,7908],{"className":84983},[1079,1080],[1023,84985,1056],{"className":84986},[1092],[1105,84988,84989,84991,84996],{},[1123,84990,84400],{},[1123,84992,84993,84994],{},"Tổng các nút có giá trị trong ",[992,84995,32970],{},[1123,84997,84998],{},"Cắt nhánh ngoài khoảng",[1105,85000,85001,85004,85007],{},[1123,85002,85003],{},"1e",[1123,85005,85006],{},"Chuyển mảng đã sắp thành BST cân bằng",[1123,85008],{},[1352,85010,85013],{"className":85011,"code":85012,"language":2241,"meta":1357},[2239],"1a: [5, 1, 4, null, null, 3, 6] -> false (3 nằm bên phải 5)\n1b: BST [3,1,4,null,2], k=1 -> 1\n1d: [10,5,15,3,7,null,18], lo=7, hi=15 -> 32\n",[992,85014,85012],{"__ignoreMap":1357},[981,85016,85018],{"id":85017},"bài-2-heap","Bài 2: Heap",[1099,85020,85021,85029],{},[1102,85022,85023],{},[1105,85024,85025,85027],{},[1108,85026,84198],{},[1108,85028,84201],{},[1118,85030,85031,85101,85108,85178],{},[1105,85032,85033,85035],{},[1123,85034,84475],{},[1123,85036,85037,85038],{},"Phần tử lớn thứ k trong mảng, ",[1023,85039,85041,85066],{"className":85040},[1026],[1023,85042,85044],{"className":85043},[1030],[1032,85045,85046],{"xmlns":1034},[1036,85047,85048,85064],{},[1039,85049,85050,85052,85054,85056,85058,85060,85062],{},[1042,85051,1044],{},[1046,85053,1049],{"stretchy":1048},[1042,85055,1262],{},[1042,85057,8397],{},[1046,85059,8400],{},[1042,85061,4022],{},[1046,85063,1056],{"stretchy":1048},[1058,85065,21767],{"encoding":1060},[1023,85067,85069],{"className":85068,"ariaHidden":1066},[1065],[1023,85070,85072,85075,85078,85081,85084,85087,85092,85095,85098],{"className":85071},[1070],[1023,85073],{"className":85074,"style":1075},[1074],[1023,85076,1044],{"className":85077,"style":1081},[1079,1080],[1023,85079,1049],{"className":85080},[1085],[1023,85082,1262],{"className":85083},[1079,1080],[1023,85085],{"className":85086,"style":8434},[2354],[1023,85088,8427,85090],{"className":85089},[8426],[1023,85091,7690],{"style":8430},[1023,85093],{"className":85094,"style":8434},[2354],[1023,85096,4022],{"className":85097,"style":4066},[1079,1080],[1023,85099,1056],{"className":85100},[1092],[1105,85102,85103,85105],{},[1123,85104,84483],{},[1123,85106,85107],{},"Gộp k danh sách liên kết đã sắp",[1105,85109,85110,85112],{},[1123,85111,84494],{},[1123,85113,85114,85115,1656,85118,85121,85122,85177],{},"Trung vị của luồng số: ",[992,85116,85117],{},"addNum",[992,85119,85120],{},"findMedian"," mỗi lần ",[1023,85123,85125,85148],{"className":85124},[1026],[1023,85126,85128],{"className":85127},[1030],[1032,85129,85130],{"xmlns":1034},[1036,85131,85132,85146],{},[1039,85133,85134,85136,85138,85140,85142,85144],{},[1042,85135,1044],{},[1046,85137,1049],{"stretchy":1048},[1042,85139,8397],{},[1046,85141,8400],{},[1042,85143,1262],{},[1046,85145,1056],{"stretchy":1048},[1058,85147,8407],{"encoding":1060},[1023,85149,85151],{"className":85150,"ariaHidden":1066},[1065],[1023,85152,85154,85157,85160,85163,85168,85171,85174],{"className":85153},[1070],[1023,85155],{"className":85156,"style":1075},[1074],[1023,85158,1044],{"className":85159,"style":1081},[1079,1080],[1023,85161,1049],{"className":85162},[1085],[1023,85164,8427,85166],{"className":85165},[8426],[1023,85167,7690],{"style":8430},[1023,85169],{"className":85170,"style":8434},[2354],[1023,85172,1262],{"className":85173},[1079,1080],[1023,85175,1056],{"className":85176},[1092]," bằng 2 heap",[1105,85179,85180,85183],{},[1123,85181,85182],{},"2d",[1123,85184,85185],{},"k từ xuất hiện nhiều nhất, hòa thì theo alphabet",[1352,85187,85190],{"className":85188,"code":85189,"language":2241,"meta":1357},[2239],"2a: [3,2,1,5,6,4], k=2 -> 5\n2c: add 1, add 2 -> 1.5; add 3 -> 2\n",[992,85191,85189],{"__ignoreMap":1357},[981,85193,85195],{"id":85194},"bài-3-kết-hợp-nâng-cao","Bài 3: Kết hợp (nâng cao)",[2273,85197,85198,85326,85329],{},[989,85199,85200,85201,85262,85263,1517],{},"k điểm gần gốc tọa độ nhất trong ",[1023,85202,85204,85221],{"className":85203},[1026],[1023,85205,85207],{"className":85206},[1030],[1032,85208,85209],{"xmlns":1034},[1036,85210,85211,85219],{},[1039,85212,85213],{},[2327,85214,85215,85217],{},[1051,85216,2331],{},[1051,85218,6866],{},[1058,85220,6869],{"encoding":1060},[1023,85222,85224],{"className":85223,"ariaHidden":1066},[1065],[1023,85225,85227,85230,85233],{"className":85226},[1070],[1023,85228],{"className":85229,"style":2369},[1074],[1023,85231,1053],{"className":85232},[1079],[1023,85234,85236,85239],{"className":85235},[1079],[1023,85237,2379],{"className":85238},[1079],[1023,85240,85242],{"className":85241},[2383],[1023,85243,85245],{"className":85244},[2387],[1023,85246,85248],{"className":85247},[2391],[1023,85249,85251],{"className":85250,"style":2369},[2395],[1023,85252,85253,85256],{"style":2398},[1023,85254],{"className":85255,"style":2403},[2402],[1023,85257,85259],{"className":85258},[2407,2408,2409,2410],[1023,85260,6866],{"className":85261},[1079,2410]," điểm, ",[1023,85264,85266,85291],{"className":85265},[1026],[1023,85267,85269],{"className":85268},[1030],[1032,85270,85271],{"xmlns":1034},[1036,85272,85273,85289],{},[1039,85274,85275,85277,85279,85281,85283,85285,85287],{},[1042,85276,1044],{},[1046,85278,1049],{"stretchy":1048},[1042,85280,1262],{},[1042,85282,8397],{},[1046,85284,8400],{},[1042,85286,4022],{},[1046,85288,1056],{"stretchy":1048},[1058,85290,21767],{"encoding":1060},[1023,85292,85294],{"className":85293,"ariaHidden":1066},[1065],[1023,85295,85297,85300,85303,85306,85309,85312,85317,85320,85323],{"className":85296},[1070],[1023,85298],{"className":85299,"style":1075},[1074],[1023,85301,1044],{"className":85302,"style":1081},[1079,1080],[1023,85304,1049],{"className":85305},[1085],[1023,85307,1262],{"className":85308},[1079,1080],[1023,85310],{"className":85311,"style":8434},[2354],[1023,85313,8427,85315],{"className":85314},[8426],[1023,85316,7690],{"style":8430},[1023,85318],{"className":85319,"style":8434},[2354],[1023,85321,4022],{"className":85322,"style":4066},[1079,1080],[1023,85324,1056],{"className":85325},[1092],[989,85327,85328],{},"Lập lịch CPU: các task có thời điểm đến và thời gian chạy. Luôn chạy task ngắn nhất đang chờ. In thứ tự hoàn thành.",[989,85330,85331,85332,2308,85335,85378,85379,1517],{},"Iterator duyệt BST theo thứ tự, ",[992,85333,85334],{},"next()",[1023,85336,85338,85357],{"className":85337},[1026],[1023,85339,85341],{"className":85340},[1030],[1032,85342,85343],{"xmlns":1034},[1036,85344,85345,85355],{},[1039,85346,85347,85349,85351,85353],{},[1042,85348,1044],{},[1046,85350,1049],{"stretchy":1048},[1051,85352,1053],{},[1046,85354,1056],{"stretchy":1048},[1058,85356,1061],{"encoding":1060},[1023,85358,85360],{"className":85359,"ariaHidden":1066},[1065],[1023,85361,85363,85366,85369,85372,85375],{"className":85362},[1070],[1023,85364],{"className":85365,"style":1075},[1074],[1023,85367,1044],{"className":85368,"style":1081},[1079,1080],[1023,85370,1049],{"className":85371},[1085],[1023,85373,1053],{"className":85374},[1079],[1023,85376,1056],{"className":85377},[1092]," trung bình, bộ nhớ ",[1023,85380,85382,85401],{"className":85381},[1026],[1023,85383,85385],{"className":85384},[1030],[1032,85386,85387],{"xmlns":1034},[1036,85388,85389,85399],{},[1039,85390,85391,85393,85395,85397],{},[1042,85392,1044],{},[1046,85394,1049],{"stretchy":1048},[1042,85396,7908],{},[1046,85398,1056],{"stretchy":1048},[1058,85400,7913],{"encoding":1060},[1023,85402,85404],{"className":85403,"ariaHidden":1066},[1065],[1023,85405,85407,85410,85413,85416,85419],{"className":85406},[1070],[1023,85408],{"className":85409,"style":1075},[1074],[1023,85411,1044],{"className":85412,"style":1081},[1079,1080],[1023,85414,1049],{"className":85415},[1085],[1023,85417,7908],{"className":85418},[1079,1080],[1023,85420,1056],{"className":85421},[1092],[981,85423,2711],{"id":2710},[986,85425,85427,85433,85442,85448],{"className":85426},[2715],[989,85428,85430,85432],{"className":85429},[2719],[2721,85431],{"disabled":2723,"type":2724}," 12 bài có test gồm ca biên.",[989,85434,85436,2308,85438,85441],{"className":85435},[2719],[2721,85437],{"disabled":2723,"type":2724},[992,85439,85440],{},"isValidBST"," bắt được lỗi ở cháu.",[989,85443,85445,85447],{"className":85444},[2719],[2721,85446],{"disabled":2723,"type":2724}," Trung vị luồng có test 10^5 số ngẫu nhiên so với sắp xếp.",[989,85449,85451,85453],{"className":85450},[2719],[2721,85452],{"disabled":2723,"type":2724}," Bảng thời gian thực tế mỗi bài.",[968,85455,2890],{"id":2889},[2273,85457,85458,85461,85464,85467],{},[989,85459,85460],{},"Quy tắc trái phải của BST là gì?",[989,85462,85463],{},"Vì sao so cha con chưa đủ?",[989,85465,85466],{},"Heapify tốn bao nhiêu?",[989,85468,85469],{},"Top-k giữ mấy món trong heap?",[3014,85471],{},[973,85473,85474],{},"🌕 Bạn đã hoàn thành ngày 162. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,85476,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":85478},[85479,85480,85485,85486,85492],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":85481},[85482,85483,85484],{"id":84622,"depth":73,"text":84623},{"id":84640,"depth":73,"text":84641},{"id":84658,"depth":73,"text":84659},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":85487},[85488,85489,85490,85491],{"id":84791,"depth":73,"text":84792},{"id":85017,"depth":73,"text":85018},{"id":85194,"depth":73,"text":85195},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện phỏng vấn cây và heap: duyệt BST, kiểm tra bất biến, heapify, top-k trên stream và đánh đổi bộ nhớ.",{},[3050,8149],{"title":867,"description":85493},[68137,8153,19407],"JG268XE9QDHMf22JXLj87sFH1lGeWPnTz6n2UmuXfBE",{"id":85500,"title":872,"body":85501,"category":8797,"day":875,"description":85905,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":85906,"navigation":2723,"outcomes":3047,"path":873,"prerequisites":85907,"seo":85908,"stem":874,"tags":85909,"__hash__":85910},"challenges\u002Fchallenges\u002F163.phong-van-graph.md",{"type":965,"value":85502,"toc":85889},[85503,85505,85508,85510,85514,85528,85532,85546,85550,85564,85614,85616,85624,85626,85633,85637,85695,85701,85758,85762,85805,85811,85815,85834,85836,85866,85868,85882,85884,85887],[968,85504,971],{"id":970},[973,85506,85507],{},"Bạn luyện bài đồ thị trên lưới. Vẽ lưới và đánh số thứ tự thăm.",[968,85509,979],{"id":978},[981,85511,85513],{"id":85512},"flood-fill-và-đếm-đảo","Flood fill và đếm đảo",[986,85515,85516,85519,85522,85525],{},[989,85517,85518],{},"Flood fill tô lan từ một ô sang ô kề.",[989,85520,85521],{},"Đếm đảo là đếm vùng đất liền nhau.",[989,85523,85524],{},"Ví dụ đời thường: giống đổ sơn loang trên giấy.",[989,85526,85527],{},"Mỗi ô chỉ tô đúng một lần.",[981,85529,85531],{"id":85530},"bfs-đường-ngắn-nhất","BFS đường ngắn nhất",[986,85533,85534,85537,85540,85543],{},[989,85535,85536],{},"BFS trên lưới tìm đường ít bước nhất.",[989,85538,85539],{},"Mê cung và lan nhiều nguồn đều dùng BFS.",[989,85541,85542],{},"Ví dụ đời thường: giống sóng lan từ tâm ra.",[989,85544,85545],{},"Đích bị bao kín thì kết luận không có đường.",[981,85547,85549],{"id":85548},"dijkstra-và-bẫy-thăm-lại","Dijkstra và bẫy thăm lại",[986,85551,85552,85555,85558,85561],{},[989,85553,85554],{},"Ô có chi phí khác nhau thì dùng Dijkstra.",[989,85556,85557],{},"Đánh dấu trước khi cho vào hàng đợi.",[989,85559,85560],{},"Ví dụ đời thường: giống đi đường thu phí, chọn rẻ nhất.",[989,85562,85563],{},"Đánh dấu muộn dễ cho một ô vào hàng đợi nhiều lần.",[1352,85565,85567],{"className":3538,"code":85566,"language":3540,"meta":1357,"style":1357},"# đếm đảo bằng flood fill\ndef dem_dao(luoi):\n    dem = 0  # số đảo tìm được\n    for i in range(len(luoi)):  # duyệt từng hàng\n        for j in range(len(luoi[0])):  # duyệt từng cột\n            if luoi[i][j] == 1:  # gặp đất mới\n                dem += 1  # thêm một đảo\n                luoi[i][j] = 0  # đánh dấu đã thăm\n    return dem\n",[992,85568,85569,85574,85579,85584,85589,85594,85599,85604,85609],{"__ignoreMap":1357},[1023,85570,85571],{"class":1362,"line":63},[1023,85572,85573],{},"# đếm đảo bằng flood fill\n",[1023,85575,85576],{"class":1362,"line":68},[1023,85577,85578],{},"def dem_dao(luoi):\n",[1023,85580,85581],{"class":1362,"line":73},[1023,85582,85583],{},"    dem = 0  # số đảo tìm được\n",[1023,85585,85586],{"class":1362,"line":78},[1023,85587,85588],{},"    for i in range(len(luoi)):  # duyệt từng hàng\n",[1023,85590,85591],{"class":1362,"line":83},[1023,85592,85593],{},"        for j in range(len(luoi[0])):  # duyệt từng cột\n",[1023,85595,85596],{"class":1362,"line":88},[1023,85597,85598],{},"            if luoi[i][j] == 1:  # gặp đất mới\n",[1023,85600,85601],{"class":1362,"line":93},[1023,85602,85603],{},"                dem += 1  # thêm một đảo\n",[1023,85605,85606],{"class":1362,"line":98},[1023,85607,85608],{},"                luoi[i][j] = 0  # đánh dấu đã thăm\n",[1023,85610,85611],{"class":1362,"line":103},[1023,85612,85613],{},"    return dem\n",[968,85615,1433],{"id":1432},[986,85617,85618,85621],{},[989,85619,85620],{},"Lưới có đảo chạm biên và đảo một ô -> đếm đủ cả hai.",[989,85622,85623],{},"Đích bị ô chặn bao kín -> BFS báo không có đường.",[968,85625,1482],{"id":1481},[973,85627,84781,85628,5599,85630,84788],{},[1487,85629,84784],{},[992,85631,85632],{},"day-163\u002F",[981,85634,85636],{"id":85635},"bài-1-flood-fill-và-đếm-vùng","Bài 1: Flood fill và đếm vùng",[1099,85638,85639,85647],{},[1102,85640,85641],{},[1105,85642,85643,85645],{},[1108,85644,84198],{},[1108,85646,84201],{},[1118,85648,85649,85660,85667,85677],{},[1105,85650,85651,85653],{},[1123,85652,84210],{},[1123,85654,85655,85656,2461,85658],{},"Đếm số đảo trong lưới ",[992,85657,22521],{},[992,85659,22518],{},[1105,85661,85662,85664],{},[1123,85663,84293],{},[1123,85665,85666],{},"Diện tích đảo lớn nhất",[1105,85668,85669,85671],{},[1123,85670,84389],{},[1123,85672,85673,85674],{},"Tô màu flood fill từ ô ",[992,85675,85676],{},"(sr, sc)",[1105,85678,85679,85681],{},[1123,85680,84400],{},[1123,85682,85683,85684,85687,85688,85691,85692,85694],{},"Lật mọi vùng ",[992,85685,85686],{},"'O'"," bị ",[992,85689,85690],{},"'X'"," bao kín thành ",[992,85693,85690],{}," (vùng chạm biên giữ nguyên)",[1352,85696,85699],{"className":85697,"code":85698,"language":2241,"meta":1357},[2239],"1a: [[\"1\",\"1\",\"0\"],[\"1\",\"0\",\"0\"],[\"0\",\"0\",\"1\"]] -> 2\n",[992,85700,85698],{"__ignoreMap":1357},[973,85702,85703,85704,85754,85755,85757],{},"Viết cả bản BFS và DFS cho 1a. Bản DFS đệ quy trên lưới ",[1023,85705,85707,85724],{"className":85706},[1026],[1023,85708,85710],{"className":85709},[1030],[1032,85711,85712],{"xmlns":1034},[1036,85713,85714,85722],{},[1039,85715,85716,85718,85720],{},[1051,85717,9989],{},[1046,85719,13768],{},[1051,85721,9989],{},[1058,85723,26091],{"encoding":1060},[1023,85725,85727,85745],{"className":85726,"ariaHidden":1066},[1065],[1023,85728,85730,85733,85736,85739,85742],{"className":85729},[1070],[1023,85731],{"className":85732,"style":18148},[1074],[1023,85734,9989],{"className":85735},[1079],[1023,85737],{"className":85738,"style":13790},[2354],[1023,85740,13768],{"className":85741},[13794],[1023,85743],{"className":85744,"style":13790},[2354],[1023,85746,85748,85751],{"className":85747},[1070],[1023,85749],{"className":85750,"style":10020},[1074],[1023,85752,9989],{"className":85753},[1079]," toàn ",[992,85756,22521],{},": ghi lại hiện tượng.",[981,85759,85761],{"id":85760},"bài-2-bfs-đường-ngắn-nhất","Bài 2: BFS đường ngắn nhất",[1099,85763,85764,85772],{},[1102,85765,85766],{},[1105,85767,85768,85770],{},[1108,85769,84198],{},[1108,85771,84201],{},[1118,85773,85774,85781,85791],{},[1105,85775,85776,85778],{},[1123,85777,84475],{},[1123,85779,85780],{},"Đường ngắn nhất trong ma trận nhị phân, đi 8 hướng",[1105,85782,85783,85785],{},[1123,85784,84483],{},[1123,85786,85787,85788,85790],{},"Cam thối lan: mỗi phút cam thối làm thối cam kề. Bao nhiêu phút để thối hết, không được thì ",[992,85789,12548],{}," (BFS đa nguồn)",[1105,85792,85793,85795],{},[1123,85794,84494],{},[1123,85796,85797,85798,35512,85801,85804],{},"Biến từ ",[992,85799,85800],{},"begin",[992,85802,85803],{},"end",", mỗi bước đổi 1 chữ, từ trung gian phải có trong từ điển. Số bước ít nhất",[1352,85806,85809],{"className":85807,"code":85808,"language":2241,"meta":1357},[2239],"2b: [[2,1,1],[1,1,0],[0,1,1]] -> 4\n2c: hit -> cog, dict [hot,dot,dog,lot,log,cog] -> 5\n",[992,85810,85808],{"__ignoreMap":1357},[981,85812,85814],{"id":85813},"bài-3-chi-phí-và-phụ-thuộc-nâng-cao","Bài 3: Chi phí và phụ thuộc (nâng cao)",[2273,85816,85817,85824,85831],{},[989,85818,85819,85820,85823],{},"Lưới chi phí: đường từ góc trên trái tới dưới phải có ",[1487,85821,85822],{},"tổng chi phí"," nhỏ nhất, đi 4 hướng (Dijkstra).",[989,85825,85826,85827,85830],{},"Lưới độ cao: đường có ",[1487,85828,85829],{},"chênh lệch độ cao lớn nhất"," nhỏ nhất (Dijkstra biến thể hoặc binary search + BFS).",[989,85832,85833],{},"Có hoàn thành được mọi môn học với danh sách môn tiên quyết không? In một thứ tự học (topo sort).",[981,85835,2711],{"id":2710},[986,85837,85839,85845,85855,85861],{"className":85838},[2715],[989,85840,85842,85844],{"className":85841},[2719],[2721,85843],{"disabled":2723,"type":2724}," 10 bài có test gồm lưới rỗng, lưới 1 ô, đích bị bao kín.",[989,85846,85848,85850,85851,85854],{"className":85847},[2719],[2721,85849],{"disabled":2723,"type":2724}," Đánh dấu thăm lúc ",[1487,85852,85853],{},"đẩy vào"," hàng đợi, có comment giải thích.",[989,85856,85858,85860],{"className":85857},[2719],[2721,85859],{"disabled":2723,"type":2724}," Ghi lại hiện tượng tràn stack của DFS đệ quy.",[989,85862,85864,85453],{"className":85863},[2719],[2721,85865],{"disabled":2723,"type":2724},[968,85867,2890],{"id":2889},[2273,85869,85870,85873,85876,85879],{},[989,85871,85872],{},"Flood fill lan sang ô nào?",[989,85874,85875],{},"BFS hợp lưới loại nào?",[989,85877,85878],{},"Ô có trọng số dùng gì?",[989,85880,85881],{},"Đánh dấu trước hay sau khi xếp hàng?",[3014,85883],{},[973,85885,85886],{},"🌕 Bạn đã hoàn thành ngày 163. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,85888,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":85890},[85891,85892,85897,85898,85904],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":85893},[85894,85895,85896],{"id":85512,"depth":73,"text":85513},{"id":85530,"depth":73,"text":85531},{"id":85548,"depth":73,"text":85549},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":85899},[85900,85901,85902,85903],{"id":85635,"depth":73,"text":85636},{"id":85760,"depth":73,"text":85761},{"id":85813,"depth":73,"text":85814},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện phỏng vấn đồ thị: flood fill, số đảo, đường ngắn nhất lưới, Dijkstra có trọng số và bẫy thăm lại.",{},[3050],{"title":872,"description":85905},[68137,29786,29787],"U1c2cSGfuezdw2TPBNK4Q1u6h_0gq6vVWsKI7MafhI0",{"id":85912,"title":877,"body":85913,"category":8797,"day":880,"description":86366,"difficulty":68559,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":86367,"navigation":2723,"outcomes":3047,"path":878,"prerequisites":86368,"seo":86369,"stem":879,"tags":86370,"__hash__":86371},"challenges\u002Fchallenges\u002F164.phong-van-dp.md",{"type":965,"value":85914,"toc":86350},[85915,85917,85920,85922,85926,85940,85944,85958,85962,85976,86011,86013,86021,86023,86031,86035,86138,86144,86148,86232,86238,86242,86293,86299,86301,86327,86329,86343,86345,86348],[968,85916,971],{"id":970},[973,85918,85919],{},"Bạn luyện quy hoạch động và tham lam. Mỗi bài DP viết đủ 4 bước.",[968,85921,979],{"id":978},[981,85923,85925],{"id":85924},"dp-một-chiều","DP một chiều",[986,85927,85928,85931,85934,85937],{},[989,85929,85930],{},"DP một chiều chỉ nhìn về quá khứ gần.",[989,85932,85933],{},"Hay gặp: bậc thang, cướp nhà, dãy con tăng.",[989,85935,85936],{},"Ví dụ đời thường: giống leo thang, bước sau dựa bước trước.",[989,85938,85939],{},"Viết công thức truy hồi trước khi code.",[981,85941,85943],{"id":85942},"dp-hai-chiều","DP hai chiều",[986,85945,85946,85949,85952,85955],{},[989,85947,85948],{},"DP hai chiều dùng bảng hàng và cột.",[989,85950,85951],{},"Hay gặp: đường đi trên lưới, chuỗi con chung, balo.",[989,85953,85954],{},"Ví dụ đời thường: giống bảng tính Excel điền từng ô.",[989,85956,85957],{},"Điền đúng thứ tự thì ô sau mới có dữ liệu.",[981,85959,85961],{"id":85960},"greedy-đúng-và-sai","Greedy đúng và sai",[986,85963,85964,85967,85970,85973],{},[989,85965,85966],{},"Greedy mỗi bước chọn tốt nhất trước mắt.",[989,85968,85969],{},"Bài đúng kinh điển: đổi tiền chuẩn, xếp lịch.",[989,85971,85972],{},"Ví dụ đời thường: greedy như luôn gắp món gần nhất.",[989,85974,85975],{},"Có bài greedy sai, chỉ DP mới đúng.",[1352,85977,85979],{"className":3538,"code":85978,"language":3540,"meta":1357,"style":1357},"# DP bậc thang đơn giản\ndef leo_thang(n):\n    a, b = 1, 1  # hai bước gần nhất\n    for _ in range(n):  # lặp n lần\n        a, b = b, a + b  # bước mới bằng tổng hai cũ\n    return a\n",[992,85980,85981,85986,85991,85996,86001,86006],{"__ignoreMap":1357},[1023,85982,85983],{"class":1362,"line":63},[1023,85984,85985],{},"# DP bậc thang đơn giản\n",[1023,85987,85988],{"class":1362,"line":68},[1023,85989,85990],{},"def leo_thang(n):\n",[1023,85992,85993],{"class":1362,"line":73},[1023,85994,85995],{},"    a, b = 1, 1  # hai bước gần nhất\n",[1023,85997,85998],{"class":1362,"line":78},[1023,85999,86000],{},"    for _ in range(n):  # lặp n lần\n",[1023,86002,86003],{"class":1362,"line":83},[1023,86004,86005],{},"        a, b = b, a + b  # bước mới bằng tổng hai cũ\n",[1023,86007,86008],{"class":1362,"line":88},[1023,86009,86010],{},"    return a\n",[968,86012,1433],{"id":1432},[986,86014,86015,86018],{},[989,86016,86017],{},"Mảng 6 số bài một chiều -> bảng dry-run khớp công thức.",[989,86019,86020],{},"Bài hai chiều -> truy vết ngược dựng được nghiệm cụ thể.",[968,86022,1482],{"id":1481},[973,86024,84781,86025,5599,86027,86030],{},[1487,86026,84784],{},[992,86028,86029],{},"day-164\u002F",". Mỗi bài DP viết comment 4 dòng: trạng thái, công thức chuyển, base case, thứ tự tính.",[981,86032,86034],{"id":86033},"bài-1-dp-một-chiều","Bài 1: DP một chiều",[1099,86036,86037,86045],{},[1102,86038,86039],{},[1105,86040,86041,86043],{},[1108,86042,84198],{},[1108,86044,84201],{},[1118,86046,86047,86054,86061,86131],{},[1105,86048,86049,86051],{},[1123,86050,84210],{},[1123,86052,86053],{},"Cướp nhà: không lấy 2 nhà kề nhau, tổng lớn nhất",[1105,86055,86056,86058],{},[1123,86057,84293],{},[1123,86059,86060],{},"Cướp nhà trên vòng tròn (nhà đầu và cuối kề nhau)",[1105,86062,86063,86065],{},[1123,86064,84389],{},[1123,86066,86067,86068],{},"Dãy con tăng dài nhất, ",[1023,86069,86071,86096],{"className":86070},[1026],[1023,86072,86074],{"className":86073},[1030],[1032,86075,86076],{"xmlns":1034},[1036,86077,86078,86094],{},[1039,86079,86080,86082,86084,86086,86088,86090,86092],{},[1042,86081,1044],{},[1046,86083,1049],{"stretchy":1048},[1042,86085,1262],{},[1042,86087,8397],{},[1046,86089,8400],{},[1042,86091,1262],{},[1046,86093,1056],{"stretchy":1048},[1058,86095,10463],{"encoding":1060},[1023,86097,86099],{"className":86098,"ariaHidden":1066},[1065],[1023,86100,86102,86105,86108,86111,86114,86117,86122,86125,86128],{"className":86101},[1070],[1023,86103],{"className":86104,"style":1075},[1074],[1023,86106,1044],{"className":86107,"style":1081},[1079,1080],[1023,86109,1049],{"className":86110},[1085],[1023,86112,1262],{"className":86113},[1079,1080],[1023,86115],{"className":86116,"style":8434},[2354],[1023,86118,8427,86120],{"className":86119},[8426],[1023,86121,7690],{"style":8430},[1023,86123],{"className":86124,"style":8434},[2354],[1023,86126,1262],{"className":86127},[1079,1080],[1023,86129,1056],{"className":86130},[1092],[1105,86132,86133,86135],{},[1123,86134,84400],{},[1123,86136,86137],{},"Số cách giải mã chuỗi số thành chữ (1 -> A, 26 -> Z)",[1352,86139,86142],{"className":86140,"code":86141,"language":2241,"meta":1357},[2239],"1a: [2,7,9,3,1] -> 12\n1b: [2,3,2] -> 3\n1c: [10,9,2,5,3,7,101,18] -> 4\n1d: \"226\" -> 3\n",[992,86143,86141],{"__ignoreMap":1357},[981,86145,86147],{"id":86146},"bài-2-dp-hai-chiều","Bài 2: DP hai chiều",[1099,86149,86150,86158],{},[1102,86151,86152],{},[1105,86153,86154,86156],{},[1108,86155,84198],{},[1108,86157,84201],{},[1118,86159,86160,86167,86174,86225],{},[1105,86161,86162,86164],{},[1123,86163,84475],{},[1123,86165,86166],{},"Chuỗi con chung dài nhất",[1105,86168,86169,86171],{},[1123,86170,84483],{},[1123,86172,86173],{},"Edit distance",[1105,86175,86176,86178],{},[1123,86177,84494],{},[1123,86179,86180,86181],{},"Ba lô 0-1, bộ nhớ ",[1023,86182,86184,86204],{"className":86183},[1026],[1023,86185,86187],{"className":86186},[1030],[1032,86188,86189],{"xmlns":1034},[1036,86190,86191,86201],{},[1039,86192,86193,86195,86197,86199],{},[1042,86194,1044],{},[1046,86196,1049],{"stretchy":1048},[1042,86198,56943],{},[1046,86200,1056],{"stretchy":1048},[1058,86202,86203],{"encoding":1060},"O(W)",[1023,86205,86207],{"className":86206,"ariaHidden":1066},[1065],[1023,86208,86210,86213,86216,86219,86222],{"className":86209},[1070],[1023,86211],{"className":86212,"style":1075},[1074],[1023,86214,1044],{"className":86215,"style":1081},[1079,1080],[1023,86217,1049],{"className":86218},[1085],[1023,86220,56943],{"className":86221,"style":37429},[1079,1080],[1023,86223,1056],{"className":86224},[1092],[1105,86226,86227,86229],{},[1123,86228,85182],{},[1123,86230,86231],{},"Chia mảng thành 2 phần tổng bằng nhau",[1352,86233,86236],{"className":86234,"code":86235,"language":2241,"meta":1357},[2239],"2b: \"horse\", \"ros\" -> 3\n2d: [1,5,11,5] -> true; [1,2,3,5] -> false\n",[992,86237,86235],{"__ignoreMap":1357},[981,86239,86241],{"id":86240},"bài-3-greedy-và-chứng-minh-nâng-cao","Bài 3: Greedy và chứng minh (nâng cao)",[1099,86243,86244,86255],{},[1102,86245,86246],{},[1105,86247,86248,86250,86252],{},[1108,86249,84198],{},[1108,86251,84201],{},[1108,86253,86254],{},"Viết thêm",[1118,86256,86257,86268,86279],{},[1105,86258,86259,86262,86265],{},[1123,86260,86261],{},"3a",[1123,86263,86264],{},"Chọn nhiều cuộc họp không chồng nhau nhất",[1123,86266,86267],{},"Chứng minh bằng lập luận \"đổi chỗ\" vì sao chọn kết thúc sớm nhất",[1105,86269,86270,86273,86276],{},[1123,86271,86272],{},"3b",[1123,86274,86275],{},"Nhảy xa: mảng bước nhảy tối đa, có tới được cuối không",[1123,86277,86278],{},"Vì sao greedy đúng",[1105,86280,86281,86284,86290],{},[1123,86282,86283],{},"3c",[1123,86285,86286,86287],{},"Đổi tiền với mệnh giá ",[992,86288,86289],{},"[1, 3, 4]",[1123,86291,86292],{},"Chỉ ra input greedy sai, giải bằng DP",[1352,86294,86297],{"className":86295,"code":86296,"language":2241,"meta":1357},[2239],"3a: [(1,3),(2,4),(3,5),(0,6),(5,7),(8,9)] -> 4\n3c: amount = 6 -> greedy 3 đồng (4+1+1), DP 2 đồng (3+3)\n",[992,86298,86296],{"__ignoreMap":1357},[981,86300,2711],{"id":2710},[986,86302,86304,86310,86316,86322],{"className":86303},[2715],[989,86305,86307,86309],{"className":86306},[2719],[2721,86308],{"disabled":2723,"type":2724}," 11 bài có test.",[989,86311,86313,86315],{"className":86312},[2719],[2721,86314],{"disabled":2723,"type":2724}," Mỗi bài DP có comment 4 dòng.",[989,86317,86319,86321],{"className":86318},[2719],[2721,86320],{"disabled":2723,"type":2724}," 3a và 3b có lập luận chứng minh viết bằng lời.",[989,86323,86325,85453],{"className":86324},[2719],[2721,86326],{"disabled":2723,"type":2724},[968,86328,2890],{"id":2889},[2273,86330,86331,86334,86337,86340],{},[989,86332,86333],{},"4 bước làm bài DP là gì?",[989,86335,86336],{},"DP hai chiều điền bảng theo thứ tự nào?",[989,86338,86339],{},"Chứng minh greedy bằng cách nào?",[989,86341,86342],{},"Nén không gian cần trả lời gì?",[3014,86344],{},[973,86346,86347],{},"🌕 Bạn đã hoàn thành ngày 164. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,86349,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":86351},[86352,86353,86358,86359,86365],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":86354},[86355,86356,86357],{"id":85924,"depth":73,"text":85925},{"id":85942,"depth":73,"text":85943},{"id":85960,"depth":73,"text":85961},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":86360},[86361,86362,86363,86364],{"id":86033,"depth":73,"text":86034},{"id":86146,"depth":73,"text":86147},{"id":86240,"depth":73,"text":86241},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện phỏng vấn DP và greedy: nhận diện bài toán con gối nhau, bảng một hai chiều, chứng minh greedy bằng đổi chỗ.",{},[8149,15143],{"title":877,"description":86366},[68137,15591,15148],"7hGg9_yFhMpQNeDcNCGl68Ra5NFX0L7LZDJ3YReORUc",{"id":86373,"title":882,"body":86374,"category":3041,"day":885,"description":86627,"difficulty":68559,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":86628,"navigation":2723,"outcomes":3047,"path":883,"prerequisites":86629,"seo":86630,"stem":884,"tags":86631,"__hash__":86632},"challenges\u002Fchallenges\u002F165.phong-van-system.md",{"type":965,"value":86375,"toc":86611},[86376,86378,86381,86383,86387,86404,86408,86422,86426,86440,86490,86492,86500,86502,86512,86515,86519,86530,86534,86545,86549,86560,86562,86588,86590,86604,86606,86609],[968,86377,971],{"id":970},[973,86379,86380],{},"Bạn luyện thiết kế hệ thống mini. Luôn hỏi tải trước khi vẽ.",[968,86382,979],{"id":978},[981,86384,86386],{"id":86385},"khung-trình-bày-5-bước","Khung trình bày 5 bước",[986,86388,86389,86392,86395,86398,86401],{},[989,86390,86391],{},"Bước 1: hỏi rõ tải và độ trễ cam kết.",[989,86393,86394],{},"Bước 2: ước lượng bộ nhớ và băng thông.",[989,86396,86397],{},"Bước 3: vẽ thành phần và luồng request.",[989,86399,86400],{},"Ví dụ đời thường: giống hỏi số khách trước khi vẽ quán.",[989,86402,86403],{},"Bước 4 và 5: đào sâu điểm khó rồi chốt đánh đổi.",[981,86405,86407],{"id":86406},"cache-và-rate-limiter","Cache và rate limiter",[986,86409,86410,86413,86416,86419],{},[989,86411,86412],{},"Cache LRU LFU giảm tải cho backend.",[989,86414,86415],{},"Rate limiter chặn khi gọi quá nhanh.",[989,86417,86418],{},"Ví dụ đời thường: limiter như bảo vệ đếm khách vào.",[989,86420,86421],{},"Token bucket cho bùng nổ ngắn hạn có giới hạn.",[981,86423,86425],{"id":86424},"search-mini","Search mini",[986,86427,86428,86431,86434,86437],{},[989,86429,86430],{},"Trie gợi ý tiền tố, Bloom lọc nhanh.",[989,86432,86433],{},"Xếp hạng đơn giản bằng độ mới và khớp từ.",[989,86435,86436],{},"Ví dụ đời thường: giống mục lục cộng danh sách đen.",[989,86438,86439],{},"Mọi con số ước lượng phải ghi giả định.",[1352,86441,86443],{"className":3538,"code":86442,"language":3540,"meta":1357,"style":1357},"# thùng token đơn giản\nclass ThungToken:  # giới hạn tốc độ gọi\n    def __init__(self, suc):\n        self.token = suc  # số lượt còn lại\n    def goi(self):\n        if self.token > 0:  # còn lượt\n            self.token -= 1  # trừ một lượt\n            return True  # cho qua\n        return False  # chặn lại\n",[992,86444,86445,86450,86455,86460,86465,86470,86475,86480,86485],{"__ignoreMap":1357},[1023,86446,86447],{"class":1362,"line":63},[1023,86448,86449],{},"# thùng token đơn giản\n",[1023,86451,86452],{"class":1362,"line":68},[1023,86453,86454],{},"class ThungToken:  # giới hạn tốc độ gọi\n",[1023,86456,86457],{"class":1362,"line":73},[1023,86458,86459],{},"    def __init__(self, suc):\n",[1023,86461,86462],{"class":1362,"line":78},[1023,86463,86464],{},"        self.token = suc  # số lượt còn lại\n",[1023,86466,86467],{"class":1362,"line":83},[1023,86468,86469],{},"    def goi(self):\n",[1023,86471,86472],{"class":1362,"line":88},[1023,86473,86474],{},"        if self.token > 0:  # còn lượt\n",[1023,86476,86477],{"class":1362,"line":93},[1023,86478,86479],{},"            self.token -= 1  # trừ một lượt\n",[1023,86481,86482],{"class":1362,"line":98},[1023,86483,86484],{},"            return True  # cho qua\n",[1023,86486,86487],{"class":1362,"line":103},[1023,86488,86489],{},"        return False  # chặn lại\n",[968,86491,1433],{"id":1432},[986,86493,86494,86497],{},[989,86495,86496],{},"Tải và tỉ lệ trúng cho trước -> tính tải còn lại cho backend.",[989,86498,86499],{},"100 request dồn một giây -> limiter cho qua đúng cam kết.",[968,86501,1482],{"id":1481},[973,86503,86504,86505,86508,86509,1517],{},"Luyện phỏng vấn thiết kế hệ thống, mỗi đề ",[1487,86506,86507],{},"45 phút",", viết ra giấy hoặc Markdown có sơ đồ. Nộp vào ",[992,86510,86511],{},"day-165\u002F",[973,86513,86514],{},"Mỗi đề đi đủ 5 bước: (1) hỏi rõ yêu cầu và tải, (2) ước lượng số liệu, (3) sơ đồ thành phần và luồng request, (4) đào sâu 2 điểm khó, (5) đánh đổi và cách mở rộng.",[981,86516,86518],{"id":86517},"bài-1-thiết-kế-rate-limiter-cho-api-gateway","Bài 1: Thiết kế rate limiter cho API gateway",[986,86520,86521,86524,86527],{},[989,86522,86523],{},"10^6 user, mỗi user 100 request\u002Fphút, 50 máy gateway.",[989,86525,86526],{},"Ước lượng: bộ nhớ cho trạng thái limiter, số lần gọi Redis mỗi giây.",[989,86528,86529],{},"Đào sâu: chọn thuật toán nào (lý do), giới hạn toàn cục khi nhiều gateway, Redis sập thì sao (fail open hay fail close).",[981,86531,86533],{"id":86532},"bài-2-thiết-kế-autocomplete-cho-ô-tìm-kiếm","Bài 2: Thiết kế autocomplete cho ô tìm kiếm",[986,86535,86536,86539,86542],{},[989,86537,86538],{},"10^7 truy vấn\u002Fngày, trả lời dưới 50 ms, cập nhật từ khóa hot mỗi giờ.",[989,86540,86541],{},"Ước lượng: kích thước trie cho 10^7 cụm từ, số máy.",[989,86543,86544],{},"Đào sâu: cập nhật trie không gián đoạn, cache ở tầng nào, cá nhân hóa.",[981,86546,86548],{"id":86547},"bài-3-thiết-kế-cache-phân-tán-và-dịch-vụ-tìm-kiếm-nâng-cao","Bài 3: Thiết kế cache phân tán và dịch vụ tìm kiếm (nâng cao)",[2273,86550,86551,86554,86557],{},[989,86552,86553],{},"Cache phân tán 1 TB trên 20 máy: consistent hashing (vẽ vòng băm, giải thích thêm\u002Fbớt máy), nhân bản, xử lý key nóng.",[989,86555,86556],{},"Tìm kiếm cho 10^8 tài liệu: chia shard chỉ mục ngược, gộp kết quả top-k từ các shard, Bloom filter ở đâu.",[989,86558,86559],{},"Nhờ 1 người đóng vai người phỏng vấn cho 1 đề, hoặc tự ghi âm. Ghi lại câu hỏi bị bí.",[981,86561,2711],{"id":2710},[986,86563,86565,86571,86577,86583],{"className":86564},[2715],[989,86566,86568,86570],{"className":86567},[2719],[2721,86569],{"disabled":2723,"type":2724}," 4 đề đủ 5 bước, có sơ đồ.",[989,86572,86574,86576],{"className":86573},[2719],[2721,86575],{"disabled":2723,"type":2724}," Mỗi đề có phép ước lượng với số cụ thể.",[989,86578,86580,86582],{"className":86579},[2719],[2721,86581],{"disabled":2723,"type":2724}," Mỗi đề nêu ít nhất 2 đánh đổi.",[989,86584,86586,84562],{"className":86585},[2719],[2721,86587],{"disabled":2723,"type":2724},[968,86589,2890],{"id":2889},[2273,86591,86592,86595,86598,86601],{},[989,86593,86594],{},"Bước đầu tiên khi thiết kế là gì?",[989,86596,86597],{},"Cache giảm tải cho ai?",[989,86599,86600],{},"Token bucket cho phép gì?",[989,86602,86603],{},"Vì sao ghi giả định cho mọi số?",[3014,86605],{},[973,86607,86608],{},"🌕 Bạn đã hoàn thành ngày 165. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,86610,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":86612},[86613,86614,86619,86620,86626],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":86615},[86616,86617,86618],{"id":86385,"depth":73,"text":86386},{"id":86406,"depth":73,"text":86407},{"id":86424,"depth":73,"text":86425},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":86621},[86622,86623,86624,86625],{"id":86517,"depth":73,"text":86518},{"id":86532,"depth":73,"text":86533},{"id":86547,"depth":73,"text":86548},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện system design mini: cache LRU LFU, rate limiter token bucket, search Trie Bloom và đánh đổi nhất quán.",{},[14055,4669],{"title":882,"description":86627},[68137,72343,29125],"yVK_cqOWAYOCPTGqCWNI3EFJS_LSuMqfRRBvKf9iff0",{"id":86634,"title":887,"body":86635,"category":5189,"day":890,"description":86875,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":86876,"navigation":2723,"outcomes":3047,"path":888,"prerequisites":86877,"seo":86878,"stem":889,"tags":86879,"__hash__":86880},"challenges\u002Fchallenges\u002F166.phong-van-patterns.md",{"type":965,"value":86636,"toc":86859},[86637,86639,86642,86644,86648,86662,86666,86680,86684,86698,86718,86720,86728,86730,86739,86743,86750,86754,86763,86774,86778,86807,86809,86836,86838,86852,86854,86857],[968,86638,971],{"id":970},[973,86640,86641],{},"Bạn luyện kể chuyện thiết kế rõ ràng. Mỗi chuyện kể dưới 2 phút.",[968,86643,979],{"id":978},[981,86645,86647],{"id":86646},"kể-chuyện-refactor","Kể chuyện refactor",[986,86649,86650,86653,86656,86659],{},[989,86651,86652],{},"Kể lại quyết định pattern trong dự án cũ.",[989,86654,86655],{},"Khung 5 phần: bối cảnh, nỗi đau, lựa chọn, đánh đổi, bài học.",[989,86657,86658],{},"Ví dụ đời thường: giống kể ca bệnh: triệu chứng, thuốc, tác dụng phụ.",[989,86660,86661],{},"Thiếu phần đánh đổi là mất điểm nặng.",[981,86663,86665],{"id":86664},"chọn-pattern-mới","Chọn pattern mới",[986,86667,86668,86671,86674,86677],{},[989,86669,86670],{},"Nghe tình huống mới rồi chọn pattern hợp.",[989,86672,86673],{},"Mọi quyết định gắn tới một nguyên lý SOLID.",[989,86675,86676],{},"Ví dụ đời thường: giống kê đơn phải đúng bệnh.",[989,86678,86679],{},"Nói sai ánh xạ SOLID là mất điểm.",[981,86681,86683],{"id":86682},"trade-off-và-over-engineering","Trade-off và over-engineering",[986,86685,86686,86689,86692,86695],{},[989,86687,86688],{},"Trade-off là giá phải trả của lựa chọn.",[989,86690,86691],{},"Over-engineering là dùng pattern quá mức cần.",[989,86693,86694],{},"Ví dụ đời thường: giống mang đại bác bắn chim sẻ.",[989,86696,86697],{},"Luôn nêu nhược điểm trước khi giám khảo hỏi.",[1352,86699,86701],{"className":3538,"code":86700,"language":3540,"meta":1357,"style":1357},"# ví dụ kể: trước rối, sau tách strategy\n# trước: if bay == \"canh\": ... elif bay == \"tenlua\": ...\n# sau: self.cach_bay.bay()  # thay khối là xong\n",[992,86702,86703,86708,86713],{"__ignoreMap":1357},[1023,86704,86705],{"class":1362,"line":63},[1023,86706,86707],{},"# ví dụ kể: trước rối, sau tách strategy\n",[1023,86709,86710],{"class":1362,"line":68},[1023,86711,86712],{},"# trước: if bay == \"canh\": ... elif bay == \"tenlua\": ...\n",[1023,86714,86715],{"class":1362,"line":73},[1023,86716,86717],{},"# sau: self.cach_bay.bay()  # thay khối là xong\n",[968,86719,1433],{"id":1432},[986,86721,86722,86725],{},[989,86723,86724],{},"Chuyện đủ 5 phần -> đạt, thiếu đánh đổi -> fail.",[989,86726,86727],{},"Mỗi quyết định gắn đúng nguyên lý SOLID -> đạt.",[968,86729,1482],{"id":1481},[973,86731,86732,86733,86735,86736,1517],{},"Luyện phỏng vấn về thiết kế hướng đối tượng. Dùng ",[992,86734,67985],{}," ngày 118. Nộp vào ",[992,86737,86738],{},"day-166\u002F",[981,86740,86742],{"id":86741},"bài-1-kể-chuyện-theo-khung-5-phần","Bài 1: Kể chuyện theo khung 5 phần",[973,86744,86745,86746,86749],{},"Viết lại 4 câu chuyện từ dự án của bạn (ưu tiên project ngày 116, 117, 125, 147-149) theo khung: ",[1487,86747,86748],{},"bối cảnh, nỗi đau, lựa chọn, đánh đổi, bài học",". Mỗi câu chuyện tối đa 250 từ và ánh xạ đúng 1-2 nguyên lý SOLID.",[981,86751,86753],{"id":86752},"bài-2-thiết-kế-oop-tại-chỗ","Bài 2: Thiết kế OOP tại chỗ",[973,86755,86756,86757,86760,86761,68007],{},"Mỗi đề ",[1487,86758,86759],{},"30 phút",": hỏi làm rõ, liệt kê lớp và trách nhiệm, vẽ sơ đồ lớp, viết interface chính (không cần cài đặt đầy đủ), chỉ ra pattern dùng và ",[1487,86762,41587],{},[2273,86764,86765,86768,86771],{},[989,86766,86767],{},"Bãi đỗ xe nhiều tầng: xe máy, ô tô, xe tải; tính tiền theo giờ; nhiều cổng vào ra.",[989,86769,86770],{},"Thang máy cho tòa nhà 20 tầng, 4 thang.",[989,86772,86773],{},"Máy bán hàng tự động nhiều loại hàng, nhiều cách thanh toán.",[981,86775,86777],{"id":86776},"bài-3-phản-biện-nâng-cao","Bài 3: Phản biện (nâng cao)",[2273,86779,86780,86787],{},[989,86781,86782,86783,86786],{},"Với mỗi đề Bài 2, viết 1 phiên bản ",[1487,86784,86785],{},"đơn giản hơn"," (ít lớp hơn) và so sánh: khi nào bản đơn giản tốt hơn.",[989,86788,86789,86790],{},"Trả lời 5 câu hỏi \"bẫy\":\n",[986,86791,86792,86795,86798,86801,86804],{},[989,86793,86794],{},"\"Tại sao không dùng Singleton cho bãi đỗ xe?\"",[989,86796,86797],{},"\"Thêm loại xe điện cần sạc thì sửa những gì?\"",[989,86799,86800],{},"\"Interface này có vi phạm ISP không?\"",[989,86802,86803],{},"\"Nếu 2 cổng cùng gán 1 chỗ đỗ thì sao?\"",[989,86805,86806],{},"\"Pattern nào bạn đã dùng mà giờ thấy thừa?\"",[981,86808,2711],{"id":2710},[986,86810,86812,86818,86824,86830],{"className":86811},[2715],[989,86813,86815,86817],{"className":86814},[2719],[2721,86816],{"disabled":2723,"type":2724}," 4 câu chuyện đủ 5 phần, có ánh xạ SOLID.",[989,86819,86821,86823],{"className":86820},[2719],[2721,86822],{"disabled":2723,"type":2724}," 3 thiết kế OOP có sơ đồ lớp và interface.",[989,86825,86827,86829],{"className":86826},[2719],[2721,86828],{"disabled":2723,"type":2724}," Mỗi thiết kế có bản đơn giản hơn để so.",[989,86831,86833,86835],{"className":86832},[2719],[2721,86834],{"disabled":2723,"type":2724}," 5 câu hỏi bẫy có câu trả lời dưới 80 từ.",[968,86837,2890],{"id":2889},[2273,86839,86840,86843,86846,86849],{},[989,86841,86842],{},"Khung kể chuyện có mấy phần?",[989,86844,86845],{},"Phần nào giám khảo trông đợi nhất?",[989,86847,86848],{},"Ánh xạ SOLID sai thì sao?",[989,86850,86851],{},"Over-engineering là gì?",[3014,86853],{},[973,86855,86856],{},"🌕 Bạn đã hoàn thành ngày 166. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,86858,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":86860},[86861,86862,86867,86868,86874],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":86863},[86864,86865,86866],{"id":86646,"depth":73,"text":86647},{"id":86664,"depth":73,"text":86665},{"id":86682,"depth":73,"text":86683},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":86869},[86870,86871,86872,86873],{"id":86741,"depth":73,"text":86742},{"id":86752,"depth":73,"text":86753},{"id":86776,"depth":73,"text":86777},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Luyện kể chuyện thiết kế: chọn pattern đúng, ánh xạ SOLID, refactor trước sau và trả lời chất vấn trade-off.",{},[5194,5195],{"title":887,"description":86875},[68137,41703,5199],"fWq_0ZzuyqKN93etDArLfvXmIIDOlZkKGBYvdYAevTA",{"id":86882,"title":892,"body":86883,"category":8797,"day":895,"description":87194,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":87195,"navigation":2723,"outcomes":3047,"path":893,"prerequisites":87196,"seo":87197,"stem":894,"tags":87198,"__hash__":87200},"challenges\u002Fchallenges\u002F167.du-an-cuoi-1.md",{"type":965,"value":86884,"toc":87178},[86885,86887,86890,86892,86896,86910,86914,86928,86932,86946,86975,86977,86985,86987,86993,86997,87004,87010,87081,87085,87099,87103,87120,87122,87155,87157,87171,87173,87176],[968,86886,971],{"id":970},[973,86888,86889],{},"Bạn khởi động dự án cuối khóa. Viết rõ trước khi code.",[968,86891,979],{"id":978},[981,86893,86895],{"id":86894},"chốt-đề-tài","Chốt đề tài",[986,86897,86898,86901,86904,86907],{},[989,86899,86900],{},"Đề tài dùng ít nhất 3 kỹ thuật đã học.",[989,86902,86903],{},"Có dữ liệu thật hoặc giả lập thực tế.",[989,86905,86906],{},"Ví dụ đời thường: giống chọn món nấu được trong 4 ngày.",[989,86908,86909],{},"Demo được trong 10 phút.",[981,86911,86913],{"id":86912},"đặc-tả-yêu-cầu","Đặc tả yêu cầu",[986,86915,86916,86919,86922,86925],{},[989,86917,86918],{},"Yêu cầu hàm là hệ thống làm gì.",[989,86920,86921],{},"Yêu cầu phi hàm là nhanh và chịu tải bao nhiêu.",[989,86923,86924],{},"Ví dụ đời thường: giống đơn đặt hàng ghi món và giờ giao.",[989,86926,86927],{},"Mỗi yêu cầu có mã số để truy vết.",[981,86929,86931],{"id":86930},"chia-module-và-kế-hoạch","Chia module và kế hoạch",[986,86933,86934,86937,86940,86943],{},[989,86935,86936],{},"Chia thành module nhỏ có sơ đồ phụ thuộc.",[989,86938,86939],{},"Hợp đồng ghi rõ request và response mỗi cặp.",[989,86941,86942],{},"Ví dụ đời thường: giống chia việc bếp theo món.",[989,86944,86945],{},"Lập mốc kiểm chứng cho 3 ngày còn lại.",[1352,86947,86949],{"className":3538,"code":86948,"language":3540,"meta":1357,"style":1357},"# ví dụ hợp đồng giữa hai module\nhop_dong = {  # thỏa thuận giao tiếp\n    \"gui\": {\"user\": \"u1\"},  # bên gửi tạo đúng\n    \"nhan\": {\"top10\": []},  # bên nhận trả đúng\n}\n",[992,86950,86951,86956,86961,86966,86971],{"__ignoreMap":1357},[1023,86952,86953],{"class":1362,"line":63},[1023,86954,86955],{},"# ví dụ hợp đồng giữa hai module\n",[1023,86957,86958],{"class":1362,"line":68},[1023,86959,86960],{},"hop_dong = {  # thỏa thuận giao tiếp\n",[1023,86962,86963],{"class":1362,"line":73},[1023,86964,86965],{},"    \"gui\": {\"user\": \"u1\"},  # bên gửi tạo đúng\n",[1023,86967,86968],{"class":1362,"line":78},[1023,86969,86970],{},"    \"nhan\": {\"top10\": []},  # bên nhận trả đúng\n",[1023,86972,86973],{"class":1362,"line":83},[1023,86974,4986],{},[968,86976,1433],{"id":1432},[986,86978,86979,86982],{},[989,86980,86981],{},"3 yêu cầu hàm -> mỗi yêu cầu truy tới module và ngày kiểm chứng.",[989,86983,86984],{},"Hai module kề nhau -> request mẫu đi qua cả hai phía đúng.",[968,86986,1482],{"id":1481},[973,86988,86989,86990,1517],{},"Dự án cuối kéo dài 4 ngày (167-170). Hôm nay chỉ viết đặc tả và dựng khung. Nộp vào repo riêng ",[992,86991,86992],{},"final-project\u002F",[981,86994,86996],{"id":86995},"bài-1-chọn-đề-và-đặc-tả","Bài 1: Chọn đề và đặc tả",[973,86998,86999,87000,87003],{},"Đề tài phải dùng ",[1487,87001,87002],{},"ít nhất 3 kỹ thuật"," đã học (ví dụ: trie + cache + rate limiter; đồ thị + heap + SA; recsys + MapReduce + stream). Gợi ý: công cụ tìm tài liệu nội bộ, hệ gợi ý bài tập, bản đồ giao hàng, chat có kiểm duyệt.",[973,87005,87006,87009],{},[992,87007,87008],{},"SPEC.md"," gồm:",[1099,87011,87012,87022],{},[1102,87013,87014],{},[1105,87015,87016,87019],{},[1108,87017,87018],{},"Mục",[1108,87020,87021],{},"Nội dung",[1118,87023,87024,87031,87043,87054,87065,87073],{},[1105,87025,87026,87028],{},[1123,87027,54328],{},[1123,87029,87030],{},"3-5 câu, ai dùng, vì sao cần",[1105,87032,87033,87036],{},[1123,87034,87035],{},"Yêu cầu chức năng",[1123,87037,87038,87039,87042],{},"Đánh mã ",[992,87040,87041],{},"F1, F2...",", mỗi cái kiểm chứng được",[1105,87044,87045,87048],{},[1123,87046,87047],{},"Yêu cầu phi chức năng",[1123,87049,87038,87050,87053],{},[992,87051,87052],{},"N1, N2..."," với con số: độ trễ p95, thông lượng, bộ nhớ, kích thước dữ liệu",[1105,87055,87056,87059],{},[1123,87057,87058],{},"Ngoài phạm vi",[1123,87060,87061,87062,87064],{},"Những gì ",[1487,87063,41587],{}," làm",[1105,87066,87067,87070],{},[1123,87068,87069],{},"Dữ liệu",[1123,87071,87072],{},"Nguồn, kích thước, cách sinh nếu giả lập",[1105,87074,87075,87078],{},[1123,87076,87077],{},"Tiêu chí demo",[1123,87079,87080],{},"Kịch bản demo 10 phút",[981,87082,87084],{"id":87083},"bài-2-kiến-trúc-và-hợp-đồng","Bài 2: Kiến trúc và hợp đồng",[2273,87086,87087,87093,87096],{},[989,87088,87089,87092],{},[992,87090,87091],{},"ARCHITECTURE.md",": sơ đồ module (Mermaid), mỗi module 1 trách nhiệm, sơ đồ phụ thuộc không có vòng.",[989,87094,87095],{},"Hợp đồng giữa các module: chữ ký hàm hoặc định dạng request\u002Fresponse, kèm ví dụ.",[989,87097,87098],{},"Bảng truy vết: yêu cầu nào do module nào đảm nhận.",[981,87100,87102],{"id":87101},"bài-3-khung-dự-án-nâng-cao","Bài 3: Khung dự án (nâng cao)",[2273,87104,87105,87108,87111,87114],{},[989,87106,87107],{},"Repo có cấu trúc thư mục theo module, build 1 lệnh, test 1 lệnh (dù chưa có test thật).",[989,87109,87110],{},"CI chạy build và test mỗi lần push.",[989,87112,87113],{},"Mỗi module có 1 test \"khói\" gọi hàm giả (stub) trả dữ liệu cố định.",[989,87115,87116,87119],{},[992,87117,87118],{},"PLAN.md",": mốc cho ngày 168, 169, 170, và rủi ro lớn nhất cùng cách giảm.",[981,87121,2711],{"id":2710},[986,87123,87125,87133,87141,87147],{"className":87124},[2715],[989,87126,87128,2308,87130,87132],{"className":87127},[2719],[2721,87129],{"disabled":2723,"type":2724},[992,87131,87008],{}," đủ 6 mục, yêu cầu phi chức năng có con số.",[989,87134,87136,2308,87138,87140],{"className":87135},[2719],[2721,87137],{"disabled":2723,"type":2724},[992,87139,87091],{}," có sơ đồ và bảng truy vết.",[989,87142,87144,87146],{"className":87143},[2719],[2721,87145],{"disabled":2723,"type":2724}," Repo build và test 1 lệnh, CI xanh.",[989,87148,87150,2308,87152,87154],{"className":87149},[2719],[2721,87151],{"disabled":2723,"type":2724},[992,87153,87118],{}," có mốc và rủi ro.",[968,87156,2890],{"id":2889},[2273,87158,87159,87162,87165,87168],{},[989,87160,87161],{},"Đề tài cần thỏa mấy điều kiện?",[989,87163,87164],{},"Yêu cầu hàm khác phi hàm ở đâu?",[989,87166,87167],{},"Hợp đồng module ghi gì?",[989,87169,87170],{},"Vì sao cấm code sản phẩm hôm nay?",[3014,87172],{},[973,87174,87175],{},"🌕 Bạn đã hoàn thành ngày 167. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,87177,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":87179},[87180,87181,87186,87187,87193],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":87182},[87183,87184,87185],{"id":86894,"depth":73,"text":86895},{"id":86912,"depth":73,"text":86913},{"id":86930,"depth":73,"text":86931},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":87188},[87189,87190,87191,87192],{"id":86995,"depth":73,"text":86996},{"id":87083,"depth":73,"text":87084},{"id":87101,"depth":73,"text":87102},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Khởi động dự án cuối khóa: chốt đề tài, viết đặc tả yêu cầu, chia module và hợp đồng giao tiếp giữa các nhóm.",{},[15144],{"title":892,"description":87194},[87199,17502],"project","lKKTzANcTPZXCd3B0MfVonF1K6AgRyJu9GZ1eg23FK0",{"id":87202,"title":897,"body":87203,"category":8797,"day":900,"description":87468,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":87469,"navigation":2723,"outcomes":3047,"path":898,"prerequisites":87470,"seo":87471,"stem":899,"tags":87472,"__hash__":87473},"challenges\u002Fchallenges\u002F168.du-an-cuoi-2.md",{"type":965,"value":87204,"toc":87452},[87205,87207,87210,87212,87216,87230,87234,87248,87252,87266,87296,87298,87306,87308,87313,87317,87328,87332,87356,87360,87387,87393,87398,87400,87429,87431,87445,87447,87450],[968,87206,971],{"id":970},[973,87208,87209],{},"Bạn xây module lõi rồi đo tốc độ. Mọi nhận định phải có số liệu.",[968,87211,979],{"id":978},[981,87213,87215],{"id":87214},"module-lõi-đúng-trước","Module lõi đúng trước",[986,87217,87218,87221,87224,87227],{},[989,87219,87220],{},"Lõi là phần quan trọng nhất của dự án.",[989,87222,87223],{},"Chạy đúng trên dữ liệu mẫu nhỏ trước.",[989,87225,87226],{},"Ví dụ đời thường: giống xây móng nhà trước khi lên tầng.",[989,87228,87229],{},"Kèm kiểm thử biên như rỗng và một phần tử.",[981,87231,87233],{"id":87232},"benchmark-và-baseline","Benchmark và baseline",[986,87235,87236,87239,87242,87245],{},[989,87237,87238],{},"Benchmark là khung đo tốc độ chuẩn.",[989,87240,87241],{},"Baseline là số đo lần đầu để so sánh.",[989,87243,87244],{},"Ví dụ đời thường: giống cân lần đầu trước khi giảm cân.",[989,87246,87247],{},"Tách thời gian thuật toán khỏi đọc file.",[981,87249,87251],{"id":87250},"profiling-và-tối-ưu","Profiling và tối ưu",[986,87253,87254,87257,87260,87263],{},[989,87255,87256],{},"Profiling tìm 3 hàm tốn thời gian nhất.",[989,87258,87259],{},"Sửa thuật toán trước, sửa hằng số sau.",[989,87261,87262],{},"Ví dụ đời thường: giống tìm đoạn kẹt xe nhất để mở đường.",[989,87264,87265],{},"Đo lại sau sửa, tệ hơn thì hoàn tác.",[1352,87267,87269],{"className":3538,"code":87268,"language":3540,"meta":1357,"style":1357},"# đo thời gian chạy hàm\nimport time  # đồng hồ đo\nbat_dau = time.time()  # mốc bắt đầu\nsum(range(1000))  # hàm cần đo\nprint(time.time() - bat_dau)  # thời gian chạy\n",[992,87270,87271,87276,87281,87286,87291],{"__ignoreMap":1357},[1023,87272,87273],{"class":1362,"line":63},[1023,87274,87275],{},"# đo thời gian chạy hàm\n",[1023,87277,87278],{"class":1362,"line":68},[1023,87279,87280],{},"import time  # đồng hồ đo\n",[1023,87282,87283],{"class":1362,"line":73},[1023,87284,87285],{},"bat_dau = time.time()  # mốc bắt đầu\n",[1023,87287,87288],{"class":1362,"line":78},[1023,87289,87290],{},"sum(range(1000))  # hàm cần đo\n",[1023,87292,87293],{"class":1362,"line":83},[1023,87294,87295],{},"print(time.time() - bat_dau)  # thời gian chạy\n",[968,87297,1433],{"id":1432},[986,87299,87300,87303],{},[989,87301,87302],{},"5 kiểm thử biên -> xanh hết trên dữ liệu mẫu.",[989,87304,87305],{},"Chạy benchmark hai lần -> chênh lệch dưới 15%.",[968,87307,1482],{"id":1481},[973,87309,87310,87311,1517],{},"Dự án cuối, ngày 2. Nộp vào repo ",[992,87312,86992],{},[981,87314,87316],{"id":87315},"bài-1-cài-đặt-lõi","Bài 1: Cài đặt lõi",[2273,87318,87319,87322,87325],{},[989,87320,87321],{},"Cài module lõi (phần chứa thuật toán chính) thay cho stub.",[989,87323,87324],{},"Test đơn vị cho lõi: ca thường, ca biên (rỗng, 1 phần tử, dữ liệu trùng, dữ liệu rất lớn), ca lỗi (input sai).",[989,87326,87327],{},"Test \"vàng\": 5 input nhỏ có đáp án tính tay, lưu thành file và so tự động.",[981,87329,87331],{"id":87330},"bài-2-benchmark-và-baseline","Bài 2: Benchmark và baseline",[2273,87333,87334,87343,87346],{},[989,87335,87336,87339,87340,87342],{},[992,87337,87338],{},"bench\u002F"," chạy lõi trên 3 cỡ dữ liệu (nhỏ, vừa, đúng cỡ yêu cầu ",[992,87341,20421],{},"). Ghi CSV kèm thông tin máy.",[989,87344,87345],{},"Tách thời gian đọc dữ liệu khỏi thời gian thuật toán.",[989,87347,87348,87349,8530,87352,87355],{},"Ghi ",[1487,87350,87351],{},"baseline",[992,87353,87354],{},"BENCHMARK.md",". So với yêu cầu phi chức năng: đạt hay chưa, thiếu bao nhiêu.",[981,87357,87359],{"id":87358},"bài-3-profile-và-tối-ưu-nâng-cao","Bài 3: Profile và tối ưu (nâng cao)",[2273,87361,87362,87381,87384],{},[989,87363,87364,87365,2461,87367,87370,87371,2461,87373,87376,87377,87380],{},"Profile bằng ",[992,87366,81065],{},[992,87368,87369],{},"gprof"," (C++), ",[992,87372,81068],{},[992,87374,87375],{},"cProfile"," (Python), hoặc ",[992,87378,87379],{},"pprof"," (Go). Lưu flame graph.",[989,87382,87383],{},"Liệt kê 3 hàm tốn thời gian nhất.",[989,87385,87386],{},"Tối ưu theo thứ tự: thuật toán, cấu trúc dữ liệu, rồi mới tới hằng số. Mỗi lần sửa 1 thứ, đo lại, ghi vào bảng:",[1352,87388,87391],{"className":87389,"code":87390,"language":2241,"meta":1357},[2239],"thay_đổi                          p95_trước   p95_sau   giữ_hay_bỏ\nđổi list sang heap                ...\nbỏ copy chuỗi trong vòng lặp      ...\n",[992,87392,87390],{"__ignoreMap":1357},[2273,87394,87395],{"start":78},[989,87396,87397],{},"Sửa nào làm chậm hơn thì hoàn tác và ghi lại.",[981,87399,2711],{"id":2710},[986,87401,87403,87409,87417,87423],{"className":87402},[2715],[989,87404,87406,87408],{"className":87405},[2719],[2721,87407],{"disabled":2723,"type":2724}," Test đơn vị và test vàng pass, CI xanh.",[989,87410,87412,2308,87414,87416],{"className":87411},[2719],[2721,87413],{"disabled":2723,"type":2724},[992,87415,87354],{}," có baseline so với yêu cầu.",[989,87418,87420,87422],{"className":87419},[2719],[2721,87421],{"disabled":2723,"type":2724}," Có flame graph và bảng tối ưu từng bước.",[989,87424,87426,87428],{"className":87425},[2719],[2721,87427],{"disabled":2723,"type":2724}," Mọi thay đổi tối ưu có số đo trước và sau.",[968,87430,2890],{"id":2889},[2273,87432,87433,87436,87439,87442],{},[989,87434,87435],{},"Module lõi là gì?",[989,87437,87438],{},"Baseline để làm gì?",[989,87440,87441],{},"Profiling tìm cái gì?",[989,87443,87444],{},"Sửa thuật toán trước hay hằng số trước?",[3014,87446],{},[973,87448,87449],{},"🌕 Bạn đã hoàn thành ngày 168. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,87451,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":87453},[87454,87455,87460,87461,87467],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":87456},[87457,87458,87459],{"id":87214,"depth":73,"text":87215},{"id":87232,"depth":73,"text":87233},{"id":87250,"depth":73,"text":87251},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":87462},[87463,87464,87465,87466],{"id":87315,"depth":73,"text":87316},{"id":87330,"depth":73,"text":87331},{"id":87358,"depth":73,"text":87359},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Xây module lõi dự án cuối khóa, benchmark hiệu năng, profiling tìm bottleneck và tối ưu có số liệu trước sau.",{},[17499,3050],{"title":897,"description":87468},[87199,79774],"9r9mI4ZvYflVhEEP7cp1lM0znS4REGJlzwk6sFlImwA",{"id":87475,"title":902,"body":87476,"category":8797,"day":905,"description":87732,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":87733,"navigation":2723,"outcomes":3047,"path":903,"prerequisites":87734,"seo":87735,"stem":904,"tags":87736,"__hash__":87738},"challenges\u002Fchallenges\u002F169.du-an-cuoi-3.md",{"type":965,"value":87477,"toc":87716},[87478,87480,87483,87485,87489,87503,87507,87521,87525,87539,87569,87571,87579,87581,87586,87590,87612,87618,87622,87640,87646,87650,87664,87666,87693,87695,87709,87711,87714],[968,87479,971],{"id":970},[973,87481,87482],{},"Bạn nâng dự án lên dữ liệu lớn gấp mười. Mọi con số cần có đối chứng.",[968,87484,979],{"id":978},[981,87486,87488],{"id":87487},"mở-rộng-pipeline","Mở rộng pipeline",[986,87490,87491,87494,87497,87500],{},[989,87492,87493],{},"Tăng dữ liệu gấp mười để lộ điểm vỡ.",[989,87495,87496],{},"Batch gom mẻ xử lý, stream xử lý ngay.",[989,87498,87499],{},"Ví dụ đời thường: giống thử quán với 10 lần khách.",[989,87501,87502],{},"Ghi lại thời gian và bộ nhớ ở quy mô mới.",[981,87504,87506],{"id":87505},"đánh-giá-đúng-cách","Đánh giá đúng cách",[986,87508,87509,87512,87515,87518],{},[989,87510,87511],{},"Chia tập huấn luyện và kiểm thử riêng.",[989,87513,87514],{},"Metric luôn so với baseline ngây thơ.",[989,87516,87517],{},"Ví dụ đời thường: giống chấm thi phải có điểm liệt để so.",[989,87519,87520],{},"Giữ seed để chạy lại ra cùng số.",[981,87522,87524],{"id":87523},"mổ-lỗi-và-chốt-metric","Mổ lỗi và chốt metric",[986,87526,87527,87530,87533,87536],{},[989,87528,87529],{},"Gom 50 lỗi mẫu rồi phân nhóm nguyên nhân.",[989,87531,87532],{},"Xử lý nhiễu, thiếu và ngoại lai.",[989,87534,87535],{},"Ví dụ đời thường: giống phân loại hàng lỗi theo nguyên nhân.",[989,87537,87538],{},"Chốt bảng metric kèm độ lệch nhiều lần chạy.",[1352,87540,87542],{"className":3538,"code":87541,"language":3540,"meta":1357,"style":1357},"# chia tập đơn giản\ndu_lieu = list(range(100))  # 100 mẫu\ncat = int(0.8 * len(du_lieu))  # mốc 80 phần trăm\ntrain, test = du_lieu[:cat], du_lieu[cat:]  # chia train test\nprint(len(train), len(test))  # ra 80 20\n",[992,87543,87544,87549,87554,87559,87564],{"__ignoreMap":1357},[1023,87545,87546],{"class":1362,"line":63},[1023,87547,87548],{},"# chia tập đơn giản\n",[1023,87550,87551],{"class":1362,"line":68},[1023,87552,87553],{},"du_lieu = list(range(100))  # 100 mẫu\n",[1023,87555,87556],{"class":1362,"line":73},[1023,87557,87558],{},"cat = int(0.8 * len(du_lieu))  # mốc 80 phần trăm\n",[1023,87560,87561],{"class":1362,"line":78},[1023,87562,87563],{},"train, test = du_lieu[:cat], du_lieu[cat:]  # chia train test\n",[1023,87565,87566],{"class":1362,"line":83},[1023,87567,87568],{},"print(len(train), len(test))  # ra 80 20\n",[968,87570,1433],{"id":1432},[986,87572,87573,87576],{},[989,87574,87575],{},"Pipeline chạy hết dữ liệu gấp mười mà không hết bộ nhớ.",[989,87577,87578],{},"Train và test không trùng mẫu, chạy lại số lệch ít.",[968,87580,1482],{"id":1481},[973,87582,87583,87584,1517],{},"Dự án cuối, ngày 3. Nộp vào repo ",[992,87585,86992],{},[981,87587,87589],{"id":87588},"bài-1-tăng-quy-mô-gấp-10","Bài 1: Tăng quy mô gấp 10",[2273,87591,87592,87599,87609],{},[989,87593,87594,87595,2528,87597,1517],{},"Sinh hoặc tải dữ liệu gấp 10 lần cỡ yêu cầu ",[992,87596,20421],{},[992,87598,87008],{},[989,87600,87601,87602,5586,87605,87608],{},"Chạy toàn bộ pipeline. Ghi thời gian, bộ nhớ đỉnh (",[992,87603,87604],{},"\u002Fusr\u002Fbin\u002Ftime -v",[992,87606,87607],{},"tracemalloc","), và chỗ vỡ đầu tiên.",[989,87610,87611],{},"Sửa chỗ vỡ: đọc theo luồng thay vì nạp hết, xử lý theo lô, hoặc chuyển phần nặng sang chế độ batch\u002Fstream phù hợp.",[1352,87613,87616],{"className":87614,"code":87615,"language":2241,"meta":1357},[2239],"quy_mô   thời_gian   bộ_nhớ_đỉnh   trạng_thái\nN        ...         ...           ok\n10N      ...         ...           vỡ ở đâu \u002F ok sau khi sửa\n",[992,87617,87615],{"__ignoreMap":1357},[981,87619,87621],{"id":87620},"bài-2-đánh-giá-có-kiểm-soát","Bài 2: Đánh giá có kiểm soát",[2273,87623,87624,87631,87637],{},[989,87625,87626,87627,87630],{},"Chia train\u002Ftest (hoặc tập truy vấn đánh giá) cố định, ",[1487,87628,87629],{},"không trùng mẫu",". Có test kiểm tra không trùng.",[989,87632,87633,87634,87636],{},"Tính metric chính trong ",[992,87635,87008],{}," và so với 1 baseline ngây thơ (đoán đa số, quét tuyến tính, gợi ý phổ biến, tùy dự án).",[989,87638,87639],{},"Chạy 3 lần với 3 seed. Báo cáo trung bình và độ lệch chuẩn.",[1352,87641,87644],{"className":87642,"code":87643,"language":2241,"meta":1357},[2239],"phương_pháp   metric_chính   độ_lệch   thời_gian\nbaseline      ...\ndự án         ...\n",[992,87645,87643],{"__ignoreMap":1357},[981,87647,87649],{"id":87648},"bài-3-phân-tích-lỗi-nâng-cao","Bài 3: Phân tích lỗi (nâng cao)",[2273,87651,87652,87655,87658],{},[989,87653,87654],{},"Lấy 50 trường hợp sai (hoặc chậm nhất). Phân nhóm nguyên nhân: dữ liệu nhiễu, thiếu giá trị, ngoại lai, giới hạn thuật toán, lỗi code.",[989,87656,87657],{},"Sửa nhóm lớn nhất. Đo lại metric.",[989,87659,87660,87663],{},[992,87661,87662],{},"EVALUATION.md",": bảng quy mô, bảng metric, bảng nhóm lỗi, việc chưa sửa và lý do.",[981,87665,2711],{"id":2710},[986,87667,87669,87675,87681,87687],{"className":87668},[2715],[989,87670,87672,87674],{"className":87671},[2719],[2721,87673],{"disabled":2723,"type":2724}," Pipeline chạy hết dữ liệu 10N, có bảng thời gian và bộ nhớ.",[989,87676,87678,87680],{"className":87677},[2719],[2721,87679],{"disabled":2723,"type":2724}," Test chứng minh train\u002Ftest không trùng.",[989,87682,87684,87686],{"className":87683},[2719],[2721,87685],{"disabled":2723,"type":2724}," Metric có baseline và độ lệch 3 lần chạy.",[989,87688,87690,87692],{"className":87689},[2719],[2721,87691],{"disabled":2723,"type":2724}," Bảng 50 lỗi phân nhóm.",[968,87694,2890],{"id":2889},[2273,87696,87697,87700,87703,87706],{},[989,87698,87699],{},"Vì sao tăng dữ liệu gấp mười?",[989,87701,87702],{},"Baseline ngây thơ để làm gì?",[989,87704,87705],{},"Seed giữ để làm gì?",[989,87707,87708],{},"Mổ lỗi xong làm gì tiếp?",[3014,87710],{},[973,87712,87713],{},"🌕 Bạn đã hoàn thành ngày 169. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,87715,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":87717},[87718,87719,87724,87725,87731],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":87720},[87721,87722,87723],{"id":87487,"depth":73,"text":87488},{"id":87505,"depth":73,"text":87506},{"id":87523,"depth":73,"text":87524},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":87726},[87727,87728,87729,87730],{"id":87588,"depth":73,"text":87589},{"id":87620,"depth":73,"text":87621},{"id":87648,"depth":73,"text":87649},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nâng dự án lên dữ liệu lớn: pipeline batch stream, đánh giá độ chính xác, xử lý nhiễu thiếu và chốt báo cáo metric.",{},[14055,18469],{"title":902,"description":87732},[87199,87737],"evaluate","AVv4wcKCFGoY9F2lczJ5jEUG_loFG1Y3QhJrkCjy23I",{"id":87740,"title":907,"body":87741,"category":5189,"day":910,"description":87996,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":87997,"navigation":2723,"outcomes":3047,"path":908,"prerequisites":87998,"seo":87999,"stem":909,"tags":88000,"__hash__":88001},"challenges\u002Fchallenges\u002F170.du-an-cuoi-4.md",{"type":965,"value":87742,"toc":87980},[87743,87745,87748,87750,87754,87768,87772,87786,87790,87804,87842,87844,87852,87854,87859,87863,87880,87886,87890,87901,87905,87928,87930,87957,87959,87973,87975,87978],[968,87744,971],{"id":970},[973,87746,87747],{},"Bạn hoàn thiện dự án cuối khóa. Sửa nhỏ từng bước có kiểm thử.",[968,87749,979],{"id":978},[981,87751,87753],{"id":87752},"áp-patterns-đúng-chỗ","Áp patterns đúng chỗ",[986,87755,87756,87759,87762,87765],{},[989,87757,87758],{},"Liệt kê mùi hôi trong code trước.",[989,87760,87761],{},"Mỗi pattern trị một mùi cụ thể.",[989,87763,87764],{},"Ví dụ đời thường: giống uống thuốc đúng bệnh.",[989,87766,87767],{},"Gỡ pattern ra mà mùi quay lại mới là cần thiết.",[981,87769,87771],{"id":87770},"review-chéo","Review chéo",[986,87773,87774,87777,87780,87783],{},[989,87775,87776],{},"Review chéo là đọc code cho nhau.",[989,87778,87779],{},"Ghi ít nhất 10 phát hiện có mức độ.",[989,87781,87782],{},"Ví dụ đời thường: giống chấm bài chéo trong lớp.",[989,87784,87785],{},"Cả hai chiều đều ghi biên bản.",[981,87787,87789],{"id":87788},"sửa-và-đóng-gói-demo","Sửa và đóng gói demo",[986,87791,87792,87795,87798,87801],{},[989,87793,87794],{},"Sửa lỗi đúng trước, làm đẹp sau.",[989,87796,87797],{},"Mỗi lần sửa chạy lại kiểm thử và benchmark.",[989,87799,87800],{},"Ví dụ đời thường: giống vá lốp xong phải chạy thử.",[989,87802,87803],{},"Đóng gói một lệnh chạy kèm kịch bản 10 phút.",[1352,87805,87807],{"className":3538,"code":87806,"language":3540,"meta":1357,"style":1357},"# strategy thay thuật toán demo\nclass CachNhanh:  # một cách làm\n    def chay(self):\n        return \"chạy nhanh\"  # bản nhanh\nclass CachChuan:  # cách khác\n    def chay(self):\n        return \"chạy chuẩn\"  # bản chuẩn\n",[992,87808,87809,87814,87819,87823,87828,87833,87837],{"__ignoreMap":1357},[1023,87810,87811],{"class":1362,"line":63},[1023,87812,87813],{},"# strategy thay thuật toán demo\n",[1023,87815,87816],{"class":1362,"line":68},[1023,87817,87818],{},"class CachNhanh:  # một cách làm\n",[1023,87820,87821],{"class":1362,"line":73},[1023,87822,83469],{},[1023,87824,87825],{"class":1362,"line":78},[1023,87826,87827],{},"        return \"chạy nhanh\"  # bản nhanh\n",[1023,87829,87830],{"class":1362,"line":83},[1023,87831,87832],{},"class CachChuan:  # cách khác\n",[1023,87834,87835],{"class":1362,"line":88},[1023,87836,83469],{},[1023,87838,87839],{"class":1362,"line":93},[1023,87840,87841],{},"        return \"chạy chuẩn\"  # bản chuẩn\n",[968,87843,1433],{"id":1432},[986,87845,87846,87849],{},[989,87847,87848],{},"3 patterns -> mỗi pattern truy tới một mùi gốc.",[989,87850,87851],{},"Biên bản review -> đủ 10 phát hiện có vị trí.",[968,87853,1482],{"id":1481},[973,87855,87856,87857,1517],{},"Dự án cuối, ngày 4. Nộp vào repo ",[992,87858,86992],{},[981,87860,87862],{"id":87861},"bài-1-mùi-hôi-và-pattern","Bài 1: Mùi hôi và pattern",[2273,87864,87865,87871,87874],{},[989,87866,87867,87868,87870],{},"Liệt kê 5 \"mùi hôi\" trong code dự án kèm vị trí file:dòng (hàm quá dài, ",[992,87869,46856],{}," theo kiểu, lặp code, lớp ôm nhiều việc, phụ thuộc cứng).",[989,87872,87873],{},"Chọn 3 mùi, trị bằng pattern phù hợp. Mỗi lần refactor 1 commit, test và benchmark trước sau phải giống nhau.",[989,87875,87876,87879],{},[992,87877,87878],{},"PATTERNS.md",": bảng mùi, pattern, lý do, và kiểm chứng \"gỡ pattern ra thì mùi quay lại\".",[973,87881,87882,87883,87885],{},"Bắt buộc: có ít nhất 1 mùi bạn quyết định ",[1487,87884,41587],{}," trị bằng pattern, và giải thích.",[981,87887,87889],{"id":87888},"bài-2-review-chéo","Bài 2: Review chéo",[2273,87891,87892,87895,87898],{},[989,87893,87894],{},"Đổi repo với 1 người khác (hoặc tự review code sau khi nghỉ 1 ngày).",[989,87896,87897],{},"Biên bản review ít nhất 10 phát hiện, mỗi phát hiện có: vị trí, mức độ (lỗi \u002F hiệu năng \u002F dễ đọc \u002F tài liệu), đề xuất.",[989,87899,87900],{},"Sửa các phát hiện mức \"lỗi\" trước. Ghi phát hiện nào không sửa và vì sao.",[981,87902,87904],{"id":87903},"bài-3-đóng-gói-demo-nâng-cao","Bài 3: Đóng gói demo (nâng cao)",[2273,87906,87907,87917,87920,87923],{},[989,87908,87909,87910,1656,87913,87916],{},"Một lệnh cài và chạy: ",[992,87911,87912],{},"make demo",[992,87914,87915],{},"docker compose up",", hoặc script tương đương.",[989,87918,87919],{},"Người khác clone repo sạch, chạy được trong 15 phút. Ghi lại mọi chỗ họ vấp và sửa README.",[989,87921,87922],{},"Kịch bản demo 10 phút: vấn đề (2 phút), chạy sống (5 phút), số liệu (2 phút), hỏi đáp (1 phút).",[989,87924,87925,87926,1517],{},"Chạy lại toàn bộ test và benchmark lần cuối, cập nhật ",[992,87927,87354],{},[981,87929,2711],{"id":2710},[986,87931,87933,87939,87945,87951],{"className":87932},[2715],[989,87934,87936,87938],{"className":87935},[2719],[2721,87937],{"disabled":2723,"type":2724}," 3 refactor có commit riêng, test và benchmark không đổi.",[989,87940,87942,87944],{"className":87941},[2719],[2721,87943],{"disabled":2723,"type":2724}," Biên bản review đủ 10 phát hiện.",[989,87946,87948,87950],{"className":87947},[2719],[2721,87949],{"disabled":2723,"type":2724}," Người khác chạy được demo từ repo sạch.",[989,87952,87954,87956],{"className":87953},[2719],[2721,87955],{"disabled":2723,"type":2724}," Kịch bản demo 10 phút viết sẵn.",[968,87958,2890],{"id":2889},[2273,87960,87961,87964,87967,87970],{},[989,87962,87963],{},"Pattern cần truy tới cái gì?",[989,87965,87966],{},"Review chéo ghi mấy phát hiện?",[989,87968,87969],{},"Sửa theo thứ tự nào?",[989,87971,87972],{},"Cấm refactor kiểu gì giờ chót?",[3014,87974],{},[973,87976,87977],{},"🌕 Bạn đã hoàn thành ngày 170. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,87979,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":87981},[87982,87983,87988,87989,87995],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":87984},[87985,87986,87987],{"id":87752,"depth":73,"text":87753},{"id":87770,"depth":73,"text":87771},{"id":87788,"depth":73,"text":87789},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":87990},[87991,87992,87993,87994],{"id":87861,"depth":73,"text":87862},{"id":87888,"depth":73,"text":87889},{"id":87903,"depth":73,"text":87904},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Hoàn thiện dự án cuối khóa: áp dụng patterns đúng chỗ, review chéo, sửa theo feedback và đóng gói bản demo.",{},[5194],{"title":907,"description":87996},[87199,41703,79772],"jn-DxFCt4yOpLrrykNfIOOICE9a37RZaDCDepkubofA",{"id":88003,"title":912,"body":88004,"category":8797,"day":915,"description":88244,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":88245,"navigation":2723,"outcomes":3047,"path":913,"prerequisites":88246,"seo":88247,"stem":914,"tags":88248,"__hash__":88250},"challenges\u002Fchallenges\u002F171.tong-ket-180-ngay.md",{"type":965,"value":88005,"toc":88228},[88006,88008,88011,88013,88017,88031,88035,88049,88053,88067,88069,88077,88079,88085,88089,88096,88116,88119,88123,88129,88166,88169,88173,88184,88186,88207,88209,88223,88225],[968,88007,971],{"id":970},[973,88009,88010],{},"Bạn nhìn lại cả hành trình 180 ngày. Vẽ một bản đồ tri thức của riêng mình.",[968,88012,979],{"id":978},[981,88014,88016],{"id":88015},"_6-cụm-kiến-thức","6 cụm kiến thức",[986,88018,88019,88022,88025,88028],{},[989,88020,88021],{},"Chia giấy thành 6 cụm đã học.",[989,88023,88024],{},"Mỗi cụm ghi ít nhất 3 chủ đề.",[989,88026,88027],{},"Ví dụ đời thường: giống vẽ bản đồ 6 tỉnh đã đi qua.",[989,88029,88030],{},"Nối mũi tên phụ thuộc giữa các cụm.",[981,88032,88034],{"id":88033},"tự-chấm-sao","Tự chấm sao",[986,88036,88037,88040,88043,88046],{},[989,88038,88039],{},"Mỗi chủ đề tự chấm 1 tới 5 sao.",[989,88041,88042],{},"Mỗi sao cần một bằng chứng cụ thể.",[989,88044,88045],{},"Ví dụ đời thường: giống chấm sao quán phải có ảnh món.",[989,88047,88048],{},"Cảm nhận cao mà không có sản phẩm thì hạ sao.",[981,88050,88052],{"id":88051},"chốt-mạnh-yếu","Chốt mạnh yếu",[986,88054,88055,88058,88061,88064],{},[989,88056,88057],{},"Khoanh 3 vùng mạnh nhất để kể với nhà tuyển dụng.",[989,88059,88060],{},"Khoanh 3 vùng yếu nhất để học tiếp.",[989,88062,88063],{},"Ví dụ đời thường: giống tổng kết đội bóng: mạnh đâu, yếu đâu.",[989,88065,88066],{},"Vùng mạnh phải có sản phẩm chứng minh.",[968,88068,1433],{"id":1432},[986,88070,88071,88074],{},[989,88072,88073],{},"Bản đồ đủ 6 cụm, mỗi cụm có bằng chứng -> đạt.",[989,88075,88076],{},"3 vùng mạnh có sản phẩm, 3 vùng yếu có kế hoạch -> đạt.",[968,88078,1482],{"id":1481},[973,88080,88081,88082,1517],{},"Không có code mới. Nộp vào ",[992,88083,88084],{},"day-171\u002F",[981,88086,88088],{"id":88087},"bài-1-bản-đồ-tri-thức","Bài 1: Bản đồ tri thức",[973,88090,88091,88092,88095],{},"Vẽ bản đồ (Mermaid ",[992,88093,88094],{},"mindmap",", Excalidraw, hoặc giấy rồi chụp) gồm 6 cụm:",[2273,88097,88098,88101,88104,88107,88110,88113],{},[989,88099,88100],{},"Cấu trúc dữ liệu cơ bản (mảng, list, stack, queue, hash, cây, heap).",[989,88102,88103],{},"Cấu trúc dữ liệu nâng cao (trie, Bloom, Union-Find, treap, k-d tree, R-tree, B+ tree, cache).",[989,88105,88106],{},"Thuật toán (sắp xếp, tìm kiếm, đồ thị, DP, greedy, tối ưu SA\u002FGA).",[989,88108,88109],{},"Dữ liệu và học máy (clustering, supervised, recsys, NLP, mạng nơ-ron).",[989,88111,88112],{},"Hệ thống (MapReduce, Spark, stream, CAP, mật mã, system design).",[989,88114,88115],{},"Thiết kế (SOLID và các design pattern).",[973,88117,88118],{},"Mỗi cụm ít nhất 5 chủ đề. Vẽ mũi tên phụ thuộc giữa các chủ đề (ví dụ heap -> Dijkstra -> A*).",[981,88120,88122],{"id":88121},"bài-2-chấm-sao-có-bằng-chứng","Bài 2: Chấm sao có bằng chứng",[973,88124,88125,88128],{},[992,88126,88127],{},"skills.md",": mỗi chủ đề 1 dòng.",[1099,88130,88131,88147],{},[1102,88132,88133],{},[1105,88134,88135,88138,88141,88144],{},[1108,88136,88137],{},"Chủ đề",[1108,88139,88140],{},"Sao (1-5)",[1108,88142,88143],{},"Bằng chứng",[1108,88145,88146],{},"Ngày",[1118,88148,88149],{},[1105,88150,88151,88154,88156,88163],{},[1123,88152,88153],{},"LRU cache",[1123,88155,25255],{},[1123,88157,88158,1656,88160,88162],{},[992,88159,28846],{},[992,88161,77518],{}," benchmark p99",[1123,88164,88165],{},"39, 144",[973,88167,88168],{},"Luật: 3 sao cần có code chạy được, 4 sao cần có test và số đo, 5 sao cần giải thích được cho người khác (có bài viết hoặc đã dạy lại). Không có bằng chứng thì tối đa 2 sao.",[981,88170,88172],{"id":88171},"bài-3-mạnh-yếu-và-kế-hoạch-nâng-cao","Bài 3: Mạnh, yếu và kế hoạch (nâng cao)",[2273,88174,88175,88178,88181],{},[989,88176,88177],{},"Khoanh 3 vùng mạnh nhất. Với mỗi vùng: 1 sản phẩm chứng minh, 1 câu chuyện kể được trong phỏng vấn.",[989,88179,88180],{},"Khoanh 3 vùng yếu nhất. Với mỗi vùng: vì sao yếu, 1 bài tập cụ thể sẽ làm trong 2 tuần tới.",[989,88182,88183],{},"So bản đồ với lúc bắt đầu (nếu có ghi chép ngày 1). Viết 5 câu về thay đổi lớn nhất.",[981,88185,2711],{"id":2710},[986,88187,88189,88195,88201],{"className":88188},[2715],[989,88190,88192,88194],{"className":88191},[2719],[2721,88193],{"disabled":2723,"type":2724}," Bản đồ đủ 6 cụm, mỗi cụm ít nhất 5 chủ đề, có mũi tên phụ thuộc.",[989,88196,88198,88200],{"className":88197},[2719],[2721,88199],{"disabled":2723,"type":2724}," Mỗi sao từ 3 trở lên có bằng chứng dẫn tới thư mục cụ thể.",[989,88202,88204,88206],{"className":88203},[2719],[2721,88205],{"disabled":2723,"type":2724}," 3 vùng mạnh có sản phẩm, 3 vùng yếu có bài tập cụ thể.",[968,88208,2890],{"id":2889},[2273,88210,88211,88214,88217,88220],{},[989,88212,88213],{},"Bản đồ có mấy cụm?",[989,88215,88216],{},"Sao cần kèm theo gì?",[989,88218,88219],{},"Cảm nhận cao mà yếu sản phẩm thì sao?",[989,88221,88222],{},"Vùng mạnh để làm gì?",[3014,88224],{},[973,88226,88227],{},"🌕 Bạn đã hoàn thành ngày 171. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":88229},[88230,88231,88236,88237,88243],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":88232},[88233,88234,88235],{"id":88015,"depth":73,"text":88016},{"id":88033,"depth":73,"text":88034},{"id":88051,"depth":73,"text":88052},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":88238},[88239,88240,88241,88242],{"id":88087,"depth":73,"text":88088},{"id":88121,"depth":73,"text":88122},{"id":88171,"depth":73,"text":88172},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Nhìn lại toàn lộ trình 180 ngày, vẽ bản đồ tri thức cá nhân và xác định vùng mạnh yếu để học tiếp.",{},[],{"title":912,"description":88244},[79772,88249],"summary","F1MukoDB7DpmUNkK1ACdpnSmPXw9hdvokrmcI6NpJ7o",{"id":88252,"title":917,"body":88253,"category":8797,"day":920,"description":88530,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":88531,"navigation":2723,"outcomes":3047,"path":918,"prerequisites":88532,"seo":88533,"stem":919,"tags":88534,"__hash__":88537},"challenges\u002Fchallenges\u002F172.lo-trinh-sau-180.md",{"type":965,"value":88254,"toc":88514},[88255,88257,88260,88262,88266,88280,88284,88298,88302,88316,88318,88326,88328,88333,88337,88340,88431,88434,88438,88441,88452,88455,88459,88470,88472,88493,88495,88509,88511],[968,88256,971],{"id":970},[973,88258,88259],{},"Bạn chọn hướng đi sau khóa học. Một hướng chính và một hướng phụ.",[968,88261,979],{"id":978},[981,88263,88265],{"id":88264},"ba-hướng-đi","Ba hướng đi",[986,88267,88268,88271,88274,88277],{},[989,88269,88270],{},"Học máy chuyên sâu: deep learning và triển khai mô hình.",[989,88272,88273],{},"Systems: backend phân tán và hiệu năng.",[989,88275,88276],{},"Ví dụ đời thường: giống chọn ngã rẽ sau khi ra trường.",[989,88278,88279],{},"Research: đọc paper và tái lập kết quả.",[981,88281,88283],{"id":88282},"chấm-điểm-bằng-bảng","Chấm điểm bằng bảng",[986,88285,88286,88289,88292,88295],{},[989,88287,88288],{},"Mỗi hướng chấm theo 5 tiêu chí thang 5.",[989,88290,88291],{},"Nhân trọng số theo giá trị cá nhân.",[989,88293,88294],{},"Ví dụ đời thường: giống chấm điểm thầu theo tiêu chí nặng nhẹ.",[989,88296,88297],{},"Hướng thắng phải thắng nhờ tiêu chí quan trọng.",[981,88299,88301],{"id":88300},"kế-hoạch-30-60-90","Kế hoạch 30-60-90",[986,88303,88304,88307,88310,88313],{},[989,88305,88306],{},"Mỗi mốc 30 ngày có một sản phẩm công khai.",[989,88308,88309],{},"Hướng chính chiếm 70% thời gian.",[989,88311,88312],{},"Ví dụ đời thường: giống lịch tập có mốc cân từng tháng.",[989,88314,88315],{},"Ghi sẵn tín hiệu đổi hướng nếu không hợp.",[968,88317,1433],{"id":1432},[986,88319,88320,88323],{},[989,88321,88322],{},"Bảng 3x5 đủ 15 ô điểm có trọng số -> đạt.",[989,88324,88325],{},"Đoạn bảo vệ 10 câu có tín hiệu đổi hướng -> đạt.",[968,88327,1482],{"id":1481},[973,88329,88081,88330,1517],{},[992,88331,88332],{},"day-172\u002F",[981,88334,88336],{"id":88335},"bài-1-ma-trận-chọn-hướng","Bài 1: Ma trận chọn hướng",[973,88338,88339],{},"Chấm 3 hướng (Học máy chuyên sâu, Systems, Research) theo 5 tiêu chí, thang 1-5, có trọng số theo giá trị của bạn:",[1099,88341,88342,88360],{},[1102,88343,88344],{},[1105,88345,88346,88348,88351,88354,88357],{},[1108,88347,5414],{},[1108,88349,88350],{},"Trọng số",[1108,88352,88353],{},"ML",[1108,88355,88356],{},"Systems",[1108,88358,88359],{},"Research",[1118,88361,88362,88376,88392,88405,88418],{},[1105,88363,88364,88367,88370,88372,88374],{},[1123,88365,88366],{},"Hứng thú thật (bằng chứng: ngày nào làm say mê nhất)",[1123,88368,88369],{},"...",[1123,88371,88369],{},[1123,88373,88369],{},[1123,88375,88369],{},[1105,88377,88378,88384,88386,88388,88390],{},[1123,88379,88380,88381,88383],{},"Điểm mạnh hiện có (từ ",[992,88382,88127],{}," ngày 171)",[1123,88385,88369],{},[1123,88387],{},[1123,88389],{},[1123,88391],{},[1105,88393,88394,88397,88399,88401,88403],{},[1123,88395,88396],{},"Cơ hội việc làm nơi bạn sống hoặc làm từ xa",[1123,88398,88369],{},[1123,88400],{},[1123,88402],{},[1123,88404],{},[1105,88406,88407,88410,88412,88414,88416],{},[1123,88408,88409],{},"Tài nguyên học có sẵn",[1123,88411,88369],{},[1123,88413],{},[1123,88415],{},[1123,88417],{},[1105,88419,88420,88423,88425,88427,88429],{},[1123,88421,88422],{},"Phù hợp mục tiêu 2 năm",[1123,88424,88369],{},[1123,88426],{},[1123,88428],{},[1123,88430],{},[973,88432,88433],{},"Tổng có trọng số. Chọn 1 hướng chính (70% thời gian) và 1 hướng phụ (30%).",[981,88435,88437],{"id":88436},"bài-2-kế-hoạch-30-60-90-ngày","Bài 2: Kế hoạch 30-60-90 ngày",[973,88439,88440],{},"Cho hướng chính, mỗi mốc có:",[986,88442,88443,88446,88449],{},[989,88444,88445],{},"1 sản phẩm công khai (repo, bài viết, demo).",[989,88447,88448],{},"Tài liệu học cụ thể (tên sách, khóa học, paper) và số giờ mỗi tuần.",[989,88450,88451],{},"Chỉ số kiểm tra \"đã xong\" đo được.",[973,88453,88454],{},"Ví dụ hướng Systems: 30 ngày viết key-value store có WAL, 60 ngày thêm nhân bản Raft, 90 ngày benchmark và bài viết so với etcd.",[981,88456,88458],{"id":88457},"bài-3-bảo-vệ-lựa-chọn-nâng-cao","Bài 3: Bảo vệ lựa chọn (nâng cao)",[2273,88460,88461,88464,88467],{},[989,88462,88463],{},"Đoạn 10 câu bảo vệ lựa chọn, như đang thuyết phục một người hướng dẫn.",[989,88465,88466],{},"3 tín hiệu đổi hướng: nếu sau 30 ngày thấy điều gì thì đổi hướng.",[989,88468,88469],{},"Chia sẻ với 1 người và ghi lại 2 câu hỏi họ đặt ra.",[981,88471,2711],{"id":2710},[986,88473,88475,88481,88487],{"className":88474},[2715],[989,88476,88478,88480],{"className":88477},[2719],[2721,88479],{"disabled":2723,"type":2724}," Bảng 3x5 đủ điểm và trọng số, có tổng.",[989,88482,88484,88486],{"className":88483},[2719],[2721,88485],{"disabled":2723,"type":2724}," Kế hoạch 3 mốc, mỗi mốc có sản phẩm và chỉ số đo được.",[989,88488,88490,88492],{"className":88489},[2719],[2721,88491],{"disabled":2723,"type":2724}," Đoạn bảo vệ 10 câu và 3 tín hiệu đổi hướng.",[968,88494,2890],{"id":2889},[2273,88496,88497,88500,88503,88506],{},[989,88498,88499],{},"Có mấy hướng đi?",[989,88501,88502],{},"Bảng điểm có mấy tiêu chí?",[989,88504,88505],{},"Hướng chính chiếm bao nhiêu thời gian?",[989,88507,88508],{},"Tín hiệu đổi hướng để làm gì?",[3014,88510],{},[973,88512,88513],{},"🌕 Bạn đã hoàn thành ngày 172. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":88515},[88516,88517,88522,88523,88529],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":88518},[88519,88520,88521],{"id":88264,"depth":73,"text":88265},{"id":88282,"depth":73,"text":88283},{"id":88300,"depth":73,"text":88301},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":88524},[88525,88526,88527,88528],{"id":88335,"depth":73,"text":88336},{"id":88436,"depth":73,"text":88437},{"id":88457,"depth":73,"text":88458},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Vạch 3 hướng đi sau khóa học gồm học máy chuyên sâu, systems và research, mỗi hướng có mốc 30-60-90 ngày.",{},[],{"title":917,"description":88530},[88535,88536],"roadmap","career","A3WhojcSKAEFO8BpBAP_46Gl5ZbZD-fT1imsnoShlv8",{"id":88539,"title":922,"body":88540,"category":8797,"day":925,"description":88830,"difficulty":5191,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":88831,"navigation":2723,"outcomes":3047,"path":923,"prerequisites":88832,"seo":88833,"stem":924,"tags":88834,"__hash__":88836},"challenges\u002Fchallenges\u002F173.checklist-nang-luc.md",{"type":965,"value":88541,"toc":88814},[88542,88544,88547,88549,88553,88567,88571,88585,88589,88603,88605,88613,88615,88621,88625,88631,88686,88689,88731,88735,88749,88753,88764,88766,88793,88795,88809,88811],[968,88543,971],{"id":970},[973,88545,88546],{},"Bạn tự chấm điểm toàn bộ kỹ năng. Chấm hai lần để lộ vùng mù.",[968,88548,979],{"id":978},[981,88550,88552],{"id":88551},"thang-4-mức","Thang 4 mức",[986,88554,88555,88558,88561,88564],{},[989,88556,88557],{},"Mức 1: chưa biết gì về kỹ năng này.",[989,88559,88560],{},"Mức 2: hiểu lý thuyết nhưng chưa làm được.",[989,88562,88563],{},"Ví dụ đời thường: giống biết luật bóng mà chưa đá được.",[989,88565,88566],{},"Mức 3 làm được sản phẩm, mức 4 dạy được người khác.",[981,88568,88570],{"id":88569},"chấm-hai-lần","Chấm hai lần",[986,88572,88573,88576,88579,88582],{},[989,88574,88575],{},"Lần một chấm theo cảm nhận, mỗi kỹ năng 30 giây.",[989,88577,88578],{},"Lần hai đối chiếu với sản phẩm thực tế.",[989,88580,88581],{},"Ví dụ đời thường: giống tự chấm thi rồi dò đáp án.",[989,88583,88584],{},"Không sản phẩm mà chấm cao thì phải hạ xuống.",[981,88586,88588],{"id":88587},"vá-top-5-lỗ-hổng","Vá top 5 lỗ hổng",[986,88590,88591,88594,88597,88600],{},[989,88592,88593],{},"Xếp hạng lỗ hổng bằng quan trọng nhân khoảng cách.",[989,88595,88596],{},"Chỉ lấy top 5 để vá, không dàn trải.",[989,88598,88599],{},"Ví dụ đời thường: giống vá 5 lỗ thủng lớn nhất của thuyền.",[989,88601,88602],{},"Mỗi lỗ hổng có một kế hoạch một dòng.",[968,88604,1433],{"id":1432},[986,88606,88607,88610],{},[989,88608,88609],{},"Bảng 60 kỹ năng đủ mức chấm và bằng chứng -> đạt.",[989,88611,88612],{},"Ít nhất 5 kỹ năng bị hạ sau đối chiếu -> đạt.",[968,88614,1482],{"id":1481},[973,88616,88617,88618,1517],{},"Không có code mới, trừ phần kiểm tra ở Bài 2. Nộp vào ",[992,88619,88620],{},"day-173\u002F",[981,88622,88624],{"id":88623},"bài-1-checklist-60-kỹ-năng","Bài 1: Checklist 60 kỹ năng",[973,88626,16860,88627,88630],{},[992,88628,88629],{},"checklist.md"," gồm 60 kỹ năng, 10 kỹ năng cho mỗi cụm của ngày 171. Mỗi kỹ năng viết dạng hành động kiểm tra được, ví dụ:",[986,88632,88633,88680,88683],{},[989,88634,88635,88636,88679],{},"\"Cài LRU cache ",[1023,88637,88639,88658],{"className":88638},[1026],[1023,88640,88642],{"className":88641},[1030],[1032,88643,88644],{"xmlns":1034},[1036,88645,88646,88656],{},[1039,88647,88648,88650,88652,88654],{},[1042,88649,1044],{},[1046,88651,1049],{"stretchy":1048},[1051,88653,1053],{},[1046,88655,1056],{"stretchy":1048},[1058,88657,1061],{"encoding":1060},[1023,88659,88661],{"className":88660,"ariaHidden":1066},[1065],[1023,88662,88664,88667,88670,88673,88676],{"className":88663},[1070],[1023,88665],{"className":88666,"style":1075},[1074],[1023,88668,1044],{"className":88669,"style":1081},[1079,1080],[1023,88671,1049],{"className":88672},[1085],[1023,88674,1053],{"className":88675},[1079],[1023,88677,1056],{"className":88678},[1092]," không dùng thư viện trong 20 phút\"",[989,88681,88682],{},"\"Giải thích vì sao Dijkstra sai với cạnh âm bằng ví dụ 4 đỉnh\"",[989,88684,88685],{},"\"Chọn giữa Strategy và State cho một tình huống cho trước và giải thích\"",[973,88687,88688],{},"Lần 1: chấm mức 1-4 theo cảm nhận, mỗi kỹ năng không quá 30 giây.",[1099,88690,88691,88701],{},[1102,88692,88693],{},[1105,88694,88695,88698],{},[1108,88696,88697],{},"Mức",[1108,88699,88700],{},"Nghĩa",[1118,88702,88703,88710,88717,88724],{},[1105,88704,88705,88707],{},[1123,88706,1053],{},[1123,88708,88709],{},"Chưa biết",[1105,88711,88712,88714],{},[1123,88713,2457],{},[1123,88715,88716],{},"Hiểu lý thuyết, chưa làm được",[1105,88718,88719,88721],{},[1123,88720,13826],{},[1123,88722,88723],{},"Làm được, có sản phẩm",[1105,88725,88726,88728],{},[1123,88727,25255],{},[1123,88729,88730],{},"Dạy lại được",[981,88732,88734],{"id":88733},"bài-2-đối-chiếu-bằng-thực-hành","Bài 2: Đối chiếu bằng thực hành",[2273,88736,88737,88740,88743,88746],{},[989,88738,88739],{},"Chọn ngẫu nhiên 10 kỹ năng bạn chấm mức 3-4. Làm thử ngay, bấm giờ, không xem code cũ.",[989,88741,88742],{},"Làm không được trong thời gian ghi trong kỹ năng thì hạ mức.",[989,88744,88745],{},"Cột \"bằng chứng\" cho mọi kỹ năng mức 3-4.",[989,88747,88748],{},"Viết 1 câu về \"vùng mù\": bạn hay đánh giá quá cao hay quá thấp loại kỹ năng nào.",[981,88750,88752],{"id":88751},"bài-3-top-5-lỗ-hổng-nâng-cao","Bài 3: Top 5 lỗ hổng (nâng cao)",[2273,88754,88755,88758,88761],{},[989,88756,88757],{},"Điểm ưu tiên mỗi kỹ năng = mức quan trọng với hướng chính (1-3) x (4 - mức hiện tại).",[989,88759,88760],{},"Lấy top 5. Mỗi lỗ hổng: 1 dòng kế hoạch, 1 bài tập cụ thể, thời hạn.",[989,88762,88763],{},"Đặt lịch nhắc kiểm tra lại checklist sau 30 ngày.",[981,88765,2711],{"id":2710},[986,88767,88769,88775,88781,88787],{"className":88768},[2715],[989,88770,88772,88774],{"className":88771},[2719],[2721,88773],{"disabled":2723,"type":2724}," 60 kỹ năng dạng hành động kiểm tra được.",[989,88776,88778,88780],{"className":88777},[2719],[2721,88779],{"disabled":2723,"type":2724}," 10 kỹ năng đã được kiểm tra bằng thực hành, có ghi thời gian.",[989,88782,88784,88786],{"className":88783},[2719],[2721,88785],{"disabled":2723,"type":2724}," Ít nhất 5 kỹ năng được điều chỉnh mức sau đối chiếu (hoặc giải thích vì sao không).",[989,88788,88790,88792],{"className":88789},[2719],[2721,88791],{"disabled":2723,"type":2724}," Top 5 lỗ hổng có kế hoạch và thời hạn.",[968,88794,2890],{"id":2889},[2273,88796,88797,88800,88803,88806],{},[989,88798,88799],{},"Thang chấm có mấy mức?",[989,88801,88802],{},"Mỗi kỹ năng chấm tối đa bao lâu?",[989,88804,88805],{},"Không có sản phẩm thì chấm sao?",[989,88807,88808],{},"Vì sao chỉ vá top 5?",[3014,88810],{},[973,88812,88813],{},"🌕 Bạn đã hoàn thành ngày 173. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":88815},[88816,88817,88822,88823,88829],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":88818},[88819,88820,88821],{"id":88551,"depth":73,"text":88552},{"id":88569,"depth":73,"text":88570},{"id":88587,"depth":73,"text":88588},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":88824},[88825,88826,88827,88828],{"id":88623,"depth":73,"text":88624},{"id":88733,"depth":73,"text":88734},{"id":88751,"depth":73,"text":88752},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tự đánh giá toàn diện qua checklist năng lực, đối chiếu chéo bằng sản phẩm và chốt kế hoạch vá 5 lỗ hổng lớn nhất.",{},[],{"title":922,"description":88830},[79772,88835],"checklist","cSo9krBipQVSnTx8aNiL6EyRWWtqgUOGQJ2rotLmrT0",{"id":88838,"title":927,"body":88839,"category":8797,"day":930,"description":89247,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":89248,"navigation":2723,"outcomes":3047,"path":928,"prerequisites":89249,"seo":89250,"stem":929,"tags":89251,"__hash__":89254},"challenges\u002Fchallenges\u002F174.bo-de-luyen-them.md",{"type":965,"value":88840,"toc":89231},[88841,88843,88846,88848,88852,88866,88870,88884,88888,88902,88904,88912,88914,88932,88936,88979,88982,89084,89145,89149,89167,89171,89179,89181,89210,89212,89226,89228],[968,88842,971],{"id":970},[973,88844,88845],{},"Bạn tự ra 50 đề luyện thêm. Vùng yếu được thêm đề nhiều hơn.",[968,88847,979],{"id":978},[981,88849,88851],{"id":88850},"phủ-6-cụm","Phủ 6 cụm",[986,88853,88854,88857,88860,88863],{},[989,88855,88856],{},"Mỗi cụm 6 tới 10 đề phủ đủ kiến thức.",[989,88858,88859],{},"Tỉ lệ 3 dễ, 4 vừa, 3 khó mỗi cụm.",[989,88861,88862],{},"Ví dụ đời thường: giống ra đề thi phủ hết chương.",[989,88864,88865],{},"Vùng yếu trong checklist được thêm đề.",[981,88867,88869],{"id":88868},"cấu-trúc-mỗi-đề","Cấu trúc mỗi đề",[986,88871,88872,88875,88878,88881],{},[989,88873,88874],{},"Mỗi đề có bối cảnh thực tế một đoạn.",[989,88876,88877],{},"Có 2 ví dụ gồm thường và biên.",[989,88879,88880],{},"Ví dụ đời thường: giống đề thi có ví dụ mẫu và bẫy.",[989,88882,88883],{},"Ghi ràng buộc kích thước và bẫy cho người chấm.",[981,88885,88887],{"id":88886},"biến-thể-và-lịch-luyện","Biến thể và lịch luyện",[986,88889,88890,88893,88896,88899],{},[989,88891,88892],{},"Ra đề bằng cách đổi ràng buộc bài cũ.",[989,88894,88895],{},"Gộp hai bài cũ hoặc đảo ngược yêu cầu.",[989,88897,88898],{},"Ví dụ đời thường: giống chế món mới từ hai món cũ.",[989,88900,88901],{},"Đề nào tác giả không giải được thì hạ tầng.",[968,88903,1433],{"id":1432},[986,88905,88906,88909],{},[989,88907,88908],{},"Mỗi cụm đủ 3 tầng, vùng yếu nhiều đề hơn -> đạt.",[989,88910,88911],{},"5 đềngẫu nhiên tác giả giải đúng giờ mục tiêu -> đạt.",[968,88913,1482],{"id":1481},[973,88915,88916,88917,88920,88921,88923,88924,88927,88928,88931],{},"Nộp vào ",[992,88918,88919],{},"day-174-problemset\u002F",". Mỗi đề là 1 thư mục có ",[992,88922,2513],{}," (đề), ",[992,88925,88926],{},"solution.*"," (lời giải), ",[992,88929,88930],{},"tests\u002F"," (ít nhất 5 test gồm biên).",[981,88933,88935],{"id":88934},"bài-1-ra-đề-cho-3-cụm","Bài 1: Ra đề cho 3 cụm",[1099,88937,88938,88950],{},[1102,88939,88940],{},[1105,88941,88942,88944,88947],{},[1108,88943,42815],{},[1108,88945,88946],{},"Số đề",[1108,88948,88949],{},"Tỉ lệ dễ\u002Fvừa\u002Fkhó",[1118,88951,88952,88962,88970],{},[1105,88953,88954,88957,88959],{},[1123,88955,88956],{},"Cấu trúc dữ liệu",[1123,88958,2331],{},[1123,88960,88961],{},"3\u002F4\u002F3",[1105,88963,88964,88966,88968],{},[1123,88965,9446],{},[1123,88967,2331],{},[1123,88969,88961],{},[1105,88971,88972,88975,88977],{},[1123,88973,88974],{},"Vùng yếu nhất của bạn (từ ngày 173)",[1123,88976,2331],{},[1123,88978,88961],{},[973,88980,88981],{},"Mỗi đề phải có:",[986,88983,88984,88987,88990,89078,89081],{},[989,88985,88986],{},"Bối cảnh thực tế 1 đoạn.",[989,88988,88989],{},"Định dạng input\u002Foutput chính xác.",[989,88991,88992,88993,89077],{},"Ràng buộc kích thước (ví dụ ",[1023,88994,88996,89018],{"className":88995},[1026],[1023,88997,88999],{"className":88998},[1030],[1032,89000,89001],{"xmlns":1034},[1036,89002,89003,89015],{},[1039,89004,89005,89007,89009],{},[1042,89006,1262],{},[1046,89008,21123],{},[2327,89010,89011,89013],{},[1051,89012,2331],{},[1051,89014,2334],{},[1058,89016,89017],{"encoding":1060},"n \\le 10^5",[1023,89019,89021,89039],{"className":89020,"ariaHidden":1066},[1065],[1023,89022,89024,89027,89030,89033,89036],{"className":89023},[1070],[1023,89025],{"className":89026,"style":47337},[1074],[1023,89028,1262],{"className":89029},[1079,1080],[1023,89031],{"className":89032,"style":2355},[2354],[1023,89034,21123],{"className":89035},[2359],[1023,89037],{"className":89038,"style":2355},[2354],[1023,89040,89042,89045,89048],{"className":89041},[1070],[1023,89043],{"className":89044,"style":2369},[1074],[1023,89046,1053],{"className":89047},[1079],[1023,89049,89051,89054],{"className":89050},[1079],[1023,89052,2379],{"className":89053},[1079],[1023,89055,89057],{"className":89056},[2383],[1023,89058,89060],{"className":89059},[2387],[1023,89061,89063],{"className":89062},[2391],[1023,89064,89066],{"className":89065,"style":2369},[2395],[1023,89067,89068,89071],{"style":2398},[1023,89069],{"className":89070,"style":2403},[2402],[1023,89072,89074],{"className":89073},[2407,2408,2409,2410],[1023,89075,2334],{"className":89076},[1079,2410],") và giới hạn thời gian.",[989,89079,89080],{},"2 ví dụ: 1 thường, 1 biên.",[989,89082,89083],{},"Mục \"bẫy\" cho người chấm: lời giải sai phổ biến là gì.",[973,89085,89086,89087,89115,89116,89144],{},"Kỹ thuật ra đề: đổi ràng buộc bài cũ (",[1023,89088,89090,89103],{"className":89089},[1026],[1023,89091,89093],{"className":89092},[1030],[1032,89094,89095],{"xmlns":1034},[1036,89096,89097,89101],{},[1039,89098,89099],{},[1042,89100,1262],{},[1058,89102,1262],{"encoding":1060},[1023,89104,89106],{"className":89105,"ariaHidden":1066},[1065],[1023,89107,89109,89112],{"className":89108},[1070],[1023,89110],{"className":89111,"style":2347},[1074],[1023,89113,1262],{"className":89114},[1079,1080]," nhỏ thành ",[1023,89117,89119,89132],{"className":89118},[1026],[1023,89120,89122],{"className":89121},[1030],[1032,89123,89124],{"xmlns":1034},[1036,89125,89126,89130],{},[1039,89127,89128],{},[1042,89129,1262],{},[1058,89131,1262],{"encoding":1060},[1023,89133,89135],{"className":89134,"ariaHidden":1066},[1065],[1023,89136,89138,89141],{"className":89137},[1070],[1023,89139],{"className":89140,"style":2347},[1074],[1023,89142,1262],{"className":89143},[1079,1080]," lớn), gộp 2 bài, đảo ngược yêu cầu (đếm thành liệt kê, tìm min thành tìm max có ràng buộc).",[981,89146,89148],{"id":89147},"bài-2-lời-giải-và-trình-chấm","Bài 2: Lời giải và trình chấm",[2273,89150,89151,89154,89161],{},[989,89152,89153],{},"Viết lời giải mẫu cho 5 đề khó nhất, kèm giải thích và độ phức tạp.",[989,89155,89156,89157,89160],{},"Với mỗi đề khó, viết thêm 1 lời giải ",[1487,89158,89159],{},"vét cạn"," đơn giản. Script sinh test ngẫu nhiên nhỏ và so 2 lời giải (đối chiếu chéo).",[989,89162,80665,89163,89166],{},[992,89164,89165],{},"judge.sh \u003Cđề> \u003Cfile_giải>"," chạy mọi test và in pass\u002Ffail, thời gian.",[981,89168,89170],{"id":89169},"bài-3-kiểm-tra-độ-khó-và-lịch-luyện-nâng-cao","Bài 3: Kiểm tra độ khó và lịch luyện (nâng cao)",[2273,89172,89173,89176],{},[989,89174,89175],{},"Chọn ngẫu nhiên 5 đề, tự giải lại sau 1 ngày, bấm giờ. Đề nào vượt giờ mục tiêu gấp đôi thì nâng tầng khó.",[989,89177,89178],{},"Lịch luyện 5 tuần, mỗi tuần 10 đề xen kẽ 3 cụm, vùng yếu nhiều hơn.",[981,89180,2711],{"id":2710},[986,89182,89184,89190,89196,89204],{"className":89183},[2715],[989,89185,89187,89189],{"className":89186},[2719],[2721,89188],{"disabled":2723,"type":2724}," 30 đề đủ các mục bắt buộc.",[989,89191,89193,89195],{"className":89192},[2719],[2721,89194],{"disabled":2723,"type":2724}," 5 lời giải mẫu có đối chiếu với vét cạn.",[989,89197,89199,2308,89201,79721],{"className":89198},[2719],[2721,89200],{"disabled":2723,"type":2724},[992,89202,89203],{},"judge.sh",[989,89205,89207,89209],{"className":89206},[2719],[2721,89208],{"disabled":2723,"type":2724}," Lịch 5 tuần.",[968,89211,2890],{"id":2889},[2273,89213,89214,89217,89220,89223],{},[989,89215,89216],{},"Mỗi cụm ra mấy đề?",[989,89218,89219],{},"Mỗi đề cần mấy ví dụ?",[989,89221,89222],{},"Ra đề mới bằng mấy cách biến thể?",[989,89224,89225],{},"Đề tác giả không giải được thì sao?",[3014,89227],{},[973,89229,89230],{},"🌕 Bạn đã hoàn thành ngày 174. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":89232},[89233,89234,89239,89240,89246],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":89235},[89236,89237,89238],{"id":88850,"depth":73,"text":88851},{"id":88868,"depth":73,"text":88869},{"id":88886,"depth":73,"text":88887},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":89241},[89242,89243,89244,89245],{"id":88934,"depth":73,"text":88935},{"id":89147,"depth":73,"text":89148},{"id":89169,"depth":73,"text":89170},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Tự biên bộ 50 đề luyện thêm phủ 6 cụm, phân tầng dễ khó, kèm đáp án gợi ý và lịch luyện 5 tuần.",{},[],{"title":927,"description":89247},[89252,89253],"practice","problems","1LVYXpaEZPqBfB-pJF3xi7CGJh7NhI2v1QJYU-2BHjk",{"id":89256,"title":932,"body":89257,"category":3041,"day":935,"description":89567,"difficulty":68559,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":89568,"navigation":2723,"outcomes":3047,"path":933,"prerequisites":89569,"seo":89570,"stem":934,"tags":89571,"__hash__":89572},"challenges\u002Fchallenges\u002F175.system-design-co-ban.md",{"type":965,"value":89258,"toc":89551},[89259,89261,89264,89266,89270,89284,89288,89302,89306,89320,89345,89347,89355,89357,89363,89367,89370,89373,89429,89433,89447,89451,89460,89485,89500,89502,89529,89531,89544,89546,89549],[968,89260,971],{"id":970},[973,89262,89263],{},"Bạn thiết kế hệ thống đọc nhiều. Tải đỉnh gấp mười trung bình.",[968,89265,979],{"id":978},[981,89267,89269],{"id":89268},"ước-lượng-tải","Ước lượng tải",[986,89271,89272,89275,89278,89281],{},[989,89273,89274],{},"Hỏi yêu cầu trước khi vẽ bất cứ gì.",[989,89276,89277],{},"Ước lượng bộ nhớ, băng thông, số nút.",[989,89279,89280],{},"Ví dụ đời thường: giống hỏi số mâm trước khi nấu cỗ.",[989,89282,89283],{},"Mọi con số phải ghi giả định kèm theo.",[981,89285,89287],{"id":89286},"cân-bằng-tải-và-cache-tầng","Cân bằng tải và cache tầng",[986,89289,89290,89293,89296,89299],{},[989,89291,89292],{},"Cân bằng tải chia request cho nhiều máy.",[989,89294,89295],{},"Cache tầng giữ dữ liệu hot gần người dùng.",[989,89297,89298],{},"Ví dụ đời thường: giống mở nhiều quầy thu ngân giờ cao điểm.",[989,89300,89301],{},"Tải đỉnh gấp mười cần phương án hấp thụ cụ thể.",[981,89303,89305],{"id":89304},"sharding-và-chịu-lỗi","Sharding và chịu lỗi",[986,89307,89308,89311,89314,89317],{},[989,89309,89310],{},"Sharding chia dữ liệu theo key ra nhiều shard.",[989,89312,89313],{},"Key nóng cần cách xử lý riêng.",[989,89315,89316],{},"Ví dụ đời thường: giống chia kho theo mã hàng.",[989,89318,89319],{},"Thêm nút thì ghi rõ dữ liệu di chuyển thế nào.",[1352,89321,89323],{"className":3538,"code":89322,"language":3540,"meta":1357,"style":1357},"# chia shard đơn giản\ndef shard(key, n):\n    return hash(key) % n  # key nào về shard đó\nprint(shard(\"user1\", 4))  # in số shard chứa key\n",[992,89324,89325,89330,89335,89340],{"__ignoreMap":1357},[1023,89326,89327],{"class":1362,"line":63},[1023,89328,89329],{},"# chia shard đơn giản\n",[1023,89331,89332],{"class":1362,"line":68},[1023,89333,89334],{},"def shard(key, n):\n",[1023,89336,89337],{"class":1362,"line":73},[1023,89338,89339],{},"    return hash(key) % n  # key nào về shard đó\n",[1023,89341,89342],{"class":1362,"line":78},[1023,89343,89344],{},"print(shard(\"user1\", 4))  # in số shard chứa key\n",[968,89346,1433],{"id":1432},[986,89348,89349,89352],{},[989,89350,89351],{},"Tải đỉnh gấp mười -> có phương án hấp thụ cụ thể.",[989,89353,89354],{},"3 key mẫu gồm key nóng -> chỉ rõ shard chứa và cách xử lý.",[968,89356,1482],{"id":1481},[973,89358,89359,89360,1517],{},"Thiết kế trên giấy hoặc Markdown, kèm 1 phần code nhỏ ở Bài 3. Nộp vào ",[992,89361,89362],{},"day-175\u002F",[981,89364,89366],{"id":89365},"bài-1-ước-lượng-tải","Bài 1: Ước lượng tải",[973,89368,89369],{},"Đề: dịch vụ rút gọn link (kiểu bit.ly). 100 triệu link mới mỗi tháng, tỉ lệ đọc\u002Fghi 100:1, lưu 5 năm.",[973,89371,89372],{},"Tính và ghi rõ giả định:",[1099,89374,89375,89385],{},[1102,89376,89377],{},[1105,89378,89379,89382],{},[1108,89380,89381],{},"Đại lượng",[1108,89383,89384],{},"Kết quả",[1118,89386,89387,89394,89401,89408,89415,89422],{},[1105,89388,89389,89392],{},[1123,89390,89391],{},"Ghi mỗi giây (trung bình và đỉnh gấp 10)",[1123,89393,88369],{},[1105,89395,89396,89399],{},[1123,89397,89398],{},"Đọc mỗi giây",[1123,89400,88369],{},[1105,89402,89403,89406],{},[1123,89404,89405],{},"Dung lượng lưu 5 năm (mỗi bản ghi ~500 byte)",[1123,89407,88369],{},[1105,89409,89410,89413],{},[1123,89411,89412],{},"Độ dài mã rút gọn cần thiết (base62)",[1123,89414,88369],{},[1105,89416,89417,89420],{},[1123,89418,89419],{},"Băng thông đọc",[1123,89421,88369],{},[1105,89423,89424,89427],{},[1123,89425,89426],{},"Bộ nhớ cache cho 20% link nóng mỗi ngày",[1123,89428,88369],{},[981,89430,89432],{"id":89431},"bài-2-sơ-đồ-triển-khai","Bài 2: Sơ đồ triển khai",[2273,89434,89435,89438,89441,89444],{},[989,89436,89437],{},"Sơ đồ gồm: load balancer, tầng API (bao nhiêu máy, vì sao), cache, cơ sở dữ liệu.",[989,89439,89440],{},"Luồng ghi và luồng đọc, đánh số từng bước.",[989,89442,89443],{},"Sinh mã rút gọn: so 3 cách (băm rồi cắt, bộ đếm tăng dần + base62, ID ngẫu nhiên). Xử lý trùng.",[989,89445,89446],{},"Tải đỉnh gấp 10: phương án hấp thụ cụ thể (tự mở rộng, hàng đợi ghi, cache).",[981,89448,89450],{"id":89449},"bài-3-sharding-và-key-nóng-nâng-cao","Bài 3: Sharding và key nóng (nâng cao)",[2273,89452,89453],{},[989,89454,89455,89456,89459],{},"Viết code nhỏ ",[1487,89457,89458],{},"consistent hashing"," có virtual node (100 virtual node mỗi máy):",[1352,89461,89463],{"className":3538,"code":89462,"language":3540,"meta":1357,"style":1357},"class HashRing:\n    def add_node(self, node: str): ...\n    def remove_node(self, node: str): ...\n    def get_node(self, key: str) -> str: ...\n",[992,89464,89465,89470,89475,89480],{"__ignoreMap":1357},[1023,89466,89467],{"class":1362,"line":63},[1023,89468,89469],{},"class HashRing:\n",[1023,89471,89472],{"class":1362,"line":68},[1023,89473,89474],{},"    def add_node(self, node: str): ...\n",[1023,89476,89477],{"class":1362,"line":73},[1023,89478,89479],{},"    def remove_node(self, node: str): ...\n",[1023,89481,89482],{"class":1362,"line":78},[1023,89483,89484],{},"    def get_node(self, key: str) -> str: ...\n",[2273,89486,89487,89494,89497],{"start":68},[989,89488,89489,89490,89493],{},"Với 10^6 key và 4 máy, in số key mỗi máy. Thêm máy thứ 5: in tỉ lệ key phải di chuyển (kỳ vọng khoảng 1\u002F5). So với ",[992,89491,89492],{},"hash(key) % n"," (kỳ vọng khoảng 4\u002F5).",[989,89495,89496],{},"1 link viral nhận 30% lưu lượng đọc: phương án xử lý (cache nhiều tầng, nhân bản key nóng).",[989,89498,89499],{},"Trình bày 10 phút cho 1 người nghe, ghi lại câu hỏi.",[981,89501,2711],{"id":2710},[986,89503,89505,89511,89517,89523],{"className":89504},[2715],[989,89506,89508,89510],{"className":89507},[2719],[2721,89509],{"disabled":2723,"type":2724}," Bảng ước lượng có công thức và giả định.",[989,89512,89514,89516],{"className":89513},[2719],[2721,89515],{"disabled":2723,"type":2724}," Sơ đồ có luồng đọc\u002Fghi đánh số.",[989,89518,89520,89522],{"className":89519},[2719],[2721,89521],{"disabled":2723,"type":2724}," Code consistent hashing có số liệu di chuyển key so với modulo.",[989,89524,89526,89528],{"className":89525},[2719],[2721,89527],{"disabled":2723,"type":2724}," Có phương án cho tải đỉnh và key nóng.",[968,89530,2890],{"id":2889},[2273,89532,89533,89536,89538,89541],{},[989,89534,89535],{},"Vẽ trước hay hỏi tải trước?",[989,89537,64297],{},[989,89539,89540],{},"Sharding chia theo gì?",[989,89542,89543],{},"Key nóng xử lý thế nào?",[3014,89545],{},[973,89547,89548],{},"🌕 Bạn đã hoàn thành ngày 175. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,89550,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":89552},[89553,89554,89559,89560,89566],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":89555},[89556,89557,89558],{"id":89268,"depth":73,"text":89269},{"id":89286,"depth":73,"text":89287},{"id":89304,"depth":73,"text":89305},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":89561},[89562,89563,89564,89565],{"id":89365,"depth":73,"text":89366},{"id":89431,"depth":73,"text":89432},{"id":89449,"depth":73,"text":89450},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thực hành system design nghề nghiệp: ước lượng tải, cân bằng tải, sharding, cache tầng và trình bày trước hội đồng.",{},[14055],{"title":932,"description":89567},[72343,88536],"T6lDSQX5dzlq3FWIW86WWFCEMeLcazK0vtscmE2dLvo",{"id":89574,"title":937,"body":89575,"category":8797,"day":940,"description":89815,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":89816,"navigation":2723,"outcomes":3047,"path":938,"prerequisites":89817,"seo":89818,"stem":939,"tags":89819,"__hash__":89821},"challenges\u002Fchallenges\u002F176.doc-paper-viet-blog.md",{"type":965,"value":89576,"toc":89799},[89577,89579,89582,89584,89588,89602,89606,89620,89624,89638,89640,89648,89650,89656,89660,89708,89712,89715,89729,89732,89736,89747,89749,89778,89780,89794,89796],[968,89578,971],{"id":970},[973,89580,89581],{},"Bạn mổ một whitepaper rồi viết lại. Diễn giải bằng lời của mình.",[968,89583,979],{"id":978},[981,89585,89587],{"id":89586},"đọc-3-lượt","Đọc 3 lượt",[986,89589,89590,89593,89596,89599],{},[989,89591,89592],{},"Lượt một 10 phút lấy vấn đề và kết quả chính.",[989,89594,89595],{},"Lượt hai 20 phút mổ phương pháp và đánh giá.",[989,89597,89598],{},"Ví dụ đời thường: giống đọc báo: tít trước, chi tiết sau.",[989,89600,89601],{},"Lượt ba 10 phút ghi câu hỏi và điểm yếu.",[981,89603,89605],{"id":89604},"tái-lập-ý-chính","Tái lập ý chính",[986,89607,89608,89611,89614,89617],{},[989,89609,89610],{},"Làm lại ý chính trên dữ liệu nhỏ.",[989,89612,89613],{},"Chứng minh bạn hiểu thật chứ không hiểu chữ.",[989,89615,89616],{},"Ví dụ đời thường: giống nấu lại món đã đọc công thức.",[989,89618,89619],{},"Kết quả cùng chiều với paper là đạt.",[981,89621,89623],{"id":89622},"viết-blog-ngàn-từ","Viết blog ngàn từ",[986,89625,89626,89629,89632,89635],{},[989,89627,89628],{},"Blog gồm vấn đề, ý chính, ví dụ, đánh giá, ứng dụng.",[989,89630,89631],{},"Cấm copy câu của paper, viết lại bằng lời mình.",[989,89633,89634],{},"Ví dụ đời thường: giống kể lại phim bằng lời mình.",[989,89636,89637],{},"Mỗi số liệu phải truy được về trang nguồn.",[968,89639,1433],{"id":1432},[986,89641,89642,89645],{},[989,89643,89644],{},"Dàn ý mỗi ý ghi số trang nguồn -> đọc lại tìm được.",[989,89646,89647],{},"Tái lập cùng chiều với paper, chênh lệch có giải thích.",[968,89649,1482],{"id":1481},[973,89651,88916,89652,89655],{},[992,89653,89654],{},"day-176\u002F",". Chọn 1 paper liên quan tới chủ đề đã học, ví dụ: \"The Bloom Filter\" (Bloom 1970), \"MapReduce\" (Dean và Ghemawat 2004), \"The PageRank Citation Ranking\" (Page và cộng sự 1998), \"Attention Is All You Need\" (Vaswani và cộng sự 2017), \"Dynamo\" (DeCandia và cộng sự 2007).",[981,89657,89659],{"id":89658},"bài-1-đọc-3-lượt","Bài 1: Đọc 3 lượt",[1099,89661,89662,89677],{},[1102,89663,89664],{},[1105,89665,89666,89669,89671],{},[1108,89667,89668],{},"Lượt",[1108,89670,29942],{},[1108,89672,89673,89674],{},"Đầu ra trong ",[992,89675,89676],{},"notes.md",[1118,89678,89679,89689,89699],{},[1105,89680,89681,89683,89686],{},[1123,89682,1053],{},[1123,89684,89685],{},"10 phút",[1123,89687,89688],{},"Đọc tiêu đề, tóm tắt, hình, kết luận. Viết 5 dòng: vấn đề, ý chính, kết quả",[1105,89690,89691,89693,89696],{},[1123,89692,2457],{},[1123,89694,89695],{},"20 phút",[1123,89697,89698],{},"Đọc phương pháp và đánh giá. Tóm tắt thuật toán bằng giả mã của bạn. Ghi số trang cho mỗi ý",[1105,89700,89701,89703,89705],{},[1123,89702,13826],{},[1123,89704,89685],{},[1123,89706,89707],{},"3 câu hỏi còn thắc mắc, 2 điểm yếu hoặc giả định mạnh",[981,89709,89711],{"id":89710},"bài-2-tái-lập-nhỏ","Bài 2: Tái lập nhỏ",[973,89713,89714],{},"Tái lập 1 kết quả chính trên quy mô nhỏ, ví dụ:",[986,89716,89717,89720,89723,89726],{},[989,89718,89719],{},"Bloom: tỉ lệ dương tính giả thực tế so với công thức (dùng code ngày 30).",[989,89721,89722],{},"MapReduce: wordcount tăng tốc theo số worker (ngày 50).",[989,89724,89725],{},"PageRank: hội tụ trên đồ thị nhỏ (ngày 73).",[989,89727,89728],{},"Attention: đảo chuỗi bằng Transformer nhỏ (ngày 102).",[973,89730,89731],{},"Kết quả phải cùng chiều với paper. Chênh lệch về số thì giải thích vì sao.",[981,89733,89735],{"id":89734},"bài-3-viết-blog-nâng-cao","Bài 3: Viết blog (nâng cao)",[2273,89737,89738,89741,89744],{},[989,89739,89740],{},"Bài khoảng 1000 từ bằng lời của bạn, 5 phần: vấn đề, ý chính, ví dụ tay nhỏ, kết quả tái lập của bạn (có hình), ứng dụng thực tế.",[989,89742,89743],{},"Không chép câu nào của paper. Mọi số liệu dẫn nguồn trang.",[989,89745,89746],{},"Nhờ 1 người đọc, ghi 3 góp ý và sửa. Đăng công khai (blog cá nhân, dev.to, Viblo...) nếu muốn.",[981,89748,2711],{"id":2710},[986,89750,89752,89760,89766,89772],{"className":89751},[2715],[989,89753,89755,2308,89757,89759],{"className":89754},[2719],[2721,89756],{"disabled":2723,"type":2724},[992,89758,89676],{}," đủ 3 lượt, có số trang.",[989,89761,89763,89765],{"className":89762},[2719],[2721,89764],{"disabled":2723,"type":2724}," Code tái lập chạy được, kết quả cùng chiều paper.",[989,89767,89769,89771],{"className":89768},[2719],[2721,89770],{"disabled":2723,"type":2724}," Blog 5 phần, có hình từ kết quả của bạn.",[989,89773,89775,89777],{"className":89774},[2719],[2721,89776],{"disabled":2723,"type":2724}," Có 3 góp ý và bản sửa.",[968,89779,2890],{"id":2889},[2273,89781,89782,89785,89788,89791],{},[989,89783,89784],{},"Đọc mấy lượt, mỗi lượt bao lâu?",[989,89786,89787],{},"Tái lập để chứng minh gì?",[989,89789,89790],{},"Blog gồm mấy phần?",[989,89792,89793],{},"Số liệu trong blog phải truy về đâu?",[3014,89795],{},[973,89797,89798],{},"🌕 Bạn đã hoàn thành ngày 176. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":89800},[89801,89802,89807,89808,89814],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":89803},[89804,89805,89806],{"id":89586,"depth":73,"text":89587},{"id":89604,"depth":73,"text":89605},{"id":89622,"depth":73,"text":89623},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":89809},[89810,89811,89812,89813],{"id":89658,"depth":73,"text":89659},{"id":89710,"depth":73,"text":89711},{"id":89734,"depth":73,"text":89735},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Rèn năng lực nghề nghiệp đọc tài liệu gốc: mổ một whitepaper, tái lập ý chính và viết blog kỹ thuật ngàn từ.",{},[15144],{"title":937,"description":89815},[89252,89820,88536],"writing","GQq6_vO3cyMZS1IgiEYlzvUUJHsSqhjdGRRQgz2k8U0",{"id":89823,"title":942,"body":89824,"category":8797,"day":945,"description":90086,"difficulty":42171,"estimatedMinutes":508,"extension":3044,"lastUpdate":3045,"meta":90087,"navigation":2723,"outcomes":3047,"path":943,"prerequisites":90088,"seo":90089,"stem":944,"tags":90090,"__hash__":90092},"challenges\u002Fchallenges\u002F177.open-source-day.md",{"type":965,"value":89825,"toc":90070},[89826,89828,89831,89833,89837,89851,89855,89869,89873,89887,89912,89914,89922,89924,89930,89934,89937,89960,89967,89971,89985,89989,90009,90012,90014,90047,90049,90063,90065,90068],[968,89827,971],{"id":970},[973,89829,89830],{},"Bạn đóng góp một issue thật cho repo mở. Sửa ít nhưng đúng chuẩn.",[968,89832,979],{"id":978},[981,89834,89836],{"id":89835},"chọn-repo-và-issue","Chọn repo và issue",[986,89838,89839,89842,89845,89848],{},[989,89840,89841],{},"Chọn repo có nhãn người mới và còn hoạt động.",[989,89843,89844],{},"Issue vừa sức sửa trong 30 phút.",[989,89846,89847],{},"Ví dụ đời thường: giống chọn việc vừa tay trong ngày đầu.",[989,89849,89850],{},"Bộ kiểm thử của repo phải chạy được.",[981,89852,89854],{"id":89853},"đọc-kiến-trúc","Đọc kiến trúc",[986,89856,89857,89860,89863,89866],{},[989,89858,89859],{},"Vẽ sơ đồ module bằng lời của mình.",[989,89861,89862],{},"Xác định issue nằm ở hàm nào.",[989,89864,89865],{},"Ví dụ đời thường: giống vẽ sơ đồ nhà trước khi sửa điện.",[989,89867,89868],{},"Đọc quy ước code trước khi viết một dòng.",[981,89870,89872],{"id":89871},"sửa-và-gửi-pull-request","Sửa và gửi pull request",[986,89874,89875,89878,89881,89884],{},[989,89876,89877],{},"Tái hiện lỗi trước, sửa tối thiểu sau.",[989,89879,89880],{},"Một việc một commit, thông điệp rõ ràng.",[989,89882,89883],{},"Ví dụ đời thường: giống vá đúng lỗ thủng, không sơn lại nhà.",[989,89885,89886],{},"Trao đổi với maintainer lịch sự và kiên nhẫn.",[1352,89888,89890],{"className":3538,"code":89889,"language":3540,"meta":1357,"style":1357},"# tái hiện lỗi trước khi sửa\ndef cong(a, b):\n    return a + b  # hàm nghi lỗi ở đây\nprint(cong(2, 3))  # chạy thử xem sai không\n",[992,89891,89892,89897,89902,89907],{"__ignoreMap":1357},[1023,89893,89894],{"class":1362,"line":63},[1023,89895,89896],{},"# tái hiện lỗi trước khi sửa\n",[1023,89898,89899],{"class":1362,"line":68},[1023,89900,89901],{},"def cong(a, b):\n",[1023,89903,89904],{"class":1362,"line":73},[1023,89905,89906],{},"    return a + b  # hàm nghi lỗi ở đây\n",[1023,89908,89909],{"class":1362,"line":78},[1023,89910,89911],{},"print(cong(2, 3))  # chạy thử xem sai không\n",[968,89913,1433],{"id":1432},[986,89915,89916,89919],{},[989,89917,89918],{},"Repo thỏa 4 tiêu chí chọn -> chốt được.",[989,89920,89921],{},"Sơ đồ module chỉ đúng tới hàm chứa issue -> đạt.",[968,89923,1482],{"id":1481},[973,89925,88916,89926,89929],{},[992,89927,89928],{},"day-177\u002F"," gồm ghi chép và link pull request.",[981,89931,89933],{"id":89932},"bài-1-chọn-repo-và-issue","Bài 1: Chọn repo và issue",[973,89935,89936],{},"Tiêu chí chọn repo:",[2273,89938,89939,89948,89951,89957],{},[989,89940,89941,89942,5586,89945,1517],{},"Có nhãn ",[992,89943,89944],{},"good first issue",[992,89946,89947],{},"help wanted",[989,89949,89950],{},"Có commit trong 30 ngày gần nhất.",[989,89952,12989,89953,89956],{},[992,89954,89955],{},"CONTRIBUTING.md"," hoặc hướng dẫn build.",[989,89958,89959],{},"Bộ test chạy được trên máy bạn.",[973,89961,89962,89963,89966],{},"Ưu tiên repo dùng kiến thức đã học (thư viện cấu trúc dữ liệu, công cụ đồ thị, thư viện ML nhỏ). Ghi vào ",[992,89964,89965],{},"choice.md",": repo, issue, 4 tiêu chí thỏa thế nào.",[981,89968,89970],{"id":89969},"bài-2-đọc-hiểu-codebase","Bài 2: Đọc hiểu codebase",[2273,89972,89973,89976,89982],{},[989,89974,89975],{},"Build và chạy toàn bộ test. Ghi thời gian và chỗ vấp.",[989,89977,89978,89981],{},[992,89979,89980],{},"architecture.md",": sơ đồ module bằng lời của bạn, chỉ ra đường đi từ điểm vào (CLI, API) tới hàm chứa issue.",[989,89983,89984],{},"Đọc quy ước code: format, đặt tên, cách viết test, cách viết commit.",[981,89986,89988],{"id":89987},"bài-3-sửa-và-gửi-pr-nâng-cao","Bài 3: Sửa và gửi PR (nâng cao)",[2273,89990,89991,89997,90000,90003],{},[989,89992,89993,89994,89996],{},"Viết test tái hiện lỗi ",[1487,89995,50377],{}," (test phải fail).",[989,89998,89999],{},"Sửa tối thiểu cho test pass. Chạy toàn bộ test và linter của repo.",[989,90001,90002],{},"Commit theo quy ước repo. Mô tả PR gồm: issue liên quan, nguyên nhân, cách sửa, cách kiểm tra.",[989,90004,90005,90006,1517],{},"Trả lời góp ý của maintainer lịch sự. Ghi lại trao đổi vào ",[992,90007,90008],{},"pr-log.md",[973,90010,90011],{},"Không tìm được issue phù hợp trong 60 phút thì làm PR sửa tài liệu (lỗi chính tả, ví dụ sai), vẫn đủ các bước.",[981,90013,2711],{"id":2710},[986,90015,90017,90025,90033,90039],{"className":90016},[2715],[989,90018,90020,2308,90022,90024],{"className":90019},[2719],[2721,90021],{"disabled":2723,"type":2724},[992,90023,89965],{}," giải thích 4 tiêu chí.",[989,90026,90028,2308,90030,90032],{"className":90027},[2719],[2721,90029],{"disabled":2723,"type":2724},[992,90031,89980],{}," chỉ tới đúng hàm chứa issue.",[989,90034,90036,90038],{"className":90035},[2719],[2721,90037],{"disabled":2723,"type":2724}," PR có test tái hiện lỗi và mô tả đủ 4 mục.",[989,90040,90042,2308,90044,90046],{"className":90041},[2719],[2721,90043],{"disabled":2723,"type":2724},[992,90045,90008],{}," ghi lại trao đổi.",[968,90048,2890],{"id":2889},[2273,90050,90051,90054,90057,90060],{},[989,90052,90053],{},"Chọn repo theo mấy tiêu chí?",[989,90055,90056],{},"Issue vừa sức sửa trong bao lâu?",[989,90058,90059],{},"Viết dòng nào trước khi sửa?",[989,90061,90062],{},"Pull request cần có gì?",[3014,90064],{},[973,90066,90067],{},"🌕 Bạn đã hoàn thành ngày 177. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",[3020,90069,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":90071},[90072,90073,90078,90079,90085],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":90074},[90075,90076,90077],{"id":89835,"depth":73,"text":89836},{"id":89853,"depth":73,"text":89854},{"id":89871,"depth":73,"text":89872},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":90080},[90081,90082,90083,90084],{"id":89932,"depth":73,"text":89933},{"id":89969,"depth":73,"text":89970},{"id":89987,"depth":73,"text":89988},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thực hành nghề nghiệp mã nguồn mở: chọn repo, đọc kiến trúc, sửa một issue thật và gửi pull request đúng chuẩn.",{},[],{"title":942,"description":90086},[89252,90091,88536],"opensource","F2-r6o0Jqrr1En-Sr9NpCUJNzBNMP9VNyNIzM6q8c_M",{"id":90094,"title":947,"body":90095,"category":8797,"day":950,"description":90393,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":90394,"navigation":2723,"outcomes":3047,"path":948,"prerequisites":90395,"seo":90396,"stem":949,"tags":90397,"__hash__":90399},"challenges\u002Fchallenges\u002F178.mock-interview.md",{"type":965,"value":90096,"toc":90377},[90097,90099,90102,90104,90108,90122,90126,90140,90144,90158,90160,90168,90170,90176,90180,90225,90228,90232,90239,90309,90312,90316,90327,90329,90356,90358,90372,90374],[968,90098,971],{"id":970},[973,90100,90101],{},"Bạn thi thử như phỏng vấn thật. Bấm giờ cắt ngang khi hết giờ.",[968,90103,979],{"id":978},[981,90105,90107],{"id":90106},"vòng-coding-40-phút","Vòng coding 40 phút",[986,90109,90110,90113,90116,90119],{},[989,90111,90112],{},"2 bài mảng chuỗi hoặc cây đồ thị.",[989,90114,90115],{},"Nói to suy nghĩ và dry-run đầy đủ.",[989,90117,90118],{},"Ví dụ đời thường: giống đá giao hữu đúng luật thi đấu.",[989,90120,90121],{},"Chuyển bài đúng mốc 20 phút.",[981,90123,90125],{"id":90124},"vòng-design-mini-30-phút","Vòng design mini 30 phút",[986,90127,90128,90131,90134,90137],{},[989,90129,90130],{},"Một hệ thống cache hoặc limiter.",[989,90132,90133],{},"Vẽ sơ đồ hộp và ghi số liệu ước lượng.",[989,90135,90136],{},"Ví dụ đời thường: giống vẽ nháp nhà trong 30 phút.",[989,90138,90139],{},"Hỏi tải trước khi vẽ.",[981,90141,90143],{"id":90142},"vòng-kể-chuyện-và-feedback","Vòng kể chuyện và feedback",[986,90145,90146,90149,90152,90155],{},[989,90147,90148],{},"Kể một chuyện refactor dưới 2 phút.",[989,90150,90151],{},"Trả lời 3 câu chất vấn trade-off.",[989,90153,90154],{},"Ví dụ đời thường: giống phản biện đồ án tốt nghiệp.",[989,90156,90157],{},"Feedback gồm 2 điểm tốt, 2 điểm sửa, 1 việc làm ngay.",[968,90159,1433],{"id":1432},[986,90161,90162,90165],{},[989,90163,90164],{},"3 vòng đúng giờ, không vòng nào lố quá 3 phút -> đạt.",[989,90166,90167],{},"Mỗi điểm rubric có hành vi cụ thể kèm theo -> đạt.",[968,90169,1482],{"id":1481},[973,90171,90172,90173,1517],{},"Cần 1 bạn cùng luyện (hoặc tự ghi hình và tự chấm). Nộp vào ",[992,90174,90175],{},"day-178\u002F",[981,90177,90179],{"id":90178},"bài-1-ba-vòng-phỏng-vấn-thử","Bài 1: Ba vòng phỏng vấn thử",[1099,90181,90182,90193],{},[1102,90183,90184],{},[1105,90185,90186,90189,90191],{},[1108,90187,90188],{},"Vòng",[1108,90190,29942],{},[1108,90192,87021],{},[1118,90194,90195,90206,90216],{},[1105,90196,90197,90200,90203],{},[1123,90198,90199],{},"Coding",[1123,90201,90202],{},"40 phút",[1123,90204,90205],{},"2 bài chưa gặp: 1 mảng\u002Fchuỗi, 1 cây\u002Fđồ thị. Chuyển bài ở phút 20. Nói to suy nghĩ, chạy tay 1 ví dụ trước khi chạy code",[1105,90207,90208,90211,90213],{},[1123,90209,90210],{},"Design mini",[1123,90212,86759],{},[1123,90214,90215],{},"Thiết kế cache phân tán hoặc rate limiter. Hỏi yêu cầu và tải trước khi vẽ",[1105,90217,90218,90220,90222],{},[1123,90219,4292],{},[1123,90221,89695],{},[1123,90223,90224],{},"Kể 1 chuyện refactor dưới 2 phút, trả lời 3 câu chất vấn đánh đổi",[973,90226,90227],{},"Ghi hình hoặc ghi âm cả 3 vòng.",[981,90229,90231],{"id":90230},"bài-2-rubric-chấm","Bài 2: Rubric chấm",[973,90233,90234,90235,90238],{},"Người chấm dùng rubric 1-4 cho mỗi mục, mỗi điểm kèm ",[1487,90236,90237],{},"hành vi cụ thể"," quan sát được:",[1099,90240,90241,90252],{},[1102,90242,90243],{},[1105,90244,90245,90247,90249],{},[1108,90246,87018],{},[1108,90248,71645],{},[1108,90250,90251],{},"Hành vi quan sát",[1118,90253,90254,90264,90273,90282,90291,90300],{},[1105,90255,90256,90259,90261],{},[1123,90257,90258],{},"Làm rõ đề",[1123,90260],{},[1123,90262,90263],{},"Ví dụ: \"hỏi về input rỗng ở phút 2\"",[1105,90265,90266,90269,90271],{},[1123,90267,90268],{},"Chọn cách giải và độ phức tạp",[1123,90270],{},[1123,90272],{},[1105,90274,90275,90278,90280],{},[1123,90276,90277],{},"Code đúng và sạch",[1123,90279],{},[1123,90281],{},[1105,90283,90284,90287,90289],{},[1123,90285,90286],{},"Kiểm tra và ca biên",[1123,90288],{},[1123,90290],{},[1105,90292,90293,90296,90298],{},[1123,90294,90295],{},"Giao tiếp",[1123,90297],{},[1123,90299],{},[1105,90301,90302,90305,90307],{},[1123,90303,90304],{},"Quản lý thời gian",[1123,90306],{},[1123,90308],{},[973,90310,90311],{},"Feedback cuối: 2 điểm tốt, 2 điểm cần sửa, 1 việc làm ngay.",[981,90313,90315],{"id":90314},"bài-3-đổi-vai-và-cải-thiện-nâng-cao","Bài 3: Đổi vai và cải thiện (nâng cao)",[2273,90317,90318,90321,90324],{},[989,90319,90320],{},"Đổi vai: bạn làm người phỏng vấn cho người kia. Ghi lại bạn học được gì khi ngồi ghế người chấm.",[989,90322,90323],{},"Xem lại bản ghi của mình. Ghi 3 thói quen xấu (ví dụ im lặng quá 1 phút, nhảy vào code ngay).",[989,90325,90326],{},"Làm lại 1 bài coding sau khi sửa \"1 việc làm ngay\". So thời gian và điểm.",[981,90328,2711],{"id":2710},[986,90330,90332,90338,90344,90350],{"className":90331},[2715],[989,90333,90335,90337],{"className":90334},[2719],[2721,90336],{"disabled":2723,"type":2724}," 3 vòng đúng giờ, không vòng nào lố quá 3 phút.",[989,90339,90341,90343],{"className":90340},[2719],[2721,90342],{"disabled":2723,"type":2724}," Rubric có hành vi cụ thể cho mọi mục.",[989,90345,90347,90349],{"className":90346},[2719],[2721,90348],{"disabled":2723,"type":2724}," Có feedback 2-2-1 và bản ghi.",[989,90351,90353,90355],{"className":90352},[2719],[2721,90354],{"disabled":2723,"type":2724}," Làm lại 1 bài và so kết quả.",[968,90357,2890],{"id":2889},[2273,90359,90360,90363,90366,90369],{},[989,90361,90362],{},"Vòng coding mấy phút mấy bài?",[989,90364,90365],{},"Design mini vẽ gì?",[989,90367,90368],{},"Feedback theo mẫu nào?",[989,90370,90371],{},"Vì sao phải ghi âm?",[3014,90373],{},[973,90375,90376],{},"🌕 Bạn đã hoàn thành ngày 178. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":90378},[90379,90380,90385,90386,90392],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":90381},[90382,90383,90384],{"id":90106,"depth":73,"text":90107},{"id":90124,"depth":73,"text":90125},{"id":90142,"depth":73,"text":90143},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":90387},[90388,90389,90390,90391],{"id":90178,"depth":73,"text":90179},{"id":90230,"depth":73,"text":90231},{"id":90314,"depth":73,"text":90315},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Thi thử tổng hợp như phỏng vấn thật: coding, design mini, kể chuyện patterns và review chéo có biên bản.",{},[],{"title":947,"description":90393},[68137,90398,88536],"mock","FtQPeY2tesZRqGX38qvp6GipwneHm2lLcZauyxb5Sq0",{"id":90401,"title":952,"body":90402,"category":8797,"day":955,"description":90630,"difficulty":68559,"estimatedMinutes":658,"extension":3044,"lastUpdate":3045,"meta":90631,"navigation":2723,"outcomes":3047,"path":953,"prerequisites":90632,"seo":90633,"stem":954,"tags":90634,"__hash__":90636},"challenges\u002Fchallenges\u002F179.san-pham-demo.md",{"type":965,"value":90403,"toc":90614},[90404,90406,90409,90411,90415,90429,90433,90447,90451,90465,90467,90475,90477,90482,90486,90504,90508,90519,90523,90561,90563,90593,90595,90609,90611],[968,90405,971],{"id":970},[973,90407,90408],{},"Bạn đóng gói sản phẩm để khoe với nhà tuyển dụng. Tin cậy hơn hoành tráng.",[968,90410,979],{"id":978},[981,90412,90414],{"id":90413},"polish-kỹ-thuật","Polish kỹ thuật",[986,90416,90417,90420,90423,90426],{},[989,90418,90419],{},"Sửa hết lỗi chặn, đóng băng tính năng mới.",[989,90421,90422],{},"Tính năng chưa ổn thì cắt hoặc giấu sau cờ.",[989,90424,90425],{},"Ví dụ đời thường: giống dọn nhà trước khi khách tới.",[989,90427,90428],{},"Quay video dự phòng cứu buổi demo sống.",[981,90430,90432],{"id":90431},"video-demo-5-phút","Video demo 5 phút",[986,90434,90435,90438,90441,90444],{},[989,90436,90437],{},"Kịch bản 3 phần: vấn đề, chạy sống, metric.",[989,90439,90440],{},"Sai số thời lượng trong 30 giây.",[989,90442,90443],{},"Ví dụ đời thường: giống quảng cáo 5 phút đúng kịch bản.",[989,90445,90446],{},"Đường demo trong video chạy thật, không cắt ghép.",[981,90448,90450],{"id":90449},"readme-và-chất-vấn","README và chất vấn",[986,90452,90453,90456,90459,90462],{},[989,90454,90455],{},"README cho người lướt 60 giây: ảnh và số liệu trước.",[989,90457,90458],{},"Có cách chạy một lệnh và giới hạn trung thực.",[989,90460,90461],{},"Ví dụ đời thường: giống CV một trang đập vào mắt trước.",[989,90463,90464],{},"Chuẩn bị 10 câu hỏi khó, mỗi câu trả lời dưới 1 phút.",[968,90466,1433],{"id":1432},[986,90468,90469,90472],{},[989,90470,90471],{},"Người lạ chạy một lệnh ra demo trong 15 phút -> đạt.",[989,90473,90474],{},"Video đúng 5 phút đủ 3 phần, tiếng hình rõ -> đạt.",[968,90476,1482],{"id":1481},[973,90478,90479,90480,1517],{},"Hoàn thiện dự án cuối (ngày 167-170). Nộp vào repo ",[992,90481,86992],{},[981,90483,90485],{"id":90484},"bài-1-đóng-băng-và-ổn-định","Bài 1: Đóng băng và ổn định",[2273,90487,90488,90491,90494,90497],{},[989,90489,90490],{},"Đóng băng tính năng: từ hôm nay chỉ sửa lỗi.",[989,90492,90493],{},"Liệt kê mọi lỗi còn mở, đánh mức P0 (chặn demo), P1, P2. Sửa hết P0.",[989,90495,90496],{},"Tính năng chưa ổn: cắt hẳn hoặc giấu sau cờ cấu hình, mặc định tắt.",[989,90498,90499,90500,90503],{},"Tag phiên bản ",[992,90501,90502],{},"v1.0.0",". CI xanh.",[981,90505,90507],{"id":90506},"bài-2-người-lạ-chạy-thử","Bài 2: Người lạ chạy thử",[2273,90509,90510,90513,90516],{},[989,90511,90512],{},"Nhờ 1 người chưa từng thấy dự án clone repo và làm theo README, không hỏi bạn.",[989,90514,90515],{},"Ghi lại: thời gian tới khi demo chạy, mọi chỗ họ vấp.",[989,90517,90518],{},"Sửa README và script tới khi họ chạy được trong 15 phút.",[981,90520,90522],{"id":90521},"bài-3-video-và-readme-chuẩn-tuyển-dụng-nâng-cao","Bài 3: Video và README chuẩn tuyển dụng (nâng cao)",[2273,90524,90525,90528,90558],{},[989,90526,90527],{},"Video 5 phút (sai số 30 giây): vấn đề (1 phút), demo chạy thật không cắt ghép (3 phút), số liệu (1 phút).",[989,90529,90530,90531],{},"README cho người lướt 60 giây:\n",[986,90532,90533,90536,90539,90546,90549,90552],{},[989,90534,90535],{},"Dòng đầu: 1 câu mô tả dự án.",[989,90537,90538],{},"Ảnh GIF hoặc ảnh chụp demo.",[989,90540,90541,90542,1656,90544,16014],{},"3 con số ấn tượng nhất (từ ",[992,90543,87354],{},[992,90545,87662],{},[989,90547,90548],{},"Cách chạy 1 lệnh.",[989,90550,90551],{},"Kiến trúc tóm tắt, kỹ thuật đã dùng.",[989,90553,90554,90557],{},[1487,90555,90556],{},"Giới hạn trung thực",": những gì chưa làm được.",[989,90559,90560],{},"Chuẩn bị 10 câu hỏi khó về dự án (vì sao chọn X không chọn Y, mở rộng 100 lần thì sao, chỗ yếu nhất ở đâu). Mỗi câu trả lời dưới 1 phút.",[981,90562,2711],{"id":2710},[986,90564,90566,90575,90581,90587],{"className":90565},[2715],[989,90567,90569,90571,90572,90574],{"className":90568},[2719],[2721,90570],{"disabled":2723,"type":2724}," Không còn lỗi P0, có tag ",[992,90573,90502],{},", CI xanh.",[989,90576,90578,90580],{"className":90577},[2719],[2721,90579],{"disabled":2723,"type":2724}," Người lạ chạy được demo trong 15 phút.",[989,90582,90584,90586],{"className":90583},[2719],[2721,90585],{"disabled":2723,"type":2724}," Video 5 phút đủ 3 phần.",[989,90588,90590,90592],{"className":90589},[2719],[2721,90591],{"disabled":2723,"type":2724}," README đủ 6 mục, có 10 câu hỏi khó và câu trả lời.",[968,90594,2890],{"id":2889},[2273,90596,90597,90600,90603,90606],{},[989,90598,90599],{},"Ưu tiên tin cậy hay hoành tráng?",[989,90601,90602],{},"Video demo mấy phút mấy phần?",[989,90604,90605],{},"README cho ai lướt bao lâu?",[989,90607,90608],{},"Tính năng chưa ổn thì làm gì?",[3014,90610],{},[973,90612,90613],{},"🌕 Bạn đã hoàn thành ngày 179. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":90615},[90616,90617,90622,90623,90629],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":90618},[90619,90620,90621],{"id":90413,"depth":73,"text":90414},{"id":90431,"depth":73,"text":90432},{"id":90449,"depth":73,"text":90450},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":90624},[90625,90626,90627,90628],{"id":90484,"depth":73,"text":90485},{"id":90506,"depth":73,"text":90507},{"id":90521,"depth":73,"text":90522},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"deposit nghề nghiệp cuối khóa: polish sản phẩm, quay video demo, viết README tuyển dụng và chuẩn bị trả lời chất vấn.",{},[],{"title":952,"description":90630},[87199,90635,88536],"demo","Il4ALCcnBcZkLlMtINknsyW1kgWBjvLoh2ETf7J9WT8",{"id":90638,"title":957,"body":90639,"category":8797,"day":960,"description":90876,"difficulty":3043,"estimatedMinutes":358,"extension":3044,"lastUpdate":3045,"meta":90877,"navigation":2723,"outcomes":3047,"path":958,"prerequisites":90878,"seo":90879,"stem":959,"tags":90880,"__hash__":90882},"challenges\u002Fchallenges\u002F180.le-tot-nghiep.md",{"type":965,"value":90640,"toc":90860},[90641,90643,90646,90648,90652,90666,90670,90684,90688,90702,90704,90712,90714,90720,90724,90735,90739,90742,90781,90785,90806,90808,90839,90841,90855,90857],[968,90642,971],{"id":970},[973,90644,90645],{},"Bạn demo sản phẩm và khép lại hành trình. Ghi lại mọi feedback nhận được.",[968,90647,979],{"id":978},[981,90649,90651],{"id":90650},"demo-10-phút","Demo 10 phút",[986,90653,90654,90657,90660,90663],{},[989,90655,90656],{},"Chỉ chạy đường hạnh phúc đã kiểm chứng.",[989,90658,90659],{},"Gặp sự cố thì chuyển video dự phòng ngay.",[989,90661,90662],{},"Ví dụ đời thường: giống diễn văn nghệ bài tủ đã tập.",[989,90664,90665],{},"Chuyển video trong một câu rồi tiếp tục.",[981,90667,90669],{"id":90668},"chia-sẻ-5-phút","Chia sẻ 5 phút",[986,90671,90672,90675,90678,90681],{},[989,90673,90674],{},"Kể 3 phần: xuất phát, bước ngoặt, đích đến.",[989,90676,90677],{},"Kết bằng cam kết 90 ngày tới.",[989,90679,90680],{},"Ví dụ đời thường: giống kể chuyến đi: khởi hành, sự cố, về đích.",[989,90682,90683],{},"Nói đúng giờ, không lố.",[981,90685,90687],{"id":90686},"feedback-và-cam-kết","Feedback và cam kết",[986,90689,90690,90693,90696,90699],{},[989,90691,90692],{},"Ghi nguyên văn mọi feedback của hội đồng.",[989,90694,90695],{},"Đối chiếu với vùng yếu đã biết.",[989,90697,90698],{},"Ví dụ đời thường: feedback như quà, nhận hết rồi mở sau.",[989,90700,90701],{},"Viết cam kết 90 ngày thành văn bản.",[968,90703,1433],{"id":1432},[986,90705,90706,90709],{},[989,90707,90708],{},"Input sự cố demo -> chuyển video dự phòng mượt mà.",[989,90710,90711],{},"Bài chia sẻ đủ 3 phần đúng 5 phút -> đạt.",[968,90713,1482],{"id":1481},[973,90715,90716,90717,1517],{},"Ngày tốt nghiệp. Nộp vào ",[992,90718,90719],{},"day-180\u002F",[981,90721,90723],{"id":90722},"bài-1-demo-day","Bài 1: Demo day",[2273,90725,90726,90729,90732],{},[989,90727,90728],{},"Demo dự án cuối 10 phút theo kịch bản ngày 179, trước ít nhất 1 người (bạn bè, đồng nghiệp, cộng đồng online).",[989,90730,90731],{},"Chỉ chạy đường đi đã kiểm chứng. Gặp sự cố thì chuyển sang video dự phòng bằng 1 câu rồi tiếp tục.",[989,90733,90734],{},"Ghi hình buổi demo.",[981,90736,90738],{"id":90737},"bài-2-chia-sẻ-hành-trình-5-phút","Bài 2: Chia sẻ hành trình 5 phút",[973,90740,90741],{},"Nói đúng 5 phút, 3 phần:",[1099,90743,90744,90753],{},[1102,90745,90746],{},[1105,90747,90748,90751],{},[1108,90749,90750],{},"Phần",[1108,90752,87021],{},[1118,90754,90755,90763,90771],{},[1105,90756,90757,90760],{},[1123,90758,90759],{},"Xuất phát",[1123,90761,90762],{},"Bạn code thế nào trước ngày 1 (thói quen vibe code, điều không hiểu)",[1105,90764,90765,90768],{},[1123,90766,90767],{},"Bước ngoặt",[1123,90769,90770],{},"1-2 ngày thay đổi cách bạn nghĩ nhất, kèm ví dụ cụ thể",[1105,90772,90773,90776],{},[1123,90774,90775],{},"Đích đến",[1123,90777,90778,90779,1056],{},"Bạn làm được gì bây giờ (dẫn bằng chứng từ ",[992,90780,88127],{},[981,90782,90784],{"id":90783},"bài-3-feedback-và-cam-kết-nâng-cao","Bài 3: Feedback và cam kết (nâng cao)",[2273,90786,90787,90797,90803],{},[989,90788,87348,90789,90792,90793,90796],{},[1487,90790,90791],{},"nguyên văn"," mọi feedback của người xem vào ",[992,90794,90795],{},"feedback.md",". Đối chiếu với vùng yếu ngày 171 và 173.",[989,90798,90799,90802],{},[992,90800,90801],{},"commitment.md",": cam kết 90 ngày tới, gồm hướng chính (ngày 172), 3 mốc có sản phẩm, 1 thói quen hằng ngày (ví dụ 1 bài mỗi sáng, không dùng AI viết code cho bài luyện).",[989,90804,90805],{},"Tổng kết số liệu 180 ngày: số ngày hoàn thành, số bài bỏ dở, tổng commit, tổng số test. Viết 1 đoạn về điều bạn sẽ làm khác nếu bắt đầu lại.",[981,90807,2711],{"id":2710},[986,90809,90811,90817,90823,90831],{"className":90810},[2715],[989,90812,90814,90816],{"className":90813},[2719],[2721,90815],{"disabled":2723,"type":2724}," Demo 10 phút có ghi hình.",[989,90818,90820,90822],{"className":90819},[2719],[2721,90821],{"disabled":2723,"type":2724}," Chia sẻ 5 phút đủ 3 phần.",[989,90824,90826,2308,90828,90830],{"className":90825},[2719],[2721,90827],{"disabled":2723,"type":2724},[992,90829,90795],{}," ghi nguyên văn, có đối chiếu vùng yếu.",[989,90832,90834,2308,90836,90838],{"className":90833},[2719],[2721,90835],{"disabled":2723,"type":2724},[992,90837,90801],{}," có 3 mốc và 1 thói quen.",[968,90840,2890],{"id":2889},[2273,90842,90843,90846,90849,90852],{},[989,90844,90845],{},"Demo chạy đường nào?",[989,90847,90848],{},"Sự cố demo thì làm gì?",[989,90850,90851],{},"Bài chia sẻ có mấy phần?",[989,90853,90854],{},"Feedback ghi thế nào?",[3014,90856],{},[973,90858,90859],{},"🌕 Bạn đã hoàn thành ngày 180. Làm hết bài tập phía trên rồi sang ngày tiếp theo.",{"title":1357,"searchDepth":68,"depth":68,"links":90861},[90862,90863,90868,90869,90875],{"id":970,"depth":68,"text":971},{"id":978,"depth":68,"text":979,"children":90864},[90865,90866,90867],{"id":90650,"depth":73,"text":90651},{"id":90668,"depth":73,"text":90669},{"id":90686,"depth":73,"text":90687},{"id":1432,"depth":68,"text":1433},{"id":1481,"depth":68,"text":1482,"children":90870},[90871,90872,90873,90874],{"id":90722,"depth":73,"text":90723},{"id":90737,"depth":73,"text":90738},{"id":90783,"depth":73,"text":90784},{"id":2710,"depth":73,"text":2711},{"id":2889,"depth":68,"text":2890},"Lễ tốt nghiệp 180 ngày: demo sản phẩm, chia sẻ hành trình, nhận feedback và khép lại với cam kết 90 ngày tới.",{},[],{"title":957,"description":90876},[90881,90635,88536],"celebration","s0eCyTR5CPdBiA7JEwLtrHDLD-NSI_I3ymg0r_51vCY",[90884,98797,99051,100059,101256,101620,101952,103080,104560,105274,105769],{"id":90885,"title":10,"body":90886,"category":7,"day":3047,"description":98789,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":98790,"navigation":2723,"outcomes":3047,"path":11,"prerequisites":3047,"seo":98791,"stem":12,"tags":98792,"__hash__":98796},"fundamentals\u002Ffundamentals\u002Fbig-o-notation.md",{"type":965,"value":90887,"toc":98776},[90888,90892,90895,90898,90902,90905,90908,90911,90915,91179,91492,91495,91785,91890,92251,92359,92391,92395,92398,92792,92795,92798,92801,93454,93705,93737,93741,93744,94377,94624,94627,94631,94678,94681,94740,94871,94918,94995,95072,95300,95303,95639,96349,96353,96356,96359,96363,96484,96487,96560,96564,96567,96570,96574,96577,96753,96900,97098,97427,97520,97796,97806,97979,98108,98217,98221],[968,90889,90891],{"id":90890},"_1-tổng-quan","1. Tổng quan",[973,90893,90894],{},"Hai thuật toán cùng giải một bài toán. Ta không hỏi máy nào chạy nhanh hơn.",[973,90896,90897],{},"Ta hỏi chi phí tăng nhanh ra sao khi đầu vào lớn dần. Big-O là ngôn ngữ trả lời câu hỏi đó.",[968,90899,90901],{"id":90900},"_2-nguồn-gốc-bachmann-và-ý-tưởng-bậc-tăng-trưởng","2. Nguồn gốc: Bachmann và ý tưởng bậc tăng trưởng",[973,90903,90904],{},"Paul Bachmann đưa ra ký hiệu O(n) năm 1894. Ý ông rất gọn: bậc tăng của chi phí không vượt bậc của n.",[973,90906,90907],{},"Thay vì đếm từng phép tính, ta nhìn hình dạng đường cong. Thuật toán A tốn 100 bước, B tốn 10 bước trên mẫu thử.",[973,90909,90910],{},"Hai con số đó chưa nói lên tương lai. Nhưng nếu A tăng theo bình phương còn B tăng theo n, ta đoán được mọi kích thước đầu vào.",[968,90912,90914],{"id":90913},"_3-định-nghĩa-chặn-trên-và-cặp-hằng-số-c-n0","3. Định nghĩa chặn trên và cặp hằng số c, n0",[973,90916,90917,90918,90962,90963,91019,91020,91089,91090,91133,91134,91178],{},"Nói ",[1023,90919,90921,90941],{"className":90920},[1026],[1023,90922,90924],{"className":90923},[1030],[1032,90925,90926],{"xmlns":1034},[1036,90927,90928,90938],{},[1039,90929,90930,90932,90934,90936],{},[1042,90931,59487],{},[1046,90933,1049],{"stretchy":1048},[1042,90935,1262],{},[1046,90937,1056],{"stretchy":1048},[1058,90939,90940],{"encoding":1060},"f(n)",[1023,90942,90944],{"className":90943,"ariaHidden":1066},[1065],[1023,90945,90947,90950,90953,90956,90959],{"className":90946},[1070],[1023,90948],{"className":90949,"style":1075},[1074],[1023,90951,59487],{"className":90952,"style":59523},[1079,1080],[1023,90954,1049],{"className":90955},[1085],[1023,90957,1262],{"className":90958},[1079,1080],[1023,90960,1056],{"className":90961},[1092]," thuộc ",[1023,90964,90966,90992],{"className":90965},[1026],[1023,90967,90969],{"className":90968},[1030],[1032,90970,90971],{"xmlns":1034},[1036,90972,90973,90989],{},[1039,90974,90975,90977,90979,90981,90983,90985,90987],{},[1042,90976,1044],{},[1046,90978,1049],{"stretchy":1048},[1042,90980,7690],{},[1046,90982,1049],{"stretchy":1048},[1042,90984,1262],{},[1046,90986,1056],{"stretchy":1048},[1046,90988,1056],{"stretchy":1048},[1058,90990,90991],{"encoding":1060},"O(g(n))",[1023,90993,90995],{"className":90994,"ariaHidden":1066},[1065],[1023,90996,90998,91001,91004,91007,91010,91013,91016],{"className":90997},[1070],[1023,90999],{"className":91000,"style":1075},[1074],[1023,91002,1044],{"className":91003,"style":1081},[1079,1080],[1023,91005,1049],{"className":91006},[1085],[1023,91008,7690],{"className":91009,"style":7723},[1079,1080],[1023,91011,1049],{"className":91012},[1085],[1023,91014,1262],{"className":91015},[1079,1080],[1023,91017,47920],{"className":91018},[1092]," nghĩa là tỉ số ",[1023,91021,91023,91053],{"className":91022},[1026],[1023,91024,91026],{"className":91025},[1030],[1032,91027,91028],{"xmlns":1034},[1036,91029,91030,91050],{},[1039,91031,91032,91034,91036,91038,91040,91042,91044,91046,91048],{},[1042,91033,59487],{},[1046,91035,1049],{"stretchy":1048},[1042,91037,1262],{},[1046,91039,1056],{"stretchy":1048},[1042,91041,2461],{"mathvariant":2460},[1042,91043,7690],{},[1046,91045,1049],{"stretchy":1048},[1042,91047,1262],{},[1046,91049,1056],{"stretchy":1048},[1058,91051,91052],{"encoding":1060},"f(n)\u002Fg(n)",[1023,91054,91056],{"className":91055,"ariaHidden":1066},[1065],[1023,91057,91059,91062,91065,91068,91071,91074,91077,91080,91083,91086],{"className":91058},[1070],[1023,91060],{"className":91061,"style":1075},[1074],[1023,91063,59487],{"className":91064,"style":59523},[1079,1080],[1023,91066,1049],{"className":91067},[1085],[1023,91069,1262],{"className":91070},[1079,1080],[1023,91072,1056],{"className":91073},[1092],[1023,91075,2461],{"className":91076},[1079],[1023,91078,7690],{"className":91079,"style":7723},[1079,1080],[1023,91081,1049],{"className":91082},[1085],[1023,91084,1262],{"className":91085},[1079,1080],[1023,91087,1056],{"className":91088},[1092]," bị chặn khi n lớn dần. Dù đầu vào phình to, ",[1023,91091,91093,91112],{"className":91092},[1026],[1023,91094,91096],{"className":91095},[1030],[1032,91097,91098],{"xmlns":1034},[1036,91099,91100,91110],{},[1039,91101,91102,91104,91106,91108],{},[1042,91103,59487],{},[1046,91105,1049],{"stretchy":1048},[1042,91107,1262],{},[1046,91109,1056],{"stretchy":1048},[1058,91111,90940],{"encoding":1060},[1023,91113,91115],{"className":91114,"ariaHidden":1066},[1065],[1023,91116,91118,91121,91124,91127,91130],{"className":91117},[1070],[1023,91119],{"className":91120,"style":1075},[1074],[1023,91122,59487],{"className":91123,"style":59523},[1079,1080],[1023,91125,1049],{"className":91126},[1085],[1023,91128,1262],{"className":91129},[1079,1080],[1023,91131,1056],{"className":91132},[1092]," không vượt ",[1023,91135,91137,91157],{"className":91136},[1026],[1023,91138,91140],{"className":91139},[1030],[1032,91141,91142],{"xmlns":1034},[1036,91143,91144,91154],{},[1039,91145,91146,91148,91150,91152],{},[1042,91147,7690],{},[1046,91149,1049],{"stretchy":1048},[1042,91151,1262],{},[1046,91153,1056],{"stretchy":1048},[1058,91155,91156],{"encoding":1060},"g(n)",[1023,91158,91160],{"className":91159,"ariaHidden":1066},[1065],[1023,91161,91163,91166,91169,91172,91175],{"className":91162},[1070],[1023,91164],{"className":91165,"style":1075},[1074],[1023,91167,7690],{"className":91168,"style":7723},[1079,1080],[1023,91170,1049],{"className":91171},[1085],[1023,91173,1262],{"className":91174},[1079,1080],[1023,91176,1056],{"className":91177},[1092]," một cách mất kiểm soát.",[973,91180,91181,91182,90962,91333,91406,91407,91491],{},"Ví dụ: ",[1023,91183,91185,91225],{"className":91184},[1026],[1023,91186,91188],{"className":91187},[1030],[1032,91189,91190],{"xmlns":1034},[1036,91191,91192,91222],{},[1039,91193,91194,91196,91198,91200,91202,91204,91206,91212,91214,91216,91218,91220],{},[1042,91195,59487],{},[1046,91197,1049],{"stretchy":1048},[1042,91199,1262],{},[1046,91201,1056],{"stretchy":1048},[1046,91203,2325],{},[1051,91205,9989],{},[2327,91207,91208,91210],{},[1042,91209,1262],{},[1051,91211,2457],{},[1046,91213,21881],{},[1051,91215,13900],{},[1042,91217,1262],{},[1046,91219,21881],{},[1051,91221,2331],{},[1058,91223,91224],{"encoding":1060},"f(n) = 1000n^2 + 100n + 10",[1023,91226,91228,91255,91303,91324],{"className":91227,"ariaHidden":1066},[1065],[1023,91229,91231,91234,91237,91240,91243,91246,91249,91252],{"className":91230},[1070],[1023,91232],{"className":91233,"style":1075},[1074],[1023,91235,59487],{"className":91236,"style":59523},[1079,1080],[1023,91238,1049],{"className":91239},[1085],[1023,91241,1262],{"className":91242},[1079,1080],[1023,91244,1056],{"className":91245},[1092],[1023,91247],{"className":91248,"style":2355},[2354],[1023,91250,2325],{"className":91251},[2359],[1023,91253],{"className":91254,"style":2355},[2354],[1023,91256,91258,91262,91265,91294,91297,91300],{"className":91257},[1070],[1023,91259],{"className":91260,"style":91261},[1074],"height:0.8974em;vertical-align:-0.0833em;",[1023,91263,9989],{"className":91264},[1079],[1023,91266,91268,91271],{"className":91267},[1079],[1023,91269,1262],{"className":91270},[1079,1080],[1023,91272,91274],{"className":91273},[2383],[1023,91275,91277],{"className":91276},[2387],[1023,91278,91280],{"className":91279},[2391],[1023,91281,91283],{"className":91282,"style":2369},[2395],[1023,91284,91285,91288],{"style":2398},[1023,91286],{"className":91287,"style":2403},[2402],[1023,91289,91291],{"className":91290},[2407,2408,2409,2410],[1023,91292,2457],{"className":91293},[1079,2410],[1023,91295],{"className":91296,"style":13790},[2354],[1023,91298,21881],{"className":91299},[13794],[1023,91301],{"className":91302,"style":13790},[2354],[1023,91304,91306,91309,91312,91315,91318,91321],{"className":91305},[1070],[1023,91307],{"className":91308,"style":18148},[1074],[1023,91310,13900],{"className":91311},[1079],[1023,91313,1262],{"className":91314},[1079,1080],[1023,91316],{"className":91317,"style":13790},[2354],[1023,91319,21881],{"className":91320},[13794],[1023,91322],{"className":91323,"style":13790},[2354],[1023,91325,91327,91330],{"className":91326},[1070],[1023,91328],{"className":91329,"style":10020},[1074],[1023,91331,2331],{"className":91332},[1079],[1023,91334,91336,91359],{"className":91335},[1026],[1023,91337,91339],{"className":91338},[1030],[1032,91340,91341],{"xmlns":1034},[1036,91342,91343,91357],{},[1039,91344,91345,91347,91349,91355],{},[1042,91346,1044],{},[1046,91348,1049],{"stretchy":1048},[2327,91350,91351,91353],{},[1042,91352,1262],{},[1051,91354,2457],{},[1046,91356,1056],{"stretchy":1048},[1058,91358,2839],{"encoding":1060},[1023,91360,91362],{"className":91361,"ariaHidden":1066},[1065],[1023,91363,91365,91368,91371,91374,91403],{"className":91364},[1070],[1023,91366],{"className":91367,"style":2476},[1074],[1023,91369,1044],{"className":91370,"style":1081},[1079,1080],[1023,91372,1049],{"className":91373},[1085],[1023,91375,91377,91380],{"className":91376},[1079],[1023,91378,1262],{"className":91379},[1079,1080],[1023,91381,91383],{"className":91382},[2383],[1023,91384,91386],{"className":91385},[2387],[1023,91387,91389],{"className":91388},[2391],[1023,91390,91392],{"className":91391,"style":2369},[2395],[1023,91393,91394,91397],{"style":2398},[1023,91395],{"className":91396,"style":2403},[2402],[1023,91398,91400],{"className":91399},[2407,2408,2409,2410],[1023,91401,2457],{"className":91402},[1079,2410],[1023,91404,1056],{"className":91405},[1092],". Tỉ số ",[1023,91408,91410,91438],{"className":91409},[1026],[1023,91411,91413],{"className":91412},[1030],[1032,91414,91415],{"xmlns":1034},[1036,91416,91417,91435],{},[1039,91418,91419,91421,91423,91425,91427,91429],{},[1042,91420,59487],{},[1046,91422,1049],{"stretchy":1048},[1042,91424,1262],{},[1046,91426,1056],{"stretchy":1048},[1042,91428,2461],{"mathvariant":2460},[2327,91430,91431,91433],{},[1042,91432,1262],{},[1051,91434,2457],{},[1058,91436,91437],{"encoding":1060},"f(n)\u002Fn^2",[1023,91439,91441],{"className":91440,"ariaHidden":1066},[1065],[1023,91442,91444,91447,91450,91453,91456,91459,91462],{"className":91443},[1070],[1023,91445],{"className":91446,"style":2476},[1074],[1023,91448,59487],{"className":91449,"style":59523},[1079,1080],[1023,91451,1049],{"className":91452},[1085],[1023,91454,1262],{"className":91455},[1079,1080],[1023,91457,1056],{"className":91458},[1092],[1023,91460,2461],{"className":91461},[1079],[1023,91463,91465,91468],{"className":91464},[1079],[1023,91466,1262],{"className":91467},[1079,1080],[1023,91469,91471],{"className":91470},[2383],[1023,91472,91474],{"className":91473},[2387],[1023,91475,91477],{"className":91476},[2391],[1023,91478,91480],{"className":91479,"style":2369},[2395],[1023,91481,91482,91485],{"style":2398},[1023,91483],{"className":91484,"style":2403},[2402],[1023,91486,91488],{"className":91487},[2407,2408,2409,2410],[1023,91489,2457],{"className":91490},[1079,2410]," quanh quẩn gần 1000.",[973,91493,91494],{},"Khi n đủ lớn, đầu vào tăng gấp đôi thì chi phí tăng xấp xỉ gấp bốn. Đó là bản chất của bậc hai.",[973,91496,91497,91498,91592,91593,91621,91622,91691,91692,4437],{},"Định nghĩa chặt chẽ: ",[1023,91499,91501,91538],{"className":91500},[1026],[1023,91502,91504],{"className":91503},[1030],[1032,91505,91506],{"xmlns":1034},[1036,91507,91508,91535],{},[1039,91509,91510,91512,91514,91516,91518,91521,91523,91525,91527,91529,91531,91533],{},[1042,91511,7690],{},[1046,91513,1049],{"stretchy":1048},[1042,91515,1262],{},[1046,91517,1056],{"stretchy":1048},[1046,91519,91520],{},"∈",[1042,91522,1044],{},[1046,91524,1049],{"stretchy":1048},[1042,91526,59487],{},[1046,91528,1049],{"stretchy":1048},[1042,91530,1262],{},[1046,91532,1056],{"stretchy":1048},[1046,91534,1056],{"stretchy":1048},[1058,91536,91537],{"encoding":1060},"g(n) \\in O(f(n))",[1023,91539,91541,91568],{"className":91540,"ariaHidden":1066},[1065],[1023,91542,91544,91547,91550,91553,91556,91559,91562,91565],{"className":91543},[1070],[1023,91545],{"className":91546,"style":1075},[1074],[1023,91548,7690],{"className":91549,"style":7723},[1079,1080],[1023,91551,1049],{"className":91552},[1085],[1023,91554,1262],{"className":91555},[1079,1080],[1023,91557,1056],{"className":91558},[1092],[1023,91560],{"className":91561,"style":2355},[2354],[1023,91563,91520],{"className":91564},[2359],[1023,91566],{"className":91567,"style":2355},[2354],[1023,91569,91571,91574,91577,91580,91583,91586,91589],{"className":91570},[1070],[1023,91572],{"className":91573,"style":1075},[1074],[1023,91575,1044],{"className":91576,"style":1081},[1079,1080],[1023,91578,1049],{"className":91579},[1085],[1023,91581,59487],{"className":91582,"style":59523},[1079,1080],[1023,91584,1049],{"className":91585},[1085],[1023,91587,1262],{"className":91588},[1079,1080],[1023,91590,47920],{"className":91591},[1092]," nghĩa là có hằng số ",[1023,91594,91596,91609],{"className":91595},[1026],[1023,91597,91599],{"className":91598},[1030],[1032,91600,91601],{"xmlns":1034},[1036,91602,91603,91607],{},[1039,91604,91605],{},[1042,91606,1356],{},[1058,91608,1356],{"encoding":1060},[1023,91610,91612],{"className":91611,"ariaHidden":1066},[1065],[1023,91613,91615,91618],{"className":91614},[1070],[1023,91616],{"className":91617,"style":2347},[1074],[1023,91619,1356],{"className":91620},[1079,1080]," và ngưỡng ",[1023,91623,91625,91642],{"className":91624},[1026],[1023,91626,91628],{"className":91627},[1030],[1032,91629,91630],{"xmlns":1034},[1036,91631,91632,91640],{},[1039,91633,91634],{},[17690,91635,91636,91638],{},[1042,91637,1262],{},[1051,91639,2379],{},[1058,91641,81892],{"encoding":1060},[1023,91643,91645],{"className":91644,"ariaHidden":1066},[1065],[1023,91646,91648,91651],{"className":91647},[1070],[1023,91649],{"className":91650,"style":54000},[1074],[1023,91652,91654,91657],{"className":91653},[1079],[1023,91655,1262],{"className":91656},[1079,1080],[1023,91658,91660],{"className":91659},[2383],[1023,91661,91663,91683],{"className":91662},[2387,17732],[1023,91664,91666,91680],{"className":91665},[2391],[1023,91667,91669],{"className":91668,"style":54019},[2395],[1023,91670,91671,91674],{"style":17783},[1023,91672],{"className":91673,"style":2403},[2402],[1023,91675,91677],{"className":91676},[2407,2408,2409,2410],[1023,91678,2379],{"className":91679},[1079,2410],[1023,91681,17797],{"className":91682},[17796],[1023,91684,91686],{"className":91685},[2391],[1023,91687,91689],{"className":91688,"style":17804},[2395],[1023,91690],{}," sao cho mọi ",[1023,91693,91695,91717],{"className":91694},[1026],[1023,91696,91698],{"className":91697},[1030],[1032,91699,91700],{"xmlns":1034},[1036,91701,91702,91714],{},[1039,91703,91704,91706,91708],{},[1042,91705,1262],{},[1046,91707,59050],{},[17690,91709,91710,91712],{},[1042,91711,1262],{},[1051,91713,2379],{},[1058,91715,91716],{"encoding":1060},"n > n_0",[1023,91718,91720,91739],{"className":91719,"ariaHidden":1066},[1065],[1023,91721,91723,91727,91730,91733,91736],{"className":91722},[1070],[1023,91724],{"className":91725,"style":91726},[1074],"height:0.5782em;vertical-align:-0.0391em;",[1023,91728,1262],{"className":91729},[1079,1080],[1023,91731],{"className":91732,"style":2355},[2354],[1023,91734,59050],{"className":91735},[2359],[1023,91737],{"className":91738,"style":2355},[2354],[1023,91740,91742,91745],{"className":91741},[1070],[1023,91743],{"className":91744,"style":54000},[1074],[1023,91746,91748,91751],{"className":91747},[1079],[1023,91749,1262],{"className":91750},[1079,1080],[1023,91752,91754],{"className":91753},[2383],[1023,91755,91757,91777],{"className":91756},[2387,17732],[1023,91758,91760,91774],{"className":91759},[2391],[1023,91761,91763],{"className":91762,"style":54019},[2395],[1023,91764,91765,91768],{"style":17783},[1023,91766],{"className":91767,"style":2403},[2402],[1023,91769,91771],{"className":91770},[2407,2408,2409,2410],[1023,91772,2379],{"className":91773},[1079,2410],[1023,91775,17797],{"className":91776},[17796],[1023,91778,91780],{"className":91779},[2391],[1023,91781,91783],{"className":91782,"style":17804},[2395],[1023,91784],{},[973,91786,91787],{},[1023,91788,91790,91824],{"className":91789},[1026],[1023,91791,91793],{"className":91792},[1030],[1032,91794,91795],{"xmlns":1034},[1036,91796,91797,91821],{},[1039,91798,91799,91801,91803,91805,91807,91809,91811,91813,91815,91817,91819],{},[1042,91800,7690],{},[1046,91802,1049],{"stretchy":1048},[1042,91804,1262],{},[1046,91806,1056],{"stretchy":1048},[1046,91808,21123],{},[1042,91810,1356],{},[1046,91812,18118],{},[1042,91814,59487],{},[1046,91816,1049],{"stretchy":1048},[1042,91818,1262],{},[1046,91820,1056],{"stretchy":1048},[1058,91822,91823],{"encoding":1060},"g(n) \\le c \\cdot f(n)",[1023,91825,91827,91854,91872],{"className":91826,"ariaHidden":1066},[1065],[1023,91828,91830,91833,91836,91839,91842,91845,91848,91851],{"className":91829},[1070],[1023,91831],{"className":91832,"style":1075},[1074],[1023,91834,7690],{"className":91835,"style":7723},[1079,1080],[1023,91837,1049],{"className":91838},[1085],[1023,91840,1262],{"className":91841},[1079,1080],[1023,91843,1056],{"className":91844},[1092],[1023,91846],{"className":91847,"style":2355},[2354],[1023,91849,21123],{"className":91850},[2359],[1023,91852],{"className":91853,"style":2355},[2354],[1023,91855,91857,91860,91863,91866,91869],{"className":91856},[1070],[1023,91858],{"className":91859,"style":81759},[1074],[1023,91861,1356],{"className":91862},[1079,1080],[1023,91864],{"className":91865,"style":13790},[2354],[1023,91867,18118],{"className":91868},[13794],[1023,91870],{"className":91871,"style":13790},[2354],[1023,91873,91875,91878,91881,91884,91887],{"className":91874},[1070],[1023,91876],{"className":91877,"style":1075},[1074],[1023,91879,59487],{"className":91880,"style":59523},[1079,1080],[1023,91882,1049],{"className":91883},[1085],[1023,91885,1262],{"className":91886},[1079,1080],[1023,91888,1056],{"className":91889},[1092],[973,91891,91892,91893,1656,91987,92053,92054,1509,92105,92197,92198,92250],{},"Ví dụ cụ thể: ",[1023,91894,91896,91927],{"className":91895},[1026],[1023,91897,91899],{"className":91898},[1030],[1032,91900,91901],{"xmlns":1034},[1036,91902,91903,91924],{},[1039,91904,91905,91907,91909,91911,91913,91915,91918,91920,91922],{},[1042,91906,7690],{},[1046,91908,1049],{"stretchy":1048},[1042,91910,1262],{},[1046,91912,1056],{"stretchy":1048},[1046,91914,2325],{},[1051,91916,91917],{},"40",[1046,91919,21881],{},[1051,91921,13826],{},[1042,91923,1262],{},[1058,91925,91926],{"encoding":1060},"g(n) = 40 + 3n",[1023,91928,91930,91957,91975],{"className":91929,"ariaHidden":1066},[1065],[1023,91931,91933,91936,91939,91942,91945,91948,91951,91954],{"className":91932},[1070],[1023,91934],{"className":91935,"style":1075},[1074],[1023,91937,7690],{"className":91938,"style":7723},[1079,1080],[1023,91940,1049],{"className":91941},[1085],[1023,91943,1262],{"className":91944},[1079,1080],[1023,91946,1056],{"className":91947},[1092],[1023,91949],{"className":91950,"style":2355},[2354],[1023,91952,2325],{"className":91953},[2359],[1023,91955],{"className":91956,"style":2355},[2354],[1023,91958,91960,91963,91966,91969,91972],{"className":91959},[1070],[1023,91961],{"className":91962,"style":18148},[1074],[1023,91964,91917],{"className":91965},[1079],[1023,91967],{"className":91968,"style":13790},[2354],[1023,91970,21881],{"className":91971},[13794],[1023,91973],{"className":91974,"style":13790},[2354],[1023,91976,91978,91981,91984],{"className":91977},[1070],[1023,91979],{"className":91980,"style":10020},[1074],[1023,91982,13826],{"className":91983},[1079],[1023,91985,1262],{"className":91986},[1079,1080],[1023,91988,91990,92014],{"className":91989},[1026],[1023,91991,91993],{"className":91992},[1030],[1032,91994,91995],{"xmlns":1034},[1036,91996,91997,92011],{},[1039,91998,91999,92001,92003,92005,92007,92009],{},[1042,92000,59487],{},[1046,92002,1049],{"stretchy":1048},[1042,92004,1262],{},[1046,92006,1056],{"stretchy":1048},[1046,92008,2325],{},[1042,92010,1262],{},[1058,92012,92013],{"encoding":1060},"f(n) = n",[1023,92015,92017,92044],{"className":92016,"ariaHidden":1066},[1065],[1023,92018,92020,92023,92026,92029,92032,92035,92038,92041],{"className":92019},[1070],[1023,92021],{"className":92022,"style":1075},[1074],[1023,92024,59487],{"className":92025,"style":59523},[1079,1080],[1023,92027,1049],{"className":92028},[1085],[1023,92030,1262],{"className":92031},[1079,1080],[1023,92033,1056],{"className":92034},[1092],[1023,92036],{"className":92037,"style":2355},[2354],[1023,92039,2325],{"className":92040},[2359],[1023,92042],{"className":92043,"style":2355},[2354],[1023,92045,92047,92050],{"className":92046},[1070],[1023,92048],{"className":92049,"style":2347},[1074],[1023,92051,1262],{"className":92052},[1079,1080],", chọn ",[1023,92055,92057,92075],{"className":92056},[1026],[1023,92058,92060],{"className":92059},[1030],[1032,92061,92062],{"xmlns":1034},[1036,92063,92064,92072],{},[1039,92065,92066,92068,92070],{},[1042,92067,1356],{},[1046,92069,2325],{},[1051,92071,25255],{},[1058,92073,92074],{"encoding":1060},"c = 4",[1023,92076,92078,92096],{"className":92077,"ariaHidden":1066},[1065],[1023,92079,92081,92084,92087,92090,92093],{"className":92080},[1070],[1023,92082],{"className":92083,"style":2347},[1074],[1023,92085,1356],{"className":92086},[1079,1080],[1023,92088],{"className":92089,"style":2355},[2354],[1023,92091,2325],{"className":92092},[2359],[1023,92094],{"className":92095,"style":2355},[2354],[1023,92097,92099,92102],{"className":92098},[1070],[1023,92100],{"className":92101,"style":10020},[1074],[1023,92103,25255],{"className":92104},[1079],[1023,92106,92108,92130],{"className":92107},[1026],[1023,92109,92111],{"className":92110},[1030],[1032,92112,92113],{"xmlns":1034},[1036,92114,92115,92127],{},[1039,92116,92117,92123,92125],{},[17690,92118,92119,92121],{},[1042,92120,1262],{},[1051,92122,2379],{},[1046,92124,2325],{},[1051,92126,91917],{},[1058,92128,92129],{"encoding":1060},"n_0 = 40",[1023,92131,92133,92188],{"className":92132,"ariaHidden":1066},[1065],[1023,92134,92136,92139,92179,92182,92185],{"className":92135},[1070],[1023,92137],{"className":92138,"style":54000},[1074],[1023,92140,92142,92145],{"className":92141},[1079],[1023,92143,1262],{"className":92144},[1079,1080],[1023,92146,92148],{"className":92147},[2383],[1023,92149,92151,92171],{"className":92150},[2387,17732],[1023,92152,92154,92168],{"className":92153},[2391],[1023,92155,92157],{"className":92156,"style":54019},[2395],[1023,92158,92159,92162],{"style":17783},[1023,92160],{"className":92161,"style":2403},[2402],[1023,92163,92165],{"className":92164},[2407,2408,2409,2410],[1023,92166,2379],{"className":92167},[1079,2410],[1023,92169,17797],{"className":92170},[17796],[1023,92172,92174],{"className":92173},[2391],[1023,92175,92177],{"className":92176,"style":17804},[2395],[1023,92178],{},[1023,92180],{"className":92181,"style":2355},[2354],[1023,92183,2325],{"className":92184},[2359],[1023,92186],{"className":92187,"style":2355},[2354],[1023,92189,92191,92194],{"className":92190},[1070],[1023,92192],{"className":92193,"style":10020},[1074],[1023,92195,91917],{"className":92196},[1079],". Tại ",[1023,92199,92201,92220],{"className":92200},[1026],[1023,92202,92204],{"className":92203},[1030],[1032,92205,92206],{"xmlns":1034},[1036,92207,92208,92217],{},[1039,92209,92210,92212,92214],{},[1042,92211,1262],{},[1046,92213,2325],{},[1051,92215,92216],{},"30",[1058,92218,92219],{"encoding":1060},"n = 30",[1023,92221,92223,92241],{"className":92222,"ariaHidden":1066},[1065],[1023,92224,92226,92229,92232,92235,92238],{"className":92225},[1070],[1023,92227],{"className":92228,"style":2347},[1074],[1023,92230,1262],{"className":92231},[1079,1080],[1023,92233],{"className":92234,"style":2355},[2354],[1023,92236,2325],{"className":92237},[2359],[1023,92239],{"className":92240,"style":2355},[2354],[1023,92242,92244,92247],{"className":92243},[1070],[1023,92245],{"className":92246,"style":10020},[1074],[1023,92248,92216],{"className":92249},[1079],", vế trái 130 lớn hơn vế phải 120 nên chưa đạt.",[973,92252,92253,92254,92305,92306,92358],{},"Tại ",[1023,92255,92257,92275],{"className":92256},[1026],[1023,92258,92260],{"className":92259},[1030],[1032,92261,92262],{"xmlns":1034},[1036,92263,92264,92272],{},[1039,92265,92266,92268,92270],{},[1042,92267,1262],{},[1046,92269,2325],{},[1051,92271,91917],{},[1058,92273,92274],{"encoding":1060},"n = 40",[1023,92276,92278,92296],{"className":92277,"ariaHidden":1066},[1065],[1023,92279,92281,92284,92287,92290,92293],{"className":92280},[1070],[1023,92282],{"className":92283,"style":2347},[1074],[1023,92285,1262],{"className":92286},[1079,1080],[1023,92288],{"className":92289,"style":2355},[2354],[1023,92291,2325],{"className":92292},[2359],[1023,92294],{"className":92295,"style":2355},[2354],[1023,92297,92299,92302],{"className":92298},[1070],[1023,92300],{"className":92301,"style":10020},[1074],[1023,92303,91917],{"className":92304},[1079],", hai vế cùng bằng 160. Từ ",[1023,92307,92309,92328],{"className":92308},[1026],[1023,92310,92312],{"className":92311},[1030],[1032,92313,92314],{"xmlns":1034},[1036,92315,92316,92325],{},[1039,92317,92318,92320,92322],{},[1042,92319,1262],{},[1046,92321,2325],{},[1051,92323,92324],{},"41",[1058,92326,92327],{"encoding":1060},"n = 41",[1023,92329,92331,92349],{"className":92330,"ariaHidden":1066},[1065],[1023,92332,92334,92337,92340,92343,92346],{"className":92333},[1070],[1023,92335],{"className":92336,"style":2347},[1074],[1023,92338,1262],{"className":92339},[1079,1080],[1023,92341],{"className":92342,"style":2355},[2354],[1023,92344,2325],{"className":92345},[2359],[1023,92347],{"className":92348,"style":2355},[2354],[1023,92350,92352,92355],{"className":92351},[1070],[1023,92353],{"className":92354,"style":10020},[1074],[1023,92356,92324],{"className":92357},[1079]," trở đi, bất đẳng thức luôn đúng.",[973,92360,92361,92362,92390],{},"Hai điểm cần nhớ: chỉ xét n đủ lớn, và ",[1023,92363,92365,92378],{"className":92364},[1026],[1023,92366,92368],{"className":92367},[1030],[1032,92369,92370],{"xmlns":1034},[1036,92371,92372,92376],{},[1039,92373,92374],{},[1042,92375,1356],{},[1058,92377,1356],{"encoding":1060},[1023,92379,92381],{"className":92380,"ariaHidden":1066},[1065],[1023,92382,92384,92387],{"className":92383},[1070],[1023,92385],{"className":92386,"style":2347},[1074],[1023,92388,1356],{"className":92389},[1079,1080]," không phụ thuộc n. Giống như chỉ so tốc độ xe trên đường dài, không so lúc mới đề pa.",[968,92392,92394],{"id":92393},"_4-chặn-khít-và-chặn-lỏng","4. Chặn khít và chặn lỏng",[973,92396,92397],{},"Một hàm thuộc vô số lớp Big-O. Nhưng không phải lớp nào cũng hữu ích.",[973,92399,92400,92401,92452,92453,1656,92504,92596,92597,92640,92641,92714,92715,1517],{},"Ví dụ hàm ",[1023,92402,92404,92422],{"className":92403},[1026],[1023,92405,92407],{"className":92406},[1030],[1032,92408,92409],{"xmlns":1034},[1036,92410,92411,92419],{},[1039,92412,92413,92415,92417],{},[1042,92414,1262],{},[1046,92416,21881],{},[1051,92418,25255],{},[1058,92420,92421],{"encoding":1060},"n + 4",[1023,92423,92425,92443],{"className":92424,"ariaHidden":1066},[1065],[1023,92426,92428,92431,92434,92437,92440],{"className":92427},[1070],[1023,92429],{"className":92430,"style":13783},[1074],[1023,92432,1262],{"className":92433},[1079,1080],[1023,92435],{"className":92436,"style":13790},[2354],[1023,92438,21881],{"className":92439},[13794],[1023,92441],{"className":92442,"style":13790},[2354],[1023,92444,92446,92449],{"className":92445},[1070],[1023,92447],{"className":92448,"style":10020},[1074],[1023,92450,25255],{"className":92451},[1079],": chọn ",[1023,92454,92456,92474],{"className":92455},[1026],[1023,92457,92459],{"className":92458},[1030],[1032,92460,92461],{"xmlns":1034},[1036,92462,92463,92471],{},[1039,92464,92465,92467,92469],{},[1042,92466,1356],{},[1046,92468,2325],{},[1051,92470,2457],{},[1058,92472,92473],{"encoding":1060},"c = 2",[1023,92475,92477,92495],{"className":92476,"ariaHidden":1066},[1065],[1023,92478,92480,92483,92486,92489,92492],{"className":92479},[1070],[1023,92481],{"className":92482,"style":2347},[1074],[1023,92484,1356],{"className":92485},[1079,1080],[1023,92487],{"className":92488,"style":2355},[2354],[1023,92490,2325],{"className":92491},[2359],[1023,92493],{"className":92494,"style":2355},[2354],[1023,92496,92498,92501],{"className":92497},[1070],[1023,92499],{"className":92500,"style":10020},[1074],[1023,92502,2457],{"className":92503},[1079],[1023,92505,92507,92529],{"className":92506},[1026],[1023,92508,92510],{"className":92509},[1030],[1032,92511,92512],{"xmlns":1034},[1036,92513,92514,92526],{},[1039,92515,92516,92522,92524],{},[17690,92517,92518,92520],{},[1042,92519,1262],{},[1051,92521,2379],{},[1046,92523,2325],{},[1051,92525,25255],{},[1058,92527,92528],{"encoding":1060},"n_0 = 4",[1023,92530,92532,92587],{"className":92531,"ariaHidden":1066},[1065],[1023,92533,92535,92538,92578,92581,92584],{"className":92534},[1070],[1023,92536],{"className":92537,"style":54000},[1074],[1023,92539,92541,92544],{"className":92540},[1079],[1023,92542,1262],{"className":92543},[1079,1080],[1023,92545,92547],{"className":92546},[2383],[1023,92548,92550,92570],{"className":92549},[2387,17732],[1023,92551,92553,92567],{"className":92552},[2391],[1023,92554,92556],{"className":92555,"style":54019},[2395],[1023,92557,92558,92561],{"style":17783},[1023,92559],{"className":92560,"style":2403},[2402],[1023,92562,92564],{"className":92563},[2407,2408,2409,2410],[1023,92565,2379],{"className":92566},[1079,2410],[1023,92568,17797],{"className":92569},[17796],[1023,92571,92573],{"className":92572},[2391],[1023,92574,92576],{"className":92575,"style":17804},[2395],[1023,92577],{},[1023,92579],{"className":92580,"style":2355},[2354],[1023,92582,2325],{"className":92583},[2359],[1023,92585],{"className":92586,"style":2355},[2354],[1023,92588,92590,92593],{"className":92589},[1070],[1023,92591],{"className":92592,"style":10020},[1074],[1023,92594,25255],{"className":92595},[1079]," thì nó thuộc ",[1023,92598,92600,92619],{"className":92599},[1026],[1023,92601,92603],{"className":92602},[1030],[1032,92604,92605],{"xmlns":1034},[1036,92606,92607,92617],{},[1039,92608,92609,92611,92613,92615],{},[1042,92610,1044],{},[1046,92612,1049],{"stretchy":1048},[1042,92614,1262],{},[1046,92616,1056],{"stretchy":1048},[1058,92618,1267],{"encoding":1060},[1023,92620,92622],{"className":92621,"ariaHidden":1066},[1065],[1023,92623,92625,92628,92631,92634,92637],{"className":92624},[1070],[1023,92626],{"className":92627,"style":1075},[1074],[1023,92629,1044],{"className":92630,"style":1081},[1079,1080],[1023,92632,1049],{"className":92633},[1085],[1023,92635,1262],{"className":92636},[1079,1080],[1023,92638,1056],{"className":92639},[1092],". Về mặt toán học, nó cũng thuộc ",[1023,92642,92644,92667],{"className":92643},[1026],[1023,92645,92647],{"className":92646},[1030],[1032,92648,92649],{"xmlns":1034},[1036,92650,92651,92665],{},[1039,92652,92653,92655,92657,92663],{},[1042,92654,1044],{},[1046,92656,1049],{"stretchy":1048},[2327,92658,92659,92661],{},[1042,92660,1262],{},[1051,92662,2457],{},[1046,92664,1056],{"stretchy":1048},[1058,92666,2839],{"encoding":1060},[1023,92668,92670],{"className":92669,"ariaHidden":1066},[1065],[1023,92671,92673,92676,92679,92682,92711],{"className":92672},[1070],[1023,92674],{"className":92675,"style":2476},[1074],[1023,92677,1044],{"className":92678,"style":1081},[1079,1080],[1023,92680,1049],{"className":92681},[1085],[1023,92683,92685,92688],{"className":92684},[1079],[1023,92686,1262],{"className":92687},[1079,1080],[1023,92689,92691],{"className":92690},[2383],[1023,92692,92694],{"className":92693},[2387],[1023,92695,92697],{"className":92696},[2391],[1023,92698,92700],{"className":92699,"style":2369},[2395],[1023,92701,92702,92705],{"style":2398},[1023,92703],{"className":92704,"style":2403},[2402],[1023,92706,92708],{"className":92707},[2407,2408,2409,2410],[1023,92709,2457],{"className":92710},[1079,2410],[1023,92712,1056],{"className":92713},[1092],", thậm chí ",[1023,92716,92718,92742],{"className":92717},[1026],[1023,92719,92721],{"className":92720},[1030],[1032,92722,92723],{"xmlns":1034},[1036,92724,92725,92739],{},[1039,92726,92727,92729,92731,92737],{},[1042,92728,1044],{},[1046,92730,1049],{"stretchy":1048},[2327,92732,92733,92735],{},[1042,92734,1262],{},[1051,92736,9989],{},[1046,92738,1056],{"stretchy":1048},[1058,92740,92741],{"encoding":1060},"O(n^{1000})",[1023,92743,92745],{"className":92744,"ariaHidden":1066},[1065],[1023,92746,92748,92751,92754,92757,92789],{"className":92747},[1070],[1023,92749],{"className":92750,"style":2476},[1074],[1023,92752,1044],{"className":92753,"style":1081},[1079,1080],[1023,92755,1049],{"className":92756},[1085],[1023,92758,92760,92763],{"className":92759},[1079],[1023,92761,1262],{"className":92762},[1079,1080],[1023,92764,92766],{"className":92765},[2383],[1023,92767,92769],{"className":92768},[2387],[1023,92770,92772],{"className":92771},[2391],[1023,92773,92775],{"className":92774,"style":2369},[2395],[1023,92776,92777,92780],{"style":2398},[1023,92778],{"className":92779,"style":2403},[2402],[1023,92781,92783],{"className":92782},[2407,2408,2409,2410],[1023,92784,92786],{"className":92785},[1079,2410],[1023,92787,9989],{"className":92788},[1079,2410],[1023,92790,1056],{"className":92791},[1092],[973,92793,92794],{},"Các phát biểu sau vẫn đúng nhưng vô dụng. Giống như nói đi chợ tốn ít hơn ngân sách cả nước.",[973,92796,92797],{},"Thực hành tốt là tìm chặn khít. Đó là lớp nhỏ nhất vẫn chặn được chi phí thật.",[973,92799,92800],{},"Ba ký hiệu đi cùng nhau:",[1099,92802,92803,92814],{},[1102,92804,92805],{},[1105,92806,92807,92810,92812],{},[1108,92808,92809],{},"Ký hiệu",[1108,92811,88700],{},[1108,92813,46198],{},[1118,92815,92816,93064,93312],{},[1105,92817,92818,92864,92867],{},[1123,92819,92820],{},[1023,92821,92823,92843],{"className":92822},[1026],[1023,92824,92826],{"className":92825},[1030],[1032,92827,92828],{"xmlns":1034},[1036,92829,92830,92840],{},[1039,92831,92832,92834,92836,92838],{},[1042,92833,1044],{},[1046,92835,1049],{"stretchy":1048},[1042,92837,7690],{},[1046,92839,1056],{"stretchy":1048},[1058,92841,92842],{"encoding":1060},"O(g)",[1023,92844,92846],{"className":92845,"ariaHidden":1066},[1065],[1023,92847,92849,92852,92855,92858,92861],{"className":92848},[1070],[1023,92850],{"className":92851,"style":1075},[1074],[1023,92853,1044],{"className":92854,"style":1081},[1079,1080],[1023,92856,1049],{"className":92857},[1085],[1023,92859,7690],{"className":92860,"style":7723},[1079,1080],[1023,92862,1056],{"className":92863},[1092],[1123,92865,92866],{},"Chặn trên",[1123,92868,92869,92972,92973],{},[1023,92870,92872,92906],{"className":92871},[1026],[1023,92873,92875],{"className":92874},[1030],[1032,92876,92877],{"xmlns":1034},[1036,92878,92879,92903],{},[1039,92880,92881,92883,92885,92887,92889,92891,92893,92895,92897,92899,92901],{},[1042,92882,59487],{},[1046,92884,1049],{"stretchy":1048},[1042,92886,1262],{},[1046,92888,1056],{"stretchy":1048},[1046,92890,21123],{},[1042,92892,1356],{},[1046,92894,18118],{},[1042,92896,7690],{},[1046,92898,1049],{"stretchy":1048},[1042,92900,1262],{},[1046,92902,1056],{"stretchy":1048},[1058,92904,92905],{"encoding":1060},"f(n) \\le c \\cdot g(n)",[1023,92907,92909,92936,92954],{"className":92908,"ariaHidden":1066},[1065],[1023,92910,92912,92915,92918,92921,92924,92927,92930,92933],{"className":92911},[1070],[1023,92913],{"className":92914,"style":1075},[1074],[1023,92916,59487],{"className":92917,"style":59523},[1079,1080],[1023,92919,1049],{"className":92920},[1085],[1023,92922,1262],{"className":92923},[1079,1080],[1023,92925,1056],{"className":92926},[1092],[1023,92928],{"className":92929,"style":2355},[2354],[1023,92931,21123],{"className":92932},[2359],[1023,92934],{"className":92935,"style":2355},[2354],[1023,92937,92939,92942,92945,92948,92951],{"className":92938},[1070],[1023,92940],{"className":92941,"style":81759},[1074],[1023,92943,1356],{"className":92944},[1079,1080],[1023,92946],{"className":92947,"style":13790},[2354],[1023,92949,18118],{"className":92950},[13794],[1023,92952],{"className":92953,"style":13790},[2354],[1023,92955,92957,92960,92963,92966,92969],{"className":92956},[1070],[1023,92958],{"className":92959,"style":1075},[1074],[1023,92961,7690],{"className":92962,"style":7723},[1079,1080],[1023,92964,1049],{"className":92965},[1085],[1023,92967,1262],{"className":92968},[1079,1080],[1023,92970,1056],{"className":92971},[1092]," với mọi ",[1023,92974,92976,92997],{"className":92975},[1026],[1023,92977,92979],{"className":92978},[1030],[1032,92980,92981],{"xmlns":1034},[1036,92982,92983,92995],{},[1039,92984,92985,92987,92989],{},[1042,92986,1262],{},[1046,92988,59050],{},[17690,92990,92991,92993],{},[1042,92992,1262],{},[1051,92994,2379],{},[1058,92996,91716],{"encoding":1060},[1023,92998,93000,93018],{"className":92999,"ariaHidden":1066},[1065],[1023,93001,93003,93006,93009,93012,93015],{"className":93002},[1070],[1023,93004],{"className":93005,"style":91726},[1074],[1023,93007,1262],{"className":93008},[1079,1080],[1023,93010],{"className":93011,"style":2355},[2354],[1023,93013,59050],{"className":93014},[2359],[1023,93016],{"className":93017,"style":2355},[2354],[1023,93019,93021,93024],{"className":93020},[1070],[1023,93022],{"className":93023,"style":54000},[1074],[1023,93025,93027,93030],{"className":93026},[1079],[1023,93028,1262],{"className":93029},[1079,1080],[1023,93031,93033],{"className":93032},[2383],[1023,93034,93036,93056],{"className":93035},[2387,17732],[1023,93037,93039,93053],{"className":93038},[2391],[1023,93040,93042],{"className":93041,"style":54019},[2395],[1023,93043,93044,93047],{"style":17783},[1023,93045],{"className":93046,"style":2403},[2402],[1023,93048,93050],{"className":93049},[2407,2408,2409,2410],[1023,93051,2379],{"className":93052},[1079,2410],[1023,93054,17797],{"className":93055},[17796],[1023,93057,93059],{"className":93058},[2391],[1023,93060,93062],{"className":93061,"style":17804},[2395],[1023,93063],{},[1105,93065,93066,93113,93116],{},[1123,93067,93068],{},[1023,93069,93071,93092],{"className":93070},[1026],[1023,93072,93074],{"className":93073},[1030],[1032,93075,93076],{"xmlns":1034},[1036,93077,93078,93089],{},[1039,93079,93080,93083,93085,93087],{},[1042,93081,93082],{"mathvariant":2460},"Ω",[1046,93084,1049],{"stretchy":1048},[1042,93086,7690],{},[1046,93088,1056],{"stretchy":1048},[1058,93090,93091],{"encoding":1060},"\\Omega(g)",[1023,93093,93095],{"className":93094,"ariaHidden":1066},[1065],[1023,93096,93098,93101,93104,93107,93110],{"className":93097},[1070],[1023,93099],{"className":93100,"style":1075},[1074],[1023,93102,93082],{"className":93103},[1079],[1023,93105,1049],{"className":93106},[1085],[1023,93108,7690],{"className":93109,"style":7723},[1079,1080],[1023,93111,1056],{"className":93112},[1092],[1123,93114,93115],{},"Chặn dưới",[1123,93117,93118,92972,93221],{},[1023,93119,93121,93155],{"className":93120},[1026],[1023,93122,93124],{"className":93123},[1030],[1032,93125,93126],{"xmlns":1034},[1036,93127,93128,93152],{},[1039,93129,93130,93132,93134,93136,93138,93140,93142,93144,93146,93148,93150],{},[1042,93131,59487],{},[1046,93133,1049],{"stretchy":1048},[1042,93135,1262],{},[1046,93137,1056],{"stretchy":1048},[1046,93139,43557],{},[1042,93141,1356],{},[1046,93143,18118],{},[1042,93145,7690],{},[1046,93147,1049],{"stretchy":1048},[1042,93149,1262],{},[1046,93151,1056],{"stretchy":1048},[1058,93153,93154],{"encoding":1060},"f(n) \\ge c \\cdot g(n)",[1023,93156,93158,93185,93203],{"className":93157,"ariaHidden":1066},[1065],[1023,93159,93161,93164,93167,93170,93173,93176,93179,93182],{"className":93160},[1070],[1023,93162],{"className":93163,"style":1075},[1074],[1023,93165,59487],{"className":93166,"style":59523},[1079,1080],[1023,93168,1049],{"className":93169},[1085],[1023,93171,1262],{"className":93172},[1079,1080],[1023,93174,1056],{"className":93175},[1092],[1023,93177],{"className":93178,"style":2355},[2354],[1023,93180,43557],{"className":93181},[2359],[1023,93183],{"className":93184,"style":2355},[2354],[1023,93186,93188,93191,93194,93197,93200],{"className":93187},[1070],[1023,93189],{"className":93190,"style":81759},[1074],[1023,93192,1356],{"className":93193},[1079,1080],[1023,93195],{"className":93196,"style":13790},[2354],[1023,93198,18118],{"className":93199},[13794],[1023,93201],{"className":93202,"style":13790},[2354],[1023,93204,93206,93209,93212,93215,93218],{"className":93205},[1070],[1023,93207],{"className":93208,"style":1075},[1074],[1023,93210,7690],{"className":93211,"style":7723},[1079,1080],[1023,93213,1049],{"className":93214},[1085],[1023,93216,1262],{"className":93217},[1079,1080],[1023,93219,1056],{"className":93220},[1092],[1023,93222,93224,93245],{"className":93223},[1026],[1023,93225,93227],{"className":93226},[1030],[1032,93228,93229],{"xmlns":1034},[1036,93230,93231,93243],{},[1039,93232,93233,93235,93237],{},[1042,93234,1262],{},[1046,93236,59050],{},[17690,93238,93239,93241],{},[1042,93240,1262],{},[1051,93242,2379],{},[1058,93244,91716],{"encoding":1060},[1023,93246,93248,93266],{"className":93247,"ariaHidden":1066},[1065],[1023,93249,93251,93254,93257,93260,93263],{"className":93250},[1070],[1023,93252],{"className":93253,"style":91726},[1074],[1023,93255,1262],{"className":93256},[1079,1080],[1023,93258],{"className":93259,"style":2355},[2354],[1023,93261,59050],{"className":93262},[2359],[1023,93264],{"className":93265,"style":2355},[2354],[1023,93267,93269,93272],{"className":93268},[1070],[1023,93270],{"className":93271,"style":54000},[1074],[1023,93273,93275,93278],{"className":93274},[1079],[1023,93276,1262],{"className":93277},[1079,1080],[1023,93279,93281],{"className":93280},[2383],[1023,93282,93284,93304],{"className":93283},[2387,17732],[1023,93285,93287,93301],{"className":93286},[2391],[1023,93288,93290],{"className":93289,"style":54019},[2395],[1023,93291,93292,93295],{"style":17783},[1023,93293],{"className":93294,"style":2403},[2402],[1023,93296,93298],{"className":93297},[2407,2408,2409,2410],[1023,93299,2379],{"className":93300},[1079,2410],[1023,93302,17797],{"className":93303},[17796],[1023,93305,93307],{"className":93306},[2391],[1023,93308,93310],{"className":93309,"style":17804},[2395],[1023,93311],{},[1105,93313,93314,93361,93364],{},[1123,93315,93316],{},[1023,93317,93319,93340],{"className":93318},[1026],[1023,93320,93322],{"className":93321},[1030],[1032,93323,93324],{"xmlns":1034},[1036,93325,93326,93337],{},[1039,93327,93328,93331,93333,93335],{},[1042,93329,93330],{"mathvariant":2460},"Θ",[1046,93332,1049],{"stretchy":1048},[1042,93334,7690],{},[1046,93336,1056],{"stretchy":1048},[1058,93338,93339],{"encoding":1060},"\\Theta(g)",[1023,93341,93343],{"className":93342,"ariaHidden":1066},[1065],[1023,93344,93346,93349,93352,93355,93358],{"className":93345},[1070],[1023,93347],{"className":93348,"style":1075},[1074],[1023,93350,93330],{"className":93351},[1079],[1023,93353,1049],{"className":93354},[1085],[1023,93356,7690],{"className":93357,"style":7723},[1079,1080],[1023,93359,1056],{"className":93360},[1092],[1123,93362,93363],{},"Chặn khít hai phía",[1123,93365,93366,93367,93410,93411],{},"Vừa ",[1023,93368,93370,93389],{"className":93369},[1026],[1023,93371,93373],{"className":93372},[1030],[1032,93374,93375],{"xmlns":1034},[1036,93376,93377,93387],{},[1039,93378,93379,93381,93383,93385],{},[1042,93380,1044],{},[1046,93382,1049],{"stretchy":1048},[1042,93384,7690],{},[1046,93386,1056],{"stretchy":1048},[1058,93388,92842],{"encoding":1060},[1023,93390,93392],{"className":93391,"ariaHidden":1066},[1065],[1023,93393,93395,93398,93401,93404,93407],{"className":93394},[1070],[1023,93396],{"className":93397,"style":1075},[1074],[1023,93399,1044],{"className":93400,"style":1081},[1079,1080],[1023,93402,1049],{"className":93403},[1085],[1023,93405,7690],{"className":93406,"style":7723},[1079,1080],[1023,93408,1056],{"className":93409},[1092]," vừa ",[1023,93412,93414,93433],{"className":93413},[1026],[1023,93415,93417],{"className":93416},[1030],[1032,93418,93419],{"xmlns":1034},[1036,93420,93421,93431],{},[1039,93422,93423,93425,93427,93429],{},[1042,93424,93082],{"mathvariant":2460},[1046,93426,1049],{"stretchy":1048},[1042,93428,7690],{},[1046,93430,1056],{"stretchy":1048},[1058,93432,93091],{"encoding":1060},[1023,93434,93436],{"className":93435,"ariaHidden":1066},[1065],[1023,93437,93439,93442,93445,93448,93451],{"className":93438},[1070],[1023,93440],{"className":93441,"style":1075},[1074],[1023,93443,93082],{"className":93444},[1079],[1023,93446,1049],{"className":93447},[1085],[1023,93449,7690],{"className":93450,"style":7723},[1079,1080],[1023,93452,1056],{"className":93453},[1092],[973,93455,91181,93456,90962,93512,93556,93557,93630,93631,1517],{},[1023,93457,93459,93479],{"className":93458},[1026],[1023,93460,93462],{"className":93461},[1030],[1032,93463,93464],{"xmlns":1034},[1036,93465,93466,93476],{},[1039,93467,93468,93470,93472,93474],{},[1051,93469,13826],{},[1042,93471,1262],{},[1046,93473,21881],{},[1051,93475,91917],{},[1058,93477,93478],{"encoding":1060},"3n + 40",[1023,93480,93482,93503],{"className":93481,"ariaHidden":1066},[1065],[1023,93483,93485,93488,93491,93494,93497,93500],{"className":93484},[1070],[1023,93486],{"className":93487,"style":18148},[1074],[1023,93489,13826],{"className":93490},[1079],[1023,93492,1262],{"className":93493},[1079,1080],[1023,93495],{"className":93496,"style":13790},[2354],[1023,93498,21881],{"className":93499},[13794],[1023,93501],{"className":93502,"style":13790},[2354],[1023,93504,93506,93509],{"className":93505},[1070],[1023,93507],{"className":93508,"style":10020},[1074],[1023,93510,91917],{"className":93511},[1079],[1023,93513,93515,93535],{"className":93514},[1026],[1023,93516,93518],{"className":93517},[1030],[1032,93519,93520],{"xmlns":1034},[1036,93521,93522,93532],{},[1039,93523,93524,93526,93528,93530],{},[1042,93525,93330],{"mathvariant":2460},[1046,93527,1049],{"stretchy":1048},[1042,93529,1262],{},[1046,93531,1056],{"stretchy":1048},[1058,93533,93534],{"encoding":1060},"\\Theta(n)",[1023,93536,93538],{"className":93537,"ariaHidden":1066},[1065],[1023,93539,93541,93544,93547,93550,93553],{"className":93540},[1070],[1023,93542],{"className":93543,"style":1075},[1074],[1023,93545,93330],{"className":93546},[1079],[1023,93548,1049],{"className":93549},[1085],[1023,93551,1262],{"className":93552},[1079,1080],[1023,93554,1056],{"className":93555},[1092],". Nó thuộc ",[1023,93558,93560,93583],{"className":93559},[1026],[1023,93561,93563],{"className":93562},[1030],[1032,93564,93565],{"xmlns":1034},[1036,93566,93567,93581],{},[1039,93568,93569,93571,93573,93579],{},[1042,93570,1044],{},[1046,93572,1049],{"stretchy":1048},[2327,93574,93575,93577],{},[1042,93576,1262],{},[1051,93578,2457],{},[1046,93580,1056],{"stretchy":1048},[1058,93582,2839],{"encoding":1060},[1023,93584,93586],{"className":93585,"ariaHidden":1066},[1065],[1023,93587,93589,93592,93595,93598,93627],{"className":93588},[1070],[1023,93590],{"className":93591,"style":2476},[1074],[1023,93593,1044],{"className":93594,"style":1081},[1079,1080],[1023,93596,1049],{"className":93597},[1085],[1023,93599,93601,93604],{"className":93600},[1079],[1023,93602,1262],{"className":93603},[1079,1080],[1023,93605,93607],{"className":93606},[2383],[1023,93608,93610],{"className":93609},[2387],[1023,93611,93613],{"className":93612},[2391],[1023,93614,93616],{"className":93615,"style":2369},[2395],[1023,93617,93618,93621],{"style":2398},[1023,93619],{"className":93620,"style":2403},[2402],[1023,93622,93624],{"className":93623},[2407,2408,2409,2410],[1023,93625,2457],{"className":93626},[1079,2410],[1023,93628,1056],{"className":93629},[1092]," nhưng không thuộc ",[1023,93632,93634,93658],{"className":93633},[1026],[1023,93635,93637],{"className":93636},[1030],[1032,93638,93639],{"xmlns":1034},[1036,93640,93641,93655],{},[1039,93642,93643,93645,93647,93653],{},[1042,93644,93330],{"mathvariant":2460},[1046,93646,1049],{"stretchy":1048},[2327,93648,93649,93651],{},[1042,93650,1262],{},[1051,93652,2457],{},[1046,93654,1056],{"stretchy":1048},[1058,93656,93657],{"encoding":1060},"\\Theta(n^2)",[1023,93659,93661],{"className":93660,"ariaHidden":1066},[1065],[1023,93662,93664,93667,93670,93673,93702],{"className":93663},[1070],[1023,93665],{"className":93666,"style":2476},[1074],[1023,93668,93330],{"className":93669},[1079],[1023,93671,1049],{"className":93672},[1085],[1023,93674,93676,93679],{"className":93675},[1079],[1023,93677,1262],{"className":93678},[1079,1080],[1023,93680,93682],{"className":93681},[2383],[1023,93683,93685],{"className":93684},[2387],[1023,93686,93688],{"className":93687},[2391],[1023,93689,93691],{"className":93690,"style":2369},[2395],[1023,93692,93693,93696],{"style":2398},[1023,93694],{"className":93695,"style":2403},[2402],[1023,93697,93699],{"className":93698},[2407,2408,2409,2410],[1023,93700,2457],{"className":93701},[1079,2410],[1023,93703,1056],{"className":93704},[1092],[973,93706,93707,93708,1517],{},"Trong tài liệu và phỏng vấn, người ta hay viết Big-O nhưng ý muốn nói chặn khít. Khi cần chính xác, hãy dùng ",[1023,93709,93711,93725],{"className":93710},[1026],[1023,93712,93714],{"className":93713},[1030],[1032,93715,93716],{"xmlns":1034},[1036,93717,93718,93722],{},[1039,93719,93720],{},[1042,93721,93330],{"mathvariant":2460},[1058,93723,93724],{"encoding":1060},"\\Theta",[1023,93726,93728],{"className":93727,"ariaHidden":1066},[1065],[1023,93729,93731,93734],{"className":93730},[1070],[1023,93732],{"className":93733,"style":27414},[1074],[1023,93735,93330],{"className":93736},[1079],[968,93738,93740],{"id":93739},"_5-các-quy-tắc-rút-gọn-khi-làm-việc-với-big-o","5. Các quy tắc rút gọn khi làm việc với Big-O",[973,93742,93743],{},"Có năm quy tắc, cùng một tinh thần.",[1099,93745,93746,93756],{},[1102,93747,93748],{},[1105,93749,93750,93752,93754],{},[1108,93751,5427],{},[1108,93753,87021],{},[1108,93755,89384],{},[1118,93757,93758,93811,94110,94298,94309],{},[1105,93759,93760,93763,93766],{},[1123,93761,93762],{},"Vòng lặp đơn",[1123,93764,93765],{},"Lặp n lần",[1123,93767,93768],{},[1023,93769,93771,93790],{"className":93770},[1026],[1023,93772,93774],{"className":93773},[1030],[1032,93775,93776],{"xmlns":1034},[1036,93777,93778,93788],{},[1039,93779,93780,93782,93784,93786],{},[1042,93781,1044],{},[1046,93783,1049],{"stretchy":1048},[1042,93785,1262],{},[1046,93787,1056],{"stretchy":1048},[1058,93789,1267],{"encoding":1060},[1023,93791,93793],{"className":93792,"ariaHidden":1066},[1065],[1023,93794,93796,93799,93802,93805,93808],{"className":93795},[1070],[1023,93797],{"className":93798,"style":1075},[1074],[1023,93800,1044],{"className":93801,"style":1081},[1079,1080],[1023,93803,1049],{"className":93804},[1085],[1023,93806,1262],{"className":93807},[1079,1080],[1023,93809,1056],{"className":93810},[1092],[1105,93812,93813,93816,93960],{},[1123,93814,93815],{},"Vòng lặp lồng",[1123,93817,93818,93819,93889,93890],{},"Ngoài ",[1023,93820,93822,93840],{"className":93821},[1026],[1023,93823,93825],{"className":93824},[1030],[1032,93826,93827],{"xmlns":1034},[1036,93828,93829,93837],{},[1039,93830,93831],{},[17690,93832,93833,93835],{},[1042,93834,1262],{},[1051,93836,1053],{},[1058,93838,93839],{"encoding":1060},"n_1",[1023,93841,93843],{"className":93842,"ariaHidden":1066},[1065],[1023,93844,93846,93849],{"className":93845},[1070],[1023,93847],{"className":93848,"style":54000},[1074],[1023,93850,93852,93855],{"className":93851},[1079],[1023,93853,1262],{"className":93854},[1079,1080],[1023,93856,93858],{"className":93857},[2383],[1023,93859,93861,93881],{"className":93860},[2387,17732],[1023,93862,93864,93878],{"className":93863},[2391],[1023,93865,93867],{"className":93866,"style":54019},[2395],[1023,93868,93869,93872],{"style":17783},[1023,93870],{"className":93871,"style":2403},[2402],[1023,93873,93875],{"className":93874},[2407,2408,2409,2410],[1023,93876,1053],{"className":93877},[1079,2410],[1023,93879,17797],{"className":93880},[17796],[1023,93882,93884],{"className":93883},[2391],[1023,93885,93887],{"className":93886,"style":17804},[2395],[1023,93888],{},", trong ",[1023,93891,93893,93911],{"className":93892},[1026],[1023,93894,93896],{"className":93895},[1030],[1032,93897,93898],{"xmlns":1034},[1036,93899,93900,93908],{},[1039,93901,93902],{},[17690,93903,93904,93906],{},[1042,93905,1262],{},[1051,93907,2457],{},[1058,93909,93910],{"encoding":1060},"n_2",[1023,93912,93914],{"className":93913,"ariaHidden":1066},[1065],[1023,93915,93917,93920],{"className":93916},[1070],[1023,93918],{"className":93919,"style":54000},[1074],[1023,93921,93923,93926],{"className":93922},[1079],[1023,93924,1262],{"className":93925},[1079,1080],[1023,93927,93929],{"className":93928},[2383],[1023,93930,93932,93952],{"className":93931},[2387,17732],[1023,93933,93935,93949],{"className":93934},[2391],[1023,93936,93938],{"className":93937,"style":54019},[2395],[1023,93939,93940,93943],{"style":17783},[1023,93941],{"className":93942,"style":2403},[2402],[1023,93944,93946],{"className":93945},[2407,2408,2409,2410],[1023,93947,2457],{"className":93948},[1079,2410],[1023,93950,17797],{"className":93951},[17796],[1023,93953,93955],{"className":93954},[2391],[1023,93956,93958],{"className":93957,"style":17804},[2395],[1023,93959],{},[1123,93961,93962],{},[1023,93963,93965,93997],{"className":93964},[1026],[1023,93966,93968],{"className":93967},[1030],[1032,93969,93970],{"xmlns":1034},[1036,93971,93972,93994],{},[1039,93973,93974,93976,93978,93984,93986,93992],{},[1042,93975,1044],{},[1046,93977,1049],{"stretchy":1048},[17690,93979,93980,93982],{},[1042,93981,1262],{},[1051,93983,1053],{},[1046,93985,13768],{},[17690,93987,93988,93990],{},[1042,93989,1262],{},[1051,93991,2457],{},[1046,93993,1056],{"stretchy":1048},[1058,93995,93996],{"encoding":1060},"O(n_1 \\times n_2)",[1023,93998,94000,94061],{"className":93999,"ariaHidden":1066},[1065],[1023,94001,94003,94006,94009,94012,94052,94055,94058],{"className":94002},[1070],[1023,94004],{"className":94005,"style":1075},[1074],[1023,94007,1044],{"className":94008,"style":1081},[1079,1080],[1023,94010,1049],{"className":94011},[1085],[1023,94013,94015,94018],{"className":94014},[1079],[1023,94016,1262],{"className":94017},[1079,1080],[1023,94019,94021],{"className":94020},[2383],[1023,94022,94024,94044],{"className":94023},[2387,17732],[1023,94025,94027,94041],{"className":94026},[2391],[1023,94028,94030],{"className":94029,"style":54019},[2395],[1023,94031,94032,94035],{"style":17783},[1023,94033],{"className":94034,"style":2403},[2402],[1023,94036,94038],{"className":94037},[2407,2408,2409,2410],[1023,94039,1053],{"className":94040},[1079,2410],[1023,94042,17797],{"className":94043},[17796],[1023,94045,94047],{"className":94046},[2391],[1023,94048,94050],{"className":94049,"style":17804},[2395],[1023,94051],{},[1023,94053],{"className":94054,"style":13790},[2354],[1023,94056,13768],{"className":94057},[13794],[1023,94059],{"className":94060,"style":13790},[2354],[1023,94062,94064,94067,94107],{"className":94063},[1070],[1023,94065],{"className":94066,"style":1075},[1074],[1023,94068,94070,94073],{"className":94069},[1079],[1023,94071,1262],{"className":94072},[1079,1080],[1023,94074,94076],{"className":94075},[2383],[1023,94077,94079,94099],{"className":94078},[2387,17732],[1023,94080,94082,94096],{"className":94081},[2391],[1023,94083,94085],{"className":94084,"style":54019},[2395],[1023,94086,94087,94090],{"style":17783},[1023,94088],{"className":94089,"style":2403},[2402],[1023,94091,94093],{"className":94092},[2407,2408,2409,2410],[1023,94094,2457],{"className":94095},[1079,2410],[1023,94097,17797],{"className":94098},[17796],[1023,94100,94102],{"className":94101},[2391],[1023,94103,94105],{"className":94104,"style":17804},[2395],[1023,94106],{},[1023,94108,1056],{"className":94109},[1092],[1105,94111,94112,94114,94203],{},[1123,94113,53001],{},[1123,94115,94116,94117,20868,94160],{},"Chạy pha ",[1023,94118,94120,94139],{"className":94119},[1026],[1023,94121,94123],{"className":94122},[1030],[1032,94124,94125],{"xmlns":1034},[1036,94126,94127,94137],{},[1039,94128,94129,94131,94133,94135],{},[1042,94130,59487],{},[1046,94132,1049],{"stretchy":1048},[1042,94134,1262],{},[1046,94136,1056],{"stretchy":1048},[1058,94138,90940],{"encoding":1060},[1023,94140,94142],{"className":94141,"ariaHidden":1066},[1065],[1023,94143,94145,94148,94151,94154,94157],{"className":94144},[1070],[1023,94146],{"className":94147,"style":1075},[1074],[1023,94149,59487],{"className":94150,"style":59523},[1079,1080],[1023,94152,1049],{"className":94153},[1085],[1023,94155,1262],{"className":94156},[1079,1080],[1023,94158,1056],{"className":94159},[1092],[1023,94161,94163,94182],{"className":94162},[1026],[1023,94164,94166],{"className":94165},[1030],[1032,94167,94168],{"xmlns":1034},[1036,94169,94170,94180],{},[1039,94171,94172,94174,94176,94178],{},[1042,94173,7690],{},[1046,94175,1049],{"stretchy":1048},[1042,94177,1262],{},[1046,94179,1056],{"stretchy":1048},[1058,94181,91156],{"encoding":1060},[1023,94183,94185],{"className":94184,"ariaHidden":1066},[1065],[1023,94186,94188,94191,94194,94197,94200],{"className":94187},[1070],[1023,94189],{"className":94190,"style":1075},[1074],[1023,94192,7690],{"className":94193,"style":7723},[1079,1080],[1023,94195,1049],{"className":94196},[1085],[1023,94198,1262],{"className":94199},[1079,1080],[1023,94201,1056],{"className":94202},[1092],[1123,94204,94205],{},[1023,94206,94208,94244],{"className":94207},[1026],[1023,94209,94211],{"className":94210},[1030],[1032,94212,94213],{"xmlns":1034},[1036,94214,94215,94241],{},[1039,94216,94217,94219,94221,94223,94225,94227,94229,94231,94233,94235,94237,94239],{},[1042,94218,1044],{},[1046,94220,1049],{"stretchy":1048},[1042,94222,59487],{},[1046,94224,1049],{"stretchy":1048},[1042,94226,1262],{},[1046,94228,1056],{"stretchy":1048},[1046,94230,21881],{},[1042,94232,7690],{},[1046,94234,1049],{"stretchy":1048},[1042,94236,1262],{},[1046,94238,1056],{"stretchy":1048},[1046,94240,1056],{"stretchy":1048},[1058,94242,94243],{"encoding":1060},"O(f(n) + g(n))",[1023,94245,94247,94280],{"className":94246,"ariaHidden":1066},[1065],[1023,94248,94250,94253,94256,94259,94262,94265,94268,94271,94274,94277],{"className":94249},[1070],[1023,94251],{"className":94252,"style":1075},[1074],[1023,94254,1044],{"className":94255,"style":1081},[1079,1080],[1023,94257,1049],{"className":94258},[1085],[1023,94260,59487],{"className":94261,"style":59523},[1079,1080],[1023,94263,1049],{"className":94264},[1085],[1023,94266,1262],{"className":94267},[1079,1080],[1023,94269,1056],{"className":94270},[1092],[1023,94272],{"className":94273,"style":13790},[2354],[1023,94275,21881],{"className":94276},[13794],[1023,94278],{"className":94279,"style":13790},[2354],[1023,94281,94283,94286,94289,94292,94295],{"className":94282},[1070],[1023,94284],{"className":94285,"style":1075},[1074],[1023,94287,7690],{"className":94288,"style":7723},[1079,1080],[1023,94290,1049],{"className":94291},[1085],[1023,94293,1262],{"className":94294},[1079,1080],[1023,94296,47920],{"className":94297},[1092],[1105,94299,94300,94303,94306],{},[1123,94301,94302],{},"Số hạng trội",[1123,94304,94305],{},"Cộng hai biểu thức",[1123,94307,94308],{},"Giữ số hạng lớn hơn",[1105,94310,94311,94314,94345],{},[1123,94312,94313],{},"Bỏ hằng số",[1123,94315,94316,94317],{},"Nhân với hằng số ",[1023,94318,94320,94333],{"className":94319},[1026],[1023,94321,94323],{"className":94322},[1030],[1032,94324,94325],{"xmlns":1034},[1036,94326,94327,94331],{},[1039,94328,94329],{},[1042,94330,4022],{},[1058,94332,4022],{"encoding":1060},[1023,94334,94336],{"className":94335,"ariaHidden":1066},[1065],[1023,94337,94339,94342],{"className":94338},[1070],[1023,94340],{"className":94341,"style":22079},[1074],[1023,94343,4022],{"className":94344,"style":4066},[1079,1080],[1123,94346,94347,94348,94376],{},"Bỏ ",[1023,94349,94351,94364],{"className":94350},[1026],[1023,94352,94354],{"className":94353},[1030],[1032,94355,94356],{"xmlns":1034},[1036,94357,94358,94362],{},[1039,94359,94360],{},[1042,94361,4022],{},[1058,94363,4022],{"encoding":1060},[1023,94365,94367],{"className":94366,"ariaHidden":1066},[1065],[1023,94368,94370,94373],{"className":94369},[1070],[1023,94371],{"className":94372,"style":22079},[1074],[1023,94374,4022],{"className":94375,"style":4066},[1079,1080]," đi",[973,94378,91181,94379,35512,94445,94488,94489,94567,94568,1517],{},[1023,94380,94382,94406],{"className":94381},[1026],[1023,94383,94385],{"className":94384},[1030],[1032,94386,94387],{"xmlns":1034},[1036,94388,94389,94403],{},[1039,94390,94391,94393,94395,94397,94399,94401],{},[1042,94392,1044],{},[1046,94394,1049],{"stretchy":1048},[1051,94396,1053],{},[1046,94398,21881],{},[1042,94400,1262],{},[1046,94402,1056],{"stretchy":1048},[1058,94404,94405],{"encoding":1060},"O(1 + n)",[1023,94407,94409,94433],{"className":94408,"ariaHidden":1066},[1065],[1023,94410,94412,94415,94418,94421,94424,94427,94430],{"className":94411},[1070],[1023,94413],{"className":94414,"style":1075},[1074],[1023,94416,1044],{"className":94417,"style":1081},[1079,1080],[1023,94419,1049],{"className":94420},[1085],[1023,94422,1053],{"className":94423},[1079],[1023,94425],{"className":94426,"style":13790},[2354],[1023,94428,21881],{"className":94429},[13794],[1023,94431],{"className":94432,"style":13790},[2354],[1023,94434,94436,94439,94442],{"className":94435},[1070],[1023,94437],{"className":94438,"style":1075},[1074],[1023,94440,1262],{"className":94441},[1079,1080],[1023,94443,1056],{"className":94444},[1092],[1023,94446,94448,94467],{"className":94447},[1026],[1023,94449,94451],{"className":94450},[1030],[1032,94452,94453],{"xmlns":1034},[1036,94454,94455,94465],{},[1039,94456,94457,94459,94461,94463],{},[1042,94458,1044],{},[1046,94460,1049],{"stretchy":1048},[1042,94462,1262],{},[1046,94464,1056],{"stretchy":1048},[1058,94466,1267],{"encoding":1060},[1023,94468,94470],{"className":94469,"ariaHidden":1066},[1065],[1023,94471,94473,94476,94479,94482,94485],{"className":94472},[1070],[1023,94474],{"className":94475,"style":1075},[1074],[1023,94477,1044],{"className":94478,"style":1081},[1079,1080],[1023,94480,1049],{"className":94481},[1085],[1023,94483,1262],{"className":94484},[1079,1080],[1023,94486,1056],{"className":94487},[1092],". Ví dụ: ",[1023,94490,94492,94522],{"className":94491},[1026],[1023,94493,94495],{"className":94494},[1030],[1032,94496,94497],{"xmlns":1034},[1036,94498,94499,94519],{},[1039,94500,94501,94503,94505,94507,94509,94511,94513,94515,94517],{},[1042,94502,1044],{},[1046,94504,1049],{"stretchy":1048},[1042,94506,4022],{},[1046,94508,13768],{},[1042,94510,59487],{},[1046,94512,1049],{"stretchy":1048},[1042,94514,1262],{},[1046,94516,1056],{"stretchy":1048},[1046,94518,1056],{"stretchy":1048},[1058,94520,94521],{"encoding":1060},"O(k \\times f(n))",[1023,94523,94525,94549],{"className":94524,"ariaHidden":1066},[1065],[1023,94526,94528,94531,94534,94537,94540,94543,94546],{"className":94527},[1070],[1023,94529],{"className":94530,"style":1075},[1074],[1023,94532,1044],{"className":94533,"style":1081},[1079,1080],[1023,94535,1049],{"className":94536},[1085],[1023,94538,4022],{"className":94539,"style":4066},[1079,1080],[1023,94541],{"className":94542,"style":13790},[2354],[1023,94544,13768],{"className":94545},[13794],[1023,94547],{"className":94548,"style":13790},[2354],[1023,94550,94552,94555,94558,94561,94564],{"className":94551},[1070],[1023,94553],{"className":94554,"style":1075},[1074],[1023,94556,59487],{"className":94557,"style":59523},[1079,1080],[1023,94559,1049],{"className":94560},[1085],[1023,94562,1262],{"className":94563},[1079,1080],[1023,94565,47920],{"className":94566},[1092]," chính là ",[1023,94569,94571,94597],{"className":94570},[1026],[1023,94572,94574],{"className":94573},[1030],[1032,94575,94576],{"xmlns":1034},[1036,94577,94578,94594],{},[1039,94579,94580,94582,94584,94586,94588,94590,94592],{},[1042,94581,1044],{},[1046,94583,1049],{"stretchy":1048},[1042,94585,59487],{},[1046,94587,1049],{"stretchy":1048},[1042,94589,1262],{},[1046,94591,1056],{"stretchy":1048},[1046,94593,1056],{"stretchy":1048},[1058,94595,94596],{"encoding":1060},"O(f(n))",[1023,94598,94600],{"className":94599,"ariaHidden":1066},[1065],[1023,94601,94603,94606,94609,94612,94615,94618,94621],{"className":94602},[1070],[1023,94604],{"className":94605,"style":1075},[1074],[1023,94607,1044],{"className":94608,"style":1081},[1079,1080],[1023,94610,1049],{"className":94611},[1085],[1023,94613,59487],{"className":94614,"style":59523},[1079,1080],[1023,94616,1049],{"className":94617},[1085],[1023,94619,1262],{"className":94620},[1079,1080],[1023,94622,47920],{"className":94623},[1092],[973,94625,94626],{},"Một lỗi phổ biến: vẽ đồ thị vài điểm rồi kết luận Big-O. Hai đường cong có thể giao nhau nhiều lần. Vẽ chỉ giúp hình dung, chứng minh vẫn cần đại số.",[968,94628,94630],{"id":94629},"_6-bốn-lớp-tăng-trưởng-nền-tảng","6. Bốn lớp tăng trưởng nền tảng",[973,94632,94633,94634,94677],{},"Lớp hằng số ",[1023,94635,94637,94656],{"className":94636},[1026],[1023,94638,94640],{"className":94639},[1030],[1032,94641,94642],{"xmlns":1034},[1036,94643,94644,94654],{},[1039,94645,94646,94648,94650,94652],{},[1042,94647,1044],{},[1046,94649,1049],{"stretchy":1048},[1051,94651,1053],{},[1046,94653,1056],{"stretchy":1048},[1058,94655,1061],{"encoding":1060},[1023,94657,94659],{"className":94658,"ariaHidden":1066},[1065],[1023,94660,94662,94665,94668,94671,94674],{"className":94661},[1070],[1023,94663],{"className":94664,"style":1075},[1074],[1023,94666,1044],{"className":94667,"style":1081},[1079,1080],[1023,94669,1049],{"className":94670},[1085],[1023,94672,1053],{"className":94673},[1079],[1023,94675,1056],{"className":94676},[1092]," tốn chi phí như nhau với mọi n. Ví dụ: đọc phần tử mảng theo vị trí, đẩy và bật ngăn xếp.",[973,94679,94680],{},"Đường chi phí của nó nằm ngang. Giống như lấy một món trong tủ, tủ to hay nhỏ cũng một tay.",[973,94682,94683,94684,94739],{},"Lớp logarit ",[1023,94685,94687,94710],{"className":94686},[1026],[1023,94688,94690],{"className":94689},[1030],[1032,94691,94692],{"xmlns":1034},[1036,94693,94694,94708],{},[1039,94695,94696,94698,94700,94702,94704,94706],{},[1042,94697,1044],{},[1046,94699,1049],{"stretchy":1048},[1042,94701,8397],{},[1046,94703,8400],{},[1042,94705,1262],{},[1046,94707,1056],{"stretchy":1048},[1058,94709,8407],{"encoding":1060},[1023,94711,94713],{"className":94712,"ariaHidden":1066},[1065],[1023,94714,94716,94719,94722,94725,94730,94733,94736],{"className":94715},[1070],[1023,94717],{"className":94718,"style":1075},[1074],[1023,94720,1044],{"className":94721,"style":1081},[1079,1080],[1023,94723,1049],{"className":94724},[1085],[1023,94726,8427,94728],{"className":94727},[8426],[1023,94729,7690],{"style":8430},[1023,94731],{"className":94732,"style":8434},[2354],[1023,94734,1262],{"className":94735},[1079,1080],[1023,94737,1056],{"className":94738},[1092]," thu hẹp phạm vi mỗi bước. Ví dụ: tìm kiếm nhị phân loại bỏ một nửa mảng sau mỗi lần so sánh.",[973,94741,94742,94743,94786,94787,94870],{},"Giống như tra từ điển: mở giữa, bỏ nửa đầu, rồi lặp lại. Sau ",[1023,94744,94746,94765],{"className":94745},[1026],[1023,94747,94749],{"className":94748},[1030],[1032,94750,94751],{"xmlns":1034},[1036,94752,94753,94763],{},[1039,94754,94755,94757,94759,94761],{},[1042,94756,1044],{},[1046,94758,1049],{"stretchy":1048},[1051,94760,1053],{},[1046,94762,1056],{"stretchy":1048},[1058,94764,1061],{"encoding":1060},[1023,94766,94768],{"className":94767,"ariaHidden":1066},[1065],[1023,94769,94771,94774,94777,94780,94783],{"className":94770},[1070],[1023,94772],{"className":94773,"style":1075},[1074],[1023,94775,1044],{"className":94776,"style":1081},[1079,1080],[1023,94778,1049],{"className":94779},[1085],[1023,94781,1053],{"className":94782},[1079],[1023,94784,1056],{"className":94785},[1092],", đây là lớp tốt nhất: ",[1023,94788,94790,94811],{"className":94789},[1026],[1023,94791,94793],{"className":94792},[1030],[1032,94794,94795],{"xmlns":1034},[1036,94796,94797,94809],{},[1039,94798,94799,94801,94803],{},[1042,94800,1262],{},[1046,94802,2325],{},[2327,94804,94805,94807],{},[1051,94806,2331],{},[1051,94808,6866],{},[1058,94810,11405],{"encoding":1060},[1023,94812,94814,94832],{"className":94813,"ariaHidden":1066},[1065],[1023,94815,94817,94820,94823,94826,94829],{"className":94816},[1070],[1023,94818],{"className":94819,"style":2347},[1074],[1023,94821,1262],{"className":94822},[1079,1080],[1023,94824],{"className":94825,"style":2355},[2354],[1023,94827,2325],{"className":94828},[2359],[1023,94830],{"className":94831,"style":2355},[2354],[1023,94833,94835,94838,94841],{"className":94834},[1070],[1023,94836],{"className":94837,"style":2369},[1074],[1023,94839,1053],{"className":94840},[1079],[1023,94842,94844,94847],{"className":94843},[1079],[1023,94845,2379],{"className":94846},[1079],[1023,94848,94850],{"className":94849},[2383],[1023,94851,94853],{"className":94852},[2387],[1023,94854,94856],{"className":94855},[2391],[1023,94857,94859],{"className":94858,"style":2369},[2395],[1023,94860,94861,94864],{"style":2398},[1023,94862],{"className":94863,"style":2403},[2402],[1023,94865,94867],{"className":94866},[2407,2408,2409,2410],[1023,94868,6866],{"className":94869},[1079,2410]," chỉ cần khoảng 20 bước.",[973,94872,94873,94874,94917],{},"Lớp tuyến tính ",[1023,94875,94877,94896],{"className":94876},[1026],[1023,94878,94880],{"className":94879},[1030],[1032,94881,94882],{"xmlns":1034},[1036,94883,94884,94894],{},[1039,94885,94886,94888,94890,94892],{},[1042,94887,1044],{},[1046,94889,1049],{"stretchy":1048},[1042,94891,1262],{},[1046,94893,1056],{"stretchy":1048},[1058,94895,1267],{"encoding":1060},[1023,94897,94899],{"className":94898,"ariaHidden":1066},[1065],[1023,94900,94902,94905,94908,94911,94914],{"className":94901},[1070],[1023,94903],{"className":94904,"style":1075},[1074],[1023,94906,1044],{"className":94907,"style":1081},[1079,1080],[1023,94909,1049],{"className":94910},[1085],[1023,94912,1262],{"className":94913},[1079,1080],[1023,94915,1056],{"className":94916},[1092]," tăng đều theo đầu vào. Ví dụ: duyệt danh sách để tính tổng hay tìm số nhỏ nhất.",[973,94919,94920,94921,94994],{},"Giống như điểm danh cả lớp: lớp đông gấp đôi thì mất giờ gấp đôi. Lớp bậc hai ",[1023,94922,94924,94947],{"className":94923},[1026],[1023,94925,94927],{"className":94926},[1030],[1032,94928,94929],{"xmlns":1034},[1036,94930,94931,94945],{},[1039,94932,94933,94935,94937,94943],{},[1042,94934,1044],{},[1046,94936,1049],{"stretchy":1048},[2327,94938,94939,94941],{},[1042,94940,1262],{},[1051,94942,2457],{},[1046,94944,1056],{"stretchy":1048},[1058,94946,2839],{"encoding":1060},[1023,94948,94950],{"className":94949,"ariaHidden":1066},[1065],[1023,94951,94953,94956,94959,94962,94991],{"className":94952},[1070],[1023,94954],{"className":94955,"style":2476},[1074],[1023,94957,1044],{"className":94958,"style":1081},[1079,1080],[1023,94960,1049],{"className":94961},[1085],[1023,94963,94965,94968],{"className":94964},[1079],[1023,94966,1262],{"className":94967},[1079,1080],[1023,94969,94971],{"className":94970},[2383],[1023,94972,94974],{"className":94973},[2387],[1023,94975,94977],{"className":94976},[2391],[1023,94978,94980],{"className":94979,"style":2369},[2395],[1023,94981,94982,94985],{"style":2398},[1023,94983],{"className":94984,"style":2403},[2402],[1023,94986,94988],{"className":94987},[2407,2408,2409,2410],[1023,94989,2457],{"className":94990},[1079,2410],[1023,94992,1056],{"className":94993},[1092]," tăng theo bình phương đầu vào.",[973,94996,94997,94998,95071],{},"Ví dụ: hai vòng lặp lồng nhau, liệt kê mọi cặp trong danh sách. Số cặp bằng ",[1023,94999,95001,95029],{"className":95000},[1026],[1023,95002,95004],{"className":95003},[1030],[1032,95005,95006],{"xmlns":1034},[1036,95007,95008,95026],{},[1039,95009,95010,95012,95014,95016,95018,95020,95022,95024],{},[1042,95011,1262],{},[1046,95013,1049],{"stretchy":1048},[1042,95015,1262],{},[1046,95017,17698],{},[1051,95019,1053],{},[1046,95021,1056],{"stretchy":1048},[1042,95023,2461],{"mathvariant":2460},[1051,95025,2457],{},[1058,95027,95028],{"encoding":1060},"n(n-1)\u002F2",[1023,95030,95032,95056],{"className":95031,"ariaHidden":1066},[1065],[1023,95033,95035,95038,95041,95044,95047,95050,95053],{"className":95034},[1070],[1023,95036],{"className":95037,"style":1075},[1074],[1023,95039,1262],{"className":95040},[1079,1080],[1023,95042,1049],{"className":95043},[1085],[1023,95045,1262],{"className":95046},[1079,1080],[1023,95048],{"className":95049,"style":13790},[2354],[1023,95051,17698],{"className":95052},[13794],[1023,95054],{"className":95055,"style":13790},[2354],[1023,95057,95059,95062,95065,95068],{"className":95058},[1070],[1023,95060],{"className":95061,"style":1075},[1074],[1023,95063,1053],{"className":95064},[1079],[1023,95066,1056],{"className":95067},[1092],[1023,95069,2509],{"className":95070},[1079],". Giống như mọi người trong lớp bắt tay nhau từng cặp.",[973,95073,95074,95075,95148,95149,95232,95233,95299],{},"Trong bốn lớp, ",[1023,95076,95078,95101],{"className":95077},[1026],[1023,95079,95081],{"className":95080},[1030],[1032,95082,95083],{"xmlns":1034},[1036,95084,95085,95099],{},[1039,95086,95087,95089,95091,95097],{},[1042,95088,1044],{},[1046,95090,1049],{"stretchy":1048},[2327,95092,95093,95095],{},[1042,95094,1262],{},[1051,95096,2457],{},[1046,95098,1056],{"stretchy":1048},[1058,95100,2839],{"encoding":1060},[1023,95102,95104],{"className":95103,"ariaHidden":1066},[1065],[1023,95105,95107,95110,95113,95116,95145],{"className":95106},[1070],[1023,95108],{"className":95109,"style":2476},[1074],[1023,95111,1044],{"className":95112,"style":1081},[1079,1080],[1023,95114,1049],{"className":95115},[1085],[1023,95117,95119,95122],{"className":95118},[1079],[1023,95120,1262],{"className":95121},[1079,1080],[1023,95123,95125],{"className":95124},[2383],[1023,95126,95128],{"className":95127},[2387],[1023,95129,95131],{"className":95130},[2391],[1023,95132,95134],{"className":95133,"style":2369},[2395],[1023,95135,95136,95139],{"style":2398},[1023,95137],{"className":95138,"style":2403},[2402],[1023,95140,95142],{"className":95141},[2407,2408,2409,2410],[1023,95143,2457],{"className":95144},[1079,2410],[1023,95146,1056],{"className":95147},[1092]," kém nhất. Với ",[1023,95150,95152,95173],{"className":95151},[1026],[1023,95153,95155],{"className":95154},[1030],[1032,95156,95157],{"xmlns":1034},[1036,95158,95159,95171],{},[1039,95160,95161,95163,95165],{},[1042,95162,1262],{},[1046,95164,2325],{},[2327,95166,95167,95169],{},[1051,95168,2331],{},[1051,95170,6866],{},[1058,95172,11405],{"encoding":1060},[1023,95174,95176,95194],{"className":95175,"ariaHidden":1066},[1065],[1023,95177,95179,95182,95185,95188,95191],{"className":95178},[1070],[1023,95180],{"className":95181,"style":2347},[1074],[1023,95183,1262],{"className":95184},[1079,1080],[1023,95186],{"className":95187,"style":2355},[2354],[1023,95189,2325],{"className":95190},[2359],[1023,95192],{"className":95193,"style":2355},[2354],[1023,95195,95197,95200,95203],{"className":95196},[1070],[1023,95198],{"className":95199,"style":2369},[1074],[1023,95201,1053],{"className":95202},[1079],[1023,95204,95206,95209],{"className":95205},[1079],[1023,95207,2379],{"className":95208},[1079],[1023,95210,95212],{"className":95211},[2383],[1023,95213,95215],{"className":95214},[2387],[1023,95216,95218],{"className":95217},[2391],[1023,95219,95221],{"className":95220,"style":2369},[2395],[1023,95222,95223,95226],{"style":2398},[1023,95224],{"className":95225,"style":2403},[2402],[1023,95227,95229],{"className":95228},[2407,2408,2409,2410],[1023,95230,6866],{"className":95231},[1079,2410],", nó cần cỡ ",[1023,95234,95236,95255],{"className":95235},[1026],[1023,95237,95239],{"className":95238},[1030],[1032,95240,95241],{"xmlns":1034},[1036,95242,95243,95252],{},[1039,95244,95245],{},[2327,95246,95247,95249],{},[1051,95248,2331],{},[1051,95250,95251],{},"12",[1058,95253,95254],{"encoding":1060},"10^{12}",[1023,95256,95258],{"className":95257,"ariaHidden":1066},[1065],[1023,95259,95261,95264,95267],{"className":95260},[1070],[1023,95262],{"className":95263,"style":2369},[1074],[1023,95265,1053],{"className":95266},[1079],[1023,95268,95270,95273],{"className":95269},[1079],[1023,95271,2379],{"className":95272},[1079],[1023,95274,95276],{"className":95275},[2383],[1023,95277,95279],{"className":95278},[2387],[1023,95280,95282],{"className":95281},[2391],[1023,95283,95285],{"className":95284,"style":2369},[2395],[1023,95286,95287,95290],{"style":2398},[1023,95288],{"className":95289,"style":2403},[2402],[1023,95291,95293],{"className":95292},[2407,2408,2409,2410],[1023,95294,95296],{"className":95295},[1079,2410],[1023,95297,95251],{"className":95298},[1079,2410]," bước, quá chậm cho một lần chạy thông thường.",[973,95301,95302],{},"Hai lớp nữa gặp suốt khóa học:",[986,95304,95305,95488],{},[989,95306,95307,95370,95371,1509,95414,95487],{},[1023,95308,95310,95335],{"className":95309},[1026],[1023,95311,95313],{"className":95312},[1030],[1032,95314,95315],{"xmlns":1034},[1036,95316,95317,95333],{},[1039,95318,95319,95321,95323,95325,95327,95329,95331],{},[1042,95320,1044],{},[1046,95322,1049],{"stretchy":1048},[1042,95324,1262],{},[1042,95326,8397],{},[1046,95328,8400],{},[1042,95330,1262],{},[1046,95332,1056],{"stretchy":1048},[1058,95334,10463],{"encoding":1060},[1023,95336,95338],{"className":95337,"ariaHidden":1066},[1065],[1023,95339,95341,95344,95347,95350,95353,95356,95361,95364,95367],{"className":95340},[1070],[1023,95342],{"className":95343,"style":1075},[1074],[1023,95345,1044],{"className":95346,"style":1081},[1079,1080],[1023,95348,1049],{"className":95349},[1085],[1023,95351,1262],{"className":95352},[1079,1080],[1023,95354],{"className":95355,"style":8434},[2354],[1023,95357,8427,95359],{"className":95358},[8426],[1023,95360,7690],{"style":8430},[1023,95362],{"className":95363,"style":8434},[2354],[1023,95365,1262],{"className":95366},[1079,1080],[1023,95368,1056],{"className":95369},[1092]," nằm giữa ",[1023,95372,95374,95393],{"className":95373},[1026],[1023,95375,95377],{"className":95376},[1030],[1032,95378,95379],{"xmlns":1034},[1036,95380,95381,95391],{},[1039,95382,95383,95385,95387,95389],{},[1042,95384,1044],{},[1046,95386,1049],{"stretchy":1048},[1042,95388,1262],{},[1046,95390,1056],{"stretchy":1048},[1058,95392,1267],{"encoding":1060},[1023,95394,95396],{"className":95395,"ariaHidden":1066},[1065],[1023,95397,95399,95402,95405,95408,95411],{"className":95398},[1070],[1023,95400],{"className":95401,"style":1075},[1074],[1023,95403,1044],{"className":95404,"style":1081},[1079,1080],[1023,95406,1049],{"className":95407},[1085],[1023,95409,1262],{"className":95410},[1079,1080],[1023,95412,1056],{"className":95413},[1092],[1023,95415,95417,95440],{"className":95416},[1026],[1023,95418,95420],{"className":95419},[1030],[1032,95421,95422],{"xmlns":1034},[1036,95423,95424,95438],{},[1039,95425,95426,95428,95430,95436],{},[1042,95427,1044],{},[1046,95429,1049],{"stretchy":1048},[2327,95431,95432,95434],{},[1042,95433,1262],{},[1051,95435,2457],{},[1046,95437,1056],{"stretchy":1048},[1058,95439,2839],{"encoding":1060},[1023,95441,95443],{"className":95442,"ariaHidden":1066},[1065],[1023,95444,95446,95449,95452,95455,95484],{"className":95445},[1070],[1023,95447],{"className":95448,"style":2476},[1074],[1023,95450,1044],{"className":95451,"style":1081},[1079,1080],[1023,95453,1049],{"className":95454},[1085],[1023,95456,95458,95461],{"className":95457},[1079],[1023,95459,1262],{"className":95460},[1079,1080],[1023,95462,95464],{"className":95463},[2383],[1023,95465,95467],{"className":95466},[2387],[1023,95468,95470],{"className":95469},[2391],[1023,95471,95473],{"className":95472,"style":2369},[2395],[1023,95474,95475,95478],{"style":2398},[1023,95476],{"className":95477,"style":2403},[2402],[1023,95479,95481],{"className":95480},[2407,2408,2409,2410],[1023,95482,2457],{"className":95483},[1079,2410],[1023,95485,1056],{"className":95486},[1092],". Đây là chi phí của các thuật toán sắp xếp hiệu quả như merge sort, heap sort.",[989,95489,95490,1509,95564,95609,95610,95638],{},[1023,95491,95493,95517],{"className":95492},[1026],[1023,95494,95496],{"className":95495},[1030],[1032,95497,95498],{"xmlns":1034},[1036,95499,95500,95514],{},[1039,95501,95502,95504,95506,95512],{},[1042,95503,1044],{},[1046,95505,1049],{"stretchy":1048},[2327,95507,95508,95510],{},[1051,95509,2457],{},[1042,95511,1262],{},[1046,95513,1056],{"stretchy":1048},[1058,95515,95516],{"encoding":1060},"O(2^n)",[1023,95518,95520],{"className":95519,"ariaHidden":1066},[1065],[1023,95521,95523,95526,95529,95532,95561],{"className":95522},[1070],[1023,95524],{"className":95525,"style":1075},[1074],[1023,95527,1044],{"className":95528,"style":1081},[1079,1080],[1023,95530,1049],{"className":95531},[1085],[1023,95533,95535,95538],{"className":95534},[1079],[1023,95536,2457],{"className":95537},[1079],[1023,95539,95541],{"className":95540},[2383],[1023,95542,95544],{"className":95543},[2387],[1023,95545,95547],{"className":95546},[2391],[1023,95548,95550],{"className":95549,"style":8348},[2395],[1023,95551,95552,95555],{"style":2398},[1023,95553],{"className":95554,"style":2403},[2402],[1023,95556,95558],{"className":95557},[2407,2408,2409,2410],[1023,95559,1262],{"className":95560},[1079,1080,2410],[1023,95562,1056],{"className":95563},[1092],[1023,95565,95567,95588],{"className":95566},[1026],[1023,95568,95570],{"className":95569},[1030],[1032,95571,95572],{"xmlns":1034},[1036,95573,95574,95586],{},[1039,95575,95576,95578,95580,95582,95584],{},[1042,95577,1044],{},[1046,95579,1049],{"stretchy":1048},[1042,95581,1262],{},[1046,95583,15001],{"stretchy":1048},[1046,95585,1056],{"stretchy":1048},[1058,95587,15006],{"encoding":1060},[1023,95589,95591],{"className":95590,"ariaHidden":1066},[1065],[1023,95592,95594,95597,95600,95603,95606],{"className":95593},[1070],[1023,95595],{"className":95596,"style":1075},[1074],[1023,95598,1044],{"className":95599,"style":1081},[1079,1080],[1023,95601,1049],{"className":95602},[1085],[1023,95604,1262],{"className":95605},[1079,1080],[1023,95607,15028],{"className":95608},[1092]," là lớp mũ và giai thừa, ví dụ vét cạn mọi tập con hay mọi hoán vị. Chỉ dùng được khi ",[1023,95611,95613,95626],{"className":95612},[1026],[1023,95614,95616],{"className":95615},[1030],[1032,95617,95618],{"xmlns":1034},[1036,95619,95620,95624],{},[1039,95621,95622],{},[1042,95623,1262],{},[1058,95625,1262],{"encoding":1060},[1023,95627,95629],{"className":95628,"ariaHidden":1066},[1065],[1023,95630,95632,95635],{"className":95631},[1070],[1023,95633],{"className":95634,"style":2347},[1074],[1023,95636,1262],{"className":95637},[1079,1080]," rất nhỏ.",[1099,95640,95641,95976],{},[1102,95642,95643],{},[1105,95644,95645,95675,95761,95855,95916],{},[1108,95646,95647],{},[1023,95648,95650,95663],{"className":95649},[1026],[1023,95651,95653],{"className":95652},[1030],[1032,95654,95655],{"xmlns":1034},[1036,95656,95657,95661],{},[1039,95658,95659],{},[1042,95660,1262],{},[1058,95662,1262],{"encoding":1060},[1023,95664,95666],{"className":95665,"ariaHidden":1066},[1065],[1023,95667,95669,95672],{"className":95668},[1070],[1023,95670],{"className":95671,"style":2347},[1074],[1023,95673,1262],{"className":95674},[1079,1080],[1108,95676,95677],{},[1023,95678,95680,95704],{"className":95679},[1026],[1023,95681,95683],{"className":95682},[1030],[1032,95684,95685],{"xmlns":1034},[1036,95686,95687,95701],{},[1039,95688,95689,95699],{},[17690,95690,95691,95697],{},[1039,95692,95693,95695],{},[1042,95694,8397],{},[1046,95696,8400],{},[1051,95698,2457],{},[1042,95700,1262],{},[1058,95702,95703],{"encoding":1060},"\\log_2 n",[1023,95705,95707],{"className":95706,"ariaHidden":1066},[1065],[1023,95708,95710,95713,95755,95758],{"className":95709},[1070],[1023,95711],{"className":95712,"style":21647},[1074],[1023,95714,95716,95721],{"className":95715},[8426],[1023,95717,8427,95719],{"className":95718},[8426],[1023,95720,7690],{"style":8430},[1023,95722,95724],{"className":95723},[2383],[1023,95725,95727,95747],{"className":95726},[2387,17732],[1023,95728,95730,95744],{"className":95729},[2391],[1023,95731,95733],{"className":95732,"style":36909},[2395],[1023,95734,95735,95738],{"style":21671},[1023,95736],{"className":95737,"style":2403},[2402],[1023,95739,95741],{"className":95740},[2407,2408,2409,2410],[1023,95742,2457],{"className":95743},[1079,2410],[1023,95745,17797],{"className":95746},[17796],[1023,95748,95750],{"className":95749},[2391],[1023,95751,95753],{"className":95752,"style":21690},[2395],[1023,95754],{},[1023,95756],{"className":95757,"style":8434},[2354],[1023,95759,1262],{"className":95760},[1079,1080],[1108,95762,95763],{},[1023,95764,95766,95792],{"className":95765},[1026],[1023,95767,95769],{"className":95768},[1030],[1032,95770,95771],{"xmlns":1034},[1036,95772,95773,95789],{},[1039,95774,95775,95777,95787],{},[1042,95776,1262],{},[17690,95778,95779,95785],{},[1039,95780,95781,95783],{},[1042,95782,8397],{},[1046,95784,8400],{},[1051,95786,2457],{},[1042,95788,1262],{},[1058,95790,95791],{"encoding":1060},"n \\log_2 n",[1023,95793,95795],{"className":95794,"ariaHidden":1066},[1065],[1023,95796,95798,95801,95804,95807,95849,95852],{"className":95797},[1070],[1023,95799],{"className":95800,"style":21647},[1074],[1023,95802,1262],{"className":95803},[1079,1080],[1023,95805],{"className":95806,"style":8434},[2354],[1023,95808,95810,95815],{"className":95809},[8426],[1023,95811,8427,95813],{"className":95812},[8426],[1023,95814,7690],{"style":8430},[1023,95816,95818],{"className":95817},[2383],[1023,95819,95821,95841],{"className":95820},[2387,17732],[1023,95822,95824,95838],{"className":95823},[2391],[1023,95825,95827],{"className":95826,"style":36909},[2395],[1023,95828,95829,95832],{"style":21671},[1023,95830],{"className":95831,"style":2403},[2402],[1023,95833,95835],{"className":95834},[2407,2408,2409,2410],[1023,95836,2457],{"className":95837},[1079,2410],[1023,95839,17797],{"className":95840},[17796],[1023,95842,95844],{"className":95843},[2391],[1023,95845,95847],{"className":95846,"style":21690},[2395],[1023,95848],{},[1023,95850],{"className":95851,"style":8434},[2354],[1023,95853,1262],{"className":95854},[1079,1080],[1108,95856,95857],{},[1023,95858,95860,95878],{"className":95859},[1026],[1023,95861,95863],{"className":95862},[1030],[1032,95864,95865],{"xmlns":1034},[1036,95866,95867,95875],{},[1039,95868,95869],{},[2327,95870,95871,95873],{},[1042,95872,1262],{},[1051,95874,2457],{},[1058,95876,95877],{"encoding":1060},"n^2",[1023,95879,95881],{"className":95880,"ariaHidden":1066},[1065],[1023,95882,95884,95887],{"className":95883},[1070],[1023,95885],{"className":95886,"style":2369},[1074],[1023,95888,95890,95893],{"className":95889},[1079],[1023,95891,1262],{"className":95892},[1079,1080],[1023,95894,95896],{"className":95895},[2383],[1023,95897,95899],{"className":95898},[2387],[1023,95900,95902],{"className":95901},[2391],[1023,95903,95905],{"className":95904,"style":2369},[2395],[1023,95906,95907,95910],{"style":2398},[1023,95908],{"className":95909,"style":2403},[2402],[1023,95911,95913],{"className":95912},[2407,2408,2409,2410],[1023,95914,2457],{"className":95915},[1079,2410],[1108,95917,95918],{},[1023,95919,95921,95938],{"className":95920},[1026],[1023,95922,95924],{"className":95923},[1030],[1032,95925,95926],{"xmlns":1034},[1036,95927,95928,95936],{},[1039,95929,95930],{},[2327,95931,95932,95934],{},[1051,95933,2457],{},[1042,95935,1262],{},[1058,95937,47994],{"encoding":1060},[1023,95939,95941],{"className":95940,"ariaHidden":1066},[1065],[1023,95942,95944,95947],{"className":95943},[1070],[1023,95945],{"className":95946,"style":8348},[1074],[1023,95948,95950,95953],{"className":95949},[1079],[1023,95951,2457],{"className":95952},[1079],[1023,95954,95956],{"className":95955},[2383],[1023,95957,95959],{"className":95958},[2387],[1023,95960,95962],{"className":95961},[2391],[1023,95963,95965],{"className":95964,"style":8348},[2395],[1023,95966,95967,95970],{"style":2398},[1023,95968],{"className":95969,"style":2403},[2402],[1023,95971,95973],{"className":95972},[2407,2408,2409,2410],[1023,95974,1262],{"className":95975},[1079,1080,2410],[1118,95977,95978,95992,96127],{},[1105,95979,95980,95982,95985,95988,95990],{},[1123,95981,2331],{},[1123,95983,95984],{},"3.3",[1123,95986,95987],{},"33",[1123,95989,13900],{},[1123,95991,64765],{},[1105,95993,95994,95996,95998,96061,96124],{},[1123,95995,9989],{},[1123,95997,2331],{},[1123,95999,96000],{},[1023,96001,96003,96020],{"className":96002},[1026],[1023,96004,96006],{"className":96005},[1030],[1032,96007,96008],{"xmlns":1034},[1036,96009,96010,96018],{},[1039,96011,96012],{},[2327,96013,96014,96016],{},[1051,96015,2331],{},[1051,96017,25255],{},[1058,96019,25339],{"encoding":1060},[1023,96021,96023],{"className":96022,"ariaHidden":1066},[1065],[1023,96024,96026,96029,96032],{"className":96025},[1070],[1023,96027],{"className":96028,"style":2369},[1074],[1023,96030,1053],{"className":96031},[1079],[1023,96033,96035,96038],{"className":96034},[1079],[1023,96036,2379],{"className":96037},[1079],[1023,96039,96041],{"className":96040},[2383],[1023,96042,96044],{"className":96043},[2387],[1023,96045,96047],{"className":96046},[2391],[1023,96048,96050],{"className":96049,"style":2369},[2395],[1023,96051,96052,96055],{"style":2398},[1023,96053],{"className":96054,"style":2403},[2402],[1023,96056,96058],{"className":96057},[2407,2408,2409,2410],[1023,96059,25255],{"className":96060},[1079,2410],[1123,96062,96063],{},[1023,96064,96066,96083],{"className":96065},[1026],[1023,96067,96069],{"className":96068},[1030],[1032,96070,96071],{"xmlns":1034},[1036,96072,96073,96081],{},[1039,96074,96075],{},[2327,96076,96077,96079],{},[1051,96078,2331],{},[1051,96080,6866],{},[1058,96082,6869],{"encoding":1060},[1023,96084,96086],{"className":96085,"ariaHidden":1066},[1065],[1023,96087,96089,96092,96095],{"className":96088},[1070],[1023,96090],{"className":96091,"style":2369},[1074],[1023,96093,1053],{"className":96094},[1079],[1023,96096,96098,96101],{"className":96097},[1079],[1023,96099,2379],{"className":96100},[1079],[1023,96102,96104],{"className":96103},[2383],[1023,96105,96107],{"className":96106},[2387],[1023,96108,96110],{"className":96109},[2391],[1023,96111,96113],{"className":96112,"style":2369},[2395],[1023,96114,96115,96118],{"style":2398},[1023,96116],{"className":96117,"style":2403},[2402],[1023,96119,96121],{"className":96120},[2407,2408,2409,2410],[1023,96122,6866],{"className":96123},[1079,2410],[1123,96125,96126],{},"quá lớn",[1105,96128,96129,96192,96195,96281,96347],{},[1123,96130,96131],{},[1023,96132,96134,96151],{"className":96133},[1026],[1023,96135,96137],{"className":96136},[1030],[1032,96138,96139],{"xmlns":1034},[1036,96140,96141,96149],{},[1039,96142,96143],{},[2327,96144,96145,96147],{},[1051,96146,2331],{},[1051,96148,6866],{},[1058,96150,6869],{"encoding":1060},[1023,96152,96154],{"className":96153,"ariaHidden":1066},[1065],[1023,96155,96157,96160,96163],{"className":96156},[1070],[1023,96158],{"className":96159,"style":2369},[1074],[1023,96161,1053],{"className":96162},[1079],[1023,96164,96166,96169],{"className":96165},[1079],[1023,96167,2379],{"className":96168},[1079],[1023,96170,96172],{"className":96171},[2383],[1023,96173,96175],{"className":96174},[2387],[1023,96176,96178],{"className":96177},[2391],[1023,96179,96181],{"className":96180,"style":2369},[2395],[1023,96182,96183,96186],{"style":2398},[1023,96184],{"className":96185,"style":2403},[2402],[1023,96187,96189],{"className":96188},[2407,2408,2409,2410],[1023,96190,6866],{"className":96191},[1079,2410],[1123,96193,96194],{},"20",[1123,96196,96197],{},[1023,96198,96200,96222],{"className":96199},[1026],[1023,96201,96203],{"className":96202},[1030],[1032,96204,96205],{"xmlns":1034},[1036,96206,96207,96219],{},[1039,96208,96209,96211,96213],{},[1051,96210,2457],{},[1046,96212,18118],{},[2327,96214,96215,96217],{},[1051,96216,2331],{},[1051,96218,21986],{},[1058,96220,96221],{"encoding":1060},"2 \\cdot 10^7",[1023,96223,96225,96243],{"className":96224,"ariaHidden":1066},[1065],[1023,96226,96228,96231,96234,96237,96240],{"className":96227},[1070],[1023,96229],{"className":96230,"style":10020},[1074],[1023,96232,2457],{"className":96233},[1079],[1023,96235],{"className":96236,"style":13790},[2354],[1023,96238,18118],{"className":96239},[13794],[1023,96241],{"className":96242,"style":13790},[2354],[1023,96244,96246,96249,96252],{"className":96245},[1070],[1023,96247],{"className":96248,"style":2369},[1074],[1023,96250,1053],{"className":96251},[1079],[1023,96253,96255,96258],{"className":96254},[1079],[1023,96256,2379],{"className":96257},[1079],[1023,96259,96261],{"className":96260},[2383],[1023,96262,96264],{"className":96263},[2387],[1023,96265,96267],{"className":96266},[2391],[1023,96268,96270],{"className":96269,"style":2369},[2395],[1023,96271,96272,96275],{"style":2398},[1023,96273],{"className":96274,"style":2403},[2402],[1023,96276,96278],{"className":96277},[2407,2408,2409,2410],[1023,96279,21986],{"className":96280},[1079,2410],[1123,96282,96283],{},[1023,96284,96286,96303],{"className":96285},[1026],[1023,96287,96289],{"className":96288},[1030],[1032,96290,96291],{"xmlns":1034},[1036,96292,96293,96301],{},[1039,96294,96295],{},[2327,96296,96297,96299],{},[1051,96298,2331],{},[1051,96300,95251],{},[1058,96302,95254],{"encoding":1060},[1023,96304,96306],{"className":96305,"ariaHidden":1066},[1065],[1023,96307,96309,96312,96315],{"className":96308},[1070],[1023,96310],{"className":96311,"style":2369},[1074],[1023,96313,1053],{"className":96314},[1079],[1023,96316,96318,96321],{"className":96317},[1079],[1023,96319,2379],{"className":96320},[1079],[1023,96322,96324],{"className":96323},[2383],[1023,96325,96327],{"className":96326},[2387],[1023,96328,96330],{"className":96329},[2391],[1023,96331,96333],{"className":96332,"style":2369},[2395],[1023,96334,96335,96338],{"style":2398},[1023,96336],{"className":96337,"style":2403},[2402],[1023,96339,96341],{"className":96340},[2407,2408,2409,2410],[1023,96342,96344],{"className":96343},[1079,2410],[1023,96345,95251],{"className":96346},[1079,2410],[1123,96348,96126],{},[968,96350,96352],{"id":96351},"_7-so-sánh-và-đánh-đổi","7. So sánh và đánh đổi",[973,96354,96355],{},"Big-O giúp dự báo trước khi cài đặt. Đo thực nghiệm giúp chọn sau khi cài đặt.",[973,96357,96358],{},"Cách khôn ngoan: dùng Big-O loại sớm thiết kế xấu. Rồi đo thực nghiệm trong nhóm ứng viên còn lại.",[968,96360,96362],{"id":96361},"_8-cạm-bẫy-tư-duy","8. Cạm bẫy tư duy",[973,96364,96365,96366,96409,96410,96483],{},"Thứ nhất: lẫn hằng số với hình dạng tăng trưởng. Thuật toán ",[1023,96367,96369,96388],{"className":96368},[1026],[1023,96370,96372],{"className":96371},[1030],[1032,96373,96374],{"xmlns":1034},[1036,96375,96376,96386],{},[1039,96377,96378,96380,96382,96384],{},[1042,96379,1044],{},[1046,96381,1049],{"stretchy":1048},[1042,96383,1262],{},[1046,96385,1056],{"stretchy":1048},[1058,96387,1267],{"encoding":1060},[1023,96389,96391],{"className":96390,"ariaHidden":1066},[1065],[1023,96392,96394,96397,96400,96403,96406],{"className":96393},[1070],[1023,96395],{"className":96396,"style":1075},[1074],[1023,96398,1044],{"className":96399,"style":1081},[1079,1080],[1023,96401,1049],{"className":96402},[1085],[1023,96404,1262],{"className":96405},[1079,1080],[1023,96407,1056],{"className":96408},[1092]," với hằng số khổng lồ có thể thua ",[1023,96411,96413,96436],{"className":96412},[1026],[1023,96414,96416],{"className":96415},[1030],[1032,96417,96418],{"xmlns":1034},[1036,96419,96420,96434],{},[1039,96421,96422,96424,96426,96432],{},[1042,96423,1044],{},[1046,96425,1049],{"stretchy":1048},[2327,96427,96428,96430],{},[1042,96429,1262],{},[1051,96431,2457],{},[1046,96433,1056],{"stretchy":1048},[1058,96435,2839],{"encoding":1060},[1023,96437,96439],{"className":96438,"ariaHidden":1066},[1065],[1023,96440,96442,96445,96448,96451,96480],{"className":96441},[1070],[1023,96443],{"className":96444,"style":2476},[1074],[1023,96446,1044],{"className":96447,"style":1081},[1079,1080],[1023,96449,1049],{"className":96450},[1085],[1023,96452,96454,96457],{"className":96453},[1079],[1023,96455,1262],{"className":96456},[1079,1080],[1023,96458,96460],{"className":96459},[2383],[1023,96461,96463],{"className":96462},[2387],[1023,96464,96466],{"className":96465},[2391],[1023,96467,96469],{"className":96468,"style":2369},[2395],[1023,96470,96471,96474],{"style":2398},[1023,96472],{"className":96473,"style":2403},[2402],[1023,96475,96477],{"className":96476},[2407,2408,2409,2410],[1023,96478,2457],{"className":96479},[1079,2410],[1023,96481,1056],{"className":96482},[1092]," trên dữ liệu thực tế.",[973,96485,96486],{},"Thứ hai: hài lòng với chặn lỏng đúng nhưng vô dụng. Thứ ba: đo vài điểm rồi gán nhãn Big-O vội vàng.",[973,96488,96489,96490,96559],{},"Thứ tư: quên ngưỡng ",[1023,96491,96493,96510],{"className":96492},[1026],[1023,96494,96496],{"className":96495},[1030],[1032,96497,96498],{"xmlns":1034},[1036,96499,96500,96508],{},[1039,96501,96502],{},[17690,96503,96504,96506],{},[1042,96505,1262],{},[1051,96507,2379],{},[1058,96509,81892],{"encoding":1060},[1023,96511,96513],{"className":96512,"ariaHidden":1066},[1065],[1023,96514,96516,96519],{"className":96515},[1070],[1023,96517],{"className":96518,"style":54000},[1074],[1023,96520,96522,96525],{"className":96521},[1079],[1023,96523,1262],{"className":96524},[1079,1080],[1023,96526,96528],{"className":96527},[2383],[1023,96529,96531,96551],{"className":96530},[2387,17732],[1023,96532,96534,96548],{"className":96533},[2391],[1023,96535,96537],{"className":96536,"style":54019},[2395],[1023,96538,96539,96542],{"style":17783},[1023,96540],{"className":96541,"style":2403},[2402],[1023,96543,96545],{"className":96544},[2407,2408,2409,2410],[1023,96546,2379],{"className":96547},[1079,2410],[1023,96549,17797],{"className":96550},[17796],[1023,96552,96554],{"className":96553},[2391],[1023,96555,96557],{"className":96556,"style":17804},[2395],[1023,96558],{},". Với dữ liệu nhỏ, chọn thuật toán nào cũng gần như nhau.",[968,96561,96563],{"id":96562},"_9-ứng-dụng-của-tư-duy-này","9. Ứng dụng của tư duy này",[973,96565,96566],{},"Mỗi khi dữ liệu có thể phình to, hãy nghĩ Big-O trước. Nó cũng là ngôn ngữ chung để đọc tài liệu.",[973,96568,96569],{},"Hai người không cần cùng máy vẫn bàn được hiệu năng. Chỉ cần cùng nói Big-O.",[968,96571,96573],{"id":96572},"️-tự-kiểm-tra","✍️ Tự kiểm tra",[973,96575,96576],{},"Tự trả lời trước, rồi mở đáp án để đối chiếu.",[973,96578,96579,2308,96582,96752],{},[1487,96580,96581],{},"Câu 1.",[1023,96583,96585,96631],{"className":96584},[1026],[1023,96586,96588],{"className":96587},[1030],[1032,96589,96590],{"xmlns":1034},[1036,96591,96592,96628],{},[1039,96593,96594,96596,96598,96600,96602,96604,96606,96612,96614,96616,96618,96620,96622,96624,96626],{},[1042,96595,59487],{},[1046,96597,1049],{"stretchy":1048},[1042,96599,1262],{},[1046,96601,1056],{"stretchy":1048},[1046,96603,2325],{},[1051,96605,2334],{},[2327,96607,96608,96610],{},[1042,96609,1262],{},[1051,96611,2457],{},[1046,96613,21881],{},[1051,96615,13826],{},[1042,96617,1262],{},[1042,96619,8397],{},[1046,96621,8400],{},[1042,96623,1262],{},[1046,96625,21881],{},[1051,96627,13900],{},[1058,96629,96630],{"encoding":1060},"f(n) = 5n^2 + 3n \\log n + 100",[1023,96632,96634,96661,96708,96743],{"className":96633,"ariaHidden":1066},[1065],[1023,96635,96637,96640,96643,96646,96649,96652,96655,96658],{"className":96636},[1070],[1023,96638],{"className":96639,"style":1075},[1074],[1023,96641,59487],{"className":96642,"style":59523},[1079,1080],[1023,96644,1049],{"className":96645},[1085],[1023,96647,1262],{"className":96648},[1079,1080],[1023,96650,1056],{"className":96651},[1092],[1023,96653],{"className":96654,"style":2355},[2354],[1023,96656,2325],{"className":96657},[2359],[1023,96659],{"className":96660,"style":2355},[2354],[1023,96662,96664,96667,96670,96699,96702,96705],{"className":96663},[1070],[1023,96665],{"className":96666,"style":91261},[1074],[1023,96668,2334],{"className":96669},[1079],[1023,96671,96673,96676],{"className":96672},[1079],[1023,96674,1262],{"className":96675},[1079,1080],[1023,96677,96679],{"className":96678},[2383],[1023,96680,96682],{"className":96681},[2387],[1023,96683,96685],{"className":96684},[2391],[1023,96686,96688],{"className":96687,"style":2369},[2395],[1023,96689,96690,96693],{"style":2398},[1023,96691],{"className":96692,"style":2403},[2402],[1023,96694,96696],{"className":96695},[2407,2408,2409,2410],[1023,96697,2457],{"className":96698},[1079,2410],[1023,96700],{"className":96701,"style":13790},[2354],[1023,96703,21881],{"className":96704},[13794],[1023,96706],{"className":96707,"style":13790},[2354],[1023,96709,96711,96714,96717,96720,96723,96728,96731,96734,96737,96740],{"className":96710},[1070],[1023,96712],{"className":96713,"style":59519},[1074],[1023,96715,13826],{"className":96716},[1079],[1023,96718,1262],{"className":96719},[1079,1080],[1023,96721],{"className":96722,"style":8434},[2354],[1023,96724,8427,96726],{"className":96725},[8426],[1023,96727,7690],{"style":8430},[1023,96729],{"className":96730,"style":8434},[2354],[1023,96732,1262],{"className":96733},[1079,1080],[1023,96735],{"className":96736,"style":13790},[2354],[1023,96738,21881],{"className":96739},[13794],[1023,96741],{"className":96742,"style":13790},[2354],[1023,96744,96746,96749],{"className":96745},[1070],[1023,96747],{"className":96748,"style":10020},[1074],[1023,96750,13900],{"className":96751},[1079]," thuộc lớp Big-O chặt nhất nào?",[96754,96755,96759],"collapsible",{"close-text":96756,"name":96757,"open-text":96758},"Ẩn","đáp án","Xem",[973,96760,96761,96834,96835,96899],{},[1023,96762,96764,96787],{"className":96763},[1026],[1023,96765,96767],{"className":96766},[1030],[1032,96768,96769],{"xmlns":1034},[1036,96770,96771,96785],{},[1039,96772,96773,96775,96777,96783],{},[1042,96774,1044],{},[1046,96776,1049],{"stretchy":1048},[2327,96778,96779,96781],{},[1042,96780,1262],{},[1051,96782,2457],{},[1046,96784,1056],{"stretchy":1048},[1058,96786,2839],{"encoding":1060},[1023,96788,96790],{"className":96789,"ariaHidden":1066},[1065],[1023,96791,96793,96796,96799,96802,96831],{"className":96792},[1070],[1023,96794],{"className":96795,"style":2476},[1074],[1023,96797,1044],{"className":96798,"style":1081},[1079,1080],[1023,96800,1049],{"className":96801},[1085],[1023,96803,96805,96808],{"className":96804},[1079],[1023,96806,1262],{"className":96807},[1079,1080],[1023,96809,96811],{"className":96810},[2383],[1023,96812,96814],{"className":96813},[2387],[1023,96815,96817],{"className":96816},[2391],[1023,96818,96820],{"className":96819,"style":2369},[2395],[1023,96821,96822,96825],{"style":2398},[1023,96823],{"className":96824,"style":2403},[2402],[1023,96826,96828],{"className":96827},[2407,2408,2409,2410],[1023,96829,2457],{"className":96830},[1079,2410],[1023,96832,1056],{"className":96833},[1092],". Số hạng trội là ",[1023,96836,96838,96858],{"className":96837},[1026],[1023,96839,96841],{"className":96840},[1030],[1032,96842,96843],{"xmlns":1034},[1036,96844,96845,96855],{},[1039,96846,96847,96849],{},[1051,96848,2334],{},[2327,96850,96851,96853],{},[1042,96852,1262],{},[1051,96854,2457],{},[1058,96856,96857],{"encoding":1060},"5n^2",[1023,96859,96861],{"className":96860,"ariaHidden":1066},[1065],[1023,96862,96864,96867,96870],{"className":96863},[1070],[1023,96865],{"className":96866,"style":2369},[1074],[1023,96868,2334],{"className":96869},[1079],[1023,96871,96873,96876],{"className":96872},[1079],[1023,96874,1262],{"className":96875},[1079,1080],[1023,96877,96879],{"className":96878},[2383],[1023,96880,96882],{"className":96881},[2387],[1023,96883,96885],{"className":96884},[2391],[1023,96886,96888],{"className":96887,"style":2369},[2395],[1023,96889,96890,96893],{"style":2398},[1023,96891],{"className":96892,"style":2403},[2402],[1023,96894,96896],{"className":96895},[2407,2408,2409,2410],[1023,96897,2457],{"className":96898},[1079,2410],", bỏ hằng số 5.",[973,96901,96902,96905,96906,92452,97000,1509,97028,97097],{},[1487,96903,96904],{},"Câu 2."," Chứng minh ",[1023,96907,96909,96939],{"className":96908},[1026],[1023,96910,96912],{"className":96911},[1030],[1032,96913,96914],{"xmlns":1034},[1036,96915,96916,96936],{},[1039,96917,96918,96920,96922,96924,96926,96928,96930,96932,96934],{},[1051,96919,13826],{},[1042,96921,1262],{},[1046,96923,21881],{},[1051,96925,91917],{},[1046,96927,91520],{},[1042,96929,1044],{},[1046,96931,1049],{"stretchy":1048},[1042,96933,1262],{},[1046,96935,1056],{"stretchy":1048},[1058,96937,96938],{"encoding":1060},"3n + 40 \\in O(n)",[1023,96940,96942,96963,96982],{"className":96941,"ariaHidden":1066},[1065],[1023,96943,96945,96948,96951,96954,96957,96960],{"className":96944},[1070],[1023,96946],{"className":96947,"style":18148},[1074],[1023,96949,13826],{"className":96950},[1079],[1023,96952,1262],{"className":96953},[1079,1080],[1023,96955],{"className":96956,"style":13790},[2354],[1023,96958,21881],{"className":96959},[13794],[1023,96961],{"className":96962,"style":13790},[2354],[1023,96964,96966,96970,96973,96976,96979],{"className":96965},[1070],[1023,96967],{"className":96968,"style":96969},[1074],"height:0.6835em;vertical-align:-0.0391em;",[1023,96971,91917],{"className":96972},[1079],[1023,96974],{"className":96975,"style":2355},[2354],[1023,96977,91520],{"className":96978},[2359],[1023,96980],{"className":96981,"style":2355},[2354],[1023,96983,96985,96988,96991,96994,96997],{"className":96984},[1070],[1023,96986],{"className":96987,"style":1075},[1074],[1023,96989,1044],{"className":96990,"style":1081},[1079,1080],[1023,96992,1049],{"className":96993},[1085],[1023,96995,1262],{"className":96996},[1079,1080],[1023,96998,1056],{"className":96999},[1092],[1023,97001,97003,97016],{"className":97002},[1026],[1023,97004,97006],{"className":97005},[1030],[1032,97007,97008],{"xmlns":1034},[1036,97009,97010,97014],{},[1039,97011,97012],{},[1042,97013,1356],{},[1058,97015,1356],{"encoding":1060},[1023,97017,97019],{"className":97018,"ariaHidden":1066},[1065],[1023,97020,97022,97025],{"className":97021},[1070],[1023,97023],{"className":97024,"style":2347},[1074],[1023,97026,1356],{"className":97027},[1079,1080],[1023,97029,97031,97048],{"className":97030},[1026],[1023,97032,97034],{"className":97033},[1030],[1032,97035,97036],{"xmlns":1034},[1036,97037,97038,97046],{},[1039,97039,97040],{},[17690,97041,97042,97044],{},[1042,97043,1262],{},[1051,97045,2379],{},[1058,97047,81892],{"encoding":1060},[1023,97049,97051],{"className":97050,"ariaHidden":1066},[1065],[1023,97052,97054,97057],{"className":97053},[1070],[1023,97055],{"className":97056,"style":54000},[1074],[1023,97058,97060,97063],{"className":97059},[1079],[1023,97061,1262],{"className":97062},[1079,1080],[1023,97064,97066],{"className":97065},[2383],[1023,97067,97069,97089],{"className":97068},[2387,17732],[1023,97070,97072,97086],{"className":97071},[2391],[1023,97073,97075],{"className":97074,"style":54019},[2395],[1023,97076,97077,97080],{"style":17783},[1023,97078],{"className":97079,"style":2403},[2402],[1023,97081,97083],{"className":97082},[2407,2408,2409,2410],[1023,97084,2379],{"className":97085},[1079,2410],[1023,97087,17797],{"className":97088},[17796],[1023,97090,97092],{"className":97091},[2391],[1023,97093,97095],{"className":97094,"style":17804},[2395],[1023,97096],{}," nào?",[96754,97099,97100],{"close-text":96756,"name":96757,"open-text":96758},[973,97101,53934,97102,1656,97152,97243,97244,49043,97295,1517],{},[1023,97103,97105,97122],{"className":97104},[1026],[1023,97106,97108],{"className":97107},[1030],[1032,97109,97110],{"xmlns":1034},[1036,97111,97112,97120],{},[1039,97113,97114,97116,97118],{},[1042,97115,1356],{},[1046,97117,2325],{},[1051,97119,25255],{},[1058,97121,92074],{"encoding":1060},[1023,97123,97125,97143],{"className":97124,"ariaHidden":1066},[1065],[1023,97126,97128,97131,97134,97137,97140],{"className":97127},[1070],[1023,97129],{"className":97130,"style":2347},[1074],[1023,97132,1356],{"className":97133},[1079,1080],[1023,97135],{"className":97136,"style":2355},[2354],[1023,97138,2325],{"className":97139},[2359],[1023,97141],{"className":97142,"style":2355},[2354],[1023,97144,97146,97149],{"className":97145},[1070],[1023,97147],{"className":97148,"style":10020},[1074],[1023,97150,25255],{"className":97151},[1079],[1023,97153,97155,97176],{"className":97154},[1026],[1023,97156,97158],{"className":97157},[1030],[1032,97159,97160],{"xmlns":1034},[1036,97161,97162,97174],{},[1039,97163,97164,97170,97172],{},[17690,97165,97166,97168],{},[1042,97167,1262],{},[1051,97169,2379],{},[1046,97171,2325],{},[1051,97173,91917],{},[1058,97175,92129],{"encoding":1060},[1023,97177,97179,97234],{"className":97178,"ariaHidden":1066},[1065],[1023,97180,97182,97185,97225,97228,97231],{"className":97181},[1070],[1023,97183],{"className":97184,"style":54000},[1074],[1023,97186,97188,97191],{"className":97187},[1079],[1023,97189,1262],{"className":97190},[1079,1080],[1023,97192,97194],{"className":97193},[2383],[1023,97195,97197,97217],{"className":97196},[2387,17732],[1023,97198,97200,97214],{"className":97199},[2391],[1023,97201,97203],{"className":97202,"style":54019},[2395],[1023,97204,97205,97208],{"style":17783},[1023,97206],{"className":97207,"style":2403},[2402],[1023,97209,97211],{"className":97210},[2407,2408,2409,2410],[1023,97212,2379],{"className":97213},[1079,2410],[1023,97215,17797],{"className":97216},[17796],[1023,97218,97220],{"className":97219},[2391],[1023,97221,97223],{"className":97222,"style":17804},[2395],[1023,97224],{},[1023,97226],{"className":97227,"style":2355},[2354],[1023,97229,2325],{"className":97230},[2359],[1023,97232],{"className":97233,"style":2355},[2354],[1023,97235,97237,97240],{"className":97236},[1070],[1023,97238],{"className":97239,"style":10020},[1074],[1023,97241,91917],{"className":97242},[1079],": với ",[1023,97245,97247,97265],{"className":97246},[1026],[1023,97248,97250],{"className":97249},[1030],[1032,97251,97252],{"xmlns":1034},[1036,97253,97254,97262],{},[1039,97255,97256,97258,97260],{},[1042,97257,1262],{},[1046,97259,43557],{},[1051,97261,91917],{},[1058,97263,97264],{"encoding":1060},"n \\ge 40",[1023,97266,97268,97286],{"className":97267,"ariaHidden":1066},[1065],[1023,97269,97271,97274,97277,97280,97283],{"className":97270},[1070],[1023,97272],{"className":97273,"style":47337},[1074],[1023,97275,1262],{"className":97276},[1079,1080],[1023,97278],{"className":97279,"style":2355},[2354],[1023,97281,43557],{"className":97282},[2359],[1023,97284],{"className":97285,"style":2355},[2354],[1023,97287,97289,97292],{"className":97288},[1070],[1023,97290],{"className":97291,"style":10020},[1074],[1023,97293,91917],{"className":97294},[1079],[1023,97296,97298,97334],{"className":97297},[1026],[1023,97299,97301],{"className":97300},[1030],[1032,97302,97303],{"xmlns":1034},[1036,97304,97305,97331],{},[1039,97306,97307,97309,97311,97313,97315,97317,97319,97321,97323,97325,97327,97329],{},[1051,97308,13826],{},[1042,97310,1262],{},[1046,97312,21881],{},[1051,97314,91917],{},[1046,97316,21123],{},[1051,97318,13826],{},[1042,97320,1262],{},[1046,97322,21881],{},[1042,97324,1262],{},[1046,97326,2325],{},[1051,97328,25255],{},[1042,97330,1262],{},[1058,97332,97333],{"encoding":1060},"3n + 40 \\le 3n + n = 4n",[1023,97335,97337,97358,97376,97397,97415],{"className":97336,"ariaHidden":1066},[1065],[1023,97338,97340,97343,97346,97349,97352,97355],{"className":97339},[1070],[1023,97341],{"className":97342,"style":18148},[1074],[1023,97344,13826],{"className":97345},[1079],[1023,97347,1262],{"className":97348},[1079,1080],[1023,97350],{"className":97351,"style":13790},[2354],[1023,97353,21881],{"className":97354},[13794],[1023,97356],{"className":97357,"style":13790},[2354],[1023,97359,97361,97364,97367,97370,97373],{"className":97360},[1070],[1023,97362],{"className":97363,"style":21142},[1074],[1023,97365,91917],{"className":97366},[1079],[1023,97368],{"className":97369,"style":2355},[2354],[1023,97371,21123],{"className":97372},[2359],[1023,97374],{"className":97375,"style":2355},[2354],[1023,97377,97379,97382,97385,97388,97391,97394],{"className":97378},[1070],[1023,97380],{"className":97381,"style":18148},[1074],[1023,97383,13826],{"className":97384},[1079],[1023,97386,1262],{"className":97387},[1079,1080],[1023,97389],{"className":97390,"style":13790},[2354],[1023,97392,21881],{"className":97393},[13794],[1023,97395],{"className":97396,"style":13790},[2354],[1023,97398,97400,97403,97406,97409,97412],{"className":97399},[1070],[1023,97401],{"className":97402,"style":2347},[1074],[1023,97404,1262],{"className":97405},[1079,1080],[1023,97407],{"className":97408,"style":2355},[2354],[1023,97410,2325],{"className":97411},[2359],[1023,97413],{"className":97414,"style":2355},[2354],[1023,97416,97418,97421,97424],{"className":97417},[1070],[1023,97419],{"className":97420,"style":10020},[1074],[1023,97422,25255],{"className":97423},[1079],[1023,97425,1262],{"className":97426},[1079,1080],[973,97428,97429,97432,97433,97461,97462,10880,97491,97519],{},[1487,97430,97431],{},"Câu 3."," Hai vòng lặp lồng: ngoài chạy ",[1023,97434,97436,97449],{"className":97435},[1026],[1023,97437,97439],{"className":97438},[1030],[1032,97440,97441],{"xmlns":1034},[1036,97442,97443,97447],{},[1039,97444,97445],{},[1042,97446,1262],{},[1058,97448,1262],{"encoding":1060},[1023,97450,97452],{"className":97451,"ariaHidden":1066},[1065],[1023,97453,97455,97458],{"className":97454},[1070],[1023,97456],{"className":97457,"style":2347},[1074],[1023,97459,1262],{"className":97460},[1079,1080]," lần, trong chạy từ ",[1023,97463,97465,97478],{"className":97464},[1026],[1023,97466,97468],{"className":97467},[1030],[1032,97469,97470],{"xmlns":1034},[1036,97471,97472,97476],{},[1039,97473,97474],{},[1042,97475,1837],{},[1058,97477,1837],{"encoding":1060},[1023,97479,97481],{"className":97480,"ariaHidden":1066},[1065],[1023,97482,97484,97488],{"className":97483},[1070],[1023,97485],{"className":97486,"style":97487},[1074],"height:0.6595em;",[1023,97489,1837],{"className":97490},[1079,1080],[1023,97492,97494,97507],{"className":97493},[1026],[1023,97495,97497],{"className":97496},[1030],[1032,97498,97499],{"xmlns":1034},[1036,97500,97501,97505],{},[1039,97502,97503],{},[1042,97504,1262],{},[1058,97506,1262],{"encoding":1060},[1023,97508,97510],{"className":97509,"ariaHidden":1066},[1065],[1023,97511,97513,97516],{"className":97512},[1070],[1023,97514],{"className":97515,"style":2347},[1074],[1023,97517,1262],{"className":97518},[1079,1080],". Độ phức tạp?",[96754,97521,97522],{"close-text":96756,"name":96757,"open-text":96758},[973,97523,97524,97525,97722,97723,1517],{},"Tổng số lần là ",[1023,97526,97528,97584],{"className":97527},[1026],[1023,97529,97531],{"className":97530},[1030],[1032,97532,97533],{"xmlns":1034},[1036,97534,97535,97581],{},[1039,97536,97537,97539,97541,97543,97545,97547,97549,97551,97553,97555,97557,97559,97561,97563,97565,97567,97569,97571,97573,97575,97577,97579],{},[1042,97538,1262],{},[1046,97540,21881],{},[1046,97542,1049],{"stretchy":1048},[1042,97544,1262],{},[1046,97546,17698],{},[1051,97548,1053],{},[1046,97550,1056],{"stretchy":1048},[1046,97552,21881],{},[1042,97554,1517],{"mathvariant":2460},[1042,97556,1517],{"mathvariant":2460},[1042,97558,1517],{"mathvariant":2460},[1046,97560,21881],{},[1051,97562,1053],{},[1046,97564,2325],{},[1042,97566,1262],{},[1046,97568,1049],{"stretchy":1048},[1042,97570,1262],{},[1046,97572,21881],{},[1051,97574,1053],{},[1046,97576,1056],{"stretchy":1048},[1042,97578,2461],{"mathvariant":2460},[1051,97580,2457],{},[1058,97582,97583],{"encoding":1060},"n + (n-1) + ... + 1 = n(n+1)\u002F2",[1023,97585,97587,97605,97626,97647,97665,97683,97707],{"className":97586,"ariaHidden":1066},[1065],[1023,97588,97590,97593,97596,97599,97602],{"className":97589},[1070],[1023,97591],{"className":97592,"style":13783},[1074],[1023,97594,1262],{"className":97595},[1079,1080],[1023,97597],{"className":97598,"style":13790},[2354],[1023,97600,21881],{"className":97601},[13794],[1023,97603],{"className":97604,"style":13790},[2354],[1023,97606,97608,97611,97614,97617,97620,97623],{"className":97607},[1070],[1023,97609],{"className":97610,"style":1075},[1074],[1023,97612,1049],{"className":97613},[1085],[1023,97615,1262],{"className":97616},[1079,1080],[1023,97618],{"className":97619,"style":13790},[2354],[1023,97621,17698],{"className":97622},[13794],[1023,97624],{"className":97625,"style":13790},[2354],[1023,97627,97629,97632,97635,97638,97641,97644],{"className":97628},[1070],[1023,97630],{"className":97631,"style":1075},[1074],[1023,97633,1053],{"className":97634},[1079],[1023,97636,1056],{"className":97637},[1092],[1023,97639],{"className":97640,"style":13790},[2354],[1023,97642,21881],{"className":97643},[13794],[1023,97645],{"className":97646,"style":13790},[2354],[1023,97648,97650,97653,97656,97659,97662],{"className":97649},[1070],[1023,97651],{"className":97652,"style":13783},[1074],[1023,97654,88369],{"className":97655},[1079],[1023,97657],{"className":97658,"style":13790},[2354],[1023,97660,21881],{"className":97661},[13794],[1023,97663],{"className":97664,"style":13790},[2354],[1023,97666,97668,97671,97674,97677,97680],{"className":97667},[1070],[1023,97669],{"className":97670,"style":10020},[1074],[1023,97672,1053],{"className":97673},[1079],[1023,97675],{"className":97676,"style":2355},[2354],[1023,97678,2325],{"className":97679},[2359],[1023,97681],{"className":97682,"style":2355},[2354],[1023,97684,97686,97689,97692,97695,97698,97701,97704],{"className":97685},[1070],[1023,97687],{"className":97688,"style":1075},[1074],[1023,97690,1262],{"className":97691},[1079,1080],[1023,97693,1049],{"className":97694},[1085],[1023,97696,1262],{"className":97697},[1079,1080],[1023,97699],{"className":97700,"style":13790},[2354],[1023,97702,21881],{"className":97703},[13794],[1023,97705],{"className":97706,"style":13790},[2354],[1023,97708,97710,97713,97716,97719],{"className":97709},[1070],[1023,97711],{"className":97712,"style":1075},[1074],[1023,97714,1053],{"className":97715},[1079],[1023,97717,1056],{"className":97718},[1092],[1023,97720,2509],{"className":97721},[1079],", tức ",[1023,97724,97726,97749],{"className":97725},[1026],[1023,97727,97729],{"className":97728},[1030],[1032,97730,97731],{"xmlns":1034},[1036,97732,97733,97747],{},[1039,97734,97735,97737,97739,97745],{},[1042,97736,1044],{},[1046,97738,1049],{"stretchy":1048},[2327,97740,97741,97743],{},[1042,97742,1262],{},[1051,97744,2457],{},[1046,97746,1056],{"stretchy":1048},[1058,97748,2839],{"encoding":1060},[1023,97750,97752],{"className":97751,"ariaHidden":1066},[1065],[1023,97753,97755,97758,97761,97764,97793],{"className":97754},[1070],[1023,97756],{"className":97757,"style":2476},[1074],[1023,97759,1044],{"className":97760,"style":1081},[1079,1080],[1023,97762,1049],{"className":97763},[1085],[1023,97765,97767,97770],{"className":97766},[1079],[1023,97768,1262],{"className":97769},[1079,1080],[1023,97771,97773],{"className":97772},[2383],[1023,97774,97776],{"className":97775},[2387],[1023,97777,97779],{"className":97778},[2391],[1023,97780,97782],{"className":97781,"style":2369},[2395],[1023,97783,97784,97787],{"style":2398},[1023,97785],{"className":97786,"style":2403},[2402],[1023,97788,97790],{"className":97789},[2407,2408,2409,2410],[1023,97791,2457],{"className":97792},[1079,2410],[1023,97794,1056],{"className":97795},[1092],[973,97797,97798,97801,97802,97805],{},[1487,97799,97800],{},"Câu 4."," Vòng lặp ",[992,97803,97804],{},"for (i = 1; i \u003C n; i *= 2)"," chạy bao nhiêu lần?",[96754,97807,97808],{"close-text":96756,"name":96757,"open-text":96758},[973,97809,10801,97810,97893,97894,97949,97950,97978],{},[1023,97811,97813,97836],{"className":97812},[1026],[1023,97814,97816],{"className":97815},[1030],[1032,97817,97818],{"xmlns":1034},[1036,97819,97820,97834],{},[1039,97821,97822,97832],{},[17690,97823,97824,97830],{},[1039,97825,97826,97828],{},[1042,97827,8397],{},[1046,97829,8400],{},[1051,97831,2457],{},[1042,97833,1262],{},[1058,97835,95703],{"encoding":1060},[1023,97837,97839],{"className":97838,"ariaHidden":1066},[1065],[1023,97840,97842,97845,97887,97890],{"className":97841},[1070],[1023,97843],{"className":97844,"style":21647},[1074],[1023,97846,97848,97853],{"className":97847},[8426],[1023,97849,8427,97851],{"className":97850},[8426],[1023,97852,7690],{"style":8430},[1023,97854,97856],{"className":97855},[2383],[1023,97857,97859,97879],{"className":97858},[2387,17732],[1023,97860,97862,97876],{"className":97861},[2391],[1023,97863,97865],{"className":97864,"style":36909},[2395],[1023,97866,97867,97870],{"style":21671},[1023,97868],{"className":97869,"style":2403},[2402],[1023,97871,97873],{"className":97872},[2407,2408,2409,2410],[1023,97874,2457],{"className":97875},[1079,2410],[1023,97877,17797],{"className":97878},[17796],[1023,97880,97882],{"className":97881},[2391],[1023,97883,97885],{"className":97884,"style":21690},[2395],[1023,97886],{},[1023,97888],{"className":97889,"style":8434},[2354],[1023,97891,1262],{"className":97892},[1079,1080]," lần, tức ",[1023,97895,97897,97920],{"className":97896},[1026],[1023,97898,97900],{"className":97899},[1030],[1032,97901,97902],{"xmlns":1034},[1036,97903,97904,97918],{},[1039,97905,97906,97908,97910,97912,97914,97916],{},[1042,97907,1044],{},[1046,97909,1049],{"stretchy":1048},[1042,97911,8397],{},[1046,97913,8400],{},[1042,97915,1262],{},[1046,97917,1056],{"stretchy":1048},[1058,97919,8407],{"encoding":1060},[1023,97921,97923],{"className":97922,"ariaHidden":1066},[1065],[1023,97924,97926,97929,97932,97935,97940,97943,97946],{"className":97925},[1070],[1023,97927],{"className":97928,"style":1075},[1074],[1023,97930,1044],{"className":97931,"style":1081},[1079,1080],[1023,97933,1049],{"className":97934},[1085],[1023,97936,8427,97938],{"className":97937},[8426],[1023,97939,7690],{"style":8430},[1023,97941],{"className":97942,"style":8434},[2354],[1023,97944,1262],{"className":97945},[1079,1080],[1023,97947,1056],{"className":97948},[1092],", vì ",[1023,97951,97953,97966],{"className":97952},[1026],[1023,97954,97956],{"className":97955},[1030],[1032,97957,97958],{"xmlns":1034},[1036,97959,97960,97964],{},[1039,97961,97962],{},[1042,97963,1837],{},[1058,97965,1837],{"encoding":1060},[1023,97967,97969],{"className":97968,"ariaHidden":1066},[1065],[1023,97970,97972,97975],{"className":97971},[1070],[1023,97973],{"className":97974,"style":97487},[1074],[1023,97976,1837],{"className":97977},[1079,1080]," nhân đôi mỗi vòng.",[973,97980,97981,97984,97985,98019,98020,98078,98079,98107],{},[1487,97982,97983],{},"Câu 5."," Thuật toán A tốn ",[1023,97986,97988,98004],{"className":97987},[1026],[1023,97989,97991],{"className":97990},[1030],[1032,97992,97993],{"xmlns":1034},[1036,97994,97995,98001],{},[1039,97996,97997,97999],{},[1051,97998,13900],{},[1042,98000,1262],{},[1058,98002,98003],{"encoding":1060},"100n",[1023,98005,98007],{"className":98006,"ariaHidden":1066},[1065],[1023,98008,98010,98013,98016],{"className":98009},[1070],[1023,98011],{"className":98012,"style":10020},[1074],[1023,98014,13900],{"className":98015},[1079],[1023,98017,1262],{"className":98018},[1079,1080]," bước, B tốn ",[1023,98021,98023,98040],{"className":98022},[1026],[1023,98024,98026],{"className":98025},[1030],[1032,98027,98028],{"xmlns":1034},[1036,98029,98030,98038],{},[1039,98031,98032],{},[2327,98033,98034,98036],{},[1042,98035,1262],{},[1051,98037,2457],{},[1058,98039,95877],{"encoding":1060},[1023,98041,98043],{"className":98042,"ariaHidden":1066},[1065],[1023,98044,98046,98049],{"className":98045},[1070],[1023,98047],{"className":98048,"style":2369},[1074],[1023,98050,98052,98055],{"className":98051},[1079],[1023,98053,1262],{"className":98054},[1079,1080],[1023,98056,98058],{"className":98057},[2383],[1023,98059,98061],{"className":98060},[2387],[1023,98062,98064],{"className":98063},[2391],[1023,98065,98067],{"className":98066,"style":2369},[2395],[1023,98068,98069,98072],{"style":2398},[1023,98070],{"className":98071,"style":2403},[2402],[1023,98073,98075],{"className":98074},[2407,2408,2409,2410],[1023,98076,2457],{"className":98077},[1079,2410]," bước. Với ",[1023,98080,98082,98095],{"className":98081},[1026],[1023,98083,98085],{"className":98084},[1030],[1032,98086,98087],{"xmlns":1034},[1036,98088,98089,98093],{},[1039,98090,98091],{},[1042,98092,1262],{},[1058,98094,1262],{"encoding":1060},[1023,98096,98098],{"className":98097,"ariaHidden":1066},[1065],[1023,98099,98101,98104],{"className":98100},[1070],[1023,98102],{"className":98103,"style":2347},[1074],[1023,98105,1262],{"className":98106},[1079,1080]," nào thì A nhanh hơn?",[96754,98109,98110],{"close-text":96756,"name":96757,"open-text":96758},[973,98111,6826,98112,98163,98164,98216],{},[1023,98113,98115,98133],{"className":98114},[1026],[1023,98116,98118],{"className":98117},[1030],[1032,98119,98120],{"xmlns":1034},[1036,98121,98122,98130],{},[1039,98123,98124,98126,98128],{},[1042,98125,1262],{},[1046,98127,59050],{},[1051,98129,13900],{},[1058,98131,98132],{"encoding":1060},"n > 100",[1023,98134,98136,98154],{"className":98135,"ariaHidden":1066},[1065],[1023,98137,98139,98142,98145,98148,98151],{"className":98138},[1070],[1023,98140],{"className":98141,"style":91726},[1074],[1023,98143,1262],{"className":98144},[1079,1080],[1023,98146],{"className":98147,"style":2355},[2354],[1023,98149,59050],{"className":98150},[2359],[1023,98152],{"className":98153,"style":2355},[2354],[1023,98155,98157,98160],{"className":98156},[1070],[1023,98158],{"className":98159,"style":10020},[1074],[1023,98161,13900],{"className":98162},[1079],". Với ",[1023,98165,98167,98186],{"className":98166},[1026],[1023,98168,98170],{"className":98169},[1030],[1032,98171,98172],{"xmlns":1034},[1036,98173,98174,98183],{},[1039,98175,98176,98178,98181],{},[1042,98177,1262],{},[1046,98179,98180],{},"\u003C",[1051,98182,13900],{},[1058,98184,98185],{"encoding":1060},"n \u003C 100",[1023,98187,98189,98207],{"className":98188,"ariaHidden":1066},[1065],[1023,98190,98192,98195,98198,98201,98204],{"className":98191},[1070],[1023,98193],{"className":98194,"style":91726},[1074],[1023,98196,1262],{"className":98197},[1079,1080],[1023,98199],{"className":98200,"style":2355},[2354],[1023,98202,98180],{"className":98203},[2359],[1023,98205],{"className":98206,"style":2355},[2354],[1023,98208,98210,98213],{"className":98209},[1070],[1023,98211],{"className":98212,"style":10020},[1074],[1023,98214,13900],{"className":98215},[1079],", B ít bước hơn dù có Big-O tệ hơn.",[968,98218,98220],{"id":98219},"tóm-tắt","Tóm tắt",[986,98222,98223,98226,98327,98330,98683,98773],{},[989,98224,98225],{},"Big-O mô tả hình dạng tăng trưởng của chi phí, bắt nguồn từ Bachmann năm 1894.",[989,98227,98228,98229,1509,98257,98326],{},"Chặn trên dùng cặp ",[1023,98230,98232,98245],{"className":98231},[1026],[1023,98233,98235],{"className":98234},[1030],[1032,98236,98237],{"xmlns":1034},[1036,98238,98239,98243],{},[1039,98240,98241],{},[1042,98242,1356],{},[1058,98244,1356],{"encoding":1060},[1023,98246,98248],{"className":98247,"ariaHidden":1066},[1065],[1023,98249,98251,98254],{"className":98250},[1070],[1023,98252],{"className":98253,"style":2347},[1074],[1023,98255,1356],{"className":98256},[1079,1080],[1023,98258,98260,98277],{"className":98259},[1026],[1023,98261,98263],{"className":98262},[1030],[1032,98264,98265],{"xmlns":1034},[1036,98266,98267,98275],{},[1039,98268,98269],{},[17690,98270,98271,98273],{},[1042,98272,1262],{},[1051,98274,2379],{},[1058,98276,81892],{"encoding":1060},[1023,98278,98280],{"className":98279,"ariaHidden":1066},[1065],[1023,98281,98283,98286],{"className":98282},[1070],[1023,98284],{"className":98285,"style":54000},[1074],[1023,98287,98289,98292],{"className":98288},[1079],[1023,98290,1262],{"className":98291},[1079,1080],[1023,98293,98295],{"className":98294},[2383],[1023,98296,98298,98318],{"className":98297},[2387,17732],[1023,98299,98301,98315],{"className":98300},[2391],[1023,98302,98304],{"className":98303,"style":54019},[2395],[1023,98305,98306,98309],{"style":17783},[1023,98307],{"className":98308,"style":2403},[2402],[1023,98310,98312],{"className":98311},[2407,2408,2409,2410],[1023,98313,2379],{"className":98314},[1079,2410],[1023,98316,17797],{"className":98317},[17796],[1023,98319,98321],{"className":98320},[2391],[1023,98322,98324],{"className":98323,"style":17804},[2395],[1023,98325],{},", cho phép bỏ hằng số và đầu vào nhỏ.",[989,98328,98329],{},"Luôn tìm chặn khít thay vì chặn lỏng đúng nhưng vô dụng.",[989,98331,98332,98333,1656,98376,1656,98431,1656,98474,1656,98537,1656,98610,1517],{},"Nắm năm quy tắc rút gọn và các lớp ",[1023,98334,98336,98355],{"className":98335},[1026],[1023,98337,98339],{"className":98338},[1030],[1032,98340,98341],{"xmlns":1034},[1036,98342,98343,98353],{},[1039,98344,98345,98347,98349,98351],{},[1042,98346,1044],{},[1046,98348,1049],{"stretchy":1048},[1051,98350,1053],{},[1046,98352,1056],{"stretchy":1048},[1058,98354,1061],{"encoding":1060},[1023,98356,98358],{"className":98357,"ariaHidden":1066},[1065],[1023,98359,98361,98364,98367,98370,98373],{"className":98360},[1070],[1023,98362],{"className":98363,"style":1075},[1074],[1023,98365,1044],{"className":98366,"style":1081},[1079,1080],[1023,98368,1049],{"className":98369},[1085],[1023,98371,1053],{"className":98372},[1079],[1023,98374,1056],{"className":98375},[1092],[1023,98377,98379,98402],{"className":98378},[1026],[1023,98380,98382],{"className":98381},[1030],[1032,98383,98384],{"xmlns":1034},[1036,98385,98386,98400],{},[1039,98387,98388,98390,98392,98394,98396,98398],{},[1042,98389,1044],{},[1046,98391,1049],{"stretchy":1048},[1042,98393,8397],{},[1046,98395,8400],{},[1042,98397,1262],{},[1046,98399,1056],{"stretchy":1048},[1058,98401,8407],{"encoding":1060},[1023,98403,98405],{"className":98404,"ariaHidden":1066},[1065],[1023,98406,98408,98411,98414,98417,98422,98425,98428],{"className":98407},[1070],[1023,98409],{"className":98410,"style":1075},[1074],[1023,98412,1044],{"className":98413,"style":1081},[1079,1080],[1023,98415,1049],{"className":98416},[1085],[1023,98418,8427,98420],{"className":98419},[8426],[1023,98421,7690],{"style":8430},[1023,98423],{"className":98424,"style":8434},[2354],[1023,98426,1262],{"className":98427},[1079,1080],[1023,98429,1056],{"className":98430},[1092],[1023,98432,98434,98453],{"className":98433},[1026],[1023,98435,98437],{"className":98436},[1030],[1032,98438,98439],{"xmlns":1034},[1036,98440,98441,98451],{},[1039,98442,98443,98445,98447,98449],{},[1042,98444,1044],{},[1046,98446,1049],{"stretchy":1048},[1042,98448,1262],{},[1046,98450,1056],{"stretchy":1048},[1058,98452,1267],{"encoding":1060},[1023,98454,98456],{"className":98455,"ariaHidden":1066},[1065],[1023,98457,98459,98462,98465,98468,98471],{"className":98458},[1070],[1023,98460],{"className":98461,"style":1075},[1074],[1023,98463,1044],{"className":98464,"style":1081},[1079,1080],[1023,98466,1049],{"className":98467},[1085],[1023,98469,1262],{"className":98470},[1079,1080],[1023,98472,1056],{"className":98473},[1092],[1023,98475,98477,98502],{"className":98476},[1026],[1023,98478,98480],{"className":98479},[1030],[1032,98481,98482],{"xmlns":1034},[1036,98483,98484,98500],{},[1039,98485,98486,98488,98490,98492,98494,98496,98498],{},[1042,98487,1044],{},[1046,98489,1049],{"stretchy":1048},[1042,98491,1262],{},[1042,98493,8397],{},[1046,98495,8400],{},[1042,98497,1262],{},[1046,98499,1056],{"stretchy":1048},[1058,98501,10463],{"encoding":1060},[1023,98503,98505],{"className":98504,"ariaHidden":1066},[1065],[1023,98506,98508,98511,98514,98517,98520,98523,98528,98531,98534],{"className":98507},[1070],[1023,98509],{"className":98510,"style":1075},[1074],[1023,98512,1044],{"className":98513,"style":1081},[1079,1080],[1023,98515,1049],{"className":98516},[1085],[1023,98518,1262],{"className":98519},[1079,1080],[1023,98521],{"className":98522,"style":8434},[2354],[1023,98524,8427,98526],{"className":98525},[8426],[1023,98527,7690],{"style":8430},[1023,98529],{"className":98530,"style":8434},[2354],[1023,98532,1262],{"className":98533},[1079,1080],[1023,98535,1056],{"className":98536},[1092],[1023,98538,98540,98563],{"className":98539},[1026],[1023,98541,98543],{"className":98542},[1030],[1032,98544,98545],{"xmlns":1034},[1036,98546,98547,98561],{},[1039,98548,98549,98551,98553,98559],{},[1042,98550,1044],{},[1046,98552,1049],{"stretchy":1048},[2327,98554,98555,98557],{},[1042,98556,1262],{},[1051,98558,2457],{},[1046,98560,1056],{"stretchy":1048},[1058,98562,2839],{"encoding":1060},[1023,98564,98566],{"className":98565,"ariaHidden":1066},[1065],[1023,98567,98569,98572,98575,98578,98607],{"className":98568},[1070],[1023,98570],{"className":98571,"style":2476},[1074],[1023,98573,1044],{"className":98574,"style":1081},[1079,1080],[1023,98576,1049],{"className":98577},[1085],[1023,98579,98581,98584],{"className":98580},[1079],[1023,98582,1262],{"className":98583},[1079,1080],[1023,98585,98587],{"className":98586},[2383],[1023,98588,98590],{"className":98589},[2387],[1023,98591,98593],{"className":98592},[2391],[1023,98594,98596],{"className":98595,"style":2369},[2395],[1023,98597,98598,98601],{"style":2398},[1023,98599],{"className":98600,"style":2403},[2402],[1023,98602,98604],{"className":98603},[2407,2408,2409,2410],[1023,98605,2457],{"className":98606},[1079,2410],[1023,98608,1056],{"className":98609},[1092],[1023,98611,98613,98636],{"className":98612},[1026],[1023,98614,98616],{"className":98615},[1030],[1032,98617,98618],{"xmlns":1034},[1036,98619,98620,98634],{},[1039,98621,98622,98624,98626,98632],{},[1042,98623,1044],{},[1046,98625,1049],{"stretchy":1048},[2327,98627,98628,98630],{},[1051,98629,2457],{},[1042,98631,1262],{},[1046,98633,1056],{"stretchy":1048},[1058,98635,95516],{"encoding":1060},[1023,98637,98639],{"className":98638,"ariaHidden":1066},[1065],[1023,98640,98642,98645,98648,98651,98680],{"className":98641},[1070],[1023,98643],{"className":98644,"style":1075},[1074],[1023,98646,1044],{"className":98647,"style":1081},[1079,1080],[1023,98649,1049],{"className":98650},[1085],[1023,98652,98654,98657],{"className":98653},[1079],[1023,98655,2457],{"className":98656},[1079],[1023,98658,98660],{"className":98659},[2383],[1023,98661,98663],{"className":98662},[2387],[1023,98664,98666],{"className":98665},[2391],[1023,98667,98669],{"className":98668,"style":8348},[2395],[1023,98670,98671,98674],{"style":2398},[1023,98672],{"className":98673,"style":2403},[2402],[1023,98675,98677],{"className":98676},[2407,2408,2409,2410],[1023,98678,1262],{"className":98679},[1079,1080,2410],[1023,98681,1056],{"className":98682},[1092],[989,98684,98685,98713,98714,98743,98744,98772],{},[1023,98686,98688,98701],{"className":98687},[1026],[1023,98689,98691],{"className":98690},[1030],[1032,98692,98693],{"xmlns":1034},[1036,98694,98695,98699],{},[1039,98696,98697],{},[1042,98698,1044],{},[1058,98700,1044],{"encoding":1060},[1023,98702,98704],{"className":98703,"ariaHidden":1066},[1065],[1023,98705,98707,98710],{"className":98706},[1070],[1023,98708],{"className":98709,"style":27414},[1074],[1023,98711,1044],{"className":98712,"style":1081},[1079,1080]," là chặn trên, ",[1023,98715,98717,98731],{"className":98716},[1026],[1023,98718,98720],{"className":98719},[1030],[1032,98721,98722],{"xmlns":1034},[1036,98723,98724,98728],{},[1039,98725,98726],{},[1042,98727,93082],{"mathvariant":2460},[1058,98729,98730],{"encoding":1060},"\\Omega",[1023,98732,98734],{"className":98733,"ariaHidden":1066},[1065],[1023,98735,98737,98740],{"className":98736},[1070],[1023,98738],{"className":98739,"style":27414},[1074],[1023,98741,93082],{"className":98742},[1079]," là chặn dưới, ",[1023,98745,98747,98760],{"className":98746},[1026],[1023,98748,98750],{"className":98749},[1030],[1032,98751,98752],{"xmlns":1034},[1036,98753,98754,98758],{},[1039,98755,98756],{},[1042,98757,93330],{"mathvariant":2460},[1058,98759,93724],{"encoding":1060},[1023,98761,98763],{"className":98762,"ariaHidden":1066},[1065],[1023,98764,98766,98769],{"className":98765},[1070],[1023,98767],{"className":98768,"style":27414},[1074],[1023,98770,93330],{"className":98771},[1079]," là chặn khít.",[989,98774,98775],{},"Dùng Big-O để loại sớm, đo thực nghiệm để chốt cuối.",{"title":1357,"searchDepth":68,"depth":68,"links":98777},[98778,98779,98780,98781,98782,98783,98784,98785,98786,98787,98788],{"id":90890,"depth":68,"text":90891},{"id":90900,"depth":68,"text":90901},{"id":90913,"depth":68,"text":90914},{"id":92393,"depth":68,"text":92394},{"id":93739,"depth":68,"text":93740},{"id":94629,"depth":68,"text":94630},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Nguồn gốc ký hiệu Bachmann, định nghĩa chặn trên, chặn khít và chặn lỏng, các quy tắc rút gọn và bốn lớp tăng trưởng nền tảng.",{},{"title":10,"description":98789},[98793,98794,98795,7],"big-o","do-phuc-tap","tang-truong","bqz5gKrebtQv6_IJ9VRdT6-hmbHmAgzZ333h46Up22Y",{"id":98798,"title":14,"body":98799,"category":7,"day":3047,"description":99042,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":99043,"navigation":2723,"outcomes":3047,"path":15,"prerequisites":3047,"seo":99044,"stem":16,"tags":99045,"__hash__":99050},"fundamentals\u002Ffundamentals\u002Fchieu-du-lieu-va-tinh-toan.md",{"type":965,"value":98800,"toc":99030},[98801,98803,98806,98809,98813,98816,98819,98822,98825,98828,98831,98834,98837,98841,98844,98847,98850,98853,98856,98859,98862,98865,98868,98871,98875,98878,98881,98884,98887,98890,98894,98897,98900,98903,98906,98909,98913,98916,98919,98922,98925,98928,98932,98935,98938,98941,98944,98948,98951,98954,98957,98959,98961,98966,98971,98976,98981,98986,98991,98996,99001,99006,99011,99013],[968,98802,90891],{"id":90890},[973,98804,98805],{},"Trước khi thiết kế lời giải, hãy mô tả bài toán trước. Dữ liệu của nó có hình dạng gì?",[973,98807,98808],{},"Nhu cầu xử lý của nó nặng nhẹ ra sao? Đó là phân tích chiều dữ liệu và chiều tính toán.",[968,98810,98812],{"id":98811},"_2-ba-họ-thuật-toán-theo-đặc-trưng-bài-toán","2. Ba họ thuật toán theo đặc trưng bài toán",[973,98814,98815],{},"Họ thứ nhất nặng dữ liệu. Lượng dữ liệu khổng lồ, phép xử lý khá đơn giản.",[973,98817,98818],{},"Ví dụ: nén một tệp khổng lồ theo từng phần. Dữ liệu lớn hơn nhiều so với bộ nhớ máy.",[973,98820,98821],{},"Họ thứ hai nặng tính toán. Dữ liệu vào ra đều nhỏ, khối lượng tính toán khổng lồ.",[973,98823,98824],{},"Ví dụ: tìm một số nguyên tố rất lớn. Chìa khóa tối ưu là chia thuật toán thành nhiều pha.",[973,98826,98827],{},"Ít nhất một pha phải song song hóa được. Họ thứ ba nặng cả hai.",[973,98829,98830],{},"Ví dụ: phân tích cảm xúc trên luồng video trực tiếp. Đây là họ tốn tài nguyên nhất.",[973,98832,98833],{},"Nó đòi thiết kế cẩn thận và chia tài nguyên thông minh. Gọi đúng tên họ giúp tránh hai sai lầm đối xứng.",[973,98835,98836],{},"Đừng mang siêu máy tính xử lý bài đơn giản. Đừng mang thiết kế đơn giản đấu bài toán khổng lồ.",[968,98838,98840],{"id":98839},"_3-chiều-dữ-liệu-và-mô-hình-3v","3. Chiều dữ liệu và mô hình 3V",[973,98842,98843],{},"Chiều dữ liệu được đo bằng 3V. V thứ nhất là khối lượng: dữ liệu lớn cỡ nào.",[973,98845,98846],{},"V thứ hai là vận tốc: dữ liệu mới sinh nhanh cỡ nào. Nó có thể bằng không.",[973,98848,98849],{},"V thứ ba là đa dạng: có bao nhiêu kiểu dữ liệu khác nhau. Tâm sơ đồ là dữ liệu đơn giản nhất.",[973,98851,98852],{},"Càng rời tâm thì dữ liệu càng phức tạp. Chiều vận tốc xếp tầng từ đơn giản tới phức tạp.",[973,98854,98855],{},"Thứ tự là: xử lý theo mẻ, xử lý định kỳ, gần thời gian thực, rồi thời gian thực. Ví dụ cả ba V đều cao: chùm video trực tiếp từ camera giám sát.",[973,98857,98858],{},"Ba kịch bản đối chiếu giúp nhớ lâu. Kịch bản một: xử lý một tệp bảng tính, cả ba V đều thấp.",[973,98860,98861],{},"Kịch bản hai: luồng video camera an ninh, cả ba V khá cao. Phải tính tới ngay từ khi thiết kế.",[973,98863,98864],{},"Kịch bản ba: lưới cảm biến nhiệt trong tòa nhà lớn. Vận tốc rất cao vì tin mới sinh liên tục.",[973,98866,98867],{},"Nhưng khối lượng lại thấp. Mỗi mẩu tin chỉ dài 16 bit, gồm 8 bit đo lường và 8 bit siêu dữ liệu.",[973,98869,98870],{},"Ba kịch bản cần lưu trữ và hạ tầng hoàn toàn khác nhau. Tất cả khác biệt đều bắt nguồn từ 3V.",[968,98872,98874],{"id":98873},"_4-chiều-tính-toán","4. Chiều tính toán",[973,98876,98877],{},"Chiều tính toán là nhu cầu xử lý của bài toán. Nhu cầu này quyết định kiểu thiết kế hiệu quả nhất.",[973,98879,98880],{},"Thuật toán phức tạp cần nhiều sức tính toán. Kiến trúc song song đa nút có thể là bắt buộc.",[973,98882,98883],{},"Thuật toán học sâu cần khối tính toán số khổng lồ. Nó có thể cần GPU hay chip chuyên dụng.",[973,98885,98886],{},"Điểm mấu chốt: hai chiều độc lập nhau. Dữ liệu lớn chưa chắc cần tính toán nặng.",[973,98888,98889],{},"Tính toán nặng chưa chắc cần dữ liệu lớn. Bỏ qua một chiều sẽ cho thiết kế khập khiễng.",[968,98891,98893],{"id":98892},"_5-từ-hai-chiều-tới-lựa-chọn-thuật-toán","5. Từ hai chiều tới lựa chọn thuật toán",[973,98895,98896],{},"Mô tả hai chiều là bước đầu của thiết kế. Nó dẫn tới ba quyết định trực tiếp.",[973,98898,98899],{},"Một là chọn họ thuật toán phù hợp. Hai là chọn ngăn xếp phần mềm và hạ tầng.",[973,98901,98902],{},"Ba là dự báo tài nguyên cần chuẩn bị. Ba mối quan tâm thiết kế gắn chặt với khung này.",[973,98904,98905],{},"Thuật toán có cho kết quả mong đợi không? Đó có phải cách tối ưu nhất không? Nó thể hiện ra sao trên dữ liệu lớn hơn?",[973,98907,98908],{},"Hai chiều giúp trả lời có căn cứ. Thay vì trả lời bằng cảm tính.",[968,98910,98912],{"id":98911},"_6-so-sánh-và-đánh-đổi","6. So sánh và đánh đổi",[973,98914,98915],{},"Phân tích hai chiều là định tính trước khi định lượng. Nó đối lập với việc lao ngay vào Big-O chi tiết.",[973,98917,98918],{},"Ưu điểm là rẻ và sớm. Chỉ cần hiểu bài toán đã loại được cả nhóm thiết kế sai.",[973,98920,98921],{},"Hạn chế là không thay thế phân tích chặt chẽ về sau. Nó chỉ đảm bảo ta phân tích đúng thứ đáng phân tích.",[973,98923,98924],{},"Đánh đổi thường gặp: xử lý tại chỗ tốn tính toán, hay tiền xử lý tốn bộ nhớ. Vị trí trên ma trận hai chiều sẽ mách nước lựa chọn.",[973,98926,98927],{},"Đánh đổi khác: hạ tầng chung đắt nhưng linh hoạt, hay hạ tầng chuyên dụng rẻ nhưng kén việc. Giống như thuê xe tải đa năng hay xe đông lạnh chuyên dụng.",[968,98929,98931],{"id":98930},"_7-cạm-bẫy-tư-duy","7. Cạm bẫy tư duy",[973,98933,98934],{},"Thứ nhất: chỉ nhìn khối lượng mà quên vận tốc và đa dạng. Tệp lớn nhưng tĩnh khác hẳn luồng nhỏ chảy xiết.",[973,98936,98937],{},"Thứ hai: lẫn hai chiều với nhau. Dữ liệu lớn chưa chắc cần siêu máy tính tính toán.",[973,98939,98940],{},"Thứ ba: chọn thuật toán ưa thích trước rồi ép bài toán vào. Phải mô tả bài toán trước khi chọn lời giải.",[973,98942,98943],{},"Thứ tư: thiết kế cho xử lý theo mẻ rồi ngỡ ngàng khi yêu cầu thật là thời gian thực. Tầng vận tốc không thể bỏ qua.",[968,98945,98947],{"id":98946},"_8-ứng-dụng-của-tư-duy-này","8. Ứng dụng của tư duy này",[973,98949,98950],{},"Khung hai chiều dùng ngay buổi họp đặc tả đầu tiên. Hỏi dữ liệu lớn bao nhiêu, chảy nhanh ra sao, có mấy kiểu.",[973,98952,98953],{},"Rồi hỏi phép tính nặng cỡ nào, phần nào song song được. Câu trả lời định hướng mọi quyết định tiếp theo.",[973,98955,98956],{},"Về lâu dài, đây là ngôn ngữ đọc tài liệu quy mô lớn. Mỗi chương thực chất là lời giải cho một góc của ma trận.",[968,98958,96573],{"id":96572},[973,98960,96576],{},[973,98962,98963,98965],{},[1487,98964,96581],{}," Ba chữ V của chiều dữ liệu là gì?",[96754,98967,98968],{"close-text":96756,"name":96757,"open-text":96758},[973,98969,98970],{},"Khối lượng (volume), vận tốc (velocity), đa dạng (variety).",[973,98972,98973,98975],{},[1487,98974,96904],{}," Tìm số nguyên tố rất lớn thuộc họ nào?",[96754,98977,98978],{"close-text":96756,"name":96757,"open-text":96758},[973,98979,98980],{},"Nặng tính toán: dữ liệu vào ra nhỏ, khối lượng tính toán khổng lồ.",[973,98982,98983,98985],{},[1487,98984,97431],{}," Lưới cảm biến nhiệt gửi tin 16 bit mỗi giây: V nào cao, V nào thấp?",[96754,98987,98988],{"close-text":96756,"name":96757,"open-text":96758},[973,98989,98990],{},"Vận tốc cao vì tin đến liên tục. Khối lượng mỗi tin thấp. Đa dạng thấp vì cùng một kiểu tin.",[973,98992,98993,98995],{},[1487,98994,97800],{}," Dữ liệu lớn có luôn cần tính toán nặng không?",[96754,98997,98998],{"close-text":96756,"name":96757,"open-text":96758},[973,98999,99000],{},"Không. Hai chiều độc lập: nén một tệp khổng lồ có dữ liệu lớn nhưng phép xử lý đơn giản.",[973,99002,99003,99005],{},[1487,99004,97983],{}," Nêu 1 quyết định thiết kế phụ thuộc vào vận tốc dữ liệu.",[96754,99007,99008],{"close-text":96756,"name":96757,"open-text":96758},[973,99009,99010],{},"Chọn xử lý theo mẻ hay xử lý luồng (stream). Dữ liệu đến liên tục và cần kết quả ngay thì phải xử lý luồng.",[968,99012,98220],{"id":98219},[986,99014,99015,99018,99021,99024,99027],{},[989,99016,99017],{},"Mô tả bài toán trước khi thiết kế lời giải, qua hai chiều dữ liệu và tính toán.",[989,99019,99020],{},"Ba họ thuật toán: nặng dữ liệu, nặng tính toán, nặng cả hai.",[989,99022,99023],{},"Chiều dữ liệu đo bằng 3V: khối lượng, vận tốc, đa dạng.",[989,99025,99026],{},"Chiều tính toán đo bằng nhu cầu xử lý và khả năng song song hóa.",[989,99028,99029],{},"Kết quả phân tích dẫn tới chọn thuật toán, hạ tầng và kế hoạch tài nguyên.",{"title":1357,"searchDepth":68,"depth":68,"links":99031},[99032,99033,99034,99035,99036,99037,99038,99039,99040,99041],{"id":90890,"depth":68,"text":90891},{"id":98811,"depth":68,"text":98812},{"id":98839,"depth":68,"text":98840},{"id":98873,"depth":68,"text":98874},{"id":98892,"depth":68,"text":98893},{"id":98911,"depth":68,"text":98912},{"id":98930,"depth":68,"text":98931},{"id":98946,"depth":68,"text":98947},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Ba họ thuật toán theo đặc trưng bài toán, mô hình 3V của dữ liệu, chiều tính toán và logic chọn thuật toán phù hợp.",{},{"title":14,"description":99042},[99046,99047,99048,99049,7],"du-lieu","tinh-toan","3V","thiet-ke","gHZSu4IWwWOFul_9nqDWQniTjS1eT-RPKb-MtuzAcvk",{"id":99052,"title":18,"body":99053,"category":7,"day":3047,"description":100052,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":100053,"navigation":2723,"outcomes":3047,"path":19,"prerequisites":3047,"seo":100054,"stem":20,"tags":100055,"__hash__":100058},"fundamentals\u002Ffundamentals\u002Fde-quy.md",{"type":965,"value":99054,"toc":100039},[99055,99057,99060,99063,99067,99070,99175,99178,99181,99184,99187,99190,99219,99223,99226,99229,99232,99235,99238,99241,99270,99396,99399,99403,99406,99409,99412,99415,99449,99452,99455,99459,99462,99465,99468,99471,99578,99581,99584,99587,99620,99623,99627,99630,99633,99636,99656,99666,99669,99671,99674,99677,99680,99682,99685,99688,99691,99693,99696,99699,99701,99703,99718,99726,99734,99923,99931,99936,99941,99946,100013,100018,100020,100037],[968,99056,90891],{"id":90890},[973,99058,99059],{},"Đệ quy là hàm gọi lại chính nó trên bài toán nhỏ hơn. Bài này trình bày toàn bộ bằng lý thuyết và lần vết bằng lời.",[973,99061,99062],{},"Các khái niệm gồm: đệ quy đơn giản, điều kiện dừng, cạm bẫy tính lại, ghi nhớ, đệ quy đuôi và đệ quy tương hỗ.",[968,99064,99066],{"id":99065},"_2-đệ-quy-đơn-giản-và-điều-kiện-dừng","2. Đệ quy đơn giản và điều kiện dừng",[973,99068,99069],{},"Dạng đơn giản nhất: một hàm gọi chính nó trong lúc chạy. Hai ví dụ kinh điển là giai thừa và Fibonacci.",[973,99071,99072,99073,1509,99124,1517],{},"Trong Fibonacci, số hạng thứ n bằng tổng hai số trước nó. Kèm hai trường hợp cơ sở cho ",[1023,99074,99076,99094],{"className":99075},[1026],[1023,99077,99079],{"className":99078},[1030],[1032,99080,99081],{"xmlns":1034},[1036,99082,99083,99091],{},[1039,99084,99085,99087,99089],{},[1042,99086,1262],{},[1046,99088,2325],{},[1051,99090,2379],{},[1058,99092,99093],{"encoding":1060},"n = 0",[1023,99095,99097,99115],{"className":99096,"ariaHidden":1066},[1065],[1023,99098,99100,99103,99106,99109,99112],{"className":99099},[1070],[1023,99101],{"className":99102,"style":2347},[1074],[1023,99104,1262],{"className":99105},[1079,1080],[1023,99107],{"className":99108,"style":2355},[2354],[1023,99110,2325],{"className":99111},[2359],[1023,99113],{"className":99114,"style":2355},[2354],[1023,99116,99118,99121],{"className":99117},[1070],[1023,99119],{"className":99120,"style":10020},[1074],[1023,99122,2379],{"className":99123},[1079],[1023,99125,99127,99145],{"className":99126},[1026],[1023,99128,99130],{"className":99129},[1030],[1032,99131,99132],{"xmlns":1034},[1036,99133,99134,99142],{},[1039,99135,99136,99138,99140],{},[1042,99137,1262],{},[1046,99139,2325],{},[1051,99141,1053],{},[1058,99143,99144],{"encoding":1060},"n = 1",[1023,99146,99148,99166],{"className":99147,"ariaHidden":1066},[1065],[1023,99149,99151,99154,99157,99160,99163],{"className":99150},[1070],[1023,99152],{"className":99153,"style":2347},[1074],[1023,99155,1262],{"className":99156},[1079,1080],[1023,99158],{"className":99159,"style":2355},[2354],[1023,99161,2325],{"className":99162},[2359],[1023,99164],{"className":99165,"style":2355},[2354],[1023,99167,99169,99172],{"className":99168},[1070],[1023,99170],{"className":99171,"style":10020},[1074],[1023,99173,1053],{"className":99174},[1079],[973,99176,99177],{},"Điều kiện dừng là thành phần bắt buộc đầu tiên. Phải đảm bảo nó luôn tới được.",[973,99179,99180],{},"Nếu quên kiểm tra số âm, lời gọi với n âm chạy mãi. Thực tế nó văng lỗi tràn ngăn xếp từ rất sớm.",[973,99182,99183],{},"Cạm bẫy tinh vi hơn nằm ở kiểu dữ liệu yếu. Truyền vào giá trị không phải số, phép trừ cho ra giá trị không phải số.",[973,99185,99186],{},"Giá trị này không khớp nhánh dừng nào. Hàm rơi vào đệ quy vô hạn rồi tràn ngăn xếp.",[973,99188,99189],{},"Bài học: điều kiện dừng phải bao phủ mọi đầu vào. Kể cả đầu vào không hợp lệ.",[1352,99191,99193],{"className":1393,"code":99192,"language":1395,"meta":1357,"style":1357},"long long fib(int n) {\n  if (n \u003C 0) throw std::invalid_argument(\"n âm\");   \u002F\u002F chặn đầu vào không hợp lệ\n  if (n \u003C= 1) return n;                              \u002F\u002F điều kiện dừng: fib(0)=0, fib(1)=1\n  return fib(n - 1) + fib(n - 2);                    \u002F\u002F bước đệ quy: bài nhỏ hơn\n}\n",[992,99194,99195,99200,99205,99210,99215],{"__ignoreMap":1357},[1023,99196,99197],{"class":1362,"line":63},[1023,99198,99199],{},"long long fib(int n) {\n",[1023,99201,99202],{"class":1362,"line":68},[1023,99203,99204],{},"  if (n \u003C 0) throw std::invalid_argument(\"n âm\");   \u002F\u002F chặn đầu vào không hợp lệ\n",[1023,99206,99207],{"class":1362,"line":73},[1023,99208,99209],{},"  if (n \u003C= 1) return n;                              \u002F\u002F điều kiện dừng: fib(0)=0, fib(1)=1\n",[1023,99211,99212],{"class":1362,"line":78},[1023,99213,99214],{},"  return fib(n - 1) + fib(n - 2);                    \u002F\u002F bước đệ quy: bài nhỏ hơn\n",[1023,99216,99217],{"class":1362,"line":83},[1023,99218,4986],{},[968,99220,99222],{"id":99221},"_3-cạm-bẫy-tính-lại-và-kỹ-thuật-ghi-nhớ","3. Cạm bẫy tính lại và kỹ thuật ghi nhớ",[973,99224,99225],{},"Hạn chế thứ hai là tính lại lãng phí. Lần vết tính Fibonacci thứ 4 bằng lời.",[973,99227,99228],{},"Lời gọi mức 4 sinh hai lời gọi mức 3 và 2. Rồi phân nhánh tiếp xuống mức 1 và 0.",[973,99230,99231],{},"Kết quả là cùng một giá trị tính đi tính lại nhiều lần. Cái giá là hàng loạt lời gọi hàm dư thừa.",[973,99233,99234],{},"Bài toán con gối nhau là dấu hiệu cần lời giải khác. Quy hoạch động thường là lựa chọn tốt hơn.",[973,99236,99237],{},"Kỹ thuật cải thiện là ghi nhớ kết quả trung gian. Trước khi gọi đệ quy, kiểm tra bộ nhớ đệm trước.",[973,99239,99240],{},"Nếu có rồi thì dùng lại. Nếu chưa thì tính rồi lưu vào cho lần sau.",[1352,99242,99244],{"className":1393,"code":99243,"language":1395,"meta":1357,"style":1357},"long long fibMemo(int n, std::vector\u003Clong long> &memo) {  \u002F\u002F memo khởi tạo -1, cỡ n+1\n  if (n \u003C= 1) return n;\n  if (memo[n] != -1) return memo[n];                       \u002F\u002F có rồi thì dùng lại\n  return memo[n] = fibMemo(n - 1, memo) + fibMemo(n - 2, memo);\n}\n",[992,99245,99246,99251,99256,99261,99266],{"__ignoreMap":1357},[1023,99247,99248],{"class":1362,"line":63},[1023,99249,99250],{},"long long fibMemo(int n, std::vector\u003Clong long> &memo) {  \u002F\u002F memo khởi tạo -1, cỡ n+1\n",[1023,99252,99253],{"class":1362,"line":68},[1023,99254,99255],{},"  if (n \u003C= 1) return n;\n",[1023,99257,99258],{"class":1362,"line":73},[1023,99259,99260],{},"  if (memo[n] != -1) return memo[n];                       \u002F\u002F có rồi thì dùng lại\n",[1023,99262,99263],{"class":1362,"line":78},[1023,99264,99265],{},"  return memo[n] = fibMemo(n - 1, memo) + fibMemo(n - 2, memo);\n",[1023,99267,99268],{"class":1362,"line":83},[1023,99269,4986],{},[973,99271,99272,99273,99276,99277,99279,99280,15466,99353,1517],{},"Bản ngây thơ gọi ",[992,99274,99275],{},"fib(30)"," hơn 2,6 triệu lần. Bản ghi nhớ chỉ tính mỗi ",[992,99278,1262],{}," một lần: từ ",[1023,99281,99283,99306],{"className":99282},[1026],[1023,99284,99286],{"className":99285},[1030],[1032,99287,99288],{"xmlns":1034},[1036,99289,99290,99304],{},[1039,99291,99292,99294,99296,99302],{},[1042,99293,1044],{},[1046,99295,1049],{"stretchy":1048},[2327,99297,99298,99300],{},[1051,99299,2457],{},[1042,99301,1262],{},[1046,99303,1056],{"stretchy":1048},[1058,99305,95516],{"encoding":1060},[1023,99307,99309],{"className":99308,"ariaHidden":1066},[1065],[1023,99310,99312,99315,99318,99321,99350],{"className":99311},[1070],[1023,99313],{"className":99314,"style":1075},[1074],[1023,99316,1044],{"className":99317,"style":1081},[1079,1080],[1023,99319,1049],{"className":99320},[1085],[1023,99322,99324,99327],{"className":99323},[1079],[1023,99325,2457],{"className":99326},[1079],[1023,99328,99330],{"className":99329},[2383],[1023,99331,99333],{"className":99332},[2387],[1023,99334,99336],{"className":99335},[2391],[1023,99337,99339],{"className":99338,"style":8348},[2395],[1023,99340,99341,99344],{"style":2398},[1023,99342],{"className":99343,"style":2403},[2402],[1023,99345,99347],{"className":99346},[2407,2408,2409,2410],[1023,99348,1262],{"className":99349},[1079,1080,2410],[1023,99351,1056],{"className":99352},[1092],[1023,99354,99356,99375],{"className":99355},[1026],[1023,99357,99359],{"className":99358},[1030],[1032,99360,99361],{"xmlns":1034},[1036,99362,99363,99373],{},[1039,99364,99365,99367,99369,99371],{},[1042,99366,1044],{},[1046,99368,1049],{"stretchy":1048},[1042,99370,1262],{},[1046,99372,1056],{"stretchy":1048},[1058,99374,1267],{"encoding":1060},[1023,99376,99378],{"className":99377,"ariaHidden":1066},[1065],[1023,99379,99381,99384,99387,99390,99393],{"className":99380},[1070],[1023,99382],{"className":99383,"style":1075},[1074],[1023,99385,1044],{"className":99386,"style":1081},[1079,1080],[1023,99388,1049],{"className":99389},[1085],[1023,99391,1262],{"className":99392},[1079,1080],[1023,99394,1056],{"className":99395},[1092],[973,99397,99398],{},"Lưu ý: cả đệ quy ngây thơ lẫn ghi nhớ đều tốn bộ nhớ khi quy mô lớn. Ghi nhớ là đánh đổi có tính toán, không phải vé miễn phí.",[968,99400,99402],{"id":99401},"_4-đệ-quy-tốt-khi-bản-chất-bài-toán-vốn-đệ-quy","4. Đệ quy tốt: khi bản chất bài toán vốn đệ quy",[973,99404,99405],{},"Ví dụ Fibonacci cho thấy đệ quy không hơn gì vòng lặp. Nhưng có lúc đệ quy là lựa chọn đúng.",[973,99407,99408],{},"Đó là khi bản chất bài toán vốn đã đệ quy. Lý do chọn lúc này là sự rõ ràng, không phải hiệu năng.",[973,99410,99411],{},"Ví dụ thanh lịch là duyệt cây nhị phân theo thứ tự trước. Gặp nút rỗng thì ghi nhận đã tới lá.",[973,99413,99414],{},"Gặp nút có giá trị thì xử lý nó. Rồi đệ quy duyệt cây trái, sau đó duyệt cây phải.",[1352,99416,99418],{"className":1393,"code":99417,"language":1395,"meta":1357,"style":1357},"void preorder(const Node *root, std::vector\u003Cint> &out) {\n  if (root == nullptr) return;    \u002F\u002F tới chỗ trống dưới lá\n  out.push_back(root->val);       \u002F\u002F xử lý nút\n  preorder(root->left, out);      \u002F\u002F duyệt cây trái\n  preorder(root->right, out);     \u002F\u002F duyệt cây phải\n}\n",[992,99419,99420,99425,99430,99435,99440,99445],{"__ignoreMap":1357},[1023,99421,99422],{"class":1362,"line":63},[1023,99423,99424],{},"void preorder(const Node *root, std::vector\u003Cint> &out) {\n",[1023,99426,99427],{"class":1362,"line":68},[1023,99428,99429],{},"  if (root == nullptr) return;    \u002F\u002F tới chỗ trống dưới lá\n",[1023,99431,99432],{"class":1362,"line":73},[1023,99433,99434],{},"  out.push_back(root->val);       \u002F\u002F xử lý nút\n",[1023,99436,99437],{"class":1362,"line":78},[1023,99438,99439],{},"  preorder(root->left, out);      \u002F\u002F duyệt cây trái\n",[1023,99441,99442],{"class":1362,"line":83},[1023,99443,99444],{},"  preorder(root->right, out);     \u002F\u002F duyệt cây phải\n",[1023,99446,99447],{"class":1362,"line":88},[1023,99448,4986],{},[973,99450,99451],{},"Bản lặp tương đương phải dùng ngăn xếp tường minh. Nó dài dòng và khó viết đúng hơn hẳn.",[973,99453,99454],{},"Hai thứ tự còn lại: duyệt giữa theo trái, nút, phải. Duyệt sau theo hai cây con rồi mới tới nút.",[968,99456,99458],{"id":99457},"_5-đệ-quy-đuôi-và-khung-ngăn-xếp","5. Đệ quy đuôi và khung ngăn xếp",[973,99460,99461],{},"Mỗi lần gọi hàm, chương trình tạo một khung ngăn xếp. Khung gồm địa chỉ quay về, đối số, biến cục bộ và chỗ giữ kết quả.",[973,99463,99464],{},"Lời gọi đệ quy không phải ngoại lệ. Điểm đặc biệt là lời gọi đầu chưa trả về cho tới khi chạm điều kiện dừng.",[973,99466,99467],{},"Tin vui: trình biên dịch hiện đại tối ưu được một dạng đặc biệt. Lời gọi đuôi là lời gọi nằm ở thao tác cuối cùng của hàm.",[973,99469,99470],{},"Hàm là đệ quy đuôi nếu các lời gọi đệ quy đều ở vị trí đuôi. Trình biên dịch bỏ qua việc tạo khung ngăn xếp, thậm chí viết lại thành vòng lặp.",[973,99472,99473,99474,99577],{},"Điểm tinh tế: viết lời gọi ở cuối dòng chưa đủ. Ví dụ trả về ",[1023,99475,99477,99511],{"className":99476},[1026],[1023,99478,99480],{"className":99479},[1030],[1032,99481,99482],{"xmlns":1034},[1036,99483,99484,99508],{},[1039,99485,99486,99488,99490,99492,99494,99496,99498,99500,99502,99504,99506],{},[1042,99487,1262],{},[1046,99489,13768],{},[1042,99491,59487],{},[1042,99493,6207],{},[1042,99495,1356],{},[1042,99497,29580],{},[1046,99499,1049],{"stretchy":1048},[1042,99501,1262],{},[1046,99503,17698],{},[1051,99505,1053],{},[1046,99507,1056],{"stretchy":1048},[1058,99509,99510],{"encoding":1060},"n \\times fact(n-1)",[1023,99512,99514,99532,99565],{"className":99513,"ariaHidden":1066},[1065],[1023,99515,99517,99520,99523,99526,99529],{"className":99516},[1070],[1023,99518],{"className":99519,"style":13783},[1074],[1023,99521,1262],{"className":99522},[1079,1080],[1023,99524],{"className":99525,"style":13790},[2354],[1023,99527,13768],{"className":99528},[13794],[1023,99530],{"className":99531,"style":13790},[2354],[1023,99533,99535,99538,99541,99544,99547,99550,99553,99556,99559,99562],{"className":99534},[1070],[1023,99536],{"className":99537,"style":1075},[1074],[1023,99539,59487],{"className":99540,"style":59523},[1079,1080],[1023,99542,6207],{"className":99543},[1079,1080],[1023,99545,1356],{"className":99546},[1079,1080],[1023,99548,29580],{"className":99549},[1079,1080],[1023,99551,1049],{"className":99552},[1085],[1023,99554,1262],{"className":99555},[1079,1080],[1023,99557],{"className":99558,"style":13790},[2354],[1023,99560,17698],{"className":99561},[13794],[1023,99563],{"className":99564,"style":13790},[2354],[1023,99566,99568,99571,99574],{"className":99567},[1070],[1023,99569],{"className":99570,"style":1075},[1074],[1023,99572,1053],{"className":99573},[1079],[1023,99575,1056],{"className":99576},[1092]," trông như đuôi nhưng không phải.",[973,99579,99580],{},"Vì thao tác cuối cùng là phép nhân, không phải lời gọi. Nên dạng này không tối ưu được.",[973,99582,99583],{},"Cách sửa là thêm đối số tích lũy giữ kết quả nhân dồn. Phép nhân xảy ra khi tính đối số, trước lời gọi đệ quy.",[973,99585,99586],{},"Nhờ đó lời gọi đệ quy thành thao tác cuối thật sự. Trình biên dịch dịch dạng này thành vòng lặp với biến tích lũy.",[1352,99588,99590],{"className":1393,"code":99589,"language":1395,"meta":1357,"style":1357},"long long fact(int n) {                      \u002F\u002F KHÔNG phải đệ quy đuôi: còn phép nhân sau lời gọi\n  return n \u003C= 1 ? 1 : n * fact(n - 1);\n}\nlong long factTail(int n, long long acc = 1) {   \u002F\u002F đệ quy đuôi: lời gọi là việc cuối cùng\n  return n \u003C= 1 ? acc : factTail(n - 1, acc * n);\n}\n",[992,99591,99592,99597,99602,99606,99611,99616],{"__ignoreMap":1357},[1023,99593,99594],{"class":1362,"line":63},[1023,99595,99596],{},"long long fact(int n) {                      \u002F\u002F KHÔNG phải đệ quy đuôi: còn phép nhân sau lời gọi\n",[1023,99598,99599],{"class":1362,"line":68},[1023,99600,99601],{},"  return n \u003C= 1 ? 1 : n * fact(n - 1);\n",[1023,99603,99604],{"class":1362,"line":73},[1023,99605,4986],{},[1023,99607,99608],{"class":1362,"line":78},[1023,99609,99610],{},"long long factTail(int n, long long acc = 1) {   \u002F\u002F đệ quy đuôi: lời gọi là việc cuối cùng\n",[1023,99612,99613],{"class":1362,"line":83},[1023,99614,99615],{},"  return n \u003C= 1 ? acc : factTail(n - 1, acc * n);\n",[1023,99617,99618],{"class":1362,"line":88},[1023,99619,4986],{},[973,99621,99622],{},"Lưu ý thêm: hỗ trợ tối ưu đuôi phụ thuộc ngôn ngữ và trình biên dịch. Đừng mặc định nó luôn có mặt.",[968,99624,99626],{"id":99625},"_6-đệ-quy-tương-hỗ","6. Đệ quy tương hỗ",[973,99628,99629],{},"Hàm có thể gọi mình trực tiếp, hoặc gọi qua hàm khác. Khi hai hay nhiều hàm gọi nhau thành vòng tròn, đó là đệ quy tương hỗ.",[973,99631,99632],{},"Về lý thuyết, đệ quy đuôi tương hỗ cũng tối ưu được. Nhưng đa số trình biên dịch chỉ tối ưu đệ quy đuôi đơn giản.",[973,99634,99635],{},"Ví dụ kinh điển là kiểm tra chẵn lẻ bằng hai hàm gọi qua lại:",[1352,99637,99639],{"className":1393,"code":99638,"language":1395,"meta":1357,"style":1357},"bool isOdd(unsigned n);\nbool isEven(unsigned n) { return n == 0 ? true : isOdd(n - 1); }\nbool isOdd(unsigned n)  { return n == 0 ? false : isEven(n - 1); }\n",[992,99640,99641,99646,99651],{"__ignoreMap":1357},[1023,99642,99643],{"class":1362,"line":63},[1023,99644,99645],{},"bool isOdd(unsigned n);\n",[1023,99647,99648],{"class":1362,"line":68},[1023,99649,99650],{},"bool isEven(unsigned n) { return n == 0 ? true : isOdd(n - 1); }\n",[1023,99652,99653],{"class":1362,"line":73},[1023,99654,99655],{},"bool isOdd(unsigned n)  { return n == 0 ? false : isEven(n - 1); }\n",[973,99657,99658,99659,99662,99663,99665],{},"Lần vết ",[992,99660,99661],{},"isEven(7)",": isEven(7), isOdd(6), isEven(5), isOdd(4), isEven(3), isOdd(2), isEven(1), isOdd(0) trả ",[992,99664,1048],{},". Chuỗi gọi luân phiên hai hàm, sâu 8 tầng. Kết luận rất dứt khoát: đệ quy tương hỗ khó theo dõi và khó tối ưu.",[973,99667,99668],{},"Chỉ dùng nó khi cấu trúc bài toán thực sự đòi hỏi. Giống như hai người gọi điện qua lại, rất dễ rối.",[968,99670,96352],{"id":96351},[973,99672,99673],{},"Đệ quy và lặp diễn đạt cùng một quá trình tính toán. Đệ quy thắng ở sự rõ ràng khi cấu trúc phân cấp.",[973,99675,99676],{},"Lặp thắng ở bộ nhớ ổn định vì không phình ngăn xếp. Ghi nhớ là đánh đổi bộ nhớ lấy thời gian.",[973,99678,99679],{},"Nhưng phải canh chừng bộ nhớ đệm phình quá to. Không có bữa trưa miễn phí ở đây.",[968,99681,96362],{"id":96361},[973,99683,99684],{},"Thứ nhất: quên điều kiện dừng, hoặc dừng không bao hết đầu vào lạ. Thứ hai: dùng đệ quy cho bài toán con gối nhau mà không ghi nhớ.",[973,99686,99687],{},"Cây gọi sẽ phình theo hàm mũ. Thứ ba: tưởng lời gọi nằm cuối dòng mã là đệ quy đuôi.",[973,99689,99690],{},"Thứ tư: mặc định trình biên dịch nào cũng tối ưu gọi đuôi. Thứ năm: đệ quy sâu cho dữ liệu lớn mà không ước lượng độ sâu ngăn xếp.",[968,99692,96563],{"id":96562},[973,99694,99695],{},"Tư duy đệ quy là chìa khóa đọc thuật toán chia để trị. Nó cũng mở cửa các thuật toán duyệt cây và đồ thị.",[973,99697,99698],{},"Thói quen lần vết bằng lời trước khi cài đặt rất đáng giá. Nó phát hiện sớm điều kiện dừng thiếu và nguy cơ tính lại.",[968,99700,96573],{"id":96572},[973,99702,96576],{},[973,99704,99705,99707,99708,7386,99711,49966,99714,99717],{},[1487,99706,96581],{}," Hàm ",[992,99709,99710],{},"f(n) = f(n-1) + 1",[992,99712,99713],{},"f(0) = 0",[992,99715,99716],{},"f(-3)"," thì sao?",[96754,99719,99720],{"close-text":96756,"name":96757,"open-text":96758},[973,99721,99722,99723,1517],{},"Không bao giờ chạm điều kiện dừng, gọi mãi tới khi tràn stack. Cần chặn ",[992,99724,99725],{},"n \u003C 0",[973,99727,99728,2308,99730,99733],{},[1487,99729,96904],{},[992,99731,99732],{},"fib(5)"," ngây thơ gọi bao nhiêu lần?",[96754,99735,99736],{"close-text":96756,"name":96757,"open-text":96758},[973,99737,99738,99739,1517],{},"15 lần. Công thức số lời gọi là ",[1023,99740,99742,99790],{"className":99741},[1026],[1023,99743,99745],{"className":99744},[1030],[1032,99746,99747],{"xmlns":1034},[1036,99748,99749,99787],{},[1039,99750,99751,99753,99755,99757,99759,99761,99763,99765,99767,99769,99771,99773,99775,99777,99779,99781,99783,99785],{},[1051,99752,2457],{},[1046,99754,18118],{},[1042,99756,59487],{},[1042,99758,1837],{},[1042,99760,17703],{},[1046,99762,1049],{"stretchy":1048},[1042,99764,1262],{},[1046,99766,21881],{},[1051,99768,1053],{},[1046,99770,1056],{"stretchy":1048},[1046,99772,17698],{},[1051,99774,1053],{},[1046,99776,2325],{},[1051,99778,2457],{},[1046,99780,18118],{},[1051,99782,14650],{},[1046,99784,17698],{},[1051,99786,1053],{},[1058,99788,99789],{"encoding":1060},"2 \\cdot fib(n+1) - 1 = 2 \\cdot 8 - 1",[1023,99791,99793,99811,99839,99860,99878,99896,99914],{"className":99792,"ariaHidden":1066},[1065],[1023,99794,99796,99799,99802,99805,99808],{"className":99795},[1070],[1023,99797],{"className":99798,"style":10020},[1074],[1023,99800,2457],{"className":99801},[1079],[1023,99803],{"className":99804,"style":13790},[2354],[1023,99806,18118],{"className":99807},[13794],[1023,99809],{"className":99810,"style":13790},[2354],[1023,99812,99814,99817,99820,99824,99827,99830,99833,99836],{"className":99813},[1070],[1023,99815],{"className":99816,"style":1075},[1074],[1023,99818,59487],{"className":99819,"style":59523},[1079,1080],[1023,99821,99823],{"className":99822},[1079,1080],"ib",[1023,99825,1049],{"className":99826},[1085],[1023,99828,1262],{"className":99829},[1079,1080],[1023,99831],{"className":99832,"style":13790},[2354],[1023,99834,21881],{"className":99835},[13794],[1023,99837],{"className":99838,"style":13790},[2354],[1023,99840,99842,99845,99848,99851,99854,99857],{"className":99841},[1070],[1023,99843],{"className":99844,"style":1075},[1074],[1023,99846,1053],{"className":99847},[1079],[1023,99849,1056],{"className":99850},[1092],[1023,99852],{"className":99853,"style":13790},[2354],[1023,99855,17698],{"className":99856},[13794],[1023,99858],{"className":99859,"style":13790},[2354],[1023,99861,99863,99866,99869,99872,99875],{"className":99862},[1070],[1023,99864],{"className":99865,"style":10020},[1074],[1023,99867,1053],{"className":99868},[1079],[1023,99870],{"className":99871,"style":2355},[2354],[1023,99873,2325],{"className":99874},[2359],[1023,99876],{"className":99877,"style":2355},[2354],[1023,99879,99881,99884,99887,99890,99893],{"className":99880},[1070],[1023,99882],{"className":99883,"style":10020},[1074],[1023,99885,2457],{"className":99886},[1079],[1023,99888],{"className":99889,"style":13790},[2354],[1023,99891,18118],{"className":99892},[13794],[1023,99894],{"className":99895,"style":13790},[2354],[1023,99897,99899,99902,99905,99908,99911],{"className":99898},[1070],[1023,99900],{"className":99901,"style":18148},[1074],[1023,99903,14650],{"className":99904},[1079],[1023,99906],{"className":99907,"style":13790},[2354],[1023,99909,17698],{"className":99910},[13794],[1023,99912],{"className":99913,"style":13790},[2354],[1023,99915,99917,99920],{"className":99916},[1070],[1023,99918],{"className":99919,"style":10020},[1074],[1023,99921,1053],{"className":99922},[1079],[973,99924,99925,2308,99927,99930],{},[1487,99926,97431],{},[992,99928,99929],{},"return n * fact(n - 1);"," có phải đệ quy đuôi không?",[96754,99932,99933],{"close-text":96756,"name":96757,"open-text":96758},[973,99934,99935],{},"Không. Việc cuối cùng là phép nhân, không phải lời gọi. Phải thêm tham số tích lũy.",[973,99937,99938,99940],{},[1487,99939,97800],{}," Duyệt cây theo thứ tự giữa (inorder) một BST cho ra gì?",[96754,99942,99943],{"close-text":96756,"name":96757,"open-text":96758},[973,99944,99945],{},"Các khóa theo thứ tự tăng dần.",[973,99947,99948,99950,99951,100012],{},[1487,99949,97983],{}," Đệ quy sâu ",[1023,99952,99954,99971],{"className":99953},[1026],[1023,99955,99957],{"className":99956},[1030],[1032,99958,99959],{"xmlns":1034},[1036,99960,99961,99969],{},[1039,99962,99963],{},[2327,99964,99965,99967],{},[1051,99966,2331],{},[1051,99968,6866],{},[1058,99970,6869],{"encoding":1060},[1023,99972,99974],{"className":99973,"ariaHidden":1066},[1065],[1023,99975,99977,99980,99983],{"className":99976},[1070],[1023,99978],{"className":99979,"style":2369},[1074],[1023,99981,1053],{"className":99982},[1079],[1023,99984,99986,99989],{"className":99985},[1079],[1023,99987,2379],{"className":99988},[1079],[1023,99990,99992],{"className":99991},[2383],[1023,99993,99995],{"className":99994},[2387],[1023,99996,99998],{"className":99997},[2391],[1023,99999,100001],{"className":100000,"style":2369},[2395],[1023,100002,100003,100006],{"style":2398},[1023,100004],{"className":100005,"style":2403},[2402],[1023,100007,100009],{"className":100008},[2407,2408,2409,2410],[1023,100010,6866],{"className":100011},[1079,2410]," tầng trên C++ mặc định thường gặp vấn đề gì?",[96754,100014,100015],{"close-text":96756,"name":96757,"open-text":96758},[973,100016,100017],{},"Tràn stack (thường giới hạn 1-8 MB). Chuyển sang vòng lặp với stack tường minh.",[968,100019,98220],{"id":98219},[986,100021,100022,100025,100028,100031,100034],{},[989,100023,100024],{},"Đệ quy gọi lại chính mình trên bài nhỏ hơn, điều kiện dừng luôn tới được là bắt buộc.",[989,100026,100027],{},"Tính lại bài toán con là cạm bẫy lớn nhất, khắc phục bằng ghi nhớ kết quả.",[989,100029,100030],{},"Đệ quy tỏa sáng khi bài toán vốn phân cấp, như duyệt cây trước, giữa, sau.",[989,100032,100033],{},"Đệ quy đuôi cho phép viết lại thành vòng lặp nếu lời gọi là thao tác cuối thật sự.",[989,100035,100036],{},"Đệ quy tương hỗ khó theo dõi và khó tối ưu nên hạn chế dùng.",[3020,100038,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":100040},[100041,100042,100043,100044,100045,100046,100047,100048,100049,100050,100051],{"id":90890,"depth":68,"text":90891},{"id":99065,"depth":68,"text":99066},{"id":99221,"depth":68,"text":99222},{"id":99401,"depth":68,"text":99402},{"id":99457,"depth":68,"text":99458},{"id":99625,"depth":68,"text":99626},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Đệ quy đơn giản, điều kiện dừng, cạm bẫy tính lại, ghi nhớ kết quả, đệ quy đuôi và đệ quy tương hỗ ở mức lý thuyết và trace bằng lời.",{},{"title":18,"description":100052},[8149,100056,100057,7],"dieu-kien-dung","memoization","aPfMAMtwFbqv7a4lmbXN92_CoiiPPN87onOYEOvQjbw",{"id":100060,"title":22,"body":100061,"category":7,"day":3047,"description":101247,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":101248,"navigation":2723,"outcomes":3047,"path":23,"prerequisites":3047,"seo":101249,"stem":24,"tags":101250,"__hash__":101255},"fundamentals\u002Ffundamentals\u002Fgiai-thuat-ngau-nhien-va-do-chinh-xac.md",{"type":965,"value":100062,"toc":101234},[100063,100065,100068,100071,100075,100078,100081,100084,100115,100176,100180,100183,100186,100189,100329,100332,100335,100339,100342,100345,100348,100351,100354,100357,100360,100363,100367,100370,100373,100376,100379,100382,100385,100388,100391,100395,100398,100401,100404,100407,100410,100413,100416,100419,100422,100744,100841,100843,100846,100849,100852,100855,100858,100860,100863,100866,100869,100872,100874,100877,100880,100882,100884,100889,100894,100899,100904,100909,100914,100919,101205,101210,101215,101217],[968,100064,90891],{"id":90890},[973,100066,100067],{},"Nhiều người mặc định thuật toán là dãy bước tất định. Cùng đầu vào luôn cho cùng đầu ra.",[973,100069,100070],{},"Thực ra đó chỉ là một lớp con. Bài này dựng khung đầy đủ: bài toán quyết định, hai họ Las Vegas và Monte Carlo, cùng ba độ đo chất lượng.",[968,100072,100074],{"id":100073},"_2-bài-toán-quyết-định-và-bài-toán-phân-loại-nhị-phân","2. Bài toán quyết định và bài toán phân loại nhị phân",[973,100076,100077],{},"Bài toán quyết định chỉ trả lời đúng hoặc sai. Thuật toán phân loại nhị phân gán mỗi dữ liệu một trong hai nhãn.",[973,100079,100080],{},"Hai nhãn có thể là bất kỳ thứ gì. Về khái niệm, chúng tương đương nhãn đúng và sai.",[973,100082,100083],{},"Chỉ xét phân loại nhị phân mà không hề hạn chế. Bộ phân loại đa lớp ghép được từ nhiều bộ nhị phân.",[973,100085,100086,100087,1517],{},"Một kết quả nền tảng: mọi bài toán tối ưu diễn đạt được thành bài toán quyết định, và ngược lại. Ví dụ thay vì tìm đường ngắn nhất, ta đặt ngưỡng ",[1023,100088,100090,100103],{"className":100089},[1026],[1023,100091,100093],{"className":100092},[1030],[1032,100094,100095],{"xmlns":1034},[1036,100096,100097,100101],{},[1039,100098,100099],{},[1042,100100,38209],{},[1058,100102,38209],{"encoding":1060},[1023,100104,100106],{"className":100105,"ariaHidden":1066},[1065],[1023,100107,100109,100112],{"className":100108},[1070],[1023,100110],{"className":100111,"style":27414},[1074],[1023,100113,38209],{"className":100114,"style":37429},[1079,1080],[973,100116,100117,100118,100146,100147,100175],{},"Rồi hỏi có đường đi nào dài không quá ",[1023,100119,100121,100134],{"className":100120},[1026],[1023,100122,100124],{"className":100123},[1030],[1032,100125,100126],{"xmlns":1034},[1036,100127,100128,100132],{},[1039,100129,100130],{},[1042,100131,38209],{},[1058,100133,38209],{"encoding":1060},[1023,100135,100137],{"className":100136,"ariaHidden":1066},[1065],[1023,100138,100140,100143],{"className":100139},[1070],[1023,100141],{"className":100142,"style":27414},[1074],[1023,100144,38209],{"className":100145,"style":37429},[1079,1080]," không. Giải bài quyết định này với nhiều ",[1023,100148,100150,100163],{"className":100149},[1026],[1023,100151,100153],{"className":100152},[1030],[1032,100154,100155],{"xmlns":1034},[1036,100156,100157,100161],{},[1039,100158,100159],{},[1042,100160,38209],{},[1058,100162,38209],{"encoding":1060},[1023,100164,100166],{"className":100165,"ariaHidden":1066},[1065],[1023,100167,100169,100172],{"className":100168},[1070],[1023,100170],{"className":100171,"style":27414},[1074],[1023,100173,38209],{"className":100174,"style":37429},[1079,1080]," sẽ ra nghiệm tối ưu gốc.",[968,100177,100179],{"id":100178},"_3-họ-las-vegas-đúng-nhưng-tốn-tài-nguyên-bất-định","3. Họ Las Vegas: đúng nhưng tốn tài nguyên bất định",[973,100181,100182],{},"Họ Las Vegas thỏa hai tính chất. Một là luôn cho nghiệm đúng hoặc báo thất bại.",[973,100184,100185],{},"Hai là chạy với tài nguyên hữu hạn nhưng không đoán trước được. Lượng tài nguyên không dự đoán được từ đầu vào.",[973,100187,100188],{},"Ví dụ nổi bật là sắp xếp nhanh ngẫu nhiên. Chốt chọn ngẫu nhiên mỗi bước nên nó luôn sắp xếp đúng.",[973,100190,100191,100192,1509,100255,100328],{},"Nhưng thời gian dao động giữa ",[1023,100193,100195,100220],{"className":100194},[1026],[1023,100196,100198],{"className":100197},[1030],[1032,100199,100200],{"xmlns":1034},[1036,100201,100202,100218],{},[1039,100203,100204,100206,100208,100210,100212,100214,100216],{},[1042,100205,1044],{},[1046,100207,1049],{"stretchy":1048},[1042,100209,1262],{},[1042,100211,8397],{},[1046,100213,8400],{},[1042,100215,1262],{},[1046,100217,1056],{"stretchy":1048},[1058,100219,10463],{"encoding":1060},[1023,100221,100223],{"className":100222,"ariaHidden":1066},[1065],[1023,100224,100226,100229,100232,100235,100238,100241,100246,100249,100252],{"className":100225},[1070],[1023,100227],{"className":100228,"style":1075},[1074],[1023,100230,1044],{"className":100231,"style":1081},[1079,1080],[1023,100233,1049],{"className":100234},[1085],[1023,100236,1262],{"className":100237},[1079,1080],[1023,100239],{"className":100240,"style":8434},[2354],[1023,100242,8427,100244],{"className":100243},[8426],[1023,100245,7690],{"style":8430},[1023,100247],{"className":100248,"style":8434},[2354],[1023,100250,1262],{"className":100251},[1079,1080],[1023,100253,1056],{"className":100254},[1092],[1023,100256,100258,100281],{"className":100257},[1026],[1023,100259,100261],{"className":100260},[1030],[1032,100262,100263],{"xmlns":1034},[1036,100264,100265,100279],{},[1039,100266,100267,100269,100271,100277],{},[1042,100268,1044],{},[1046,100270,1049],{"stretchy":1048},[2327,100272,100273,100275],{},[1042,100274,1262],{},[1051,100276,2457],{},[1046,100278,1056],{"stretchy":1048},[1058,100280,2839],{"encoding":1060},[1023,100282,100284],{"className":100283,"ariaHidden":1066},[1065],[1023,100285,100287,100290,100293,100296,100325],{"className":100286},[1070],[1023,100288],{"className":100289,"style":2476},[1074],[1023,100291,1044],{"className":100292,"style":1081},[1079,1080],[1023,100294,1049],{"className":100295},[1085],[1023,100297,100299,100302],{"className":100298},[1079],[1023,100300,1262],{"className":100301},[1079,1080],[1023,100303,100305],{"className":100304},[2383],[1023,100306,100308],{"className":100307},[2387],[1023,100309,100311],{"className":100310},[2391],[1023,100312,100314],{"className":100313,"style":2369},[2395],[1023,100315,100316,100319],{"style":2398},[1023,100317],{"className":100318,"style":2403},[2402],[1023,100320,100322],{"className":100321},[2407,2408,2409,2410],[1023,100323,2457],{"className":100324},[1079,2410],[1023,100326,1056],{"className":100327},[1092],". Tùy các lựa chọn ngẫu nhiên gặp hên hay xui.",[973,100330,100331],{},"Nói cách khác, họ này đổi tính đoán trước lấy đảm bảo đúng. Bạn chắc chắn nhận đáp án đúng, nhưng không biết chờ bao lâu.",[973,100333,100334],{},"Giống như tìm chìa khóa khắp nhà: chắc chắn thấy, nhưng không biết mất bao lâu.",[968,100336,100338],{"id":100337},"_4-họ-monte-carlo-tốn-tài-nguyên-xác-định-nhưng-có-thể-sai","4. Họ Monte Carlo: tốn tài nguyên xác định nhưng có thể sai",[973,100340,100341],{},"Ngược với Las Vegas, họ Monte Carlo đôi khi cho đáp án sai. Xác suất sai thường đổi chác với tài nguyên đầu tư.",[973,100343,100344],{},"Giải thuật thực tế giữ xác suất này ở mức nhỏ. Trong khi chỉ dùng tính toán và bộ nhớ hợp lý.",[973,100346,100347],{},"Có tranh luận liệu họ này có xứng gọi là thuật toán không. Khóa học coi chúng là thuật toán, vì dãy bước vẫn hữu hạn và định nghĩa rõ, chỉ đầu vào có thêm số ngẫu nhiên.",[973,100349,100350],{},"Với bài quyết định đáp án đúng hoặc sai, có ba tình huống. Thiên lệch sai: khi trả về sai thì luôn đúng.",[973,100352,100353],{},"Thiên lệch đúng: khi trả về đúng thì luôn đúng. Còn lại là có thể sai cả hai phía.",[973,100355,100356],{},"Họ Monte Carlo tốn tài nguyên đơn định. Nó là đối ngẫu của Las Vegas.",[973,100358,100359],{},"Hai họ chuyển đổi được cho nhau. Giả sử A là thuật toán Las Vegas: luôn đúng nhưng thời gian bất định. Ta chạy A tối đa T bước; hết T bước mà chưa xong thì trả một đáp án đoán.",[973,100361,100362],{},"Thuật toán mới luôn xong trong T bước nhưng có thể sai, tức là một thuật toán Monte Carlo. Ta đổi đảm bảo đúng lấy đảm bảo thời gian. Giống như đoán nhanh khi sắp hết giờ thi.",[968,100364,100366],{"id":100365},"_5-độ-đo-accuracy-và-hạn-chế-của-nó","5. Độ đo accuracy và hạn chế của nó",[973,100368,100369],{},"Với cấu trúc như bộ lọc Bloom (có thể trả lời sai), thời gian và bộ nhớ chưa đủ để đánh giá. Với Monte Carlo còn phải hỏi: nó làm việc tốt tới mức nào.",[973,100371,100372],{},"Muốn trả lời cần độ đo. Đó là hàm đo khoảng cách giữa nghiệm xấp xỉ và nghiệm tối ưu.",[973,100374,100375],{},"Với phân loại, chất lượng là mức gán đúng lớp mỗi đầu vào. Độ đo đầu tiên là accuracy: tỉ lệ dự đoán đúng trên tổng số.",[973,100377,100378],{},"Bài này định nghĩa qua bốn khái niệm. Dương tính thật là điểm vừa đoán đúng vừa thực sự đúng.",[973,100380,100381],{},"Tương tự với lớp sai cho ra âm tính thật. Accuracy bằng tổng hai loại thật chia cho tổng số điểm.",[973,100383,100384],{},"Khi accuracy bằng 1 thì giải thuật luôn đúng. Hạn chế lộ ra trong ví dụ 99 phần trăm điểm thuộc lớp đúng.",[973,100386,100387],{},"Bộ phân loại luôn trả nhãn đúng cho mọi điểm có accuracy cao nhất. Dù nó trượt toàn bộ điểm lớp sai.",[973,100389,100390],{},"Bài học: trên dữ liệu lệch, accuracy cao có thể che giấu mô hình kém. Giống như đoán mọi email đều không phải rác, vẫn đúng 99 phần trăm.",[968,100392,100394],{"id":100393},"_6-precision-recall-và-đường-cong-đánh-đổi","6. Precision, recall và đường cong đánh đổi",[973,100396,100397],{},"Để vượt hạn chế của accuracy, cần theo dõi từng lớp riêng. Hai độ đo mới là precision và recall.",[973,100399,100400],{},"Precision là tỉ lệ dương tính thật trên tổng số điểm được đoán là đúng. Nó trả lời: trong số ta khẳng định đúng, bao nhiêu là đúng thật.",[973,100402,100403],{},"Recall là tỉ lệ dương tính thật trên tổng số điểm thực sự đúng. Nó trả lời: trong số đúng thật, ta bắt được bao nhiêu.",[973,100405,100406],{},"Diễn đạt qua dương tính giả và âm tính giả cho gọn. Accuracy chỉ đo ta đoán tốt ra sao.",[973,100408,100409],{},"Còn precision và recall cân thành công với sai lầm từng phía. Hai độ đo này giằng co nhau.",[973,100411,100412],{},"Cải thiện recall thường làm precision giảm đôi chút, và ngược lại. Ví dụ bộ lọc Bloom: khi nó trả lời \"không có\" thì chắc chắn đúng.",[973,100414,100415],{},"Nên recall của nó luôn bằng 100 phần trăm. Nó không bao giờ có âm tính giả.",[973,100417,100418],{},"Với giải thuật thiên lệch một phía, muốn tăng precision chỉ còn cách đầu tư thêm tài nguyên (với Bloom là thêm bit hoặc chỉnh số hàm băm).",[973,100420,100421],{},"Khi cần một con số duy nhất, dùng F1, trung bình điều hòa của hai độ đo:",[973,100423,100424],{},[1023,100425,100427,100521],{"className":100426},[1026],[1023,100428,100430],{"className":100429},[1030],[1032,100431,100432],{"xmlns":1034},[1036,100433,100434,100518],{},[1039,100435,100436,100442,100444],{},[17690,100437,100438,100440],{},[1042,100439,29697],{},[1051,100441,1053],{},[1046,100443,2325],{},[18110,100445,100446,100484],{},[1039,100447,100448,100450,100452,100454,100456,100458,100460,100462,100464,100466,100468,100470,100472,100474,100476,100478,100480,100482],{},[1051,100449,2457],{},[1046,100451,18118],{},[1042,100453,973],{},[1042,100455,12970],{},[1042,100457,24035],{},[1042,100459,1356],{},[1042,100461,1837],{},[1042,100463,29577],{},[1042,100465,1837],{},[1042,100467,7687],{},[1042,100469,1262],{},[1046,100471,18118],{},[1042,100473,12970],{},[1042,100475,24035],{},[1042,100477,1356],{},[1042,100479,6207],{},[1042,100481,7684],{},[1042,100483,7684],{},[1039,100485,100486,100488,100490,100492,100494,100496,100498,100500,100502,100504,100506,100508,100510,100512,100514,100516],{},[1042,100487,973],{},[1042,100489,12970],{},[1042,100491,24035],{},[1042,100493,1356],{},[1042,100495,1837],{},[1042,100497,29577],{},[1042,100499,1837],{},[1042,100501,7687],{},[1042,100503,1262],{},[1046,100505,21881],{},[1042,100507,12970],{},[1042,100509,24035],{},[1042,100511,1356],{},[1042,100513,6207],{},[1042,100515,7684],{},[1042,100517,7684],{},[1058,100519,100520],{"encoding":1060},"F_1 = \\frac{2 \\cdot precision \\cdot recall}{precision + recall}",[1023,100522,100524,100581],{"className":100523,"ariaHidden":1066},[1065],[1023,100525,100527,100531,100572,100575,100578],{"className":100526},[1070],[1023,100528],{"className":100529,"style":100530},[1074],"height:0.8333em;vertical-align:-0.15em;",[1023,100532,100534,100537],{"className":100533},[1079],[1023,100535,29697],{"className":100536,"style":37429},[1079,1080],[1023,100538,100540],{"className":100539},[2383],[1023,100541,100543,100564],{"className":100542},[2387,17732],[1023,100544,100546,100561],{"className":100545},[2391],[1023,100547,100549],{"className":100548,"style":54019},[2395],[1023,100550,100552,100555],{"style":100551},"top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;",[1023,100553],{"className":100554,"style":2403},[2402],[1023,100556,100558],{"className":100557},[2407,2408,2409,2410],[1023,100559,1053],{"className":100560},[1079,2410],[1023,100562,17797],{"className":100563},[17796],[1023,100565,100567],{"className":100566},[2391],[1023,100568,100570],{"className":100569,"style":17804},[2395],[1023,100571],{},[1023,100573],{"className":100574,"style":2355},[2354],[1023,100576,2325],{"className":100577},[2359],[1023,100579],{"className":100580,"style":2355},[2354],[1023,100582,100584,100588],{"className":100583},[1070],[1023,100585],{"className":100586,"style":100587},[1074],"height:1.4133em;vertical-align:-0.4811em;",[1023,100589,100591,100594,100741],{"className":100590},[1079],[1023,100592],{"className":100593},[1085,18174],[1023,100595,100597],{"className":100596},[18110],[1023,100598,100600,100732],{"className":100599},[2387,17732],[1023,100601,100603,100729],{"className":100602},[2391],[1023,100604,100607,100661,100669],{"className":100605,"style":100606},[2395],"height:0.9322em;",[1023,100608,100609,100612],{"style":18190},[1023,100610],{"className":100611,"style":18194},[2402],[1023,100613,100615],{"className":100614},[2407,2408,2409,2410],[1023,100616,100618,100621,100624,100628,100631,100634,100637,100640,100643,100646,100649,100652,100655,100658],{"className":100617},[1079,2410],[1023,100619,973],{"className":100620},[1079,1080,2410],[1023,100622,12970],{"className":100623,"style":1081},[1079,1080,2410],[1023,100625,100627],{"className":100626},[1079,1080,2410],"ec",[1023,100629,1837],{"className":100630},[1079,1080,2410],[1023,100632,29577],{"className":100633},[1079,1080,2410],[1023,100635,1837],{"className":100636},[1079,1080,2410],[1023,100638,7687],{"className":100639},[1079,1080,2410],[1023,100641,1262],{"className":100642},[1079,1080,2410],[1023,100644,21881],{"className":100645},[13794,2410],[1023,100647,12970],{"className":100648,"style":1081},[1079,1080,2410],[1023,100650,100627],{"className":100651},[1079,1080,2410],[1023,100653,6207],{"className":100654},[1079,1080,2410],[1023,100656,7684],{"className":100657,"style":7716},[1079,1080,2410],[1023,100659,7684],{"className":100660,"style":7716},[1079,1080,2410],[1023,100662,100663,100666],{"style":18221},[1023,100664],{"className":100665,"style":18194},[2402],[1023,100667],{"className":100668,"style":18229},[18228],[1023,100670,100672,100675],{"style":100671},"top:-3.4461em;",[1023,100673],{"className":100674,"style":18194},[2402],[1023,100676,100678],{"className":100677},[2407,2408,2409,2410],[1023,100679,100681,100684,100687,100690,100693,100696,100699,100702,100705,100708,100711,100714,100717,100720,100723,100726],{"className":100680},[1079,2410],[1023,100682,2457],{"className":100683},[1079,2410],[1023,100685,18118],{"className":100686},[13794,2410],[1023,100688,973],{"className":100689},[1079,1080,2410],[1023,100691,12970],{"className":100692,"style":1081},[1079,1080,2410],[1023,100694,100627],{"className":100695},[1079,1080,2410],[1023,100697,1837],{"className":100698},[1079,1080,2410],[1023,100700,29577],{"className":100701},[1079,1080,2410],[1023,100703,1837],{"className":100704},[1079,1080,2410],[1023,100706,7687],{"className":100707},[1079,1080,2410],[1023,100709,1262],{"className":100710},[1079,1080,2410],[1023,100712,18118],{"className":100713},[13794,2410],[1023,100715,12970],{"className":100716,"style":1081},[1079,1080,2410],[1023,100718,100627],{"className":100719},[1079,1080,2410],[1023,100721,6207],{"className":100722},[1079,1080,2410],[1023,100724,7684],{"className":100725,"style":7716},[1079,1080,2410],[1023,100727,7684],{"className":100728,"style":7716},[1079,1080,2410],[1023,100730,17797],{"className":100731},[17796],[1023,100733,100735],{"className":100734},[2391],[1023,100736,100739],{"className":100737,"style":100738},[2395],"height:0.4811em;",[1023,100740],{},[1023,100742],{"className":100743},[1092,18174],[973,100745,100746,100747,100840],{},"Ví dụ precision 0.9, recall 0.5 cho ",[1023,100748,100750,100773],{"className":100749},[1026],[1023,100751,100753],{"className":100752},[1030],[1032,100754,100755],{"xmlns":1034},[1036,100756,100757,100770],{},[1039,100758,100759,100765,100767],{},[17690,100760,100761,100763],{},[1042,100762,29697],{},[1051,100764,1053],{},[1046,100766,24020],{},[1051,100768,100769],{},"0.64",[1058,100771,100772],{"encoding":1060},"F_1 \\approx 0.64",[1023,100774,100776,100831],{"className":100775,"ariaHidden":1066},[1065],[1023,100777,100779,100782,100822,100825,100828],{"className":100778},[1070],[1023,100780],{"className":100781,"style":100530},[1074],[1023,100783,100785,100788],{"className":100784},[1079],[1023,100786,29697],{"className":100787,"style":37429},[1079,1080],[1023,100789,100791],{"className":100790},[2383],[1023,100792,100794,100814],{"className":100793},[2387,17732],[1023,100795,100797,100811],{"className":100796},[2391],[1023,100798,100800],{"className":100799,"style":54019},[2395],[1023,100801,100802,100805],{"style":100551},[1023,100803],{"className":100804,"style":2403},[2402],[1023,100806,100808],{"className":100807},[2407,2408,2409,2410],[1023,100809,1053],{"className":100810},[1079,2410],[1023,100812,17797],{"className":100813},[17796],[1023,100815,100817],{"className":100816},[2391],[1023,100818,100820],{"className":100819,"style":17804},[2395],[1023,100821],{},[1023,100823],{"className":100824,"style":2355},[2354],[1023,100826,24020],{"className":100827},[2359],[1023,100829],{"className":100830,"style":2355},[2354],[1023,100832,100834,100837],{"className":100833},[1070],[1023,100835],{"className":100836,"style":10020},[1074],[1023,100838,100769],{"className":100839},[1079],": F1 bị kéo về phía độ đo thấp hơn. Giống như lưới bắt cá: mắt dày bắt hết cá nhưng tốn công gỡ rác.",[968,100842,96352],{"id":96351},[973,100844,100845],{},"Las Vegas và Monte Carlo là hai cực của một đánh đổi. Cực một đảm bảo đúng nhưng chi phí bất định.",[973,100847,100848],{},"Cực hai đảm bảo chi phí nhưng đáp án có thể sai. Kỹ thuật dừng sớm biến Las Vegas thành Monte Carlo.",[973,100850,100851],{},"Đó chính là di chuyển trên trục đánh đổi cho hợp ngân sách. Trong họ Monte Carlo còn một đánh đổi thứ hai.",[973,100853,100854],{},"Siết tiêu chuẩn để tăng precision sẽ làm tuột vài ca đúng thật. Khi đó recall giảm xuống.",[973,100856,100857],{},"Với giải thuật thiên lệch một phía như Bloom, đánh đổi này mất một chiều. Chỉ còn đánh đổi giữa precision và tài nguyên.",[968,100859,96362],{"id":96361},[973,100861,100862],{},"Thứ nhất: mặc định mọi thuật toán đều tất định. Rồi ngạc nhiên khi cùng đầu vào cho đầu ra khác nhau.",[973,100864,100865],{},"Thứ hai: tôn thờ accuracy trên dữ liệu lệch. Tưởng mô hình đoán lớp đa số là mô hình tốt.",[973,100867,100868],{},"Thứ ba: tin rằng tối ưu precision và recall cùng lúc vô hạn. Thực ra chúng giằng co nhau theo bản chất.",[973,100870,100871],{},"Thứ tư: lẫn hai họ với nhau. Đòi Monte Carlo luôn đúng, hoặc đòi Las Vegas xong trong giờ cố định.",[968,100873,96563],{"id":96562},[973,100875,100876],{},"Khung hai họ giúp đọc hiểu cấu trúc ngẫu nhiên trong khóa học. Ba độ đo là ngôn ngữ chuẩn đọc báo cáo học máy.",[973,100878,100879],{},"Khi nhận mô hình mới, hãy hỏi accuracy, precision, recall ngay. Rồi mới quyết định có dùng được không.",[968,100881,96573],{"id":96572},[973,100883,96576],{},[973,100885,100886,100888],{},[1487,100887,96581],{}," Quicksort chọn chốt ngẫu nhiên thuộc họ nào?",[96754,100890,100891],{"close-text":96756,"name":96757,"open-text":96758},[973,100892,100893],{},"Las Vegas: luôn sắp đúng, thời gian dao động.",[973,100895,100896,100898],{},[1487,100897,96904],{}," Bloom filter thuộc họ nào, thiên lệch phía nào?",[96754,100900,100901],{"close-text":96756,"name":96757,"open-text":96758},[973,100902,100903],{},"Monte Carlo thiên lệch một phía: trả lời \"không có\" thì luôn đúng, \"có\" thì có thể sai.",[973,100905,100906,100908],{},[1487,100907,97431],{}," 100 email, 5 rác. Mô hình đoán tất cả là thường. Accuracy và recall lớp rác?",[96754,100910,100911],{"close-text":96756,"name":96757,"open-text":96758},[973,100912,100913],{},"Accuracy 95%, recall lớp rác 0%.",[973,100915,100916,100918],{},[1487,100917,97800],{}," TP = 40, FP = 10, FN = 20. Tính precision, recall, F1.",[96754,100920,100921],{"close-text":96756,"name":96757,"open-text":96758},[973,100922,100923,100924,100981,100982,1656,101040,1517],{},"Precision ",[1023,100925,100927,100950],{"className":100926},[1026],[1023,100928,100930],{"className":100929},[1030],[1032,100931,100932],{"xmlns":1034},[1036,100933,100934,100947],{},[1039,100935,100936,100938,100940,100942,100944],{},[1051,100937,91917],{},[1042,100939,2461],{"mathvariant":2460},[1051,100941,13894],{},[1046,100943,2325],{},[1051,100945,100946],{},"0.8",[1058,100948,100949],{"encoding":1060},"40\u002F50 = 0.8",[1023,100951,100953,100972],{"className":100952,"ariaHidden":1066},[1065],[1023,100954,100956,100959,100963,100966,100969],{"className":100955},[1070],[1023,100957],{"className":100958,"style":1075},[1074],[1023,100960,100962],{"className":100961},[1079],"40\u002F50",[1023,100964],{"className":100965,"style":2355},[2354],[1023,100967,2325],{"className":100968},[2359],[1023,100970],{"className":100971,"style":2355},[2354],[1023,100973,100975,100978],{"className":100974},[1070],[1023,100976],{"className":100977,"style":10020},[1074],[1023,100979,100946],{"className":100980},[1079],", recall ",[1023,100983,100985,101009],{"className":100984},[1026],[1023,100986,100988],{"className":100987},[1030],[1032,100989,100990],{"xmlns":1034},[1036,100991,100992,101006],{},[1039,100993,100994,100996,100998,101001,101003],{},[1051,100995,91917],{},[1042,100997,2461],{"mathvariant":2460},[1051,100999,101000],{},"60",[1046,101002,24020],{},[1051,101004,101005],{},"0.667",[1058,101007,101008],{"encoding":1060},"40\u002F60 \\approx 0.667",[1023,101010,101012,101031],{"className":101011,"ariaHidden":1066},[1065],[1023,101013,101015,101018,101022,101025,101028],{"className":101014},[1070],[1023,101016],{"className":101017,"style":1075},[1074],[1023,101019,101021],{"className":101020},[1079],"40\u002F60",[1023,101023],{"className":101024,"style":2355},[2354],[1023,101026,24020],{"className":101027},[2359],[1023,101029],{"className":101030,"style":2355},[2354],[1023,101032,101034,101037],{"className":101033},[1070],[1023,101035],{"className":101036,"style":10020},[1074],[1023,101038,101005],{"className":101039},[1079],[1023,101041,101043,101083],{"className":101042},[1026],[1023,101044,101046],{"className":101045},[1030],[1032,101047,101048],{"xmlns":1034},[1036,101049,101050,101080],{},[1039,101051,101052,101058,101060,101062,101064,101066,101068,101070,101072,101075,101077],{},[17690,101053,101054,101056],{},[1042,101055,29697],{},[1051,101057,1053],{},[1046,101059,2325],{},[1051,101061,2457],{},[1046,101063,18118],{},[1051,101065,100946],{},[1046,101067,18118],{},[1051,101069,101005],{},[1042,101071,2461],{"mathvariant":2460},[1051,101073,101074],{},"1.467",[1046,101076,24020],{},[1051,101078,101079],{},"0.727",[1058,101081,101082],{"encoding":1060},"F_1 = 2 \\cdot 0.8 \\cdot 0.667 \u002F 1.467 \\approx 0.727",[1023,101084,101086,101141,101159,101177,101196],{"className":101085,"ariaHidden":1066},[1065],[1023,101087,101089,101092,101132,101135,101138],{"className":101088},[1070],[1023,101090],{"className":101091,"style":100530},[1074],[1023,101093,101095,101098],{"className":101094},[1079],[1023,101096,29697],{"className":101097,"style":37429},[1079,1080],[1023,101099,101101],{"className":101100},[2383],[1023,101102,101104,101124],{"className":101103},[2387,17732],[1023,101105,101107,101121],{"className":101106},[2391],[1023,101108,101110],{"className":101109,"style":54019},[2395],[1023,101111,101112,101115],{"style":100551},[1023,101113],{"className":101114,"style":2403},[2402],[1023,101116,101118],{"className":101117},[2407,2408,2409,2410],[1023,101119,1053],{"className":101120},[1079,2410],[1023,101122,17797],{"className":101123},[17796],[1023,101125,101127],{"className":101126},[2391],[1023,101128,101130],{"className":101129,"style":17804},[2395],[1023,101131],{},[1023,101133],{"className":101134,"style":2355},[2354],[1023,101136,2325],{"className":101137},[2359],[1023,101139],{"className":101140,"style":2355},[2354],[1023,101142,101144,101147,101150,101153,101156],{"className":101143},[1070],[1023,101145],{"className":101146,"style":10020},[1074],[1023,101148,2457],{"className":101149},[1079],[1023,101151],{"className":101152,"style":13790},[2354],[1023,101154,18118],{"className":101155},[13794],[1023,101157],{"className":101158,"style":13790},[2354],[1023,101160,101162,101165,101168,101171,101174],{"className":101161},[1070],[1023,101163],{"className":101164,"style":10020},[1074],[1023,101166,100946],{"className":101167},[1079],[1023,101169],{"className":101170,"style":13790},[2354],[1023,101172,18118],{"className":101173},[13794],[1023,101175],{"className":101176,"style":13790},[2354],[1023,101178,101180,101183,101187,101190,101193],{"className":101179},[1070],[1023,101181],{"className":101182,"style":1075},[1074],[1023,101184,101186],{"className":101185},[1079],"0.667\u002F1.467",[1023,101188],{"className":101189,"style":2355},[2354],[1023,101191,24020],{"className":101192},[2359],[1023,101194],{"className":101195,"style":2355},[2354],[1023,101197,101199,101202],{"className":101198},[1070],[1023,101200],{"className":101201,"style":10020},[1074],[1023,101203,101079],{"className":101204},[1079],[973,101206,101207,101209],{},[1487,101208,97983],{}," Biến thuật toán Las Vegas thành Monte Carlo bằng cách nào?",[96754,101211,101212],{"close-text":96756,"name":96757,"open-text":96758},[973,101213,101214],{},"Giới hạn số bước chạy. Hết giới hạn mà chưa xong thì trả một đáp án đoán.",[968,101216,98220],{"id":98219},[986,101218,101219,101222,101225,101228,101231],{},[989,101220,101221],{},"Bài toán quyết định nhị phân là khung chung để định nghĩa giải thuật ngẫu nhiên.",[989,101223,101224],{},"Las Vegas luôn đúng nhưng tốn tài nguyên bất định; Monte Carlo đúng giờ nhưng đáp án có thể sai.",[989,101226,101227],{},"Accuracy là tỉ lệ đoán đúng, dễ gây hiểu lầm trên dữ liệu lệch.",[989,101229,101230],{},"Precision và recall đo từng phía, giằng co nhau trên đường cong đánh đổi.",[989,101232,101233],{},"Giải thuật thiên lệch một phía như Bloom có recall 100 phần trăm, muốn tốt hơn chỉ còn cách thêm tài nguyên.",{"title":1357,"searchDepth":68,"depth":68,"links":101235},[101236,101237,101238,101239,101240,101241,101242,101243,101244,101245,101246],{"id":90890,"depth":68,"text":90891},{"id":100073,"depth":68,"text":100074},{"id":100178,"depth":68,"text":100179},{"id":100337,"depth":68,"text":100338},{"id":100365,"depth":68,"text":100366},{"id":100393,"depth":68,"text":100394},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Bài toán quyết định, Las Vegas và Monte Carlo, ba độ đo accuracy-precision-recall và quan hệ đánh đổi giữa chúng.",{},{"title":22,"description":101247},[101251,101252,101253,101254,7],"ngau-nhien","las-vegas","monte-carlo","do-do","BVqMnPkBL8-j41StCFWWhswHV0LC5qGoI-y709wiLmA",{"id":101257,"title":26,"body":101258,"category":7,"day":3047,"description":101613,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":101614,"navigation":2723,"outcomes":3047,"path":27,"prerequisites":3047,"seo":101615,"stem":28,"tags":101616,"__hash__":101619},"fundamentals\u002Ffundamentals\u002Fnguyen-ly-thiet-ke-huong-doi-tuong.md",{"type":965,"value":101259,"toc":101600},[101260,101262,101265,101268,101271,101275,101278,101281,101284,101287,101290,101294,101297,101300,101303,101306,101309,101312,101315,101319,101322,101325,101328,101331,101334,101337,101340,101344,101347,101350,101353,101356,101359,101362,101365,101373,101384,101430,101434,101437,101440,101443,101446,101449,101452,101454,101457,101460,101463,101466,101469,101472,101474,101477,101480,101483,101486,101489,101491,101494,101497,101500,101502,101504,101513,101518,101528,101540,101550,101555,101563,101571,101576,101581,101583],[968,101261,90891],{"id":90890},[973,101263,101264],{},"Trước khi học mẫu thiết kế cụ thể, cần nắm nguyên lý đứng sau chúng. Mẫu chỉ là cách áp dụng nguyên lý vào tình huống cụ thể.",[973,101266,101267],{},"Bài này tổng hợp các nguyên lý thiết kế, gồm đủ năm chữ SOLID. Kèm tư duy về quan hệ đối tượng và mục tiêu ghép lỏng.",[973,101269,101270],{},"Toàn bộ trình bày ở mức lý thuyết thuần túy. Không dạy bất kỳ mẫu cụ thể nào ở đây.",[968,101272,101274],{"id":101273},"_2-đóng-gói-cái-biến-thiên","2. Đóng gói cái biến thiên",[973,101276,101277],{},"Nguyên lý đầu tiên: xác định khía cạnh hay biến thiên rồi đóng gói nó lại. Mọi thiết kế tốt đều bắt đầu từ quan sát cái gì đổi theo thời gian.",[973,101279,101280],{},"Ví dụ: cách bay và cách kêu của từng loài vịt. Chính sách giá đổi theo mùa, quy tắc kiểm tra đổi theo vùng miền.",[973,101282,101283],{},"Phần ổn định giữ nguyên. Phần biến thiên tách ra, đóng sau ranh giới rõ ràng.",[973,101285,101286],{},"Khi yêu cầu đổi, thay đổi bị giam trong phạm vi hẹp. Thay vì lan khắp hệ thống.",[973,101288,101289],{},"Hệ quả: thiết kế tốt không đoán trước mọi thay đổi. Nó tổ chức mã sao cho thay đổi xảy ra nơi đã chuẩn bị sẵn.",[968,101291,101293],{"id":101292},"_3-lập-trình-theo-giao-diện-và-ưu-tiên-hợp-thành","3. Lập trình theo giao diện và ưu tiên hợp thành",[973,101295,101296],{},"Nguyên lý thứ hai: lập trình theo giao diện, không theo cài đặt. Mã phía trên chỉ biết vai trò và hợp đồng hành vi.",[973,101298,101299],{},"Nhờ đó ta thay cài đặt sau vai trò mà phía trên không hay biết. Giống như remote chỉ biết nút bấm, không cần biết ruột máy nào.",[973,101301,101302],{},"Nguyên lý thứ ba: ưu tiên hợp thành hơn kế thừa. Kế thừa mô tả quan hệ IS-A: một lớp là một loại của lớp khác.",[973,101304,101305],{},"Nó ràng buộc hai lớp theo chiều dọc cứng nhắc. Đổi lớp cha lan xuống mọi lớp con.",[973,101307,101308],{},"Hợp thành mô tả quan hệ HAS-A: một đối tượng có một đối tượng khác đóng vai hành vi. Vai trò này thay được lúc đang chạy.",[973,101310,101311],{},"Hai nguyên lý đi thành cặp. Giao diện định nghĩa vai trò, hợp thành lắp ráp vai trò.",[973,101313,101314],{},"Giống như ráp xe bằng phụ tùng chuẩn. Thay vì đúc nguyên chiếc không sửa được.",[968,101316,101318],{"id":101317},"_4-ghép-lỏng-và-nguyên-tắc-hollywood","4. Ghép lỏng và nguyên tắc Hollywood",[973,101320,101321],{},"Nguyên lý thứ tư: phấn đấu cho thiết kế ghép lỏng. Hai thành phần ghép lỏng tương tác nhưng ít biết về nhau.",[973,101323,101324],{},"Mỗi bên chỉ biết vừa đủ để phối hợp. Không biết chi tiết nội tại của bên kia.",[973,101326,101327],{},"Lợi ích là đổi một bên ít gây chấn động bên còn lại. Mỗi bên tiến hóa độc lập.",[973,101329,101330],{},"Ví dụ: bên phát hành thông tin và bên theo dõi thông tin. Bên phát hành không cần biết có bao nhiêu người nghe.",[973,101332,101333],{},"Không cần biết họ là ai, làm gì với thông tin. Chỉ cần biết cơ chế đăng ký và thông báo chung.",[973,101335,101336],{},"Nguyên lý Hollywood: đừng gọi chúng tôi, chúng tôi sẽ gọi bạn. Thành phần mức thấp đăng ký vào khung rồi chờ khung gọi lại.",[973,101338,101339],{},"Nhờ đó thành phần mức cao giữ quyền điều phối luồng chung. Các thành phần mức thấp vẫn đóng góp hành vi riêng.",[968,101341,101343],{"id":101342},"_5-năm-nguyên-lý-solid","5. Năm nguyên lý SOLID",[973,101345,101346],{},"Nguyên lý đơn trách nhiệm: một lớp chỉ nên có một lý do để thay đổi. Lớp gánh hai việc thì sửa việc này dễ phá việc kia.",[973,101348,101349],{},"Hai nhóm yêu cầu khác nhau giằng co cùng một đơn vị mã. Tách mỗi trách nhiệm riêng giúp thay đổi khoanh vùng và kiểm thử độc lập.",[973,101351,101352],{},"Nguyên lý đóng mở: mở cho mở rộng, đóng cho sửa đổi. Hành vi mới thêm bằng đơn vị mới, mã cũ đã kiểm chứng không phải mở ra sửa.",[973,101354,101355],{},"Đây là nguyên lý khó nhất. Nó đòi đoán đúng điểm biến thiên ngay từ đầu.",[973,101357,101358],{},"Thước đo trưởng thành của thiết kế: đón yêu cầu mới bằng thêm mới thay vì sửa cũ. Nguyên lý đảo ngược phụ thuộc: phụ thuộc vào trừu tượng, đừng phụ thuộc lớp cụ thể.",[973,101360,101361],{},"Cả mô đun mức cao chứa chính sách lẫn mức thấp chứa chi tiết đều phụ thuộc trừu tượng ở giữa. Nhờ đó chi tiết thay được mà chính sách không lung lay.",[973,101363,101364],{},"Giống như ổ cắm điện chung cho mọi hãng sạc. Chuẩn cắm ổn định, thiết bị đổi tùy ý.",[973,101366,101367,101368,5073,101370,101372],{},"Nguyên lý thay thế Liskov (chữ L): lớp con phải dùng được ở mọi chỗ lớp cha được dùng mà không làm hỏng kỳ vọng. Ví dụ kinh điển: ",[992,101369,5072],{},[992,101371,5058],{},". Đoạn mã đặt rộng 5, cao 4 rồi kỳ vọng diện tích 20 sẽ sai với hình vuông. Kế thừa đúng cú pháp nhưng sai hành vi.",[973,101374,101375,101376,101379,101380,101383],{},"Nguyên lý tách giao diện (chữ I): đừng ép lớp phụ thuộc vào phương thức nó không dùng. Máy in rẻ không nên phải cài ",[992,101377,101378],{},"fax()"," rỗng chỉ vì giao diện ",[992,101381,101382],{},"IMachine"," gom cả in, quét, fax. Tách thành nhiều giao diện nhỏ.",[1099,101385,101386,101394],{},[1102,101387,101388],{},[1105,101389,101390,101392],{},[1108,101391,4747],{},[1108,101393,4750],{},[1118,101395,101396,101402,101409,101416,101423],{},[1105,101397,101398,101400],{},[1123,101399,4757],{},[1123,101401,4760],{},[1105,101403,101404,101406],{},[1123,101405,1044],{},[1123,101407,101408],{},"Thêm tính năng có phải sửa mã cũ không?",[1105,101410,101411,101413],{},[1123,101412,4772],{},[1123,101414,101415],{},"Thay lớp cha bằng lớp con có gây bất ngờ không?",[1105,101417,101418,101420],{},[1123,101419,38218],{},[1123,101421,101422],{},"Có lớp nào cài phương thức rỗng cho đủ giao diện không?",[1105,101424,101425,101427],{},[1123,101426,4780],{},[1123,101428,101429],{},"Mô đun chính sách đang phụ thuộc lớp cụ thể hay trừu tượng?",[968,101431,101433],{"id":101432},"_6-nguyên-tắc-ít-hiểu-biết-nhất-và-quan-hệ-đối-tượng","6. Nguyên tắc ít hiểu biết nhất và quan hệ đối tượng",[973,101435,101436],{},"Nguyên tắc ít hiểu biết nhất còn gọi là luật Demeter. Mỗi đơn vị chỉ nên nói chuyện với bạn bè thân thiết.",[973,101438,101439],{},"Tránh dây dưa với người lạ. Thực tế là hạn chế số đối tác tương tác trực tiếp.",[973,101441,101442],{},"Đừng thò tay qua nhiều tầng trung gian để chạm đối tượng xa. Ít đường phụ thuộc thì thay đổi ít lan truyền hơn.",[973,101444,101445],{},"Đối chiếu hai quan hệ nền tảng. IS-A diễn đạt bằng kế thừa, hợp khi phân loại bền vững.",[973,101447,101448],{},"HAS-A diễn đạt bằng hợp thành, hợp khi hành vi biến thiên hoặc cần thay lúc chạy. Quy tắc ngón tay cái: mặc định ưu tiên HAS-A.",[973,101450,101451],{},"Chỉ dùng IS-A khi quan hệ phân loại thực sự bền và đã kiểm chứng. Giống như chỉ đúc khuôn khi mẫu đã chốt, còn thử nghiệm thì ráp modul.",[968,101453,96352],{"id":96351},[973,101455,101456],{},"Các nguyên lý bổ sung chứ không thay thế nhau. Đóng gói chỉ ra cái gì cần tách.",[973,101458,101459],{},"Giao diện và hợp thành chỉ ra tách bằng cơ chế nào. Ghép lỏng và ít hiểu biết đo chất lượng quan hệ sau khi tách.",[973,101461,101462],{},"Ba nguyên lý SOLID đặt ràng buộc để thiết kế không thoái hóa theo thời gian. Đánh đổi chung là khái niệm phức tạp tăng lên.",[973,101464,101465],{},"Thêm tầng trừu tượng, thêm đơn vị, thêm quan hệ gián tiếp. Với bài nhỏ và ổn định, áp dụng máy móc mọi nguyên lý thành quan liêu.",[973,101467,101468],{},"Nghệ thuật nằm ở liều lượng. Càng dự báo nhiều biến thiên thì càng đầu tư trừu tượng.",[973,101470,101471],{},"Phần ổn định thì giữ đơn giản. Giống như không cần khung thép cho chòi lá.",[968,101473,96362],{"id":96361},[973,101475,101476],{},"Thứ nhất: nhầm lập trình theo giao diện với từ khóa interface của ngôn ngữ. Tinh thần thật là phụ thuộc vào hợp đồng hành vi.",[973,101478,101479],{},"Thứ hai: lạm dụng kế thừa cho mọi tái sử dụng. Cây kế thừa giòn, đổi cha gây chấn động toàn bộ con.",[973,101481,101482],{},"Thứ ba: hiểu nguyên lý đóng mở như cấm sửa mã. Ý đúng là tổ chức để yêu cầu mới thường đáp ứng bằng thêm mới.",[973,101484,101485],{},"Thứ tư: áp dụng luật Demeter cực đoan thành thêm tầng trung gian vô tội vạ. Hệ thống khó theo dõi hơn thay vì đơn giản hơn.",[973,101487,101488],{},"Thứ năm: thuộc tên nguyên lý mà không nhận ra chúng trong mã thật. Đó là biết chữ mà không biết nghĩa.",[968,101490,96563],{"id":96562},[973,101492,101493],{},"Các nguyên lý này là bộ tiêu chí đánh giá mọi thiết kế. Mỗi khi xem một mẫu cụ thể, câu hỏi đầu tiên là nó thể hiện nguyên lý nào.",[973,101495,101496],{},"Về lâu dài, nguyên lý bền hơn mẫu. Mẫu cụ thể có thể lỗi thời theo công nghệ.",[973,101498,101499],{},"Nhưng tư duy đóng gói biến thiên và ghép lỏng áp dụng cho mọi hệ thống. Từ ứng dụng nhỏ tới nền tảng lớn.",[968,101501,96573],{"id":96572},[973,101503,96576],{},[973,101505,101506,101508,101509,101512],{},[1487,101507,96581],{}," Lớp ",[992,101510,101511],{},"Report"," vừa tính số liệu vừa xuất PDF. Vi phạm nguyên lý nào?",[96754,101514,101515],{"close-text":96756,"name":96757,"open-text":96758},[973,101516,101517],{},"Đơn trách nhiệm (S): có 2 lý do để đổi. Tách thành lớp tính toán và lớp xuất.",[973,101519,101520,101522,101523,2528,101525,101527],{},[1487,101521,96904],{}," Thêm phương thức thanh toán mới phải sửa ",[992,101524,7335],{},[992,101526,5015],{},". Vi phạm nguyên lý nào, sửa ra sao?",[96754,101529,101530],{"close-text":96756,"name":96757,"open-text":96758},[973,101531,101532,101533,101536,101537,101539],{},"Đóng mở (O). Tạo giao diện ",[992,101534,101535],{},"PaymentMethod",", mỗi phương thức một lớp, ",[992,101538,5015],{}," chỉ gọi giao diện.",[973,101541,101542,101544,101545,5073,101547,101549],{},[1487,101543,97431],{}," Vì sao ",[992,101546,5072],{},[992,101548,5058],{}," vi phạm Liskov?",[96754,101551,101552],{"close-text":96756,"name":96757,"open-text":96758},[973,101553,101554],{},"Mã đặt rộng và cao khác nhau rồi kỳ vọng diện tích bằng tích hai số sẽ sai với hình vuông.",[973,101556,101557,2308,101559,101562],{},[1487,101558,97800],{},[992,101560,101561],{},"order.getCustomer().getAddress().getCity()"," vi phạm nguyên lý nào?",[96754,101564,101565],{"close-text":96756,"name":96757,"open-text":96758},[973,101566,101567,101568,1517],{},"Luật Demeter (ít hiểu biết nhất): gọi xuyên qua nhiều đối tượng lạ. Nên có ",[992,101569,101570],{},"order.shippingCity()",[973,101572,101573,101575],{},[1487,101574,97983],{}," Khi nào nên dùng kế thừa (IS-A) thay vì hợp thành (HAS-A)?",[96754,101577,101578],{"close-text":96756,"name":96757,"open-text":96758},[973,101579,101580],{},"Khi quan hệ phân loại thật sự bền và lớp con thay thế được lớp cha ở mọi chỗ. Còn hành vi hay đổi thì dùng hợp thành.",[968,101582,98220],{"id":98219},[986,101584,101585,101588,101591,101594,101597],{},[989,101586,101587],{},"Các nguyên lý hợp thành một hệ tư duy thống nhất, từ đóng gói biến thiên tới SOLID.",[989,101589,101590],{},"Giao diện và hợp thành đi thành cặp; HAS-A linh hoạt hơn IS-A cho hành vi biến thiên.",[989,101592,101593],{},"Ghép lỏng và Hollywood phân chia quyền điều khiển rõ ràng giữa các thành phần.",[989,101595,101596],{},"SOLID: một lớp một việc, thêm mới thay vì sửa cũ, lớp con thay được lớp cha, giao diện nhỏ, phụ thuộc trừu tượng.",[989,101598,101599],{},"Áp dụng đúng liều theo mức biến thiên dự báo của bài toán.",{"title":1357,"searchDepth":68,"depth":68,"links":101601},[101602,101603,101604,101605,101606,101607,101608,101609,101610,101611,101612],{"id":90890,"depth":68,"text":90891},{"id":101273,"depth":68,"text":101274},{"id":101292,"depth":68,"text":101293},{"id":101317,"depth":68,"text":101318},{"id":101342,"depth":68,"text":101343},{"id":101432,"depth":68,"text":101433},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Chín nguyên lý thiết kế phần mềm, SOLID, quan hệ HAS-A và IS-A cùng tư duy ghép lỏng.",{},{"title":26,"description":101613},[101617,5199,101618,99049,7],"oop","nguyen-ly","K14T8hUKqImH4KYEZPpwDQ-WA7PhW-Au6kPxOoZ3Zng",{"id":101621,"title":30,"body":101622,"category":7,"day":3047,"description":101944,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":101945,"navigation":2723,"outcomes":3047,"path":31,"prerequisites":3047,"seo":101946,"stem":32,"tags":101947,"__hash__":101951},"fundamentals\u002Ffundamentals\u002Fnhap-mon-design-patterns.md",{"type":965,"value":101623,"toc":101931},[101624,101626,101629,101632,101635,101638,101642,101645,101648,101651,101654,101657,101660,101663,101667,101670,101673,101676,101679,101683,101686,101736,101739,101742,101745,101748,101751,101754,101757,101761,101764,101767,101770,101773,101776,101779,101782,101785,101789,101792,101795,101798,101801,101804,101807,101809,101812,101815,101818,101821,101824,101826,101829,101832,101835,101838,101841,101843,101846,101849,101852,101855,101857,101859,101864,101869,101874,101879,101884,101889,101894,101899,101907,101912,101914],[968,101625,90891],{"id":90890},[973,101627,101628],{},"Lập trình viên gặp lại bài toán giống nhau ở nhiều dự án. Mỗi lần giải lại từ đầu vừa tốn công vừa lặp sai lầm cũ.",[973,101630,101631],{},"Mẫu thiết kế ra đời từ quan sát giản dị: ai đó đã giải bài của bạn rồi. Lời giải đó ghi lại được để tái sử dụng.",[973,101633,101634],{},"Bài này trình bày ở mức meta. Mẫu là gì, vì sao từ vựng chung quan trọng, cấu trúc một mẫu ra sao.",[973,101636,101637],{},"Cách học và dùng mẫu đúng thế nào, cùng tư duy siêu nhận thức khi học. Bài này không dạy mẫu cụ thể nào.",[968,101639,101641],{"id":101640},"_2-mẫu-là-gì-và-không-là-gì","2. Mẫu là gì và không là gì",[973,101643,101644],{},"Tuyên bố mở đầu: ai đó đã giải quyết vấn đề của bạn rồi. Thay vì phát minh lại, hãy học từ người đã vấp ngã và chắt lọc lời giải tốt.",[973,101646,101647],{},"Mẫu là mô tả đã kiểm chứng của lời giải. Dành cho bài toán thiết kế lặp đi lặp lại trong một ngữ cảnh nhất định.",[973,101649,101650],{},"Ba thành phần làm nên một mẫu: tên gọi, bài toán cùng ngữ cảnh, và lời giải đúc kết. Điều mẫu không phải cũng quan trọng không kém.",[973,101652,101653],{},"Mẫu không phải đoạn mã chép vào là chạy. Cùng một mẫu cài đặt khác nhau tùy ngôn ngữ và tình huống.",[973,101655,101656],{},"Mẫu không phải công thức máy móc áp mọi nơi. Dùng sai ngữ cảnh gây hại nhiều hơn lợi.",[973,101658,101659],{},"Quy tắc ba lần thể hiện tinh thần này. Đừng phong thủ thuật thành mẫu cho tới khi thấy nó thành công ít nhất ba lần thực tế.",[973,101661,101662],{},"Giống như công thức nấu ăn: tùy bếp mà nêm nếm. Không ai bê nguyên xi mọi gia vị.",[968,101664,101666],{"id":101665},"_3-từ-vựng-chung-và-sức-mạnh-của-tên-gọi","3. Từ vựng chung và sức mạnh của tên gọi",[973,101668,101669],{},"Lợi ích đầu tiên là từ vựng chung với lập trình viên khác. Khi cả nhóm biết tên mẫu, một câu ngắn thay cả đoạn giải thích dài.",[973,101671,101672],{},"Sức mạnh tên gọi nằm ở mật độ tri thức. Mỗi cái tên gói bài toán, ngữ cảnh, lời giải, hệ quả và đánh đổi đã biết.",[973,101674,101675],{},"Bài này cảnh báo đừng coi thường từ vựng chung. Cùng một ngôn ngữ mẫu thì thảo luận thiết kế nhanh vọt lên.",[973,101677,101678],{},"Hiểu lầm cũng giảm hẳn. Giống như tên món ăn: gọi một từ cả quán đều hiểu.",[968,101680,101682],{"id":101681},"_4-cấu-trúc-của-một-mẫu-và-bản-đồ-các-mẫu","4. Cấu trúc của một mẫu và bản đồ các mẫu",[973,101684,101685],{},"Mỗi mẫu trình bày theo cấu trúc ổn định. Nhờ đó người đọc tra cứu và so sánh dễ dàng.",[1099,101687,101688,101696],{},[1102,101689,101690],{},[1105,101691,101692,101694],{},[1108,101693,90750],{},[1108,101695,87021],{},[1118,101697,101698,101706,101713,101721,101729],{},[1105,101699,101700,101703],{},[1123,101701,101702],{},"Tên và phân loại",[1123,101704,101705],{},"Đặt mẫu vào bản đồ chung",[1105,101707,101708,101710],{},[1123,101709,30679],{},[1123,101711,101712],{},"Tình huống lặp lại và lực giằng co",[1105,101714,101715,101718],{},[1123,101716,101717],{},"Lời giải",[1123,101719,101720],{},"Cách sắp xếp thành phần, độc lập ngôn ngữ",[1105,101722,101723,101726],{},[1123,101724,101725],{},"Hệ quả",[1123,101727,101728],{},"Kết quả và đánh đổi khi áp dụng",[1105,101730,101731,101733],{},[1123,101732,1433],{},[1123,101734,101735],{},"Tình huống cụ thể giúp ghi nhớ",[973,101737,101738],{},"Không mẫu nào chỉ có lợi mà không có giá. Phần hệ quả bắt buộc phải đọc kỹ.",[973,101740,101741],{},"Kho mẫu tổ chức thành ba nhóm lớn. Nhóm khởi tạo lo việc tạo đối tượng.",[973,101743,101744],{},"Nhóm cấu trúc lo ghép lớp và đối tượng thành cấu trúc lớn hơn. Nhóm hành vi lo phân phối trách nhiệm và giao tiếp.",[973,101746,101747],{},"Bản đồ này giúp định vị mẫu mới. Bài toán về cách tạo thì nghĩ nhóm khởi tạo.",[973,101749,101750],{},"Bài toán về cách ghép thì nghĩ nhóm cấu trúc. Bài toán về phối hợp thì nghĩ nhóm hành vi.",[973,101752,101753],{},"Ngoài ra còn khái niệm phản mẫu. Đó là lời giải trông hợp lý nhưng thực chất gây hại.",[973,101755,101756],{},"Cấu trúc mô tả phản mẫu gồm tên, bài toán, lời giải sai lầm và hậu quả. Học nó giúp nhận diện và tránh từ sớm.",[968,101758,101760],{"id":101759},"_5-cách-học-và-dùng-mẫu-đúng","5. Cách học và dùng mẫu đúng",[973,101762,101763],{},"Phương pháp học đi từ cụ thể tới trừu tượng. Bắt đầu bằng tình huống đời thực dễ hình dung.",[973,101765,101766],{},"Quan sát thiết kế ngây thơ bộc lộ vấn đề gì. Xem mẫu hóa giải từng vấn đề ra sao.",[973,101768,101769],{},"Cuối cùng rút ra nguyên lý tổng quát. Triết lý đằng sau: não nhớ tốt hơn khi phải suy nghĩ và làm.",[973,101771,101772],{},"Đọc thụ động lướt qua rất nhanh quên. Giống như học bơi phải xuống nước, không học trên bờ.",[973,101774,101775],{},"Về cách dùng, có bốn điểm. Một là dùng khi bài toán thực sự khớp ngữ cảnh, không dùng vì mẫu nghe hay.",[973,101777,101778],{},"Hai là giữ thiết kế đơn giản nhất có thể. Đưa mẫu vào khi áp lực thay đổi xuất hiện.",[973,101780,101781],{},"Ba là luôn đọc phần hệ quả trước khi áp dụng. Mỗi mẫu đều có giá phải trả.",[973,101783,101784],{},"Bốn là ghi lại quyết định dùng mẫu nào ở đâu. Người tới sau đọc sẽ hiểu ý đồ.",[968,101786,101788],{"id":101787},"_6-siêu-nhận-thức-học-cách-học-mẫu","6. Siêu nhận thức: học cách học mẫu",[973,101790,101791],{},"Điểm đặc sắc là bàn công khai về siêu nhận thức. Tức suy nghĩ về cách mình học.",[973,101793,101794],{},"Đa số chưa từng học lý thuyết học tập. Nên hay dùng cách kém hiệu quả như đọc lướt rồi tưởng đã hiểu.",[973,101796,101797],{},"Cách thay thế là học chủ động. Tự đặt câu hỏi trước khi đọc đáp án.",[973,101799,101800],{},"Tự giải thích lại bằng lời của mình. Xen kẽ nhiều loại bài khác nhau, quay lại ôn sau một khoảng thời gian.",[973,101802,101803],{},"Áp vào học mẫu, siêu nhận thức là theo dõi mức của mình. Mới nghe tên, hiểu ý tưởng, áp dụng được, hay đã nhận ra tình huống dùng trong dự án thực.",[973,101805,101806],{},"Học nhóm qua thảo luận từ vựng chung rất hiệu quả. Giải thích mẫu cho người khác chính là bài kiểm tra hiểu sâu nhất.",[968,101808,96352],{"id":96351},[973,101810,101811],{},"Học mẫu kiểu này đổi tốc độ đọc lấy độ sâu hiểu. Đọc chậm hơn nhưng nhớ lâu và dùng được.",[973,101813,101814],{},"Dùng mẫu đổi đơn giản trước mắt lấy linh hoạt lâu dài. Mã có mẫu phức tạp hơn mã ngây thơ.",[973,101816,101817],{},"Nhưng khi yêu cầu đổi, mã có mẫu rẻ hơn nhiều. Từ vựng chung đổi công học thuật ngữ lấy tốc độ giao tiếp.",[973,101819,101820],{},"Tốn công học tên ban đầu, mỗi thảo luận sau đều nhanh hơn. Nhận diện phản mẫu đổi khiêm tốn lấy an toàn.",[973,101822,101823],{},"Dám thừa nhận lời giải ưa thích có thể sai để tránh hậu quả lớn hơn.",[968,101825,96362],{"id":96361},[973,101827,101828],{},"Thứ nhất là sốt mẫu: thấy mẫu nào cũng muốn dùng. Rải mẫu khắp thiết kế còn đơn giản.",[973,101830,101831],{},"Thứ hai là học tên mà không học ngữ cảnh. Nhắc vanh vách tên mẫu nhưng áp sai chỗ.",[973,101833,101834],{},"Thứ ba là coi mẫu là mã chép sẵn. Thực ra mẫu là ý tưởng cần điều chỉnh cho tình huống.",[973,101836,101837],{},"Thứ tư là đọc thụ động, lướt ví dụ mà không tự làm. Rồi tưởng mình đã biết.",[973,101839,101840],{},"Thứ năm là bỏ qua phần hệ quả. Chỉ thấy lợi mà không thấy giá của mẫu.",[968,101842,96563],{"id":96562},[973,101844,101845],{},"Tư duy meta dùng suốt khóa học. Mỗi khi gặp mẫu cụ thể, hãy hỏi bốn điều.",[973,101847,101848],{},"Tên gọi của nó là gì? Ngữ cảnh nào thì dùng? Hệ quả và cái giá ra sao? Nó thể hiện nguyên lý thiết kế nào?",[973,101850,101851],{},"Từ vựng chung dùng ngay trong thảo luận nhóm và phỏng vấn. Gọi đúng tên giúp cuộc trò chuyện ở tầm thiết kế.",[973,101853,101854],{},"Phương pháp học chủ động và siêu nhận thức áp dụng cho mọi chủ đề khó. Không riêng gì mẫu thiết kế.",[968,101856,96573],{"id":96572},[973,101858,96576],{},[973,101860,101861,101863],{},[1487,101862,96581],{}," Ba thành phần cốt lõi của một mẫu là gì?",[96754,101865,101866],{"close-text":96756,"name":96757,"open-text":96758},[973,101867,101868],{},"Tên gọi, bài toán cùng ngữ cảnh, lời giải. Kèm hệ quả và đánh đổi.",[973,101870,101871,101873],{},[1487,101872,96904],{}," Ba nhóm mẫu là gì? Cho mỗi nhóm 1 ví dụ.",[96754,101875,101876],{"close-text":96756,"name":96757,"open-text":96758},[973,101877,101878],{},"Khởi tạo (Factory Method), cấu trúc (Decorator), hành vi (Observer).",[973,101880,101881,101883],{},[1487,101882,97431],{}," Phản mẫu là gì? Cho 1 ví dụ.",[96754,101885,101886],{"close-text":96756,"name":96757,"open-text":96758},[973,101887,101888],{},"Lời giải trông hợp lý nhưng gây hại. Ví dụ lớp chúa (God object) ôm mọi việc.",[973,101890,101891,101893],{},[1487,101892,97800],{}," Quy tắc ba lần nói gì?",[96754,101895,101896],{"close-text":96756,"name":96757,"open-text":96758},[973,101897,101898],{},"Chỉ coi một cách làm là mẫu khi đã thấy nó thành công ít nhất 3 lần trong thực tế.",[973,101900,101901,101903,101904,101906],{},[1487,101902,97983],{}," Khi nào ",[1487,101905,41587],{}," nên dùng mẫu?",[96754,101908,101909],{"close-text":96756,"name":96757,"open-text":96758},[973,101910,101911],{},"Khi bài toán nhỏ, chỉ có 1 biến thể và không có dấu hiệu sẽ đổi. Thêm mẫu lúc đó chỉ làm mã khó đọc.",[968,101913,98220],{"id":98219},[986,101915,101916,101919,101922,101925,101928],{},[989,101917,101918],{},"Mẫu là lời giải đã kiểm chứng cho bài toán lặp lại trong một ngữ cảnh, phát hiện từ thực tiễn.",[989,101920,101921],{},"Giá trị lớn nhất là từ vựng chung giúp giao tiếp ở tầm thiết kế.",[989,101923,101924],{},"Mỗi mẫu gồm tên, bài toán, lời giải và hệ quả; kho mẫu chia ba nhóm khởi tạo, cấu trúc, hành vi.",[989,101926,101927],{},"Học hiệu quả bằng cách chủ động từ cụ thể tới trừu tượng, dùng mẫu đúng bằng cách khớp ngữ cảnh.",[989,101929,101930],{},"Theo dõi mức hiểu của bản thân bằng siêu nhận thức và đọc kỹ hệ quả trước khi áp dụng.",{"title":1357,"searchDepth":68,"depth":68,"links":101932},[101933,101934,101935,101936,101937,101938,101939,101940,101941,101942,101943],{"id":90890,"depth":68,"text":90891},{"id":101640,"depth":68,"text":101641},{"id":101665,"depth":68,"text":101666},{"id":101681,"depth":68,"text":101682},{"id":101759,"depth":68,"text":101760},{"id":101787,"depth":68,"text":101788},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Mẫu thiết kế là gì, từ vựng chung, cấu trúc của một mẫu, cách học và dùng mẫu đúng, cùng siêu nhận thức về học tập.",{},{"title":30,"description":101944},[101948,101949,101950,7],"design-patterns","tu-vung","phuong-phap","Vr6mMe-BqZRemrnfK6xoMHkp7lHPouCOv5KXswlsFmY",{"id":101953,"title":34,"body":101954,"category":7,"day":3047,"description":103071,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":103072,"navigation":2723,"outcomes":3047,"path":35,"prerequisites":3047,"seo":103073,"stem":36,"tags":103074,"__hash__":103079},"fundamentals\u002Ffundamentals\u002Fp-np-va-do-kho.md",{"type":965,"value":101955,"toc":103059},[101956,101958,101961,101964,101967,101971,102106,102113,102150,102185,102188,102325,102328,102332,102367,102377,102380,102383,102387,102393,102402,102408,102414,102543,102623,102626,102630,102633,102636,102639,102642,102645,102647,102650,102653,102656,102659,102662,102664,102667,102670,102673,102680,102683,102685,102688,102691,102694,102696,102698,102703,102773,102778,102783,102788,102822,102827,102835,102886,102966,102968],[968,101957,90891],{"id":90890},[973,101959,101960],{},"Không phải bài toán nào cũng khó như nhau. Biết bài của mình khó cỡ nào giúp chọn chiến lược đúng.",[973,101962,101963],{},"Bài dễ thì tìm lời giải tối ưu. Bài khó thì chấp nhận lời giải khả thi.",[973,101965,101966],{},"Cộng đồng phân loại độ khó thành P, NP, NP-complete và NP-hard. Câu hỏi P có bằng NP không treo giải một triệu đô la.",[968,101968,101970],{"id":101969},"_2-thuật-toán-đa-thức-bài-toán-quyết-định-và-chứng-chỉ","2. Thuật toán đa thức, bài toán quyết định và chứng chỉ",[973,101972,101973,101974,7386,102048,102076,102077,102105],{},"Thuật toán đa thức có thời gian chạy ",[1023,101975,101977,102001],{"className":101976},[1026],[1023,101978,101980],{"className":101979},[1030],[1032,101981,101982],{"xmlns":1034},[1036,101983,101984,101998],{},[1039,101985,101986,101988,101990,101996],{},[1042,101987,1044],{},[1046,101989,1049],{"stretchy":1048},[2327,101991,101992,101994],{},[1042,101993,1262],{},[1042,101995,4022],{},[1046,101997,1056],{"stretchy":1048},[1058,101999,102000],{"encoding":1060},"O(n^k)",[1023,102002,102004],{"className":102003,"ariaHidden":1066},[1065],[1023,102005,102007,102010,102013,102016,102045],{"className":102006},[1070],[1023,102008],{"className":102009,"style":34041},[1074],[1023,102011,1044],{"className":102012,"style":1081},[1079,1080],[1023,102014,1049],{"className":102015},[1085],[1023,102017,102019,102022],{"className":102018},[1079],[1023,102020,1262],{"className":102021},[1079,1080],[1023,102023,102025],{"className":102024},[2383],[1023,102026,102028],{"className":102027},[2387],[1023,102029,102031],{"className":102030},[2391],[1023,102032,102034],{"className":102033,"style":34075},[2395],[1023,102035,102036,102039],{"style":2398},[1023,102037],{"className":102038,"style":2403},[2402],[1023,102040,102042],{"className":102041},[2407,2408,2409,2410],[1023,102043,4022],{"className":102044,"style":4066},[1079,1080,2410],[1023,102046,1056],{"className":102047},[1092],[1023,102049,102051,102064],{"className":102050},[1026],[1023,102052,102054],{"className":102053},[1030],[1032,102055,102056],{"xmlns":1034},[1036,102057,102058,102062],{},[1039,102059,102060],{},[1042,102061,4022],{},[1058,102063,4022],{"encoding":1060},[1023,102065,102067],{"className":102066,"ariaHidden":1066},[1065],[1023,102068,102070,102073],{"className":102069},[1070],[1023,102071],{"className":102072,"style":22079},[1074],[1023,102074,4022],{"className":102075,"style":4066},[1079,1080]," là hằng số. Hàm đa thức tăng chậm hơn hàm mũ rất nhiều khi ",[1023,102078,102080,102093],{"className":102079},[1026],[1023,102081,102083],{"className":102082},[1030],[1032,102084,102085],{"xmlns":1034},[1036,102086,102087,102091],{},[1039,102088,102089],{},[1042,102090,1262],{},[1058,102092,1262],{"encoding":1060},[1023,102094,102096],{"className":102095,"ariaHidden":1066},[1065],[1023,102097,102099,102102],{"className":102098},[1070],[1023,102100],{"className":102101,"style":2347},[1074],[1023,102103,1262],{"className":102104},[1079,1080]," lớn, nên lời giải đa thức được coi là khả thi.",[973,102107,102108,102109,102112],{},"Lý thuyết độ khó làm việc với ",[1487,102110,102111],{},"bài toán quyết định",": câu trả lời chỉ là có hoặc không. Bài tối ưu được đổi thành bài quyết định bằng một ngưỡng.",[986,102114,102115,102118],{},[989,102116,102117],{},"Bài tối ưu: tìm tour ngắn nhất qua mọi thành phố.",[989,102119,102120,102121,102149],{},"Bài quyết định: có tour nào dài không quá ",[1023,102122,102124,102137],{"className":102123},[1026],[1023,102125,102127],{"className":102126},[1030],[1032,102128,102129],{"xmlns":1034},[1036,102130,102131,102135],{},[1039,102132,102133],{},[1042,102134,20401],{},[1058,102136,20401],{"encoding":1060},[1023,102138,102140],{"className":102139,"ariaHidden":1066},[1065],[1023,102141,102143,102146],{"className":102142},[1070],[1023,102144],{"className":102145,"style":27414},[1074],[1023,102147,20401],{"className":102148,"style":20466},[1079,1080]," không?",[973,102151,102152,102155,102156,102184],{},[1487,102153,102154],{},"Chứng chỉ"," là bằng chứng cho câu trả lời \"có\". Với câu hỏi tour trên, chứng chỉ chính là một tour cụ thể. Ai cầm tour đó cũng kiểm tra được trong thời gian đa thức: đi qua đủ mọi thành phố chưa, tổng độ dài có không quá ",[1023,102157,102159,102172],{"className":102158},[1026],[1023,102160,102162],{"className":102161},[1030],[1032,102163,102164],{"xmlns":1034},[1036,102165,102166,102170],{},[1039,102167,102168],{},[1042,102169,20401],{},[1058,102171,20401],{"encoding":1060},[1023,102173,102175],{"className":102174,"ariaHidden":1066},[1065],[1023,102176,102178,102181],{"className":102177},[1070],[1023,102179],{"className":102180,"style":27414},[1074],[1023,102182,20401],{"className":102183,"style":20466},[1079,1080]," không.",[973,102186,102187],{},"Từ đó tách hai loại công việc:",[1099,102189,102190,102202],{},[1102,102191,102192],{},[1105,102193,102194,102196,102199],{},[1108,102195,61474],{},[1108,102197,102198],{},"Ví dụ với tour",[1108,102200,102201],{},"Độ khó",[1118,102203,102204,102243],{},[1105,102205,102206,102209,102240],{},[1123,102207,102208],{},"Tìm chứng chỉ",[1123,102210,102211,102212],{},"Tìm một tour dài không quá ",[1023,102213,102215,102228],{"className":102214},[1026],[1023,102216,102218],{"className":102217},[1030],[1032,102219,102220],{"xmlns":1034},[1036,102221,102222,102226],{},[1039,102223,102224],{},[1042,102225,20401],{},[1058,102227,20401],{"encoding":1060},[1023,102229,102231],{"className":102230,"ariaHidden":1066},[1065],[1023,102232,102234,102237],{"className":102233},[1070],[1023,102235],{"className":102236,"style":27414},[1074],[1023,102238,20401],{"className":102239,"style":20466},[1079,1080],[1123,102241,102242],{},"Có thể rất khó",[1105,102244,102245,102248,102279],{},[1123,102246,102247],{},"Kiểm tra chứng chỉ",[1123,102249,102250,102251],{},"Cho sẵn tour, cộng độ dài và so với ",[1023,102252,102254,102267],{"className":102253},[1026],[1023,102255,102257],{"className":102256},[1030],[1032,102258,102259],{"xmlns":1034},[1036,102260,102261,102265],{},[1039,102262,102263],{},[1042,102264,20401],{},[1058,102266,20401],{"encoding":1060},[1023,102268,102270],{"className":102269,"ariaHidden":1066},[1065],[1023,102271,102273,102276],{"className":102272},[1070],[1023,102274],{"className":102275,"style":27414},[1074],[1023,102277,20401],{"className":102278,"style":20466},[1079,1080],[1123,102280,102281,102282],{},"Dễ, ",[1023,102283,102285,102304],{"className":102284},[1026],[1023,102286,102288],{"className":102287},[1030],[1032,102289,102290],{"xmlns":1034},[1036,102291,102292,102302],{},[1039,102293,102294,102296,102298,102300],{},[1042,102295,1044],{},[1046,102297,1049],{"stretchy":1048},[1042,102299,1262],{},[1046,102301,1056],{"stretchy":1048},[1058,102303,1267],{"encoding":1060},[1023,102305,102307],{"className":102306,"ariaHidden":1066},[1065],[1023,102308,102310,102313,102316,102319,102322],{"className":102309},[1070],[1023,102311],{"className":102312,"style":1075},[1074],[1023,102314,1044],{"className":102315,"style":1081},[1079,1080],[1023,102317,1049],{"className":102318},[1085],[1023,102320,1262],{"className":102321},[1079,1080],[1023,102323,1056],{"className":102324},[1092],[973,102326,102327],{},"Giống như giải Sudoku thì khó, nhưng chấm một lời giải Sudoku thì nhanh. Phân biệt này là chìa khóa của toàn bộ lý thuyết.",[968,102329,102331],{"id":102330},"_3-lớp-p-và-lớp-np","3. Lớp P và lớp NP",[973,102333,102334,102337,102338,102366],{},[1487,102335,102336],{},"Lớp P"," gồm bài toán quyết định giải được bằng thuật toán đa thức. Ví dụ: có đường đi từ A tới B không (BFS), mảng đã sắp xếp chưa, có đường đi ngắn hơn ",[1023,102339,102341,102354],{"className":102340},[1026],[1023,102342,102344],{"className":102343},[1030],[1032,102345,102346],{"xmlns":1034},[1036,102347,102348,102352],{},[1039,102349,102350],{},[1042,102351,20401],{},[1058,102353,20401],{"encoding":1060},[1023,102355,102357],{"className":102356,"ariaHidden":1066},[1065],[1023,102358,102360,102363],{"className":102359},[1070],[1023,102361],{"className":102362,"style":27414},[1074],[1023,102364,20401],{"className":102365,"style":20466},[1079,1080]," không (Dijkstra).",[973,102368,102369,102372,102373,102376],{},[1487,102370,102371],{},"Lớp NP"," gồm bài toán quyết định mà mọi câu trả lời \"có\" đều có chứng chỉ ",[1487,102374,102375],{},"kiểm tra được"," trong thời gian đa thức. NP viết tắt của nondeterministic polynomial: một máy \"đoán\" đúng chứng chỉ rồi kiểm tra nó trong đa thức.",[973,102378,102379],{},"Mọi bài trong P đều thuộc NP: nếu tự giải được trong đa thức thì kiểm tra càng dễ. Vậy P là tập con của NP.",[973,102381,102382],{},"Điều ngược lại, NP có nằm trong P không, chưa ai biết. Đây là câu hỏi P có bằng NP không, một trong bảy bài toán thiên niên kỷ với giải thưởng một triệu đô la của Viện Clay.",[968,102384,102386],{"id":102385},"_4-quy-dẫn-np-complete-và-np-hard","4. Quy dẫn, NP-complete và NP-hard",[973,102388,102389,102392],{},[1487,102390,102391],{},"Quy dẫn"," bài A về bài B nghĩa là: biến mọi đầu vào của A thành đầu vào của B trong thời gian đa thức, sao cho đáp án giữ nguyên. Nếu giải được B nhanh thì giải được A nhanh. Nói cách khác, B khó ít nhất bằng A.",[973,102394,102395,102398,102399,102401],{},[1487,102396,102397],{},"NP-hard"," là bài mà ",[1487,102400,46509],{}," bài trong NP đều quy dẫn được về nó. Nó khó ít nhất bằng mọi bài trong NP, nhưng không bắt buộc thuộc NP. Ví dụ bài toán dừng (halting problem) là NP-hard mà thậm chí không giải được.",[973,102403,102404,102407],{},[1487,102405,102406],{},"NP-complete"," là bài vừa NP-hard vừa thuộc NP. Đây là những bài khó nhất trong NP. Bài NP-complete đầu tiên là SAT (Cook, 1971).",[973,102409,102410,102411,102413],{},"Tính chất đáng chú ý: chỉ cần tìm ra thuật toán đa thức cho ",[1487,102412,49567],{}," bài NP-complete, mọi bài trong NP đều giải được trong đa thức, tức P = NP.",[1099,102415,102416,102424],{},[1102,102417,102418],{},[1105,102419,102420,102422],{},[1108,102421,4881],{},[1108,102423,1433],{},[1118,102425,102426,102433,102527,102535],{},[1105,102427,102428,102430],{},[1123,102429,37334],{},[1123,102431,102432],{},"Tìm kiếm nhị phân, sắp xếp, BFS, Dijkstra, cây khung nhỏ nhất, ghép cặp",[1105,102434,102435,102438],{},[1123,102436,102437],{},"NP-complete (dạng quyết định)",[1123,102439,102440,102441,102469,102470,102498,102499],{},"SAT, có tour TSP dài không quá ",[1023,102442,102444,102457],{"className":102443},[1026],[1023,102445,102447],{"className":102446},[1030],[1032,102448,102449],{"xmlns":1034},[1036,102450,102451,102455],{},[1039,102452,102453],{},[1042,102454,20401],{},[1058,102456,20401],{"encoding":1060},[1023,102458,102460],{"className":102459,"ariaHidden":1066},[1065],[1023,102461,102463,102466],{"className":102462},[1070],[1023,102464],{"className":102465,"style":27414},[1074],[1023,102467,20401],{"className":102468,"style":20466},[1079,1080],", ba lô 0-1 có giá trị ít nhất ",[1023,102471,102473,102486],{"className":102472},[1026],[1023,102474,102476],{"className":102475},[1030],[1032,102477,102478],{"xmlns":1034},[1036,102479,102480,102484],{},[1039,102481,102482],{},[1042,102483,29619],{},[1058,102485,29619],{"encoding":1060},[1023,102487,102489],{"className":102488,"ariaHidden":1066},[1065],[1023,102490,102492,102495],{"className":102491},[1070],[1023,102493],{"className":102494,"style":27414},[1074],[1023,102496,29619],{"className":102497,"style":13790},[1079,1080],", tô 3 màu đồ thị, phủ đỉnh cỡ ",[1023,102500,102502,102515],{"className":102501},[1026],[1023,102503,102505],{"className":102504},[1030],[1032,102506,102507],{"xmlns":1034},[1036,102508,102509,102513],{},[1039,102510,102511],{},[1042,102512,4022],{},[1058,102514,4022],{"encoding":1060},[1023,102516,102518],{"className":102517,"ariaHidden":1066},[1065],[1023,102519,102521,102524],{"className":102520},[1070],[1023,102522],{"className":102523,"style":22079},[1074],[1023,102525,4022],{"className":102526,"style":4066},[1079,1080],[1105,102528,102529,102532],{},[1123,102530,102531],{},"NP-hard (dạng tối ưu)",[1123,102533,102534],{},"Tìm tour TSP ngắn nhất, phân cụm K-means tối ưu toàn cục",[1105,102536,102537,102540],{},[1123,102538,102539],{},"Thuộc NP, chưa biết có NP-complete không",[1123,102541,102542],{},"Phân tích số nguyên ra thừa số nguyên tố (nền tảng của RSA)",[973,102544,102545,102546,102593,102594,102622],{},"Hai nhầm lẫn hay gặp: RSA không dựa trên bài NP-complete, và ba lô 0-1 có thuật toán quy hoạch động ",[1023,102547,102549,102571],{"className":102548},[1026],[1023,102550,102552],{"className":102551},[1030],[1032,102553,102554],{"xmlns":1034},[1036,102555,102556,102568],{},[1039,102557,102558,102560,102562,102564,102566],{},[1042,102559,1044],{},[1046,102561,1049],{"stretchy":1048},[1042,102563,1262],{},[1042,102565,56943],{},[1046,102567,1056],{"stretchy":1048},[1058,102569,102570],{"encoding":1060},"O(nW)",[1023,102572,102574],{"className":102573,"ariaHidden":1066},[1065],[1023,102575,102577,102580,102583,102586,102590],{"className":102576},[1070],[1023,102578],{"className":102579,"style":1075},[1074],[1023,102581,1044],{"className":102582,"style":1081},[1079,1080],[1023,102584,1049],{"className":102585},[1085],[1023,102587,102589],{"className":102588,"style":37429},[1079,1080],"nW",[1023,102591,1056],{"className":102592},[1092],", chỉ là giả đa thức vì ",[1023,102595,102597,102610],{"className":102596},[1026],[1023,102598,102600],{"className":102599},[1030],[1032,102601,102602],{"xmlns":1034},[1036,102603,102604,102608],{},[1039,102605,102606],{},[1042,102607,56943],{},[1058,102609,56943],{"encoding":1060},[1023,102611,102613],{"className":102612,"ariaHidden":1066},[1065],[1023,102614,102616,102619],{"className":102615},[1070],[1023,102617],{"className":102618,"style":27414},[1074],[1023,102620,56943],{"className":102621,"style":37429},[1079,1080]," có thể lớn theo hàm mũ số bit.",[973,102624,102625],{},"Sơ đồ quan hệ, giả định P khác NP: P nằm trong NP, NP-complete là phần khó nhất của NP, NP-hard bao NP-complete và tràn ra ngoài NP. Nếu P bằng NP thì P, NP và NP-complete trùng nhau.",[968,102627,102629],{"id":102628},"_5-vì-sao-bài-toán-khó-buộc-phải-xấp-xỉ","5. Vì sao bài toán khó buộc phải xấp xỉ",[973,102631,102632],{},"Lý thuyết độ khó gắn với thực hành qua một câu hỏi. Liệu có nên nhắm nghiệm tối ưu ngay từ đầu không.",[973,102634,102635],{},"Nếu tìm và xác minh tối ưu tốn công khổng lồ, lời giải khả thi thực tế tốt hơn. Lời giải khả thi dựa trên kinh nghiệm gọi là heuristic.",[973,102637,102638],{},"Điện toán đám mây co giãn mang lựa chọn mới. Dữ liệu tăng thì cấp thêm CPU hay máy ảo để giữ thời gian.",[973,102640,102641],{},"Nhưng co giãn không cứu được tăng trưởng hàm mũ của NP-hard. Nó chỉ trì hoãn điểm sụp đổ chứ không xóa bỏ nó.",[973,102643,102644],{},"Giống như thêm xô múc nước lũ. Nước lên theo hàm mũ thì bao nhiêu xô cũng tràn.",[968,102646,98912],{"id":98911},[973,102648,102649],{},"Bốn lớp cho bốn chiến lược khác nhau. Bài lớp P thì đầu tư tìm tối ưu vì công bỏ ra được đền đáp.",[973,102651,102652],{},"Bài NP-complete hay NP-hard thì chấp nhận heuristic và xấp xỉ. Đặt ngưỡng sai số từ đầu và kiểm chứng sai số.",[973,102654,102655],{},"Đừng đòi nghiệm tối ưu. Đánh đổi cốt lõi là giữa tối ưu và khả thi.",[973,102657,102658],{},"Càng khăng khăng tối ưu cho bài khó, chi phí càng phình theo hàm mũ. Đánh đổi thứ hai là giữa phân loại và giải.",[973,102660,102661],{},"Một ngày phân tích độ khó có thể tiết kiệm hàng tháng cài đặt lời giải không tưởng.",[968,102663,98931],{"id":98930},[973,102665,102666],{},"Thứ nhất: lẫn khó kiểm tra với khó giải. Thấy nghiệm dễ kiểm tra thì tưởng bài dễ giải.",[973,102668,102669],{},"Trong khi đó chính là đặc trưng của NP. Thứ hai: không phân loại độ khó mà lao ngay vào tìm tối ưu cho NP-hard.",[973,102671,102672],{},"Rồi kẹt trong vòng lặp tối ưu vô vọng. Thứ ba: hiểu sai quan hệ tập con.",[973,102674,102675,102676,102679],{},"Mọi P đều là NP nhưng ngược lại chưa chứng minh được. Không thể mặc định bài NP nào cũng có lời giải đa thức. Chiều quy dẫn cũng hay bị đảo: muốn chứng minh bài mới khó, phải quy dẫn một bài đã biết là NP-complete ",[1487,102677,102678],{},"về"," bài mới.",[973,102681,102682],{},"Thứ tư: tin thêm phần cứng giải được NP-hard quy mô lớn. Tăng trưởng hàm mũ nuốt chửng mọi nâng cấp tuyến tính.",[968,102684,98947],{"id":98946},[973,102686,102687],{},"Tư duy độ khó dùng ngay khi nhận bài mới. Thử xem nó có lời giải đa thức đã biết không.",[973,102689,102690],{},"Thử xem nó có phải biến thể của ba lô hay người bán hàng rong không. Từ đó quyết định theo đuổi tối ưu hay chấp nhận heuristic.",[973,102692,102693],{},"Thói quen này rẻ mà cứu nhiều công sức. Phân loại một giờ đỡ hơn cài đặt một tháng vô vọng.",[968,102695,96573],{"id":96572},[973,102697,96576],{},[973,102699,102700,102702],{},[1487,102701,96581],{}," Chứng chỉ cho bài \"đồ thị có tô được 3 màu không\" là gì, và kiểm tra mất bao lâu?",[96754,102704,102705],{"close-text":96756,"name":96757,"open-text":96758},[973,102706,102707,102708,1517],{},"Một cách gán màu cho mọi đỉnh. Kiểm tra: duyệt mọi cạnh xem 2 đầu khác màu, ",[1023,102709,102711,102734],{"className":102710},[1026],[1023,102712,102714],{"className":102713},[1030],[1032,102715,102716],{"xmlns":1034},[1036,102717,102718,102732],{},[1039,102719,102720,102722,102724,102726,102728,102730],{},[1042,102721,1044],{},[1046,102723,1049],{"stretchy":1048},[1042,102725,29619],{},[1046,102727,21881],{},[1042,102729,26217],{},[1046,102731,1056],{"stretchy":1048},[1058,102733,29628],{"encoding":1060},[1023,102735,102737,102761],{"className":102736,"ariaHidden":1066},[1065],[1023,102738,102740,102743,102746,102749,102752,102755,102758],{"className":102739},[1070],[1023,102741],{"className":102742,"style":1075},[1074],[1023,102744,1044],{"className":102745,"style":1081},[1079,1080],[1023,102747,1049],{"className":102748},[1085],[1023,102750,29619],{"className":102751,"style":13790},[1079,1080],[1023,102753],{"className":102754,"style":13790},[2354],[1023,102756,21881],{"className":102757},[13794],[1023,102759],{"className":102760,"style":13790},[2354],[1023,102762,102764,102767,102770],{"className":102763},[1070],[1023,102765],{"className":102766,"style":1075},[1074],[1023,102768,26217],{"className":102769,"style":26247},[1079,1080],[1023,102771,1056],{"className":102772},[1092],[973,102774,102775,102777],{},[1487,102776,96904],{}," Vì sao P là tập con của NP?",[96754,102779,102780],{"close-text":96756,"name":96757,"open-text":96758},[973,102781,102782],{},"Nếu giải được trong đa thức thì kiểm tra cũng được: bỏ qua chứng chỉ, tự giải lại rồi so.",[973,102784,102785,102787],{},[1487,102786,97431],{}," Tìm tour TSP ngắn nhất là NP-complete hay NP-hard?",[96754,102789,102790],{"close-text":96756,"name":96757,"open-text":96758},[973,102791,102792,102793,102821],{},"NP-hard. Bản quyết định \"có tour dài không quá ",[1023,102794,102796,102809],{"className":102795},[1026],[1023,102797,102799],{"className":102798},[1030],[1032,102800,102801],{"xmlns":1034},[1036,102802,102803,102807],{},[1039,102804,102805],{},[1042,102806,20401],{},[1058,102808,20401],{"encoding":1060},[1023,102810,102812],{"className":102811,"ariaHidden":1066},[1065],[1023,102813,102815,102818],{"className":102814},[1070],[1023,102816],{"className":102817,"style":27414},[1074],[1023,102819,20401],{"className":102820,"style":20466},[1079,1080]," không\" mới là NP-complete, vì bản tối ưu không phải bài quyết định nên không thuộc NP.",[973,102823,102824,102826],{},[1487,102825,97800],{}," Muốn chứng minh bài X mới là NP-hard, quy dẫn theo chiều nào?",[96754,102828,102829],{"close-text":96756,"name":96757,"open-text":96758},[973,102830,102831,102832,102834],{},"Quy dẫn một bài đã biết là NP-complete (ví dụ SAT) ",[1487,102833,102678],{}," X trong thời gian đa thức.",[973,102836,102837,102839,102840,102885],{},[1487,102838,97983],{}," Ba lô 0-1 có DP ",[1023,102841,102843,102864],{"className":102842},[1026],[1023,102844,102846],{"className":102845},[1030],[1032,102847,102848],{"xmlns":1034},[1036,102849,102850,102862],{},[1039,102851,102852,102854,102856,102858,102860],{},[1042,102853,1044],{},[1046,102855,1049],{"stretchy":1048},[1042,102857,1262],{},[1042,102859,56943],{},[1046,102861,1056],{"stretchy":1048},[1058,102863,102570],{"encoding":1060},[1023,102865,102867],{"className":102866,"ariaHidden":1066},[1065],[1023,102868,102870,102873,102876,102879,102882],{"className":102869},[1070],[1023,102871],{"className":102872,"style":1075},[1074],[1023,102874,1044],{"className":102875,"style":1081},[1079,1080],[1023,102877,1049],{"className":102878},[1085],[1023,102880,102589],{"className":102881,"style":37429},[1079,1080],[1023,102883,1056],{"className":102884},[1092],". Vậy nó có thuộc P không?",[96754,102887,102888],{"close-text":96756,"name":96757,"open-text":96758},[973,102889,102890,102891,102936,102937,102965],{},"Chưa biết. ",[1023,102892,102894,102915],{"className":102893},[1026],[1023,102895,102897],{"className":102896},[1030],[1032,102898,102899],{"xmlns":1034},[1036,102900,102901,102913],{},[1039,102902,102903,102905,102907,102909,102911],{},[1042,102904,1044],{},[1046,102906,1049],{"stretchy":1048},[1042,102908,1262],{},[1042,102910,56943],{},[1046,102912,1056],{"stretchy":1048},[1058,102914,102570],{"encoding":1060},[1023,102916,102918],{"className":102917,"ariaHidden":1066},[1065],[1023,102919,102921,102924,102927,102930,102933],{"className":102920},[1070],[1023,102922],{"className":102923,"style":1075},[1074],[1023,102925,1044],{"className":102926,"style":1081},[1079,1080],[1023,102928,1049],{"className":102929},[1085],[1023,102931,102589],{"className":102932,"style":37429},[1079,1080],[1023,102934,1056],{"className":102935},[1092]," là giả đa thức: ",[1023,102938,102940,102953],{"className":102939},[1026],[1023,102941,102943],{"className":102942},[1030],[1032,102944,102945],{"xmlns":1034},[1036,102946,102947,102951],{},[1039,102948,102949],{},[1042,102950,56943],{},[1058,102952,56943],{"encoding":1060},[1023,102954,102956],{"className":102955,"ariaHidden":1066},[1065],[1023,102957,102959,102962],{"className":102958},[1070],[1023,102960],{"className":102961,"style":27414},[1074],[1023,102963,56943],{"className":102964,"style":37429},[1079,1080]," có thể lớn theo hàm mũ của số bit biểu diễn nó, nên đây không phải thuật toán đa thức theo kích thước đầu vào.",[968,102967,98220],{"id":98219},[986,102969,102970,103047,103050,103053,103056],{},[989,102971,102972,102973,103046],{},"Thuật toán đa thức ",[1023,102974,102976,102999],{"className":102975},[1026],[1023,102977,102979],{"className":102978},[1030],[1032,102980,102981],{"xmlns":1034},[1036,102982,102983,102997],{},[1039,102984,102985,102987,102989,102995],{},[1042,102986,1044],{},[1046,102988,1049],{"stretchy":1048},[2327,102990,102991,102993],{},[1042,102992,1262],{},[1042,102994,4022],{},[1046,102996,1056],{"stretchy":1048},[1058,102998,102000],{"encoding":1060},[1023,103000,103002],{"className":103001,"ariaHidden":1066},[1065],[1023,103003,103005,103008,103011,103014,103043],{"className":103004},[1070],[1023,103006],{"className":103007,"style":34041},[1074],[1023,103009,1044],{"className":103010,"style":1081},[1079,1080],[1023,103012,1049],{"className":103013},[1085],[1023,103015,103017,103020],{"className":103016},[1079],[1023,103018,1262],{"className":103019},[1079,1080],[1023,103021,103023],{"className":103022},[2383],[1023,103024,103026],{"className":103025},[2387],[1023,103027,103029],{"className":103028},[2391],[1023,103030,103032],{"className":103031,"style":34075},[2395],[1023,103033,103034,103037],{"style":2398},[1023,103035],{"className":103036,"style":2403},[2402],[1023,103038,103040],{"className":103039},[2407,2408,2409,2410],[1023,103041,4022],{"className":103042,"style":4066},[1079,1080,2410],[1023,103044,1056],{"className":103045},[1092]," là chuẩn mực của lời giải khả thi; chứng chỉ là bằng chứng cho câu trả lời \"có\" của bài quyết định.",[989,103048,103049],{},"P: giải được trong đa thức. NP: kiểm tra chứng chỉ được trong đa thức. P là tập con của NP.",[989,103051,103052],{},"NP-hard: mọi bài NP quy dẫn được về nó. NP-complete: vừa NP-hard vừa thuộc NP.",[989,103054,103055],{},"Với bài khó, chiến lược đúng là heuristic và xấp xỉ có ngưỡng sai số.",[989,103057,103058],{},"Thêm phần cứng không xóa được bản chất hàm mũ của bài toán khó.",{"title":1357,"searchDepth":68,"depth":68,"links":103060},[103061,103062,103063,103064,103065,103066,103067,103068,103069,103070],{"id":90890,"depth":68,"text":90891},{"id":101969,"depth":68,"text":101970},{"id":102330,"depth":68,"text":102331},{"id":102385,"depth":68,"text":102386},{"id":102628,"depth":68,"text":102629},{"id":98911,"depth":68,"text":98912},{"id":98930,"depth":68,"text":98931},{"id":98946,"depth":68,"text":98947},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Thuật toán đa thức, chứng chỉ, quan hệ P là tập con của NP, NP-complete, NP-hard và chiến lược ứng phó với bài toán khó.",{},{"title":34,"description":103071},[103075,103076,103077,103078,7],"p-np","np-complete","np-hard","do-kho","QJnlywleVMvMnrKAMmV7xlBeONSAZM9zFtoHptUWbFE",{"id":103081,"title":38,"body":103082,"category":7,"day":3047,"description":104552,"difficulty":3043,"estimatedMinutes":258,"extension":3044,"lastUpdate":3045,"meta":104553,"navigation":2723,"outcomes":3047,"path":39,"prerequisites":3047,"seo":104554,"stem":40,"tags":104555,"__hash__":104559},"fundamentals\u002Ffundamentals\u002Fram-model-va-chi-phi.md",{"type":965,"value":103083,"toc":104540},[103084,103086,103089,103092,103095,103099,103102,103105,103108,103111,103114,103118,103121,103165,103168,103171,103216,103220,103223,103226,103229,103312,103315,103318,103322,103325,103638,103783,103830,103833,103836,103946,103978,103980,103983,103986,103989,103992,103994,103997,104000,104003,104006,104009,104011,104078,104081,104084,104086,104088,104093,104098,104107,104155,104160,104165,104261,104266,104445,104521,104523],[968,103085,90891],{"id":90890},[973,103087,103088],{},"Mọi phát biểu về độ phức tạp đều đứng trên một mô hình tính toán. Đó là tập quy ước về phép nào tốn bao nhiêu chi phí.",[973,103090,103091],{},"Không thống nhất mô hình thì so hai thuật toán như đua trên hai địa hình khác nhau. Mô hình RAM là máy trừu tượng tối giản để đếm bước logic.",[973,103093,103094],{},"Thay vì đếm giây hay lệnh máy cụ thể. Bài này trình bày vì sao cần mô hình, các giả định RAM, cách đếm bước và ý nghĩa bỏ hằng số.",[968,103096,103098],{"id":103097},"_2-vì-sao-cần-một-mô-hình-trừu-tượng","2. Vì sao cần một mô hình trừu tượng",[973,103100,103101],{},"Bài này mở đầu bằng câu hỏi ngây thơ: hiệu năng là gì, đo bằng gì. Đo giờ chạy trên một đầu vào nghe thẳng thắn.",[973,103103,103104],{},"Nhưng kết quả nhiễu vì chip đa nhân, hệ điều hành và tiến trình nền. Tệ hơn, con số tuyệt đối gắn chặt với máy chạy thử.",[973,103106,103107],{},"Nên nó không có ý nghĩa phổ quát. So tương đối bằng benchmark vẫn còn quá nhiều biến số.",[973,103109,103110],{},"Đếm lệnh thì gắn với nền tảng và ngôn ngữ. Lối thoát là trừu tượng hóa chi tiết ít quan trọng bằng mô hình tối giản.",[973,103112,103113],{},"Đó chính là mô hình RAM. Giống như thi chạy cùng một đường mới so được.",[968,103115,103117],{"id":103116},"_3-các-giả-định-của-mô-hình-ram","3. Các giả định của mô hình RAM",[973,103119,103120],{},"Mô hình RAM coi máy tính là bộ nhớ truy cập ngẫu nhiên và tập phép tính cơ sở. Có bốn giả định nền tảng.",[1099,103122,103123,103132],{},[1102,103124,103125],{},[1105,103126,103127,103130],{},[1108,103128,103129],{},"Giả định",[1108,103131,87021],{},[1118,103133,103134,103142,103150,103158],{},[1105,103135,103136,103139],{},[1123,103137,103138],{},"Phép cơ sở",[1123,103140,103141],{},"Số học, rẽ nhánh, gọi hàm đều tốn một bước",[1105,103143,103144,103147],{},[1123,103145,103146],{},"Tổ hợp",[1123,103148,103149],{},"Vòng lặp và chương trình con tốn theo số lần thực hiện",[1105,103151,103152,103155],{},[1123,103153,103154],{},"Truy cập nhớ",[1123,103156,103157],{},"Mỗi lần đọc ghi bộ nhớ tốn một bước",[1105,103159,103160,103162],{},[1123,103161,48345],{},[1123,103163,103164],{},"Coi như vô hạn",[973,103166,103167],{},"Giả định bộ nhớ vô hạn nghe phi thực tế. Nhưng mô hình cố tình không phân biệt nhớ đệm, RAM, đĩa hay kho dữ liệu.",[973,103169,103170],{},"Nhờ đó hiệu năng đo bằng số bước logic trên đầu vào cho trước. Lấy món nào trong tủ cũng tính một tay.",[973,103172,103173,103174,103215],{},"Một giả định ngầm nữa: mỗi ô nhớ chứa một số có kích thước giới hạn (cỡ ",[1023,103175,103177,103195],{"className":103176},[1026],[1023,103178,103180],{"className":103179},[1030],[1032,103181,103182],{"xmlns":1034},[1036,103183,103184,103192],{},[1039,103185,103186,103188,103190],{},[1042,103187,8397],{},[1046,103189,8400],{},[1042,103191,1262],{},[1058,103193,103194],{"encoding":1060},"\\log n",[1023,103196,103198],{"className":103197,"ariaHidden":1066},[1065],[1023,103199,103201,103204,103209,103212],{"className":103200},[1070],[1023,103202],{"className":103203,"style":59519},[1074],[1023,103205,8427,103207],{"className":103206},[8426],[1023,103208,7690],{"style":8430},[1023,103210],{"className":103211,"style":8434},[2354],[1023,103213,1262],{"className":103214},[1079,1080]," bit). Nếu cho phép số nguyên lớn tùy ý với phép nhân một bước, mô hình sẽ \"gian lận\": nhân hai số một triệu chữ số không thể tốn một bước.",[968,103217,103219],{"id":103218},"_4-từ-đếm-bước-sang-bậc-tăng-trưởng","4. Từ đếm bước sang bậc tăng trưởng",[973,103221,103222],{},"Có cách đếm bước rồi, ta hỏi tiếp: cải thiện nào mới đáng kể. Biến động nhỏ về số bước hiếm khi có ý nghĩa.",[973,103224,103225],{},"Thay vào đó ta nghĩ theo bậc độ lớn: gấp đôi, gấp mười, gấp trăm. Bước giác ngộ thứ hai còn quan trọng hơn.",[973,103227,103228],{},"Phải biểu diễn số bước thành hàm của kích thước bài toán. Nói A tốn 100 bước, B tốn 10 bước trên một mẫu thử thì chưa dự báo được gì.",[973,103230,103231,103232,103282,103283,103311],{},"Nhưng nếu trên mảng n phần tử, A đổi chỗ tỉ lệ ",[1023,103233,103235,103252],{"className":103234},[1026],[1023,103236,103238],{"className":103237},[1030],[1032,103239,103240],{"xmlns":1034},[1036,103241,103242,103250],{},[1039,103243,103244,103246,103248],{},[1042,103245,1262],{},[1046,103247,13768],{},[1042,103249,1262],{},[1058,103251,13773],{"encoding":1060},[1023,103253,103255,103273],{"className":103254,"ariaHidden":1066},[1065],[1023,103256,103258,103261,103264,103267,103270],{"className":103257},[1070],[1023,103259],{"className":103260,"style":13783},[1074],[1023,103262,1262],{"className":103263},[1079,1080],[1023,103265],{"className":103266,"style":13790},[2354],[1023,103268,13768],{"className":103269},[13794],[1023,103271],{"className":103272,"style":13790},[2354],[1023,103274,103276,103279],{"className":103275},[1070],[1023,103277],{"className":103278,"style":2347},[1074],[1023,103280,1262],{"className":103281},[1079,1080]," còn B tỉ lệ ",[1023,103284,103286,103299],{"className":103285},[1026],[1023,103287,103289],{"className":103288},[1030],[1032,103290,103291],{"xmlns":1034},[1036,103292,103293,103297],{},[1039,103294,103295],{},[1042,103296,1262],{},[1058,103298,1262],{"encoding":1060},[1023,103300,103302],{"className":103301,"ariaHidden":1066},[1065],[1023,103303,103305,103308],{"className":103304},[1070],[1023,103306],{"className":103307,"style":2347},[1074],[1023,103309,1262],{"className":103310},[1079,1080],". Ta đã có công cụ dự báo mọi kích thước đầu vào.",[973,103313,103314],{},"Chính tại đây ký hiệu Big-O xuất hiện để phát biểu bậc tăng trưởng. Mô hình RAM là mặt đếm chi phí, Big-O là mặt phát biểu chi phí.",[973,103316,103317],{},"Hai mặt gắn chặt thành một khung phân tích hoàn chỉnh. Chi tiết Big-O đã trình bày ở bài Big-O.",[968,103319,103321],{"id":103320},"_5-hệ-quả-hằng-số-không-quan-trọng-và-số-hạng-trội-thắng","5. Hệ quả: hằng số không quan trọng và số hạng trội thắng",[973,103323,103324],{},"Từ định nghĩa chặn trên, bài này rút ra hệ quả thực tiễn sâu sắc. Thứ nhất, ta chỉ quan tâm n rất lớn, không bận tâm n nhỏ.",[973,103326,103327,103328,7386,103361,103419,103420,1656,103470,103528,103529,1656,103579,103637],{},"Ví dụ so ",[1023,103329,103331,103346],{"className":103330},[1026],[1023,103332,103334],{"className":103333},[1030],[1032,103335,103336],{"xmlns":1034},[1036,103337,103338,103344],{},[1039,103339,103340,103342],{},[1051,103341,13900],{},[1042,103343,1262],{},[1058,103345,98003],{"encoding":1060},[1023,103347,103349],{"className":103348,"ariaHidden":1066},[1065],[1023,103350,103352,103355,103358],{"className":103351},[1070],[1023,103353],{"className":103354,"style":10020},[1074],[1023,103356,13900],{"className":103357},[1079],[1023,103359,1262],{"className":103360},[1079,1080],[1023,103362,103364,103381],{"className":103363},[1026],[1023,103365,103367],{"className":103366},[1030],[1032,103368,103369],{"xmlns":1034},[1036,103370,103371,103379],{},[1039,103372,103373],{},[2327,103374,103375,103377],{},[1042,103376,1262],{},[1051,103378,2457],{},[1058,103380,95877],{"encoding":1060},[1023,103382,103384],{"className":103383,"ariaHidden":1066},[1065],[1023,103385,103387,103390],{"className":103386},[1070],[1023,103388],{"className":103389,"style":2369},[1074],[1023,103391,103393,103396],{"className":103392},[1079],[1023,103394,1262],{"className":103395},[1079,1080],[1023,103397,103399],{"className":103398},[2383],[1023,103400,103402],{"className":103401},[2387],[1023,103403,103405],{"className":103404},[2391],[1023,103406,103408],{"className":103407,"style":2369},[2395],[1023,103409,103410,103413],{"style":2398},[1023,103411],{"className":103412,"style":2403},[2402],[1023,103414,103416],{"className":103415},[2407,2408,2409,2410],[1023,103417,2457],{"className":103418},[1079,2410],": khi ",[1023,103421,103423,103440],{"className":103422},[1026],[1023,103424,103426],{"className":103425},[1030],[1032,103427,103428],{"xmlns":1034},[1036,103429,103430,103438],{},[1039,103431,103432,103434,103436],{},[1042,103433,1262],{},[1046,103435,98180],{},[1051,103437,13900],{},[1058,103439,98185],{"encoding":1060},[1023,103441,103443,103461],{"className":103442,"ariaHidden":1066},[1065],[1023,103444,103446,103449,103452,103455,103458],{"className":103445},[1070],[1023,103447],{"className":103448,"style":91726},[1074],[1023,103450,1262],{"className":103451},[1079,1080],[1023,103453],{"className":103454,"style":2355},[2354],[1023,103456,98180],{"className":103457},[2359],[1023,103459],{"className":103460,"style":2355},[2354],[1023,103462,103464,103467],{"className":103463},[1070],[1023,103465],{"className":103466,"style":10020},[1074],[1023,103468,13900],{"className":103469},[1079],[1023,103471,103473,103490],{"className":103472},[1026],[1023,103474,103476],{"className":103475},[1030],[1032,103477,103478],{"xmlns":1034},[1036,103479,103480,103488],{},[1039,103481,103482],{},[2327,103483,103484,103486],{},[1042,103485,1262],{},[1051,103487,2457],{},[1058,103489,95877],{"encoding":1060},[1023,103491,103493],{"className":103492,"ariaHidden":1066},[1065],[1023,103494,103496,103499],{"className":103495},[1070],[1023,103497],{"className":103498,"style":2369},[1074],[1023,103500,103502,103505],{"className":103501},[1079],[1023,103503,1262],{"className":103504},[1079,1080],[1023,103506,103508],{"className":103507},[2383],[1023,103509,103511],{"className":103510},[2387],[1023,103512,103514],{"className":103513},[2391],[1023,103515,103517],{"className":103516,"style":2369},[2395],[1023,103518,103519,103522],{"style":2398},[1023,103520],{"className":103521,"style":2403},[2402],[1023,103523,103525],{"className":103524},[2407,2408,2409,2410],[1023,103526,2457],{"className":103527},[1079,2410]," còn nhỏ hơn. Nhưng từ ",[1023,103530,103532,103549],{"className":103531},[1026],[1023,103533,103535],{"className":103534},[1030],[1032,103536,103537],{"xmlns":1034},[1036,103538,103539,103547],{},[1039,103540,103541,103543,103545],{},[1042,103542,1262],{},[1046,103544,59050],{},[1051,103546,13900],{},[1058,103548,98132],{"encoding":1060},[1023,103550,103552,103570],{"className":103551,"ariaHidden":1066},[1065],[1023,103553,103555,103558,103561,103564,103567],{"className":103554},[1070],[1023,103556],{"className":103557,"style":91726},[1074],[1023,103559,1262],{"className":103560},[1079,1080],[1023,103562],{"className":103563,"style":2355},[2354],[1023,103565,59050],{"className":103566},[2359],[1023,103568],{"className":103569,"style":2355},[2354],[1023,103571,103573,103576],{"className":103572},[1070],[1023,103574],{"className":103575,"style":10020},[1074],[1023,103577,13900],{"className":103578},[1079],[1023,103580,103582,103599],{"className":103581},[1026],[1023,103583,103585],{"className":103584},[1030],[1032,103586,103587],{"xmlns":1034},[1036,103588,103589,103597],{},[1039,103590,103591],{},[2327,103592,103593,103595],{},[1042,103594,1262],{},[1051,103596,2457],{},[1058,103598,95877],{"encoding":1060},[1023,103600,103602],{"className":103601,"ariaHidden":1066},[1065],[1023,103603,103605,103608],{"className":103604},[1070],[1023,103606],{"className":103607,"style":2369},[1074],[1023,103609,103611,103614],{"className":103610},[1079],[1023,103612,1262],{"className":103613},[1079,1080],[1023,103615,103617],{"className":103616},[2383],[1023,103618,103620],{"className":103619},[2387],[1023,103621,103623],{"className":103622},[2391],[1023,103624,103626],{"className":103625,"style":2369},[2395],[1023,103627,103628,103631],{"style":2398},[1023,103629],{"className":103630,"style":2403},[2402],[1023,103632,103634],{"className":103633},[2407,2408,2409,2410],[1023,103635,2457],{"className":103636},[1079,2410]," vượt lên và bỏ xa mãi mãi.",[973,103639,103640,103641,1656,103684,1509,103733,103782],{},"Thứ hai, hệ số hằng không quan trọng. ",[1023,103642,103644,103663],{"className":103643},[1026],[1023,103645,103647],{"className":103646},[1030],[1032,103648,103649],{"xmlns":1034},[1036,103650,103651,103661],{},[1039,103652,103653,103655,103657,103659],{},[1042,103654,1044],{},[1046,103656,1049],{"stretchy":1048},[1042,103658,1262],{},[1046,103660,1056],{"stretchy":1048},[1058,103662,1267],{"encoding":1060},[1023,103664,103666],{"className":103665,"ariaHidden":1066},[1065],[1023,103667,103669,103672,103675,103678,103681],{"className":103668},[1070],[1023,103670],{"className":103671,"style":1075},[1074],[1023,103673,1044],{"className":103674,"style":1081},[1079,1080],[1023,103676,1049],{"className":103677},[1085],[1023,103679,1262],{"className":103680},[1079,1080],[1023,103682,1056],{"className":103683},[1092],[1023,103685,103687,103709],{"className":103686},[1026],[1023,103688,103690],{"className":103689},[1030],[1032,103691,103692],{"xmlns":1034},[1036,103693,103694,103706],{},[1039,103695,103696,103698,103700,103702,103704],{},[1042,103697,1044],{},[1046,103699,1049],{"stretchy":1048},[1051,103701,13826],{},[1042,103703,1262],{},[1046,103705,1056],{"stretchy":1048},[1058,103707,103708],{"encoding":1060},"O(3n)",[1023,103710,103712],{"className":103711,"ariaHidden":1066},[1065],[1023,103713,103715,103718,103721,103724,103727,103730],{"className":103714},[1070],[1023,103716],{"className":103717,"style":1075},[1074],[1023,103719,1044],{"className":103720,"style":1081},[1079,1080],[1023,103722,1049],{"className":103723},[1085],[1023,103725,13826],{"className":103726},[1079],[1023,103728,1262],{"className":103729},[1079,1080],[1023,103731,1056],{"className":103732},[1092],[1023,103734,103736,103758],{"className":103735},[1026],[1023,103737,103739],{"className":103738},[1030],[1032,103740,103741],{"xmlns":1034},[1036,103742,103743,103755],{},[1039,103744,103745,103747,103749,103751,103753],{},[1042,103746,1044],{},[1046,103748,1049],{"stretchy":1048},[1051,103750,13900],{},[1042,103752,1262],{},[1046,103754,1056],{"stretchy":1048},[1058,103756,103757],{"encoding":1060},"O(100n)",[1023,103759,103761],{"className":103760,"ariaHidden":1066},[1065],[1023,103762,103764,103767,103770,103773,103776,103779],{"className":103763},[1070],[1023,103765],{"className":103766,"style":1075},[1074],[1023,103768,1044],{"className":103769,"style":1081},[1079,1080],[1023,103771,1049],{"className":103772},[1085],[1023,103774,13900],{"className":103775},[1079],[1023,103777,1262],{"className":103778},[1079,1080],[1023,103780,1056],{"className":103781},[1092]," là một.",[973,103784,103785,103786,103829],{},"Thứ ba, mọi hằng số dương đều thuộc ",[1023,103787,103789,103808],{"className":103788},[1026],[1023,103790,103792],{"className":103791},[1030],[1032,103793,103794],{"xmlns":1034},[1036,103795,103796,103806],{},[1039,103797,103798,103800,103802,103804],{},[1042,103799,1044],{},[1046,103801,1049],{"stretchy":1048},[1051,103803,1053],{},[1046,103805,1056],{"stretchy":1048},[1058,103807,1061],{"encoding":1060},[1023,103809,103811],{"className":103810,"ariaHidden":1066},[1065],[1023,103812,103814,103817,103820,103823,103826],{"className":103813},[1070],[1023,103815],{"className":103816,"style":1075},[1074],[1023,103818,1044],{"className":103819,"style":1081},[1079,1080],[1023,103821,1049],{"className":103822},[1085],[1023,103824,1053],{"className":103825},[1079],[1023,103827,1056],{"className":103828},[1092],". Nghĩa là chi phí không phụ thuộc đầu vào.",[973,103831,103832],{},"Ví dụ tính tổng n số đầu bằng công thức Gauss. Chỉ cần một cộng, một nhân, một chia với mọi n.",[973,103834,103835],{},"Thứ tư, cộng hai biểu thức thì số hạng lớn hơn thắng. Hai thuật toán nối tiếp bị chi phối bởi thuật toán chậm hơn.",[973,103837,103838,103839,103902,103903,1517],{},"Thứ năm, tích hai biểu thức không rút gọn được, trừ khi một bên là hằng số. Ví dụ ",[1023,103840,103842,103867],{"className":103841},[1026],[1023,103843,103845],{"className":103844},[1030],[1032,103846,103847],{"xmlns":1034},[1036,103848,103849,103865],{},[1039,103850,103851,103853,103855,103857,103859,103861,103863],{},[1042,103852,1044],{},[1046,103854,1049],{"stretchy":1048},[1042,103856,1262],{},[1042,103858,8397],{},[1046,103860,8400],{},[1042,103862,1262],{},[1046,103864,1056],{"stretchy":1048},[1058,103866,10463],{"encoding":1060},[1023,103868,103870],{"className":103869,"ariaHidden":1066},[1065],[1023,103871,103873,103876,103879,103882,103885,103888,103893,103896,103899],{"className":103872},[1070],[1023,103874],{"className":103875,"style":1075},[1074],[1023,103877,1044],{"className":103878,"style":1081},[1079,1080],[1023,103880,1049],{"className":103881},[1085],[1023,103883,1262],{"className":103884},[1079,1080],[1023,103886],{"className":103887,"style":8434},[2354],[1023,103889,8427,103891],{"className":103890},[8426],[1023,103892,7690],{"style":8430},[1023,103894],{"className":103895,"style":8434},[2354],[1023,103897,1262],{"className":103898},[1079,1080],[1023,103900,1056],{"className":103901},[1092]," giữ nguyên, không thành ",[1023,103904,103906,103925],{"className":103905},[1026],[1023,103907,103909],{"className":103908},[1030],[1032,103910,103911],{"xmlns":1034},[1036,103912,103913,103923],{},[1039,103914,103915,103917,103919,103921],{},[1042,103916,1044],{},[1046,103918,1049],{"stretchy":1048},[1042,103920,1262],{},[1046,103922,1056],{"stretchy":1048},[1058,103924,1267],{"encoding":1060},[1023,103926,103928],{"className":103927,"ariaHidden":1066},[1065],[1023,103929,103931,103934,103937,103940,103943],{"className":103930},[1070],[1023,103932],{"className":103933,"style":1075},[1074],[1023,103935,1044],{"className":103936,"style":1081},[1079,1080],[1023,103938,1049],{"className":103939},[1085],[1023,103941,1262],{"className":103942},[1079,1080],[1023,103944,1056],{"className":103945},[1092],[973,103947,103948,103949,103977],{},"Lưu ý: trong thực tế người ta hay viết Big-O nhưng ý muốn nói chặn khít ",[1023,103950,103952,103965],{"className":103951},[1026],[1023,103953,103955],{"className":103954},[1030],[1032,103956,103957],{"xmlns":1034},[1036,103958,103959,103963],{},[1039,103960,103961],{},[1042,103962,93330],{"mathvariant":2460},[1058,103964,93724],{"encoding":1060},[1023,103966,103968],{"className":103967,"ariaHidden":1066},[1065],[1023,103969,103971,103974],{"className":103970},[1070],[1023,103972],{"className":103973,"style":27414},[1074],[1023,103975,93330],{"className":103976},[1079],". Khi cần chính xác thì phân biệt rõ.",[968,103979,98912],{"id":98911},[973,103981,103982],{},"Mô hình RAM đổi chính xác phần cứng lấy tính phổ quát. So với benchmark thực nghiệm, nó đúng trên mọi máy.",[973,103984,103985],{},"Nhưng nó không nói được thuật toán nào nhanh hơn trên cấu hình cụ thể với dữ liệu vừa. So với mô hình chi tiết phân biệt nhớ đệm và đĩa, nó đơn giản và dễ suy luận hơn.",[973,103987,103988],{},"Nhưng có thể gây hiểu lầm khi chi phí thật nằm ở phân cấp bộ nhớ. Thực hành tốt là dùng RAM cho phân tích ban đầu.",[973,103990,103991],{},"Rồi đưa chi tiết phần cứng trở lại khi tối ưu điểm nóng đã chứng minh. Giống như phác thảo trước, đo đạc chi tiết sau.",[968,103993,98931],{"id":98930},[973,103995,103996],{},"Thứ nhất: lẫn bước logic với giây thực tế. Thuật toán ít bước hơn vẫn có thể chạy chậm hơn vì mỗi bước ẩn chi phí phần cứng khác nhau.",[973,103998,103999],{},"Thứ hai: quên giả định bộ nhớ vô hạn. Rồi áp kết luận RAM cho môi trường chật hẹp mà không hiệu chỉnh.",[973,104001,104002],{},"Thứ ba: tôn thờ hằng số. Tối ưu vài chục phần trăm số bước trong khi hình dạng tăng trưởng vẫn xấu.",[973,104004,104005],{},"Đó là thắng trận nhỏ mà thua cuộc chiến lớn. Thứ tư: đếm lệnh máy hay dòng code rồi tưởng đó là phân tích độc lập nền tảng.",[973,104007,104008],{},"Đúng điều bài này cảnh báo ngay từ đầu. Đếm dòng code vẫn gắn với ngôn ngữ.",[968,104010,98947],{"id":98946},[973,104012,104013,104014,104077],{},"Mô hình RAM là nền của mọi phát biểu Big-O trong tài liệu. Mỗi khi đọc ",[1023,104015,104017,104042],{"className":104016},[1026],[1023,104018,104020],{"className":104019},[1030],[1032,104021,104022],{"xmlns":1034},[1036,104023,104024,104040],{},[1039,104025,104026,104028,104030,104032,104034,104036,104038],{},[1042,104027,1044],{},[1046,104029,1049],{"stretchy":1048},[1042,104031,1262],{},[1042,104033,8397],{},[1046,104035,8400],{},[1042,104037,1262],{},[1046,104039,1056],{"stretchy":1048},[1058,104041,10463],{"encoding":1060},[1023,104043,104045],{"className":104044,"ariaHidden":1066},[1065],[1023,104046,104048,104051,104054,104057,104060,104063,104068,104071,104074],{"className":104047},[1070],[1023,104049],{"className":104050,"style":1075},[1074],[1023,104052,1044],{"className":104053,"style":1081},[1079,1080],[1023,104055,1049],{"className":104056},[1085],[1023,104058,1262],{"className":104059},[1079,1080],[1023,104061],{"className":104062,"style":8434},[2354],[1023,104064,8427,104066],{"className":104065},[8426],[1023,104067,7690],{"style":8430},[1023,104069],{"className":104070,"style":8434},[2354],[1023,104072,1262],{"className":104073},[1079,1080],[1023,104075,1056],{"className":104076},[1092],", ta hiểu đó là số bước RAM chứ không phải số giây.",[973,104079,104080],{},"Nó cũng là điểm tựa thảo luận công bằng trong nhóm. Thay vì cãi máy ai nhanh hơn, mọi người cùng đếm bước logic.",[973,104082,104083],{},"Về lâu dài, hiểu rõ giả định giúp biết khi nào cần mô hình tinh chỉnh hơn. Ví dụ khi dữ liệu không vừa bộ nhớ hay hệ phân tán.",[968,104085,96573],{"id":96572},[973,104087,96576],{},[973,104089,104090,104092],{},[1487,104091,96581],{}," Vì sao không dùng số giây đo được để so sánh hai thuật toán?",[96754,104094,104095],{"close-text":96756,"name":96757,"open-text":96758},[973,104096,104097],{},"Số giây phụ thuộc máy, hệ điều hành, tiến trình nền và ngôn ngữ, nên không so được giữa các môi trường.",[973,104099,104100,104102,104103,104106],{},[1487,104101,96904],{}," Trong mô hình RAM, đoạn ",[992,104104,104105],{},"x = a[i] + a[j] * 2"," tốn khoảng bao nhiêu bước?",[96754,104108,104109],{"close-text":96756,"name":96757,"open-text":96758},[973,104110,104111,104112,1517],{},"Vài bước hằng số: 2 lần đọc nhớ, 1 nhân, 1 cộng, 1 ghi. Tổng là ",[1023,104113,104115,104134],{"className":104114},[1026],[1023,104116,104118],{"className":104117},[1030],[1032,104119,104120],{"xmlns":1034},[1036,104121,104122,104132],{},[1039,104123,104124,104126,104128,104130],{},[1042,104125,1044],{},[1046,104127,1049],{"stretchy":1048},[1051,104129,1053],{},[1046,104131,1056],{"stretchy":1048},[1058,104133,1061],{"encoding":1060},[1023,104135,104137],{"className":104136,"ariaHidden":1066},[1065],[1023,104138,104140,104143,104146,104149,104152],{"className":104139},[1070],[1023,104141],{"className":104142,"style":1075},[1074],[1023,104144,1044],{"className":104145,"style":1081},[1079,1080],[1023,104147,1049],{"className":104148},[1085],[1023,104150,1053],{"className":104151},[1079],[1023,104153,1056],{"className":104154},[1092],[973,104156,104157,104159],{},[1487,104158,97431],{}," Giả định nào của RAM sai nhiều nhất trên máy thật?",[96754,104161,104162],{"close-text":96756,"name":96757,"open-text":96758},[973,104163,104164],{},"Mọi truy cập bộ nhớ tốn như nhau. Thực tế đọc cache L1 nhanh hơn RAM cả trăm lần, đọc đĩa còn chậm hơn nữa.",[973,104166,104167,2308,104169,1509,104217,104260],{},[1487,104168,97800],{},[1023,104170,104172,104193],{"className":104171},[1026],[1023,104173,104175],{"className":104174},[1030],[1032,104176,104177],{"xmlns":1034},[1036,104178,104179,104191],{},[1039,104180,104181,104183,104185,104187,104189],{},[1042,104182,1044],{},[1046,104184,1049],{"stretchy":1048},[1051,104186,13826],{},[1042,104188,1262],{},[1046,104190,1056],{"stretchy":1048},[1058,104192,103708],{"encoding":1060},[1023,104194,104196],{"className":104195,"ariaHidden":1066},[1065],[1023,104197,104199,104202,104205,104208,104211,104214],{"className":104198},[1070],[1023,104200],{"className":104201,"style":1075},[1074],[1023,104203,1044],{"className":104204,"style":1081},[1079,1080],[1023,104206,1049],{"className":104207},[1085],[1023,104209,13826],{"className":104210},[1079],[1023,104212,1262],{"className":104213},[1079,1080],[1023,104215,1056],{"className":104216},[1092],[1023,104218,104220,104239],{"className":104219},[1026],[1023,104221,104223],{"className":104222},[1030],[1032,104224,104225],{"xmlns":1034},[1036,104226,104227,104237],{},[1039,104228,104229,104231,104233,104235],{},[1042,104230,1044],{},[1046,104232,1049],{"stretchy":1048},[1042,104234,1262],{},[1046,104236,1056],{"stretchy":1048},[1058,104238,1267],{"encoding":1060},[1023,104240,104242],{"className":104241,"ariaHidden":1066},[1065],[1023,104243,104245,104248,104251,104254,104257],{"className":104244},[1070],[1023,104246],{"className":104247,"style":1075},[1074],[1023,104249,1044],{"className":104250,"style":1081},[1079,1080],[1023,104252,1049],{"className":104253},[1085],[1023,104255,1262],{"className":104256},[1079,1080],[1023,104258,1056],{"className":104259},[1092]," có khác nhau không?",[96754,104262,104263],{"close-text":96756,"name":96757,"open-text":96758},[973,104264,104265],{},"Không. Hằng số bị bỏ trong Big-O.",[973,104267,104268,104270,104271,104370,104371,104444],{},[1487,104269,97983],{}," Tính tổng ",[1023,104272,104274,104304],{"className":104273},[1026],[1023,104275,104277],{"className":104276},[1030],[1032,104278,104279],{"xmlns":1034},[1036,104280,104281,104301],{},[1039,104282,104283,104285,104287,104289,104291,104293,104295,104297,104299],{},[1051,104284,1053],{},[1046,104286,21881],{},[1051,104288,2457],{},[1046,104290,21881],{},[1042,104292,1517],{"mathvariant":2460},[1042,104294,1517],{"mathvariant":2460},[1042,104296,1517],{"mathvariant":2460},[1046,104298,21881],{},[1042,104300,1262],{},[1058,104302,104303],{"encoding":1060},"1 + 2 + ... + n",[1023,104305,104307,104325,104343,104361],{"className":104306,"ariaHidden":1066},[1065],[1023,104308,104310,104313,104316,104319,104322],{"className":104309},[1070],[1023,104311],{"className":104312,"style":18148},[1074],[1023,104314,1053],{"className":104315},[1079],[1023,104317],{"className":104318,"style":13790},[2354],[1023,104320,21881],{"className":104321},[13794],[1023,104323],{"className":104324,"style":13790},[2354],[1023,104326,104328,104331,104334,104337,104340],{"className":104327},[1070],[1023,104329],{"className":104330,"style":18148},[1074],[1023,104332,2457],{"className":104333},[1079],[1023,104335],{"className":104336,"style":13790},[2354],[1023,104338,21881],{"className":104339},[13794],[1023,104341],{"className":104342,"style":13790},[2354],[1023,104344,104346,104349,104352,104355,104358],{"className":104345},[1070],[1023,104347],{"className":104348,"style":13783},[1074],[1023,104350,88369],{"className":104351},[1079],[1023,104353],{"className":104354,"style":13790},[2354],[1023,104356,21881],{"className":104357},[13794],[1023,104359],{"className":104360,"style":13790},[2354],[1023,104362,104364,104367],{"className":104363},[1070],[1023,104365],{"className":104366,"style":2347},[1074],[1023,104368,1262],{"className":104369},[1079,1080]," bằng công thức ",[1023,104372,104374,104402],{"className":104373},[1026],[1023,104375,104377],{"className":104376},[1030],[1032,104378,104379],{"xmlns":1034},[1036,104380,104381,104399],{},[1039,104382,104383,104385,104387,104389,104391,104393,104395,104397],{},[1042,104384,1262],{},[1046,104386,1049],{"stretchy":1048},[1042,104388,1262],{},[1046,104390,21881],{},[1051,104392,1053],{},[1046,104394,1056],{"stretchy":1048},[1042,104396,2461],{"mathvariant":2460},[1051,104398,2457],{},[1058,104400,104401],{"encoding":1060},"n(n+1)\u002F2",[1023,104403,104405,104429],{"className":104404,"ariaHidden":1066},[1065],[1023,104406,104408,104411,104414,104417,104420,104423,104426],{"className":104407},[1070],[1023,104409],{"className":104410,"style":1075},[1074],[1023,104412,1262],{"className":104413},[1079,1080],[1023,104415,1049],{"className":104416},[1085],[1023,104418,1262],{"className":104419},[1079,1080],[1023,104421],{"className":104422,"style":13790},[2354],[1023,104424,21881],{"className":104425},[13794],[1023,104427],{"className":104428,"style":13790},[2354],[1023,104430,104432,104435,104438,104441],{"className":104431},[1070],[1023,104433],{"className":104434,"style":1075},[1074],[1023,104436,1053],{"className":104437},[1079],[1023,104439,1056],{"className":104440},[1092],[1023,104442,2509],{"className":104443},[1079]," tốn bao nhiêu bước?",[96754,104446,104447],{"close-text":96756,"name":96757,"open-text":96758},[973,104448,104449,104492,104493,1517],{},[1023,104450,104452,104471],{"className":104451},[1026],[1023,104453,104455],{"className":104454},[1030],[1032,104456,104457],{"xmlns":1034},[1036,104458,104459,104469],{},[1039,104460,104461,104463,104465,104467],{},[1042,104462,1044],{},[1046,104464,1049],{"stretchy":1048},[1051,104466,1053],{},[1046,104468,1056],{"stretchy":1048},[1058,104470,1061],{"encoding":1060},[1023,104472,104474],{"className":104473,"ariaHidden":1066},[1065],[1023,104475,104477,104480,104483,104486,104489],{"className":104476},[1070],[1023,104478],{"className":104479,"style":1075},[1074],[1023,104481,1044],{"className":104482,"style":1081},[1079,1080],[1023,104484,1049],{"className":104485},[1085],[1023,104487,1053],{"className":104488},[1079],[1023,104490,1056],{"className":104491},[1092],": một cộng, một nhân, một chia, không phụ thuộc ",[1023,104494,104496,104509],{"className":104495},[1026],[1023,104497,104499],{"className":104498},[1030],[1032,104500,104501],{"xmlns":1034},[1036,104502,104503,104507],{},[1039,104504,104505],{},[1042,104506,1262],{},[1058,104508,1262],{"encoding":1060},[1023,104510,104512],{"className":104511,"ariaHidden":1066},[1065],[1023,104513,104515,104518],{"className":104514},[1070],[1023,104516],{"className":104517,"style":2347},[1074],[1023,104519,1262],{"className":104520},[1079,1080],[968,104522,98220],{"id":98219},[986,104524,104525,104528,104531,104534,104537],{},[989,104526,104527],{},"Đo bằng giây hay đếm lệnh đều không khái quát được, nên cần mô hình RAM tối giản.",[989,104529,104530],{},"Bốn giả định RAM: phép cơ sở một bước, vòng lặp theo số lần, nhớ một bước, bộ nhớ vô hạn.",[989,104532,104533],{},"Chi phí phải biểu diễn thành hàm của n, rồi phát biểu bằng Big-O.",[989,104535,104536],{},"Hệ quả: bỏ hằng số, số hạng trội thắng, tích không rút gọn được.",[989,104538,104539],{},"Dùng RAM để phân tích ban đầu, đưa phần cứng trở lại khi tối ưu điểm nóng.",{"title":1357,"searchDepth":68,"depth":68,"links":104541},[104542,104543,104544,104545,104546,104547,104548,104549,104550,104551],{"id":90890,"depth":68,"text":90891},{"id":103097,"depth":68,"text":103098},{"id":103116,"depth":68,"text":103117},{"id":103218,"depth":68,"text":103219},{"id":103320,"depth":68,"text":103321},{"id":98911,"depth":68,"text":98912},{"id":98930,"depth":68,"text":98931},{"id":98946,"depth":68,"text":98947},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Các giả định của mô hình RAM, cách đếm bước trừu tượng, bậc tăng trưởng và ý nghĩa của việc bỏ qua hằng số.",{},{"title":38,"description":104552},[104556,104557,104558,7],"ram-model","chi-phi","ly-thuyet","YUSHmSnnvkvxVGEjolGjVlJu8SQAzrXu18seBoXUUkY",{"id":104561,"title":42,"body":104562,"category":7,"day":3047,"description":105267,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":105268,"navigation":2723,"outcomes":3047,"path":43,"prerequisites":3047,"seo":105269,"stem":44,"tags":105270,"__hash__":105273},"fundamentals\u002Ffundamentals\u002Fthiet-ke-va-kiem-chung-thuat-toan.md",{"type":965,"value":104563,"toc":105255},[104564,104566,104569,104572,104575,104579,104582,104585,104588,104591,104594,104597,104600,104604,104607,104610,104613,104616,104619,104622,104625,104782,104786,104789,104792,104795,104798,104801,104804,104807,104811,104814,104817,104820,104823,104826,104829,104831,104834,104837,104840,104843,104846,104848,104851,104854,104857,104860,104862,104865,104868,104871,104873,104875,104880,104885,104890,104895,104900,104905,104910,105226,105231,105236,105238],[968,104565,90891],{"id":90890},[973,104567,104568],{},"Thiết kế mà không kiểm chứng chẳng khác xây cầu không thử tải. Khung đầy đủ gồm bốn phần.",[973,104570,104571],{},"Ba mối quan tâm khi thiết kế là gì. Ba họ thuật toán với logic kiểm chứng khác nhau ra sao.",[973,104573,104574],{},"Cách dùng độ đo để kiểm chứng thế nào. Yêu cầu mới về tính giải thích được là gì.",[968,104576,104578],{"id":104577},"_2-ba-mối-quan-tâm-khi-thiết-kế","2. Ba mối quan tâm khi thiết kế",[973,104580,104581],{},"Ba câu hỏi phải thường trực suốt quá trình thiết kế và tinh chỉnh. Mối thứ nhất: thuật toán có cho kết quả mong đợi không.",[973,104583,104584],{},"Đây là câu hỏi về tính đúng đắn. Câu trả lời đến từ kiểm thử rộng khắp, nhất là trường hợp biên.",[973,104586,104587],{},"Mối thứ hai: đó có phải cách tối ưu nhất không. Đây là câu hỏi về tính tối ưu.",[973,104589,104590],{},"Nhân loại đã tốn hàng thập kỷ cho một lớp bài mà vẫn chưa biết lời giải hiện có tốt nhất chưa. Mối thứ ba: thuật toán thể hiện ra sao trên dữ liệu lớn hơn.",[973,104592,104593],{},"Đây là câu hỏi về khả năng mở rộng. Câu trả lời đến từ phân tích độ phức tạp và hạ tầng co giãn.",[973,104595,104596],{},"Thứ tự ưu tiên thực tế: đúng trước, tối ưu sau, mở rộng cuối cùng. Thuật toán nhanh mà sai là vô giá trị.",[973,104598,104599],{},"Thuật toán đúng mà không mở rộng được chỉ dùng cho bài nhỏ. Giống như món ngon, ra nhanh, giá rõ: thiếu món ngon thì hai thứ còn lại vô nghĩa.",[968,104601,104603],{"id":104602},"_3-ba-họ-thuật-toán-và-logic-kiểm-chứng-khác-nhau","3. Ba họ thuật toán và logic kiểm chứng khác nhau",[973,104605,104606],{},"Kiểm chứng phụ thuộc vào họ thuật toán. Vì kỹ thuật kiểm thử mỗi họ khác nhau.",[973,104608,104609],{},"Trước hết phân biệt tất định và ngẫu nhiên. Thuật toán tất định cho cùng một đầu vào luôn ra một đầu ra.",[973,104611,104612],{},"Nên kiểm chứng bằng tập kiểm thử cố định với kết quả kỳ vọng cố định. Thuật toán ngẫu nhiên đưa thêm dãy số ngẫu nhiên làm đầu vào.",[973,104614,104615],{},"Mỗi lần chạy cho đầu ra khác nhau. Kiểm chứng họ này phải kiểm tính chất thống kê, không trông đợi kết quả cố định.",[973,104617,104618],{},"Trên trục khác, chia thành chính xác và xấp xỉ. Thuật toán chính xác cho nghiệm đúng mà không thêm giả định hay xấp xỉ nào.",[973,104620,104621],{},"Thuật toán xấp xỉ đơn giản hóa bài toán bằng giả định khi tài nguyên không kham nổi. Nên nó không cho nghiệm đúng tuyệt đối.",[973,104623,104624],{},"Ví dụ minh họa là người bán hàng rong ra đời năm 1930. Tìm hành trình ngắn nhất thăm mỗi thành phố một lần rồi về điểm xuất phát.",[973,104626,104627,104628,104692,104693,104781],{},"Cách trực diện liệt kê mọi hoán vị rồi chọn rẻ nhất: ",[1023,104629,104631,104655],{"className":104630},[1026],[1023,104632,104634],{"className":104633},[1030],[1032,104635,104636],{"xmlns":1034},[1036,104637,104638,104652],{},[1039,104639,104640,104642,104644,104646,104648,104650],{},[1046,104641,1049],{"stretchy":1048},[1042,104643,1262],{},[1046,104645,17698],{},[1051,104647,1053],{},[1046,104649,1056],{"stretchy":1048},[1046,104651,15001],{"stretchy":1048},[1058,104653,104654],{"encoding":1060},"(n-1)!",[1023,104656,104658,104679],{"className":104657,"ariaHidden":1066},[1065],[1023,104659,104661,104664,104667,104670,104673,104676],{"className":104660},[1070],[1023,104662],{"className":104663,"style":1075},[1074],[1023,104665,1049],{"className":104666},[1085],[1023,104668,1262],{"className":104669},[1079,1080],[1023,104671],{"className":104672,"style":13790},[2354],[1023,104674,17698],{"className":104675},[13794],[1023,104677],{"className":104678,"style":13790},[2354],[1023,104680,104682,104685,104688],{"className":104681},[1070],[1023,104683],{"className":104684,"style":1075},[1074],[1023,104686,1053],{"className":104687},[1079],[1023,104689,104691],{"className":104690},[1092],")!"," tour. Với 15 thành phố đã là khoảng ",[1023,104694,104696,104719],{"className":104695},[1026],[1023,104697,104699],{"className":104698},[1030],[1032,104700,104701],{"xmlns":1034},[1036,104702,104703,104716],{},[1039,104704,104705,104708,104710],{},[1051,104706,104707],{},"8.7",[1046,104709,18118],{},[2327,104711,104712,104714],{},[1051,104713,2331],{},[1051,104715,2331],{},[1058,104717,104718],{"encoding":1060},"8.7 \\cdot 10^{10}",[1023,104720,104722,104740],{"className":104721,"ariaHidden":1066},[1065],[1023,104723,104725,104728,104731,104734,104737],{"className":104724},[1070],[1023,104726],{"className":104727,"style":10020},[1074],[1023,104729,104707],{"className":104730},[1079],[1023,104732],{"className":104733,"style":13790},[2354],[1023,104735,18118],{"className":104736},[13794],[1023,104738],{"className":104739,"style":13790},[2354],[1023,104741,104743,104746,104749],{"className":104742},[1070],[1023,104744],{"className":104745,"style":2369},[1074],[1023,104747,1053],{"className":104748},[1079],[1023,104750,104752,104755],{"className":104751},[1079],[1023,104753,2379],{"className":104754},[1079],[1023,104756,104758],{"className":104757},[2383],[1023,104759,104761],{"className":104760},[2387],[1023,104762,104764],{"className":104763},[2391],[1023,104765,104767],{"className":104766,"style":2369},[2395],[1023,104768,104769,104772],{"style":2398},[1023,104770],{"className":104771,"style":2403},[2402],[1023,104773,104775],{"className":104774},[2407,2408,2409,2410],[1023,104776,104778],{"className":104777},[1079,2410],[1023,104779,2331],{"className":104780},[1079,2410]," tour, vét cạn không còn khả thi. Quy hoạch động Held-Karp đẩy ngưỡng lên khoảng 25-30 thành phố, sau đó phải dùng xấp xỉ.",[968,104783,104785],{"id":104784},"_4-kiểm-chứng-bằng-độ-đo-và-trường-hợp-biên","4. Kiểm chứng bằng độ đo và trường hợp biên",[973,104787,104788],{},"Kiểm chứng là xác nhận thuật toán thực sự giải đúng bài toán. Quy trình phải thử càng nhiều giá trị và kiểu đầu vào càng tốt.",[973,104790,104791],{},"Với học có giám sát, dữ liệu gán nhãn sẵn đóng vai trò chân lý. Ta đo độ lệch qua độ đo như accuracy (tỉ lệ đúng), precision (độ chuẩn) và recall (độ phủ).",[973,104793,104794],{},"Đôi khi đầu ra đúng không phải một giá trị đơn mà là một khoảng. Thiết kế lặp cải tiến dần cho tới khi nằm trong khoảng yêu cầu.",[973,104796,104797],{},"Với thuật toán lặp (tối ưu, học máy), mỗi vòng sinh một nghiệm ứng viên. Kiểm chứng gồm hai việc: kiểm tra từng nghiệm ứng viên có hợp lệ không, và theo dõi chất lượng qua các vòng để biết khi nào dừng.",[973,104799,104800],{},"Nội dung không thể thiếu là trường hợp biên. Đó là khi thuật toán vận hành ở cực trị tham số, hiếm gặp nhưng có thể gây sụp đổ.",[973,104802,104803],{},"Phần còn lại gọi là đường hạnh phúc, nơi tham số bình thường và thuật toán thường đi qua. Không ai liệt kê được mọi trường hợp biên.",[973,104805,104806],{},"Nhưng phải nghĩ tới càng nhiều càng tốt. Bỏ qua chúng là mời gọi sự cố.",[968,104808,104810],{"id":104809},"_5-tính-giải-thích-được-và-lime","5. Tính giải thích được và LIME",[973,104812,104813],{},"Khi thuật toán dùng cho việc trọng yếu, khả năng giải thích từng kết quả thành bắt buộc. Để đảm bảo quyết định dựa trên nó không tạo thiên kiến.",[973,104815,104816],{},"Khả năng chỉ ra đặc trưng nào dẫn tới một quyết định cụ thể gọi là tính giải thích được. Thuật toán ảnh hưởng đời người cần đánh giá thiên kiến và định kiến.",[973,104818,104819],{},"Phân tích đạo đức thuật toán đã thành phần chuẩn của kiểm chứng. Với học sâu, tính giải thích được rất khó đạt.",[973,104821,104822],{},"Ví dụ thuật toán từ chối đơn vay thế chấp của một người. Việc minh bạch lý do là bắt buộc.",[973,104824,104825],{},"Kỹ thuật hiệu quả là LIME. Đưa thay đổi nhỏ vào từng đầu vào rồi vẽ biên quyết định cục bộ quanh đó.",[973,104827,104828],{},"Từ đó lượng hóa ảnh hưởng của từng biến với từng trường hợp cụ thể. Giống như gõ nhẹ từng chỗ để xem chỗ nào làm đổi kết quả.",[968,104830,98912],{"id":98911},[973,104832,104833],{},"Đánh đổi trung tâm là giữa chính xác và hiệu năng. Thuật toán chính xác tốn tài nguyên khổng lồ cho bài khó.",[973,104835,104836],{},"Thuật toán xấp xỉ chạy nhanh nhưng đòi chấp nhận sai số. Đánh đổi thứ hai là giữa chi phí kiểm chứng và độ tin cậy.",[973,104838,104839],{},"Thử càng nhiều đầu vào và biên càng tốn kém nhưng càng an toàn. Đánh đổi thứ ba là giữa giải thích được và sức mạnh mô hình.",[973,104841,104842],{},"Mô hình càng phức tạp càng khó giải thích. Với ứng dụng trọng yếu đôi khi phải chấp nhận mô hình yếu hơn nhưng minh bạch hơn.",[973,104844,104845],{},"Giống như cân tiểu ly và cân ước lượng ngoài chợ. Mỗi loại hợp một việc.",[968,104847,98931],{"id":98930},[973,104849,104850],{},"Thứ nhất: kiểm chứng thuật toán ngẫu nhiên như tất định. Trông đợi cùng một đầu ra mọi lần chạy.",[973,104852,104853],{},"Thứ hai: dùng xấp xỉ mà không đặt ngưỡng sai số từ đầu. Không ai biết lệch bao nhiêu thì chấp nhận được.",[973,104855,104856],{},"Thứ ba: chỉ thử đường hạnh phúc mà quên trường hợp biên. Sự cố thường ẩn náu ở đó.",[973,104858,104859],{},"Thứ tư: coi kiểm chứng là việc một lần cuối dự án. Thực ra thiết kế là quá trình lặp, mỗi vòng đều kiểm chứng lại ba mối quan tâm.",[968,104861,98947],{"id":98946},[973,104863,104864],{},"Khung ba mối quan tâm dùng như danh sách kiểm tra mọi buổi đánh giá thiết kế. Đúng chưa, tối ưu chưa, mở rộng được không.",[973,104866,104867],{},"Yêu cầu giải thích được ngày càng vào đặc tả hệ trọng yếu. Như tín dụng, tuyển dụng và y tế.",[973,104869,104870],{},"Hỏi ba câu này sớm giúp tránh sửa lớn về sau. Rẻ hơn nhiều so với vá khi đã triển khai.",[968,104872,96573],{"id":96572},[973,104874,96576],{},[973,104876,104877,104879],{},[1487,104878,96581],{}," Ba mối quan tâm khi thiết kế, theo thứ tự ưu tiên?",[96754,104881,104882],{"close-text":96756,"name":96757,"open-text":96758},[973,104883,104884],{},"Đúng đắn, tối ưu, khả năng mở rộng.",[973,104886,104887,104889],{},[1487,104888,96904],{}," Làm sao kiểm thử một thuật toán ngẫu nhiên?",[96754,104891,104892],{"close-text":96756,"name":96757,"open-text":96758},[973,104893,104894],{},"Cố định seed để tái lập, và kiểm tra tính chất thống kê qua nhiều lần chạy thay vì so một đầu ra cố định.",[973,104896,104897,104899],{},[1487,104898,97431],{}," Kể 4 trường hợp biên khi kiểm thử hàm sắp xếp.",[96754,104901,104902],{"close-text":96756,"name":96757,"open-text":96758},[973,104903,104904],{},"Mảng rỗng, 1 phần tử, toàn phần tử bằng nhau, đã sắp xếp hoặc sắp ngược. Thêm: số âm, giá trị lớn nhất của kiểu dữ liệu.",[973,104906,104907,104909],{},[1487,104908,97800],{}," TSP 20 thành phố: vét cạn có khả thi không?",[96754,104911,104912],{"close-text":96756,"name":96757,"open-text":96758},[973,104913,104914,104915,105031,105032,105140,105141,105225],{},"Không. ",[1023,104916,104918,104948],{"className":104917},[1026],[1023,104919,104921],{"className":104920},[1030],[1032,104922,104923],{"xmlns":1034},[1036,104924,104925,104945],{},[1039,104926,104927,104930,104932,104934,104936,104938],{},[1051,104928,104929],{},"19",[1046,104931,15001],{"stretchy":1048},[1046,104933,24020],{},[1051,104935,71735],{},[1046,104937,18118],{},[2327,104939,104940,104942],{},[1051,104941,2331],{},[1051,104943,104944],{},"17",[1058,104946,104947],{"encoding":1060},"19! \\approx 1.2 \\cdot 10^{17}",[1023,104949,104951,104972,104990],{"className":104950,"ariaHidden":1066},[1065],[1023,104952,104954,104957,104960,104963,104966,104969],{"className":104953},[1070],[1023,104955],{"className":104956,"style":22079},[1074],[1023,104958,104929],{"className":104959},[1079],[1023,104961,15001],{"className":104962},[1092],[1023,104964],{"className":104965,"style":2355},[2354],[1023,104967,24020],{"className":104968},[2359],[1023,104970],{"className":104971,"style":2355},[2354],[1023,104973,104975,104978,104981,104984,104987],{"className":104974},[1070],[1023,104976],{"className":104977,"style":10020},[1074],[1023,104979,71735],{"className":104980},[1079],[1023,104982],{"className":104983,"style":13790},[2354],[1023,104985,18118],{"className":104986},[13794],[1023,104988],{"className":104989,"style":13790},[2354],[1023,104991,104993,104996,104999],{"className":104992},[1070],[1023,104994],{"className":104995,"style":2369},[1074],[1023,104997,1053],{"className":104998},[1079],[1023,105000,105002,105005],{"className":105001},[1079],[1023,105003,2379],{"className":105004},[1079],[1023,105006,105008],{"className":105007},[2383],[1023,105009,105011],{"className":105010},[2387],[1023,105012,105014],{"className":105013},[2391],[1023,105015,105017],{"className":105016,"style":2369},[2395],[1023,105018,105019,105022],{"style":2398},[1023,105020],{"className":105021,"style":2403},[2402],[1023,105023,105025],{"className":105024},[2407,2408,2409,2410],[1023,105026,105028],{"className":105027},[1079,2410],[1023,105029,104944],{"className":105030},[1079,2410]," tour. Held-Karp ",[1023,105033,105035,105064],{"className":105034},[1026],[1023,105036,105038],{"className":105037},[1030],[1032,105039,105040],{"xmlns":1034},[1036,105041,105042,105062],{},[1039,105043,105044,105046,105048,105054,105060],{},[1042,105045,1044],{},[1046,105047,1049],{"stretchy":1048},[2327,105049,105050,105052],{},[1042,105051,1262],{},[1051,105053,2457],{},[2327,105055,105056,105058],{},[1051,105057,2457],{},[1042,105059,1262],{},[1046,105061,1056],{"stretchy":1048},[1058,105063,48701],{"encoding":1060},[1023,105065,105067],{"className":105066,"ariaHidden":1066},[1065],[1023,105068,105070,105073,105076,105079,105108,105137],{"className":105069},[1070],[1023,105071],{"className":105072,"style":2476},[1074],[1023,105074,1044],{"className":105075,"style":1081},[1079,1080],[1023,105077,1049],{"className":105078},[1085],[1023,105080,105082,105085],{"className":105081},[1079],[1023,105083,1262],{"className":105084},[1079,1080],[1023,105086,105088],{"className":105087},[2383],[1023,105089,105091],{"className":105090},[2387],[1023,105092,105094],{"className":105093},[2391],[1023,105095,105097],{"className":105096,"style":2369},[2395],[1023,105098,105099,105102],{"style":2398},[1023,105100],{"className":105101,"style":2403},[2402],[1023,105103,105105],{"className":105104},[2407,2408,2409,2410],[1023,105106,2457],{"className":105107},[1079,2410],[1023,105109,105111,105114],{"className":105110},[1079],[1023,105112,2457],{"className":105113},[1079],[1023,105115,105117],{"className":105116},[2383],[1023,105118,105120],{"className":105119},[2387],[1023,105121,105123],{"className":105122},[2391],[1023,105124,105126],{"className":105125,"style":8348},[2395],[1023,105127,105128,105131],{"style":2398},[1023,105129],{"className":105130,"style":2403},[2402],[1023,105132,105134],{"className":105133},[2407,2408,2409,2410],[1023,105135,1262],{"className":105136},[1079,1080,2410],[1023,105138,1056],{"className":105139},[1092]," chỉ khoảng ",[1023,105142,105144,105166],{"className":105143},[1026],[1023,105145,105147],{"className":105146},[1030],[1032,105148,105149],{"xmlns":1034},[1036,105150,105151,105163],{},[1039,105152,105153,105155,105157],{},[1051,105154,25255],{},[1046,105156,18118],{},[2327,105158,105159,105161],{},[1051,105160,2331],{},[1051,105162,14650],{},[1058,105164,105165],{"encoding":1060},"4 \\cdot 10^8",[1023,105167,105169,105187],{"className":105168,"ariaHidden":1066},[1065],[1023,105170,105172,105175,105178,105181,105184],{"className":105171},[1070],[1023,105173],{"className":105174,"style":10020},[1074],[1023,105176,25255],{"className":105177},[1079],[1023,105179],{"className":105180,"style":13790},[2354],[1023,105182,18118],{"className":105183},[13794],[1023,105185],{"className":105186,"style":13790},[2354],[1023,105188,105190,105193,105196],{"className":105189},[1070],[1023,105191],{"className":105192,"style":2369},[1074],[1023,105194,1053],{"className":105195},[1079],[1023,105197,105199,105202],{"className":105198},[1079],[1023,105200,2379],{"className":105201},[1079],[1023,105203,105205],{"className":105204},[2383],[1023,105206,105208],{"className":105207},[2387],[1023,105209,105211],{"className":105210},[2391],[1023,105212,105214],{"className":105213,"style":2369},[2395],[1023,105215,105216,105219],{"style":2398},[1023,105217],{"className":105218,"style":2403},[2402],[1023,105220,105222],{"className":105221},[2407,2408,2409,2410],[1023,105223,14650],{"className":105224},[1079,2410]," bước nên vẫn chạy được.",[973,105227,105228,105230],{},[1487,105229,97983],{}," LIME giải thích một dự đoán bằng cách nào?",[96754,105232,105233],{"close-text":96756,"name":96757,"open-text":96758},[973,105234,105235],{},"Thay đổi nhẹ đầu vào quanh điểm cần giải thích, quan sát đầu ra đổi ra sao, rồi khớp một mô hình đơn giản cục bộ để đo ảnh hưởng từng đặc trưng.",[968,105237,98220],{"id":98219},[986,105239,105240,105243,105246,105249,105252],{},[989,105241,105242],{},"Thiết kế tốt trả lời ba câu hỏi: đúng đắn, tối ưu và mở rộng, theo quá trình lặp.",[989,105244,105245],{},"Bốn họ tất định, ngẫu nhiên, chính xác, xấp xỉ cần logic kiểm chứng khác nhau.",[989,105247,105248],{},"Kiểm chứng dùng độ đo so với chân lý, kiểm tra nghiệm ứng viên và bao phủ trường hợp biên.",[989,105250,105251],{},"Người bán hàng rong minh họa ngưỡng phải chuyển sang xấp xỉ: vét cạn tắc ở khoảng 15 thành phố, quy hoạch động ở khoảng 30.",[989,105253,105254],{},"Tính giải thích được với LIME là bắt buộc với ứng dụng trọng yếu.",{"title":1357,"searchDepth":68,"depth":68,"links":105256},[105257,105258,105259,105260,105261,105262,105263,105264,105265,105266],{"id":90890,"depth":68,"text":90891},{"id":104577,"depth":68,"text":104578},{"id":104602,"depth":68,"text":104603},{"id":104784,"depth":68,"text":104785},{"id":104809,"depth":68,"text":104810},{"id":98911,"depth":68,"text":98912},{"id":98930,"depth":68,"text":98931},{"id":98946,"depth":68,"text":98947},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Ba mối quan tâm thiết kế, phân biệt exact-approximate-randomized, kiểm chứng bằng độ đo và tính giải thích được của thuật toán.",{},{"title":42,"description":105267},[99049,105271,105272,7],"kiem-chung","explainability","Jqca6gPr3xVnTwD9HHAuet2d4k-UQj4G33-6cvWtFmo",{"id":105275,"title":46,"body":105276,"category":7,"day":3047,"description":105762,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":105763,"navigation":2723,"outcomes":3047,"path":47,"prerequisites":3047,"seo":105764,"stem":48,"tags":105765,"__hash__":105768},"fundamentals\u002Ffundamentals\u002Fthuat-toan-moi-truong-phat-trien.md",{"type":965,"value":105277,"toc":105746},[105278,105280,105283,105286,105289,105293,105296,105299,105302,105305,105308,105311,105315,105318,105321,105324,105327,105330,105333,105336,105340,105343,105346,105349,105352,105356,105359,105362,105365,105368,105416,105419,105433,105436,105440,105444,105518,105564,105568,105571,105616,105623,105625,105628,105631,105634,105637,105640,105642,105645,105648,105651,105654,105656,105659,105662,105665,105667,105669,105674,105679,105684,105689,105694,105699,105704,105711,105716,105724,105726,105743],[968,105279,90891],{"id":90890},[973,105281,105282],{},"Trước khi học thuật toán cụ thể, cần thống nhất ba điều. Thuật toán là gì, nó đi từ ý tưởng tới sản phẩm qua chặng nào.",[973,105284,105285],{},"Môi trường thử nghiệm nào phù hợp để học và nghiên cứu. Bài này trình bày toàn bộ khung cảnh đó ở mức lý thuyết.",[973,105287,105288],{},"Làm bệ đỡ cho mọi bài học thuật toán phía sau. Không đi vào thuật toán coding cụ thể nào.",[968,105290,105292],{"id":105291},"_2-thuật-toán-là-gì","2. Thuật toán là gì",[973,105294,105295],{},"Định nghĩa gọn nhất: thuật toán là tập quy tắc thực hiện phép tính để giải một bài toán. Nó cho ra kết quả với mọi đầu vào hợp lệ theo chỉ dẫn định nghĩa chính xác.",[973,105297,105298],{},"Từ điển American Heritage định nghĩa: tập hữu hạn chỉ dẫn không mơ hồ, với điều kiện ban đầu cho trước, thực hiện theo trình tự quy định để đạt mục tiêu, và có điều kiện kết thúc nhận biết được.",[973,105300,105301],{},"Ba tính từ đáng suy ngẫm. Hữu hạn nghĩa là thuật toán phải dừng, không phải quá trình vô tận.",[973,105303,105304],{},"Không mơ hồ nghĩa là mỗi bước rõ tới mức ai làm cũng ra cùng kết quả. Có điều kiện kết thúc nhận biết được nghĩa là ta luôn biết khi nào xong việc.",[973,105306,105307],{},"Thiết kế thuật toán là tạo công thức toán hiệu quả nhất cho bài thực tế. Công thức đó có thể thành nền tảng tái dùng cho cả họ bài tương tự.",[973,105309,105310],{},"Giống như công thức nấu ăn từng bước rõ ràng. Bước mơ hồ thì không phải thuật toán.",[968,105312,105314],{"id":105313},"_3-các-pha-từ-yêu-cầu-tới-triển-khai","3. Các pha: từ yêu cầu tới triển khai",[973,105316,105317],{},"Vòng đời thuật toán đi qua sơ đồ các pha. Mọi thứ bắt đầu từ hiểu yêu cầu trong phát biểu bài toán.",[973,105319,105320],{},"Tức làm rõ cần làm gì trước khi nghĩ làm như thế nào. Từ đó bước vào pha phát triển gồm hai chặng nhỏ.",[973,105322,105323],{},"Chặng thiết kế hình dung và ghi lại kiến trúc, logic và chi tiết cài đặt. Trong đầu luôn giữ cả chính xác và hiệu năng.",[973,105325,105326],{},"Khi có nhiều ứng viên, chặng thiết kế là quá trình lặp. So sánh ứng viên với mọi đánh đổi rồi mới lựa chọn.",[973,105328,105329],{},"Chặng viết mã chuyển thiết kế thành chương trình máy tính. Yêu cầu quan trọng là triển khai đầy đủ logic và kiến trúc đã đề ra.",[973,105331,105332],{},"Xong thiết kế và viết mã thì sẵn sàng triển khai. Thiết kế môi trường sản phẩm nơi mã sẽ chạy.",[973,105334,105335],{},"Rồi đưa thuật toán vào vận hành với dữ liệu thật để sinh đầu ra theo yêu cầu. Giống như tập lái ở sân rồi mới chạy thật ngoài đường.",[968,105337,105339],{"id":105338},"_4-yêu-cầu-chức-năng-và-phi-chức-năng","4. Yêu cầu chức năng và phi chức năng",[973,105341,105342],{},"Bài toán thực tế có hai loại yêu cầu. Yêu cầu chức năng quy định tính năng mong đợi, tức mô tả hành vi.",[973,105344,105345],{},"Với một đầu vào nhất định thì đầu ra kỳ vọng là gì. Yêu cầu phi chức năng nói về hiệu năng, mở rộng, khả dụng và chính xác.",[973,105347,105348],{},"Đồng thời đặt kỳ vọng về bảo mật dữ liệu. Ví dụ món ăn là chức năng, giao trong 30 phút là phi chức năng.",[973,105350,105351],{},"Phi chức năng phải có số đo được. Không đo được thì không nghiệm thu được.",[968,105353,105355],{"id":105354},"_5-môi-trường-phát-triển-và-môi-trường-sản-phẩm","5. Môi trường phát triển và môi trường sản phẩm",[973,105357,105358],{},"Môi trường phát triển là nơi học, thử và cài đặt thuật toán. Môi trường sản phẩm là nơi thuật toán vận hành thực tế.",[973,105360,105361],{},"Môi trường sản phẩm thiết kế theo nhu cầu dữ liệu và xử lý. Thuật toán song song được cần cụm máy với số nút phù hợp.",[973,105363,105364],{},"Thuật toán nặng dữ liệu cần đường ống nạp, chiến lược đệm và lưu trữ. Chi tiết môi trường cho hệ lớn dành cho các bài sau.",[973,105366,105367],{},"Về phía phát triển, khóa học dùng hai ngôn ngữ, mỗi ngôn ngữ cho một việc:",[1099,105369,105370,105382],{},[1102,105371,105372],{},[1105,105373,105374,105377,105380],{},[1108,105375,105376],{},"Nhóm bài",[1108,105378,105379],{},"Ngôn ngữ",[1108,105381,1116],{},[1118,105383,105384,105395,105406],{},[1105,105385,105386,105389,105392],{},[1123,105387,105388],{},"Cấu trúc dữ liệu, thuật toán cổ điển",[1123,105390,105391],{},"C hoặc C++17",[1123,105393,105394],{},"Thấy rõ bộ nhớ, con trỏ, chi phí từng thao tác",[1105,105396,105397,105400,105403],{},[1123,105398,105399],{},"Design pattern",[1123,105401,105402],{},"C++17 hoặc Java",[1123,105404,105405],{},"Có lớp, kế thừa, giao diện rõ ràng",[1105,105407,105408,105411,105413],{},[1123,105409,105410],{},"Dữ liệu, học máy, hệ thống lớn",[1123,105412,13531],{},[1123,105414,105415],{},"Hệ sinh thái NumPy, pandas, PyTorch, Spark",[973,105417,105418],{},"Mỗi ngày học ghi rõ ngôn ngữ ở đầu mục bài tập. Bạn được đổi sang ngôn ngữ khác nếu viết lại API tương đương.",[973,105420,105421,105422,105425,105426,5586,105429,105432],{},"Thực hành bắt buộc: môi trường phải dựng lại được bằng một lệnh. Với Python là tệp ",[992,105423,105424],{},"requirements.txt"," ghim phiên bản thư viện. Với C\u002FC++ là ",[992,105427,105428],{},"CMakeLists.txt",[992,105430,105431],{},"Makefile"," ghi rõ cờ biên dịch.",[973,105434,105435],{},"Không lẫn số đo của môi trường phát triển với môi trường sản phẩm.",[968,105437,105439],{"id":105438},"_6-bộ-công-cụ","6. Bộ công cụ",[981,105441,105443],{"id":105442},"c-và-c","C và C++",[1099,105445,105446,105455],{},[1102,105447,105448],{},[1105,105449,105450,105453],{},[1108,105451,105452],{},"Công cụ",[1108,105454,60961],{},[1118,105456,105457,105474,105484,105494,105507],{},[1105,105458,105459,105467],{},[1123,105460,105461,5586,105464],{},[992,105462,105463],{},"gcc",[992,105465,105466],{},"clang",[1123,105468,105469,105470,105473],{},"Biên dịch. Bật ",[992,105471,105472],{},"-Wall -Wextra"," để thấy cảnh báo",[1105,105475,105476,105481],{},[1123,105477,105478],{},[992,105479,105480],{},"-fsanitize=address,undefined",[1123,105482,105483],{},"Bắt lỗi tràn mảng, dùng sau khi giải phóng, hành vi không xác định",[1105,105485,105486,105491],{},[1123,105487,105488],{},[992,105489,105490],{},"valgrind --leak-check=full",[1123,105492,105493],{},"Bắt rò bộ nhớ",[1105,105495,105496,105504],{},[1123,105497,105498,5586,105501],{},[992,105499,105500],{},"gdb",[992,105502,105503],{},"lldb",[1123,105505,105506],{},"Chạy từng bước, xem biến",[1105,105508,105509,105515],{},[1123,105510,105511,1509,105513],{},[992,105512,11494],{},[992,105514,81065],{},[1123,105516,105517],{},"Build để đo hiệu năng và tìm điểm nóng",[1352,105519,105523],{"className":105520,"code":105521,"language":105522,"meta":1357,"style":1357},"language-bash shiki shiki-themes github-light github-light github-dark","g++ -std=c++17 -Wall -Wextra -g -fsanitize=address,undefined main.cpp -o main && .\u002Fmain\n","bash",[992,105524,105525],{"__ignoreMap":1357},[1023,105526,105527,105531,105535,105538,105541,105544,105547,105551,105554,105557,105561],{"class":1362,"line":63},[1023,105528,105530],{"class":105529},"snPdu","g++",[1023,105532,105534],{"class":105533},"sBjJW"," -std=c++17",[1023,105536,105537],{"class":105533}," -Wall",[1023,105539,105540],{"class":105533}," -Wextra",[1023,105542,105543],{"class":105533}," -g",[1023,105545,105546],{"class":105533}," -fsanitize=address,undefined",[1023,105548,105550],{"class":105549},"sIIMD"," main.cpp",[1023,105552,105553],{"class":105533}," -o",[1023,105555,105556],{"class":105549}," main",[1023,105558,105560],{"class":105559},"sxrX7"," && ",[1023,105562,105563],{"class":105529},".\u002Fmain\n",[981,105565,105567],{"id":105566},"python-và-hệ-sinh-thái-scipy","Python và hệ sinh thái SciPy",[973,105569,105570],{},"Hệ sinh thái SciPy là nhóm gói Python cho cộng đồng khoa học. Nó chứa bộ sinh số ngẫu nhiên, thủ tục đại số tuyến tính và bộ tối ưu. Vì là lớp bọc mỏng quanh mã tối ưu viết bằng C, C++ và Fortran, SciPy vừa tiện vừa nhanh.",[1099,105572,105573,105582],{},[1102,105574,105575],{},[1105,105576,105577,105580],{},[1108,105578,105579],{},"Thành viên",[1108,105581,60961],{},[1118,105583,105584,105592,105600,105608],{},[1105,105585,105586,105589],{},[1123,105587,105588],{},"NumPy",[1123,105590,105591],{},"Mảng và ma trận đa chiều",[1105,105593,105594,105597],{},[1123,105595,105596],{},"scikit-learn",[1123,105598,105599],{},"Phân loại, hồi quy, phân cụm, kiểm định mô hình",[1105,105601,105602,105605],{},[1123,105603,105604],{},"pandas",[1123,105606,105607],{},"Nhập, xuất và xử lý dữ liệu dạng bảng",[1105,105609,105610,105613],{},[1123,105611,105612],{},"Matplotlib",[1123,105614,105615],{},"Trực quan hóa dữ liệu",[973,105617,105618,105619,105622],{},"Jupyter và Colab cho phép chạy thử từng đoạn, xem kết quả ngay và ghi chú xen kẽ. Rất hợp để khám phá dữ liệu. Code nộp bài vẫn nên là tệp ",[992,105620,105621],{},".py"," có test, không chỉ là notebook.",[968,105624,96352],{"id":96351},[973,105626,105627],{},"Đánh đổi đầu tiên nằm giữa thiết kế và viết mã. Đầu tư nhiều vào thiết kế tốn giờ ban đầu.",[973,105629,105630],{},"Nhưng rẻ hơn nhiều so với viết mã rồi mới phát hiện thiết kế sai. Đánh đổi thứ hai nằm giữa chức năng và phi chức năng.",[973,105632,105633],{},"Thuật toán đúng mà chậm hoặc nhanh mà sai đều không đạt. Hai nhóm yêu cầu phải cân cùng lúc.",[973,105635,105636],{},"Đánh đổi thứ ba nằm giữa phát triển tiện lợi và sản phẩm hiệu quả. Python và Jupyter tuyệt vời để thử nhanh, C++ cho quyền kiểm soát bộ nhớ và tốc độ.",[973,105638,105639],{},"Nhưng thuật toán cần mã biên dịch tối ưu mức thấp có thể phải chuyển ngôn ngữ khi lên sản phẩm. Giống như xe tập lái và xe đua dùng việc khác nhau.",[968,105641,96362],{"id":96361},[973,105643,105644],{},"Thứ nhất: nhảy vào viết mã khi phát biểu bài toán còn mơ hồ. Tức bỏ qua bước hiểu yêu cầu.",[973,105646,105647],{},"Thứ hai: lẫn cần làm gì với làm như thế nào. Tức đưa giải pháp vào trong đặc tả yêu cầu.",[973,105649,105650],{},"Thứ ba: coi môi trường phát triển mặc định là môi trường sản phẩm. Thuật toán chạy tốt trên máy cá nhân nhưng sụp đổ với dữ liệu thật.",[973,105652,105653],{},"Thứ tư: không ghim phiên bản thư viện. Kết quả hôm nay không tái tạo được ngày mai vì môi trường đã trôi.",[968,105655,96563],{"id":96562},[973,105657,105658],{},"Khung pha phát triển dùng cho mọi dự án thuật toán. Viết đặc tả yêu cầu trước, thiết kế và so ứng viên trên giấy.",[973,105660,105661],{},"Rồi mới viết mã và thiết kế môi trường triển khai. Phân biệt chức năng và phi chức năng giúp nhóm và khách hàng cùng ngôn ngữ nghiệm thu.",[973,105663,105664],{},"Thực hành tệp yêu cầu và môi trường tái tạo được giúp mọi thử nghiệm đáng tin. Mọi kết quả trong khóa học đều kiểm chứng lại được.",[968,105666,96573],{"id":96572},[973,105668,96576],{},[973,105670,105671,105673],{},[1487,105672,96581],{}," Ba tính chất của một thuật toán theo định nghĩa trong bài?",[96754,105675,105676],{"close-text":96756,"name":96757,"open-text":96758},[973,105677,105678],{},"Hữu hạn (phải dừng), không mơ hồ (mỗi bước rõ ràng), có điều kiện kết thúc nhận biết được.",[973,105680,105681,105683],{},[1487,105682,96904],{}," \"Tìm kiếm trả kết quả trong 200 ms với 1 triệu bản ghi\" là yêu cầu gì?",[96754,105685,105686],{"close-text":96756,"name":96757,"open-text":96758},[973,105687,105688],{},"Yêu cầu phi chức năng: nó đặt ngưỡng hiệu năng đo được.",[973,105690,105691,105693],{},[1487,105692,97431],{}," Vì sao phải ghim phiên bản thư viện?",[96754,105695,105696],{"close-text":96756,"name":96757,"open-text":96758},[973,105697,105698],{},"Để người khác và chính bạn sau này dựng lại đúng môi trường, và kết quả đo có thể tái lập.",[973,105700,105701,105703],{},[1487,105702,97800],{}," Lệnh biên dịch C++ nào bắt lỗi tràn mảng lúc chạy?",[96754,105705,105706],{"close-text":96756,"name":96757,"open-text":96758},[973,105707,105708,1517],{},[992,105709,105710],{},"g++ -g -fsanitize=address,undefined main.cpp",[973,105712,105713,105715],{},[1487,105714,97983],{}," Vì sao không nên đo hiệu năng với bản build có sanitizer?",[96754,105717,105718],{"close-text":96756,"name":96757,"open-text":96758},[973,105719,105720,105721,105723],{},"Sanitizer thêm kiểm tra vào mỗi lần truy cập bộ nhớ, làm chương trình chậm đi nhiều lần. Đo hiệu năng phải dùng bản ",[992,105722,11494],{}," không sanitizer.",[968,105725,98220],{"id":98219},[986,105727,105728,105731,105734,105737,105740],{},[989,105729,105730],{},"Thuật toán là tập hữu hạn chỉ dẫn không mơ hồ, có điều kiện kết thúc nhận biết được.",[989,105732,105733],{},"Vòng đời đi từ hiểu yêu cầu qua thiết kế và viết mã tới triển khai sản phẩm.",[989,105735,105736],{},"Yêu cầu chức năng mô tả hành vi, phi chức năng đặt ngưỡng đo được về hiệu năng và bảo mật.",[989,105738,105739],{},"Môi trường phát triển và sản phẩm phải thiết kế khác nhau, không lẫn số đo.",[989,105741,105742],{},"Khóa học dùng C\u002FC++ cho cấu trúc dữ liệu và thuật toán, Python cho dữ liệu và học máy; môi trường phải dựng lại được bằng một lệnh.",[3020,105744,105745],{},"html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":1357,"searchDepth":68,"depth":68,"links":105747},[105748,105749,105750,105751,105752,105753,105757,105758,105759,105760,105761],{"id":90890,"depth":68,"text":90891},{"id":105291,"depth":68,"text":105292},{"id":105313,"depth":68,"text":105314},{"id":105338,"depth":68,"text":105339},{"id":105354,"depth":68,"text":105355},{"id":105438,"depth":68,"text":105439,"children":105754},[105755,105756],{"id":105442,"depth":73,"text":105443},{"id":105566,"depth":73,"text":105567},{"id":96351,"depth":68,"text":96352},{"id":96361,"depth":68,"text":96362},{"id":96562,"depth":68,"text":96563},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Định nghĩa thuật toán, các pha phát triển và triển khai, yêu cầu chức năng và phi chức năng, môi trường học tập và môi trường vận hành.",{},{"title":46,"description":105762},[105766,105767,104558,7],"thuat-toan","moi-truong","KyVHKaU2gUcVUofGIaMipNX9Sp7Ovpv_OMcfYclI7lQ",{"id":105770,"title":50,"body":105771,"category":7,"day":3047,"description":106628,"difficulty":3043,"estimatedMinutes":283,"extension":3044,"lastUpdate":3045,"meta":106629,"navigation":2723,"outcomes":3047,"path":51,"prerequisites":3047,"seo":106630,"stem":52,"tags":106631,"__hash__":106634},"fundamentals\u002Ffundamentals\u002Ftime-space-complexity.md",{"type":965,"value":105772,"toc":106614},[105773,105775,105778,105781,105784,105788,105791,105794,105797,105800,105803,105806,105809,105813,105816,105823,105826,105829,105832,105930,105933,105936,105939,105943,105946,105949,105952,105955,105958,105961,105964,105968,105975,106032,106035,106039,106042,106045,106048,106051,106054,106057,106059,106062,106065,106068,106071,106074,106076,106079,106082,106085,106088,106090,106093,106096,106099,106101,106103,106137,106207,106212,106260,106265,106369,106374,106379,106384,106593,106595,106612],[968,105774,90891],{"id":90890},[973,105776,105777],{},"Mọi thuật toán đều tiêu hai tài nguyên hữu hạn: giờ chạy và bộ nhớ. Bài này trình bày hai trục phân tích thời gian và không gian.",[973,105779,105780],{},"Kèm ba kịch bản tốt nhất, tệ nhất và trung bình. Thêm ba kiểu vòng lặp hội tụ, phân kỳ và phẳng.",[973,105782,105783],{},"Cùng nguyên tắc ước lượng và tiết kiệm chi phí đúc kết từ đó. Nắm khung này rồi mới đọc mọi phân tích cụ thể.",[968,105785,105787],{"id":105786},"_2-hai-trục-phân-tích-thời-gian-và-không-gian","2. Hai trục phân tích: thời gian và không gian",[973,105789,105790],{},"Phân tích thời gian ước lượng thuật toán mất bao lâu dựa trên cấu trúc của nó. Điểm đáng chú ý là nó không phụ thuộc phần cứng, ngăn xếp chạy hay ngôn ngữ.",[973,105792,105793],{},"Mục tiêu trả lời hai câu hỏi lớn. Thuật toán có mở rộng được không, và nó xử lý tập lớn hơn ra sao.",[973,105795,105796],{},"Phân tích không gian ước lượng bộ nhớ cần để thực thi. Gồm nhớ cho đầu vào, cấu trúc tạm sinh lúc chạy và bản thân quá trình thực thi.",[973,105798,105799],{},"Phân tích không gian ngày càng quan trọng trong thời đại phân tán. Nếu không tính kỹ từ khâu thiết kế, nhớ thiếu cho cấu trúc tạm sẽ gây tràn đĩa.",[973,105801,105802],{},"Hiệu năng khi đó sụt nghiêm trọng. Hai cách tiếp cận phân tích được đối chiếu.",[973,105804,105805],{},"Đo sau khi cài đặt: triển khai ứng viên rồi so hiệu năng thực tế. Lý thuyết trước khi cài đặt: xấp xỉ bằng toán mà không tốn công cài đặt.",[973,105807,105808],{},"Giống như nấu nhanh cần nhiều bếp cùng lúc. Muốn nhanh thường phải trả bằng nhớ.",[968,105810,105812],{"id":105811},"_3-ba-kịch-bản-hiệu-năng-tốt-nhất-tệ-nhất-trung-bình","3. Ba kịch bản hiệu năng: tốt nhất, tệ nhất, trung bình",[973,105814,105815],{},"Hiệu năng thường phụ thuộc hình dạng đầu vào. Nên bài này trình bày ba kịch bản.",[973,105817,105818,105819,105822],{},"Kịch bản tốt nhất xét đầu vào có lợi nhất cho thuật toán. Nó cho biết thời gian chạy ",[1487,105820,105821],{},"ít nhất"," có thể, tức mức tốt nhất có thể hy vọng.",[973,105824,105825],{},"Nhưng hiếm khi phản ánh dùng thực tế. Kịch bản tệ nhất tìm giờ tối đa thuật toán có thể tốn trong điều kiện cho trước.",[973,105827,105828],{},"Giá trị của nó là đảm bảo. Bất kể điều kiện ra sao, thực tế luôn tốt hơn con số này.",[973,105830,105831],{},"Kịch bản trung bình là kỳ vọng thời gian chạy khi đầu vào tuân theo một phân phối, thường giả định mọi đầu vào cùng khả năng. Cách làm thủ công: chia đầu vào khả dĩ thành nhiều nhóm, tính chi phí mỗi nhóm rồi lấy trung bình có trọng số.",[973,105833,105834,105835,105863,105864,105892,105893,105929],{},"Ví dụ tìm tuyến tính trong mảng ",[1023,105836,105838,105851],{"className":105837},[1026],[1023,105839,105841],{"className":105840},[1030],[1032,105842,105843],{"xmlns":1034},[1036,105844,105845,105849],{},[1039,105846,105847],{},[1042,105848,1262],{},[1058,105850,1262],{"encoding":1060},[1023,105852,105854],{"className":105853,"ariaHidden":1066},[1065],[1023,105855,105857,105860],{"className":105856},[1070],[1023,105858],{"className":105859,"style":2347},[1074],[1023,105861,1262],{"className":105862},[1079,1080]," phần tử: tốt nhất 1 phép so sánh (phần tử ở đầu), tệ nhất ",[1023,105865,105867,105880],{"className":105866},[1026],[1023,105868,105870],{"className":105869},[1030],[1032,105871,105872],{"xmlns":1034},[1036,105873,105874,105878],{},[1039,105875,105876],{},[1042,105877,1262],{},[1058,105879,1262],{"encoding":1060},[1023,105881,105883],{"className":105882,"ariaHidden":1066},[1065],[1023,105884,105886,105889],{"className":105885},[1070],[1023,105887],{"className":105888,"style":2347},[1074],[1023,105890,1262],{"className":105891},[1079,1080]," (không có), trung bình khoảng ",[1023,105894,105896,105914],{"className":105895},[1026],[1023,105897,105899],{"className":105898},[1030],[1032,105900,105901],{"xmlns":1034},[1036,105902,105903,105911],{},[1039,105904,105905,105907,105909],{},[1042,105906,1262],{},[1042,105908,2461],{"mathvariant":2460},[1051,105910,2457],{},[1058,105912,105913],{"encoding":1060},"n\u002F2",[1023,105915,105917],{"className":105916,"ariaHidden":1066},[1065],[1023,105918,105920,105923,105926],{"className":105919},[1070],[1023,105921],{"className":105922,"style":1075},[1074],[1023,105924,1262],{"className":105925},[1079,1080],[1023,105927,2509],{"className":105928},[1079]," nếu phần tử có mặt ở vị trí ngẫu nhiên.",[973,105931,105932],{},"Hạn chế là không phải lúc nào cũng chính xác. Vì cần xét mọi tổ hợp và khả năng đầu vào, điều không phải lúc nào cũng dễ.",[973,105934,105935],{},"Thực tế người thiết kế dựa vào tệ nhất để quyết định an toàn. Dùng trung bình để dự báo thực tế, xem tốt nhất như mốc lạc quan.",[973,105937,105938],{},"Giống như đường vắng đi nhanh, giờ cao điểm kẹt cứng. Kế hoạch chắc chắn phải tính giờ kẹt.",[968,105940,105942],{"id":105941},"_4-ba-kiểu-vòng-lặp-và-ý-nghĩa-với-bộ-nhớ","4. Ba kiểu vòng lặp và ý nghĩa với bộ nhớ",[973,105944,105945],{},"Thuật toán phức tạp thường mang tính lặp. Thay vì nạp hết vào nhớ một lúc, chúng điền dần cấu trúc qua từng vòng.",[973,105947,105948],{},"Ba kiểu vòng lặp ảnh hưởng khác nhau tới không gian. Vòng hội tụ xử lý ít dần mỗi vòng, thách thức nằm ở vòng đầu nặng nhất.",[973,105950,105951],{},"Hạ tầng co giãn hợp kiểu này vì cấp nhiều lúc đầu rồi thu hẹp dần. Vòng phân kỳ xử lý nhiều dần mỗi vòng.",[973,105953,105954],{},"Vì không gian tăng theo giờ, cần đặt ràng buộc để hệ thống không mất ổn định. Bằng cách giới hạn số vòng hoặc kích thước dữ liệu ban đầu.",[973,105956,105957],{},"Vòng phẳng xử lý đều mỗi vòng. Vì không gian không đổi nên không cần tính co giãn hạ tầng.",[973,105959,105960],{},"Để ước lượng không gian, tập trung vào vòng phức tạp nhất. Nhiều thuật toán càng gần nghiệm càng nhẹ, nên vòng đầu cho ước lượng tốt nhất.",[973,105962,105963],{},"Khi đã chọn vòng đó, ước lượng tổng nhớ cho cấu trúc tạm, thực thi và đầu vào. Giống như chia đôi tờ giấy: mỗi lần một nửa, nhanh mỏng dần.",[981,105965,105967],{"id":105966},"đếm-bộ-nhớ-phụ","Đếm bộ nhớ phụ",[973,105969,105970,105971,105974],{},"Độ phức tạp không gian thường chỉ tính ",[1487,105972,105973],{},"bộ nhớ phụ",": phần cấp thêm ngoài đầu vào. Ba ví dụ:",[1352,105976,105978],{"className":1393,"code":105977,"language":1395,"meta":1357,"style":1357},"int sum(const std::vector\u003Cint> &a) {          \u002F\u002F bộ nhớ phụ O(1): chỉ 1 biến\n  int s = 0;\n  for (int x : a) s += x;\n  return s;\n}\nstd::vector\u003Cint> reversedCopy(const std::vector\u003Cint> &a) {   \u002F\u002F O(n): tạo mảng mới\n  return std::vector\u003Cint>(a.rbegin(), a.rend());\n}\nint sumRec(const std::vector\u003Cint> &a, size_t i) {           \u002F\u002F O(n): n khung stack\n  return i == a.size() ? 0 : a[i] + sumRec(a, i + 1);\n}\n",[992,105979,105980,105985,105990,105995,106000,106004,106009,106014,106018,106023,106028],{"__ignoreMap":1357},[1023,105981,105982],{"class":1362,"line":63},[1023,105983,105984],{},"int sum(const std::vector\u003Cint> &a) {          \u002F\u002F bộ nhớ phụ O(1): chỉ 1 biến\n",[1023,105986,105987],{"class":1362,"line":68},[1023,105988,105989],{},"  int s = 0;\n",[1023,105991,105992],{"class":1362,"line":73},[1023,105993,105994],{},"  for (int x : a) s += x;\n",[1023,105996,105997],{"class":1362,"line":78},[1023,105998,105999],{},"  return s;\n",[1023,106001,106002],{"class":1362,"line":83},[1023,106003,4986],{},[1023,106005,106006],{"class":1362,"line":88},[1023,106007,106008],{},"std::vector\u003Cint> reversedCopy(const std::vector\u003Cint> &a) {   \u002F\u002F O(n): tạo mảng mới\n",[1023,106010,106011],{"class":1362,"line":93},[1023,106012,106013],{},"  return std::vector\u003Cint>(a.rbegin(), a.rend());\n",[1023,106015,106016],{"class":1362,"line":98},[1023,106017,4986],{},[1023,106019,106020],{"class":1362,"line":103},[1023,106021,106022],{},"int sumRec(const std::vector\u003Cint> &a, size_t i) {           \u002F\u002F O(n): n khung stack\n",[1023,106024,106025],{"class":1362,"line":108},[1023,106026,106027],{},"  return i == a.size() ? 0 : a[i] + sumRec(a, i + 1);\n",[1023,106029,106030],{"class":1362,"line":113},[1023,106031,4986],{},[973,106033,106034],{},"Hàm thứ ba cho thấy đệ quy cũng tốn bộ nhớ: mỗi lời gọi chưa trả về giữ một khung trên stack.",[968,106036,106038],{"id":106037},"_5-nguyên-tắc-tiết-kiệm-không-gian-và-tư-duy-mở-rộng","5. Nguyên tắc tiết kiệm không gian và tư duy mở rộng",[973,106040,106041],{},"Ba chỉ dẫn giảm độ phức tạp không gian. Một là thiết kế dạng lặp thay vì nạp tất cả vào nhớ cùng lúc.",[973,106043,106044],{},"Hai là khi phải chọn, ưu tiên vòng nhiều và mịn hơn vòng ít và thô. Ba là chỉ giữ trong nhớ thứ cần cho xử lý hiện tại.",[973,106046,106047],{},"Thứ không cần thì đẩy ra ngoài. Tái dùng mảng cũ cũng tiết kiệm nhớ đáng kể.",[973,106049,106050],{},"Hai câu hỏi mở rộng mà phân tích thời gian phải trả lời. Thuật toán có tận dụng hạ tầng co giãn hiện đại không.",[973,106052,106053],{},"Tức có dùng thêm CPU, nhân xử lý, GPU và nhớ khi được cấp không. Thuật toán xử lý tập lớn hơn ra sao.",[973,106055,106056],{},"Vì hiệu năng ngày càng quan trọng trong thế giới dữ liệu lớn. Lúc phát triển nhiều thuật toán chỉ thử trên mẫu nhỏ, lên dữ liệu lớn mới lộ vấn đề.",[968,106058,98912],{"id":98911},[973,106060,106061],{},"Hai trục giờ và nhớ thường giằng co nhau. Dùng thêm nhớ lưu kết quả trung gian có thể rút ngắn giờ.",[973,106063,106064],{},"Tiết kiệm nhớ bằng tính lại nhiều lần sẽ kéo dài giờ. Phân tích cả hai trục giúp thấy điểm cân bằng thay vì tối ưu mù một trục.",[973,106066,106067],{},"Đánh đổi thứ hai nằm giữa tệ nhất và trung bình. Thiết kế theo tệ nhất cho đảm bảo chắc nhưng có thể quá thận trọng và tốn kém.",[973,106069,106070],{},"Thiết kế theo trung bình cho thực tế tốt hơn nhưng rủi ro khi gặp đầu vào thù địch. Đánh đổi thứ ba nằm ở vòng lặp mịn.",[973,106072,106073],{},"Vòng mịn tiết kiệm nhớ nhưng chi phí điều phối tăng khi số vòng quá nhiều. Giống như chia việc quá vụn thì tốn công giao nhận.",[968,106075,98931],{"id":98930},[973,106077,106078],{},"Thứ nhất: đo trên đầu vào thuận lợi rồi tưởng đó là thực tế. Ví dụ benchmark trên dữ liệu đã sắp xếp.",[973,106080,106081],{},"Thứ hai: chỉ phân tích giờ mà quên nhớ. Tới lúc triển khai mới phát hiện tràn nhớ và tràn đĩa.",[973,106083,106084],{},"Thứ ba: lẫn hai trục, cho rằng nhanh thì mặc nhiên ít tốn nhớ. Thực ra nhiều thuật toán nhanh chính nhờ dùng nhiều nhớ tạm.",[973,106086,106087],{},"Thứ tư: áp kết quả mẫu nhỏ cho dữ liệu lớn mà không xét lại mở rộng. Đúng điều bài này cảnh báo từ đầu.",[968,106089,98947],{"id":98946},[973,106091,106092],{},"Tư duy hai trục dùng ngay từ đặc tả yêu cầu phi chức năng. Ngưỡng giờ phản hồi và ngưỡng nhớ khả dụng sẽ loại nhiều thiết kế không hợp.",[973,106094,106095],{},"Trước khi tốn công cài đặt. Nó cũng định hướng chọn hạ tầng triển khai theo kiểu vòng lặp của thuật toán.",[973,106097,106098],{},"Hội tụ thì thuê co giãn, phẳng thì thuê cố định. Phân kỳ thì đặt giới hạn ngay từ đầu.",[968,106100,96573],{"id":96572},[973,106102,96576],{},[973,106104,106105,106107,106108,106136],{},[1487,106106,96581],{}," Tìm tuyến tính trong mảng ",[1023,106109,106111,106124],{"className":106110},[1026],[1023,106112,106114],{"className":106113},[1030],[1032,106115,106116],{"xmlns":1034},[1036,106117,106118,106122],{},[1039,106119,106120],{},[1042,106121,1262],{},[1058,106123,1262],{"encoding":1060},[1023,106125,106127],{"className":106126,"ariaHidden":1066},[1065],[1023,106128,106130,106133],{"className":106129},[1070],[1023,106131],{"className":106132,"style":2347},[1074],[1023,106134,1262],{"className":106135},[1079,1080]," phần tử: tốt nhất, tệ nhất, trung bình bao nhiêu phép so sánh?",[96754,106138,106139],{"close-text":96756,"name":96757,"open-text":96758},[973,106140,106141,106142,106170,106171,106206],{},"Tốt nhất 1, tệ nhất ",[1023,106143,106145,106158],{"className":106144},[1026],[1023,106146,106148],{"className":106147},[1030],[1032,106149,106150],{"xmlns":1034},[1036,106151,106152,106156],{},[1039,106153,106154],{},[1042,106155,1262],{},[1058,106157,1262],{"encoding":1060},[1023,106159,106161],{"className":106160,"ariaHidden":1066},[1065],[1023,106162,106164,106167],{"className":106163},[1070],[1023,106165],{"className":106166,"style":2347},[1074],[1023,106168,1262],{"className":106169},[1079,1080],", trung bình khoảng ",[1023,106172,106174,106191],{"className":106173},[1026],[1023,106175,106177],{"className":106176},[1030],[1032,106178,106179],{"xmlns":1034},[1036,106180,106181,106189],{},[1039,106182,106183,106185,106187],{},[1042,106184,1262],{},[1042,106186,2461],{"mathvariant":2460},[1051,106188,2457],{},[1058,106190,105913],{"encoding":1060},[1023,106192,106194],{"className":106193,"ariaHidden":1066},[1065],[1023,106195,106197,106200,106203],{"className":106196},[1070],[1023,106198],{"className":106199,"style":1075},[1074],[1023,106201,1262],{"className":106202},[1079,1080],[1023,106204,2509],{"className":106205},[1079]," khi phần tử có mặt ở vị trí ngẫu nhiên.",[973,106208,106209,106211],{},[1487,106210,96904],{}," Hàm đảo mảng tại chỗ bằng 2 con trỏ tốn bao nhiêu bộ nhớ phụ?",[96754,106213,106214],{"close-text":96756,"name":96757,"open-text":96758},[973,106215,106216,106259],{},[1023,106217,106219,106238],{"className":106218},[1026],[1023,106220,106222],{"className":106221},[1030],[1032,106223,106224],{"xmlns":1034},[1036,106225,106226,106236],{},[1039,106227,106228,106230,106232,106234],{},[1042,106229,1044],{},[1046,106231,1049],{"stretchy":1048},[1051,106233,1053],{},[1046,106235,1056],{"stretchy":1048},[1058,106237,1061],{"encoding":1060},[1023,106239,106241],{"className":106240,"ariaHidden":1066},[1065],[1023,106242,106244,106247,106250,106253,106256],{"className":106243},[1070],[1023,106245],{"className":106246,"style":1075},[1074],[1023,106248,1044],{"className":106249,"style":1081},[1079,1080],[1023,106251,1049],{"className":106252},[1085],[1023,106254,1053],{"className":106255},[1079],[1023,106257,1056],{"className":106258},[1092],": chỉ vài biến chỉ số và 1 biến tạm để đổi chỗ.",[973,106261,106262,106264],{},[1487,106263,97431],{}," Merge sort tốn bao nhiêu bộ nhớ phụ?",[96754,106266,106267],{"close-text":96756,"name":96757,"open-text":96758},[973,106268,106269,106312,106313,106368],{},[1023,106270,106272,106291],{"className":106271},[1026],[1023,106273,106275],{"className":106274},[1030],[1032,106276,106277],{"xmlns":1034},[1036,106278,106279,106289],{},[1039,106280,106281,106283,106285,106287],{},[1042,106282,1044],{},[1046,106284,1049],{"stretchy":1048},[1042,106286,1262],{},[1046,106288,1056],{"stretchy":1048},[1058,106290,1267],{"encoding":1060},[1023,106292,106294],{"className":106293,"ariaHidden":1066},[1065],[1023,106295,106297,106300,106303,106306,106309],{"className":106296},[1070],[1023,106298],{"className":106299,"style":1075},[1074],[1023,106301,1044],{"className":106302,"style":1081},[1079,1080],[1023,106304,1049],{"className":106305},[1085],[1023,106307,1262],{"className":106308},[1079,1080],[1023,106310,1056],{"className":106311},[1092]," cho mảng tạm khi trộn, cộng ",[1023,106314,106316,106339],{"className":106315},[1026],[1023,106317,106319],{"className":106318},[1030],[1032,106320,106321],{"xmlns":1034},[1036,106322,106323,106337],{},[1039,106324,106325,106327,106329,106331,106333,106335],{},[1042,106326,1044],{},[1046,106328,1049],{"stretchy":1048},[1042,106330,8397],{},[1046,106332,8400],{},[1042,106334,1262],{},[1046,106336,1056],{"stretchy":1048},[1058,106338,8407],{"encoding":1060},[1023,106340,106342],{"className":106341,"ariaHidden":1066},[1065],[1023,106343,106345,106348,106351,106354,106359,106362,106365],{"className":106344},[1070],[1023,106346],{"className":106347,"style":1075},[1074],[1023,106349,1044],{"className":106350,"style":1081},[1079,1080],[1023,106352,1049],{"className":106353},[1085],[1023,106355,8427,106357],{"className":106356},[8426],[1023,106358,7690],{"style":8430},[1023,106360],{"className":106361,"style":8434},[2354],[1023,106363,1262],{"className":106364},[1079,1080],[1023,106366,1056],{"className":106367},[1092]," cho stack đệ quy.",[973,106370,106371,106373],{},[1487,106372,97800],{}," Vì sao thiết kế theo trường hợp tệ nhất lại an toàn?",[96754,106375,106376],{"close-text":96756,"name":96757,"open-text":96758},[973,106377,106378],{},"Vì nó là đảm bảo: mọi đầu vào đều không chậm hơn con số đó, kể cả đầu vào xấu cố tình.",[973,106380,106381,106383],{},[1487,106382,97983],{}," Cho 1 ví dụ đánh đổi dùng thêm bộ nhớ để giảm thời gian.",[96754,106385,106386],{"close-text":96756,"name":96757,"open-text":96758},[973,106387,106388,106389,106432,106433,15466,106506,106549,106550,1517],{},"Ghi nhớ kết quả (memo) cho Fibonacci: thêm ",[1023,106390,106392,106411],{"className":106391},[1026],[1023,106393,106395],{"className":106394},[1030],[1032,106396,106397],{"xmlns":1034},[1036,106398,106399,106409],{},[1039,106400,106401,106403,106405,106407],{},[1042,106402,1044],{},[1046,106404,1049],{"stretchy":1048},[1042,106406,1262],{},[1046,106408,1056],{"stretchy":1048},[1058,106410,1267],{"encoding":1060},[1023,106412,106414],{"className":106413,"ariaHidden":1066},[1065],[1023,106415,106417,106420,106423,106426,106429],{"className":106416},[1070],[1023,106418],{"className":106419,"style":1075},[1074],[1023,106421,1044],{"className":106422,"style":1081},[1079,1080],[1023,106424,1049],{"className":106425},[1085],[1023,106427,1262],{"className":106428},[1079,1080],[1023,106430,1056],{"className":106431},[1092]," bộ nhớ, giảm thời gian từ ",[1023,106434,106436,106459],{"className":106435},[1026],[1023,106437,106439],{"className":106438},[1030],[1032,106440,106441],{"xmlns":1034},[1036,106442,106443,106457],{},[1039,106444,106445,106447,106449,106455],{},[1042,106446,1044],{},[1046,106448,1049],{"stretchy":1048},[2327,106450,106451,106453],{},[1051,106452,2457],{},[1042,106454,1262],{},[1046,106456,1056],{"stretchy":1048},[1058,106458,95516],{"encoding":1060},[1023,106460,106462],{"className":106461,"ariaHidden":1066},[1065],[1023,106463,106465,106468,106471,106474,106503],{"className":106464},[1070],[1023,106466],{"className":106467,"style":1075},[1074],[1023,106469,1044],{"className":106470,"style":1081},[1079,1080],[1023,106472,1049],{"className":106473},[1085],[1023,106475,106477,106480],{"className":106476},[1079],[1023,106478,2457],{"className":106479},[1079],[1023,106481,106483],{"className":106482},[2383],[1023,106484,106486],{"className":106485},[2387],[1023,106487,106489],{"className":106488},[2391],[1023,106490,106492],{"className":106491,"style":8348},[2395],[1023,106493,106494,106497],{"style":2398},[1023,106495],{"className":106496,"style":2403},[2402],[1023,106498,106500],{"className":106499},[2407,2408,2409,2410],[1023,106501,1262],{"className":106502},[1079,1080,2410],[1023,106504,1056],{"className":106505},[1092],[1023,106507,106509,106528],{"className":106508},[1026],[1023,106510,106512],{"className":106511},[1030],[1032,106513,106514],{"xmlns":1034},[1036,106515,106516,106526],{},[1039,106517,106518,106520,106522,106524],{},[1042,106519,1044],{},[1046,106521,1049],{"stretchy":1048},[1042,106523,1262],{},[1046,106525,1056],{"stretchy":1048},[1058,106527,1267],{"encoding":1060},[1023,106529,106531],{"className":106530,"ariaHidden":1066},[1065],[1023,106532,106534,106537,106540,106543,106546],{"className":106533},[1070],[1023,106535],{"className":106536,"style":1075},[1074],[1023,106538,1044],{"className":106539,"style":1081},[1079,1080],[1023,106541,1049],{"className":106542},[1085],[1023,106544,1262],{"className":106545},[1079,1080],[1023,106547,1056],{"className":106548},[1092],". Hoặc bảng băm để tra ",[1023,106551,106553,106572],{"className":106552},[1026],[1023,106554,106556],{"className":106555},[1030],[1032,106557,106558],{"xmlns":1034},[1036,106559,106560,106570],{},[1039,106561,106562,106564,106566,106568],{},[1042,106563,1044],{},[1046,106565,1049],{"stretchy":1048},[1051,106567,1053],{},[1046,106569,1056],{"stretchy":1048},[1058,106571,1061],{"encoding":1060},[1023,106573,106575],{"className":106574,"ariaHidden":1066},[1065],[1023,106576,106578,106581,106584,106587,106590],{"className":106577},[1070],[1023,106579],{"className":106580,"style":1075},[1074],[1023,106582,1044],{"className":106583,"style":1081},[1079,1080],[1023,106585,1049],{"className":106586},[1085],[1023,106588,1053],{"className":106589},[1079],[1023,106591,1056],{"className":106592},[1092],[968,106594,98220],{"id":98219},[986,106596,106597,106600,106603,106606,106609],{},[989,106598,106599],{},"Giờ đo tốc độ tăng của bước chạy, độc lập phần cứng; nhớ đo bộ nhớ cho đầu vào, cấu trúc tạm và thực thi.",[989,106601,106602],{},"Ba kịch bản tốt nhất, tệ nhất, trung bình cho ba góc nhìn bổ sung nhau.",[989,106604,106605],{},"Ba kiểu vòng lặp hội tụ, phân kỳ, phẳng quyết định chiến lược cấp nhớ và hạ tầng.",[989,106607,106608],{},"Tiết kiệm nhớ bằng lặp mịn, chỉ giữ thứ đang cần, tái dùng mảng cũ.",[989,106610,106611],{},"Nhanh thường đổi bằng nhớ; thiết kế theo tệ nhất để an toàn, theo trung bình để dự báo.",[3020,106613,3022],{},{"title":1357,"searchDepth":68,"depth":68,"links":106615},[106616,106617,106618,106619,106622,106623,106624,106625,106626,106627],{"id":90890,"depth":68,"text":90891},{"id":105786,"depth":68,"text":105787},{"id":105811,"depth":68,"text":105812},{"id":105941,"depth":68,"text":105942,"children":106620},[106621],{"id":105966,"depth":73,"text":105967},{"id":106037,"depth":68,"text":106038},{"id":98911,"depth":68,"text":98912},{"id":98930,"depth":68,"text":98931},{"id":98946,"depth":68,"text":98947},{"id":96572,"depth":68,"text":96573},{"id":98219,"depth":68,"text":98220},"Hai trục phân tích độ phức tạp, ba kịch bản best-worst-average, ba kiểu vòng lặp hội tụ-phân kỳ-phẳng và nguyên tắc ước lượng chi phí.",{},{"title":50,"description":106628},[106632,106633,7],"time-complexity","space-complexity","-M0cgv8059TJiPj08sMWMzDmJxu3nXvblY89O66MJGY",1790133085706]