diff --git a/README.ar-AR.md b/README.ar-AR.md
deleted file mode 100644
index cbcfd02409..0000000000
--- a/README.ar-AR.md
+++ /dev/null
@@ -1,326 +0,0 @@
-# جافا سكريبت خوارزميات  وهياكل البيانات
-
-[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-تحتوي هذا مقالة على أمثلة عديدة تستند إلى الخوارزميات الشائعة وهياكل البيانات في الجافا سكريبت.
-
-كل خوارزمية وهياكل البيانات لها برنامج README منفصل خاص بها
-مع التفسيرات والروابط ذات الصلة لمزيد من القراءة (بما في ذلك تلك
-إلى مقاطع فيديو YouTube).
-
-
-_اقرأ هذا في لغات أخرى:_
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
- ☝ ملاحضة هذا المشروع مخصص للاستخدام لأغراض التعلم والبحث
-فقط ، و ** ليست ** معدة للاستخدام في **الإنتاج**
-
-## هياكل البيانات
-
-هياكل البيانات هي طريقة خاصة لتنظيم البيانات وتخزينها في جهاز الكمبيوتر بحيث
-يمكن الوصول إليها وتعديلها بكفاءة. بتعبير أدق ، هيكل البيانات هو مجموعة من البيانات
-القيم والعلاقات فيما بينها والوظائف أو العمليات التي يمكن تطبيقها عليها
-البيانات.
-
-
-`B` - مبتدئ, `A` - المتقدمة
-
-* `B` [قائمة مرتبطة](src/data-structures/linked-list)
-* `B` [قائمة مرتبطة بشكل مضاعف](src/data-structures/doubly-linked-list)
-* `B` [طابور, Queue](src/data-structures/queue)
-* `B` [كومة](src/data-structures/stack)
-* `B` [جدول التجزئة](src/data-structures/hash-table)
-* `B` [كومة](src/data-structures/heap) -الحد الأقصى والحد الأدنى من إصدارات الكومة
-* `B` [طابور الأولوية](src/data-structures/priority-queue)
-* `A` [تري](src/data-structures/trie)
-* `A` [شجرة](src/data-structures/tree)
-  * `A` [شجرة البحث الثنائية](src/data-structures/tree/binary-search-tree)
-  * `A` [شجرة AVL](src/data-structures/tree/avl-tree)
-  * `A` [شجرة الأحمر والأسود](src/data-structures/tree/red-black-tree)
-  * `A` [شجرة القطعة](src/data-structures/tree/segment-tree) - مع أمثلة على استفسارات النطاق الأدنى / الأقصى / المجموع
-  * `A` [شجرة فينويك](src/data-structures/tree/fenwick-tree) (شجرة ثنائية مفهرسة)
-* `A` [Graph](src/data-structures/graph) (كلاهما موجه وغير موجه)
-* `A` [مجموعة منفصلة](src/data-structures/disjoint-set)
-* `A` [مرشح بلوم](src/data-structures/bloom-filter)
-
-
-## الخوارزميات
-
-الخوارزمية هي تحديد لا لبس فيه لكيفية حل فئة من المشاكل. أنه
-مجموعة من القواعد التي تحدد بدقة تسلسل العمليات.
-
-`B` - مبتدئ ، `A` - متقدم
-
-
-### الخوارزميات حسب الموضوع
-
-* **رياضيات**
-  * `B` [معالجة البت](src/algorithms/math/bits)
-  * `B` [عاملي](src/algorithms/math/factorial)
-  * `B` [رقم فيبوناتشي](src/algorithms/math/fibonacci) - الإصدارات الكلاسيكية والمغلقة
-  * `B` [اختبار البدائية](src/algorithms/math/primality-test) (طريقة تقسيم المحاكمة)
-  * `B` [الخوارزمية الإقليدية](src/algorithms/math/euclidean-algorithm) - احسب القاسم المشترك الأكبر (GCD)
-  * `B` [أقل مضاعف مشترك](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [منخل إراتوستينس](src/algorithms/math/sieve-of-eratosthenes) - إيجاد جميع الأعداد الأولية حتى أي حد معين
-  * `B` [هي قوة اثنين](src/algorithms/math/is-power-of-two) - تحقق مما إذا كان الرقم هو قوة اثنين (الخوارزميات الساذجة والبتية)
-  * `B` [مثلث باسكال](src/algorithms/math/pascal-triangle)
-  * `B` [عدد مركب](src/algorithms/math/complex-number) - الأعداد المركبة والعمليات الأساسية معهم
-  * `B` [راديان ودرجة](src/algorithms/math/radian) - راديان لدرجة التحويل والعكس
-  * `B` [تشغيل سريع](src/algorithms/math/fast-powering)
-  * `B` [طريقة هورنر](src/algorithms/math/horner-method) - تقييم متعدد الحدود
-  * `A` [قسم صحيح](src/algorithms/math/integer-partition)
-  * `A` [الجذر التربيعي](src/algorithms/math/square-root) - طريقة نيوتن
-  * `A` [خوارزمية ليو هوي π](src/algorithms/math/liu-hui) - π حسابات تقريبية على أساس N-gons
-  * `A` [تحويل فورييه المنفصل](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها
-* **مجموعات**
-  * `B` [المنتج الديكارتي](src/algorithms/sets/cartesian-product) - منتج من مجموعات متعددة
-  * `B` [فيشر ييتس شافل](src/algorithms/sets/fisher-yates) - التقليب العشوائي لتسلسل محدود
-  * `A` [مجموعة الطاقة](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة (حلول البت والتتبع التراجعي)
-  * `A` [التباديل](src/algorithms/sets/permutations) (مع وبدون التكرار)
-  * `A` [مجموعات](src/algorithms/sets/combinations) (مع وبدون التكرار)
-  * `A` [أطول نتيجة مشتركة](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [أطول زيادة متتالية](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [أقصر تسلسل فائق مشترك](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [مشكلة حقيبة الظهر](src/algorithms/sets/knapsack-problem) - "0/1" و "غير منضم"
-  * `A` [الحد الأقصى من Subarray](src/algorithms/sets/maximum-subarray) -إصدارات "القوة الغاشمة" و "البرمجة الديناميكية" (كادان)
-  * `A` [مجموع الجمع](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا
-* **سلاسل**
-  * `B` [مسافة هامنج](src/algorithms/string/hamming-distance) - عدد المواقف التي تختلف فيها الرموز
-  * `A` [المسافة ليفنشتاين](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين
-  * `A` [خوارزمية كنوث - موريس - برات](src/algorithms/string/knuth-morris-pratt) (خوارزمية KMP) - بحث السلسلة الفرعية (مطابقة النمط)
-  * `A` [خوارزمية Z](src/algorithms/string/z-algorithm) - بحث سلسلة فرعية (مطابقة النمط)
-  * `A` [خوارزمية رابين كارب](src/algorithms/string/rabin-karp) - بحث السلسلة الفرعية
-  * `A` [أطول سلسلة فرعية مشتركة](src/algorithms/string/longest-common-substring)
-  * `A` [مطابقة التعبير العادي](src/algorithms/string/regular-expression-matching)
-* **عمليات البحث**
-  * `B` [البحث الخطي](src/algorithms/search/linear-search)
-  * `B` [بحث سريع](src/algorithms/search/jump-search) (أو حظر البحث) - ابحث في مصفوفة مرتبة
-  * `B` [بحث ثنائي](src/algorithms/search/binary-search) - البحث في مجموعة مرتبة
-  * `B` [بحث الاستيفاء](src/algorithms/search/interpolation-search) - البحث في مجموعة مرتبة موزعة بشكل موحد
-
-* **فرز**
-  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)
-  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)
-  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)
-  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - عمليات التنفيذ في المكان وغير في المكان
-  * `B` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)
-  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)
-* **القوائم المرتبطة**
-  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)
-  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)
-* **الأشجار**
-  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)
-* **الرسوم البيانية**
-  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) -إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس
-  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - لكل من الرسوم البيانية الموجهة وغير الموجهة (الإصدارات القائمة على DFS و Disjoint Set)
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه
-  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - طريقة البحث العمق الأول (DFS)
-  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - خوارزمية تارجان (تعتمد على DFS)
-  * `A` [Bridges](src/algorithms/graph/bridges) - خوارزمية تعتمد على DFS
-  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - خوارزمية فلوري - قم بزيارة كل حافة مرة واحدة بالضبط
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط
-  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - خوارزمية Kosaraju
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية
-* **التشفير
-  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - المتداول دالة التجزئة على أساس متعدد الحدود
-  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - استبدال بسيط للشفرات
-* **التعلم الالي**
-  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 وظائف JS بسيطة توضح كيف يمكن للآلات أن تتعلم بالفعل (الانتشار إلى الأمام / الخلف)
-* **غير مصنف**
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - خوارزمية في المكان
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - التراجع ، البرمجة الديناميكية (من أعلى إلى أسفل + من أسفل إلى أعلى) والأمثلة الجشعة
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - التراجع والبرمجة الديناميكية والأمثلة القائمة على مثلث باسكال
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار (البرمجة الديناميكية وإصدارات القوة الغاشمة)
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة (4 حلول)
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-
-### الخوارزميات حسب النموذج
-
-النموذج الحسابي هو طريقة أو نهج عام يكمن وراء تصميم الفصل
-من الخوارزميات. إنه تجريد أعلى من مفهوم الخوارزمية ، تمامًا مثل
-الخوارزمية هي تجريد أعلى من برنامج الكمبيوتر.
-
-* **القوة الغاشمة** - انظر في جميع الاحتمالات وحدد الحل الأفضل
-  * `B` [Linear Search](src/algorithms/search/linear-search)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية
-  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها
-* **جشع** - اختر الخيار الأفضل في الوقت الحالي ، دون أي اعتبار للمستقبل
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه
-  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه
-* **فرق تسد** - قسّم المشكلة إلى أجزاء أصغر ثم حل تلك الأجزاء
-  * `B` [Binary Search](src/algorithms/search/binary-search)
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
-  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - حساب القاسم المشترك الأكبر (GCD)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Fast Powering](src/algorithms/math/fast-powering)
-  * `A` [Permutations](src/algorithms/sets/permutations) (مع التكرار وبدونه)
-  * `A` [Combinations](src/algorithms/sets/combinations) (مع التكرار وبدونه)
-* **البرمجة الديناميكية** - بناء حل باستخدام الحلول الفرعية التي تم العثور عليها مسبقًا
-  * `B` [Fibonacci Number](src/algorithms/math/fibonacci)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة
-  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين
-  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
-  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Integer Partition](src/algorithms/math/integer-partition)
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس
-  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
-* **التراجع** - على غرار القوة الغاشمة ، حاول إنشاء جميع الحلول الممكنة ، ولكن في كل مرة تقوم فيها بإنشاء الحل التالي الذي تختبره
-إذا استوفت جميع الشروط ، وعندها فقط استمر في إنشاء الحلول اللاحقة. خلاف ذلك ، تراجع ، واذهب إلى
-طريق مختلف لإيجاد حل. عادةً ما يتم استخدام اجتياز DFS لمساحة الدولة.
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [Power Set](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا
-
-
-* ** Branch & Bound ** - تذكر الحل الأقل تكلفة الموجود في كل مرحلة من مراحل التراجع
-البحث ، واستخدام تكلفة الحل الأقل تكلفة الموجود حتى الآن بحد أدنى لتكلفة
-الحل الأقل تكلفة للمشكلة ، من أجل تجاهل الحلول الجزئية بتكاليف أكبر من
-تم العثور على حل بأقل تكلفة حتى الآن. اجتياز BFS عادةً بالاشتراك مع اجتياز DFS لمساحة الحالة
-يتم استخدام الشجرة.
-
-## كيفية استخدام هذا المستودع
-
-**تثبيت كل التبعيات**
-```
-npm install
-```
-
-**قم بتشغيل ESLint**
-
-قد ترغب في تشغيله للتحقق من جودة الكود.
-
-```
-npm run lint
-```
-
-**قم بإجراء جميع الاختبارات**
-```
-npm test
-```
-
-**قم بإجراء الاختبارات بالاسم**
-```
-npm test -- 'LinkedList'
-```
-
-**ملعب**
-
-يمكنك اللعب بهياكل البيانات والخوارزميات في ملف `. /src/playground/playground.js` والكتابة
-اختبارات لها في `./src/playground/__test__/playground.test.js`.
-
-ثم قم ببساطة بتشغيل الأمر التالي لاختبار ما إذا كان كود الملعب الخاص بك يعمل كما هو متوقع:
-
-```
-npm test -- 'playground'
-```
-
-## معلومات مفيدة
-
-### المراجع
-
-[▶ هياكل البيانات والخوارزميات على موقع يوتيوب](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Big O Notation
-
-* يتم استخدام **Big O notation** لتصنيف الخوارزميات وفقًا لكيفية نمو متطلبات وقت التشغيل أو المساحة مع نمو حجم الإدخال.
-قد تجد في الرسم البياني أدناه الأوامر الأكثر شيوعًا لنمو الخوارزميات المحددة في تBig O notation.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-مصدر: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-فيما يلي قائمة ببعض رموز Big O notation الأكثر استخدامًا ومقارنات أدائها مقابل أحجام مختلفة من بيانات الإدخال.
-
-| Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### تعقيد عمليات بنية البيانات
-
-| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Array**               | 1         | n         | n         | n         |           |
-| **Stack**               | n         | n         | 1         | 1         |           |
-| **Queue**               | n         | n         | 1         | 1         |           |
-| **Linked List**         | n         | n         | 1         | n         |           |
-| **Hash Table**          | -         | n         | n         | n         |في حالة وجود تكاليف دالة تجزئة مثالية ستكون O (1)|
-| **Binary Search Tree**  | n         | n         | n         | n         | في حالة توازن تكاليف الشجرة ستكون O (log (n))|
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bloom Filter**        | -         | 1         | 1         | -         |الإيجابيات الكاذبة ممكنة أثناء البحث|
-
-### تعقيد خوارزميات فرز الصفيف
-
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | نعم       |           |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | نعم       |           |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | لا        |           |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | لا        |           |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | نعم       |           |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        | عادةً ما يتم إجراء الفرز السريع في مكانه مع مساحة مكدس O (log (n))|
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | لا       |           |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       |r - أكبر رقم في المجموعة|
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | ك - طول أطول مفتاح |
-
-## مؤيدو المشروع
-
-> يمكنك دعم هذا المشروع عبر ❤️️ [GitHub](https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-[الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.de-DE.md b/README.de-DE.md
deleted file mode 100644
index b34ad3563f..0000000000
--- a/README.de-DE.md
+++ /dev/null
@@ -1,336 +0,0 @@
-# JavaScript-Algorithmen und Datenstrukturen
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Dieses Repository enthält JavaScript Beispiele für viele
-gängige Algorithmen und Datenstrukturen.
-
-Jeder Algorithmus und jede Datenstruktur hat eine eigene README
-mit zugehörigen Erklärungen und weiterführenden Links (einschließlich zu YouTube-Videos).
-
-_Lies dies in anderen Sprachen:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/)
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md)
-
-_☝ Beachte, dass dieses Projekt nur für Lern- und Forschungszwecke gedacht ist und **nicht** für den produktiven Einsatz verwendet werden soll_
-
-## Datenstrukturen
-
-Eine Datenstruktur ist eine bestimmte Art und Weise, Daten in einem Computer so zu organisieren und zu speichern, dass sie
-effizient erreicht und verändert werden können. Genauer gesagt, ist eine Datenstruktur eine Sammlung von Werten,
-den Beziehungen zwischen ihnen und den Funktionen oder Operationen, die auf die Daten angewendet werden können.
-
-`B` - Anfänger:innen, `A` - Fortgeschrittene
-
-* `B` [Verkettete Liste (Linked List)](src/data-structures/linked-list)
-* `B` [Doppelt verkettete Liste (Doubly Linked List)](src/data-structures/doubly-linked-list)
-* `B` [Warteschlange (Queue)](src/data-structures/queue)
-* `B` [Stapelspeicher (Stack)](src/data-structures/stack)
-* `B` [Hashtabelle (Hash Table)](src/data-structures/hash-table)
-* `B` [Heap-Algorithmus (Heap)](src/data-structures/heap) - max und min Heap-Versionen
-* `B` [Vorrangwarteschlange (Priority Queue)](src/data-structures/priority-queue)
-* `A` [Trie (Trie)](src/data-structures/trie)
-* `A` [Baum (Tree)](src/data-structures/tree)
-  * `A` [Binärer Suchbaum (Binary Search Tree)](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL-Baum (AVL Tree)](src/data-structures/tree/avl-tree)
-  * `A` [Rot-Schwarz-Baum (Red-Black Tree)](src/data-structures/tree/red-black-tree)
-  * `A` [Segment-Baum (Segment Tree)](src/data-structures/tree/segment-tree) - mit Min/Max/Summenbereich-Abfrage Beispiel
-  * `A` [Fenwick Baum (Fenwick Tree)](src/data-structures/tree/fenwick-tree) (Binär indizierter Baum / Binary Indexed Tree)
-* `A` [Graph (Graph)](src/data-structures/graph) (sowohl gerichtet als auch ungerichtet)
-* `A` [Union-Find-Struktur (Disjoint Set)](src/data-structures/disjoint-set)
-* `A` [Bloomfilter (Bloom Filter)](src/data-structures/bloom-filter)
-
-## Algorithmen
-
-Ein Algorithmus ist eine eindeutige Spezifikation, wie eine Klasse von Problemen zu lösen ist. Er besteht
-aus einem Satz von Regeln, die eine Abfolge von Operationen genau definieren.
-
-`B` - Anfänger:innen, `A` - Fortgeschrittene
-
-### Algorithmen nach Thema
-
-* **Mathe**
-  * `B` [Bitmanipulation (Bit Manipulation)](src/algorithms/math/bits) - Bits setzen/lesen/aktualisieren/löschen, Multiplikation/Division durch zwei negieren usw..
-  * `B` [Faktoriell (Factorial)](src/algorithms/math/factorial)
-  * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci) - Klassische und geschlossene Version
-  * `B` [Primfaktoren (Prime Factors)](src/algorithms/math/prime-factors) - Auffinden von Primfaktoren und deren Zählung mit Hilfe des Satz von Hardy-Ramanujan (Hardy-Ramanujan's theorem)
-  * `B` [Primzahl-Test (Primality Test)](src/algorithms/math/primality-test) (Probedivision / trial division method)
-  * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - Berechnen des größten gemeinsamen Teilers (ggT)
-  * `B` [Kleinstes gemeinsames Vielfaches (Least Common Multiple)](src/algorithms/math/least-common-multiple) (kgV)
-  * `B` [Sieb des Eratosthenes (Sieve of Eratosthenes)](src/algorithms/math/sieve-of-eratosthenes) - Finden aller Primzahlen bis zu einer bestimmten Grenze
-  * `B` [Power of two (Is Power of Two)](src/algorithms/math/is-power-of-two) - Prüft, ob die Zahl eine Zweierpotenz ist (naive und bitweise Algorithmen)
-  * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle)
-  * `B` [Komplexe Zahlen (Complex Number)](src/algorithms/math/complex-number) - Komplexe Zahlen und Grundoperationen mit ihnen
-  * `B` [Bogenmaß & Grad (Radian & Degree)](src/algorithms/math/radian) - Umrechnung von Bogenmaß in Grad und zurück
-  * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering)
-  * `B` [Horner-Schema (Horner's method)](src/algorithms/math/horner-method) - Polynomauswertung
-  * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.)
-  * `B` [Euklidischer Abstand (Euclidean Distance)](src/algorithms/math/euclidean-distance) - Abstand zwischen zwei Punkten/Vektoren/Matrizen
-  * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition)
-  * `A` [Quadratwurzel (Square Root)](src/algorithms/math/square-root) - Newtonverfahren (Newton's method)
-  * `A` [Liu Hui π Algorithmus (Liu Hui π Algorithm)](src/algorithms/math/liu-hui) - Näherungsweise π-Berechnungen auf Basis von N-gons
-  * `A` [Diskrete Fourier-Transformation (Discrete Fourier Transform)](src/algorithms/math/fourier-transform) - Eine Funktion der Zeit (ein Signal) in die Frequenzen zerlegen, aus denen sie sich zusammensetzt
-* **Sets**
-  * `B` [Kartesisches Produkt (Cartesian Product)](src/algorithms/sets/cartesian-product) - Produkt aus mehreren Mengen
-  * `B` [Fisher-Yates-Verfahren (Fisher–Yates Shuffle)](src/algorithms/sets/fisher-yates) - Zufällige Permutation einer endlichen Folge
-  * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge (Bitweise und Rücksetzverfahren Lösungen(backtracking solutions))
-  * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen)
-  * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen)
-  * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Rucksackproblem (Knapsack Problem)](src/algorithms/sets/knapsack-problem) - "0/1" und "Ungebunden"
-  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray) - "Brute-Force-Methode" und "Dynamische Programmierung" (Kadane' Algorithmus)
-  * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden
-* **Zeichenketten (Strings)**
-  * `B` [Hamming-Abstand (Hamming Distance)](src/algorithms/string/hamming-distance) - Anzahl der Positionen, an denen die Symbole unterschiedlich sind
-  * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen
-  * `A` [Knuth-Morris-Pratt-Algorithmus (Knuth–Morris–Pratt Algorithm)](src/algorithms/string/knuth-morris-pratt) (KMP Algorithmus) - Teilstringsuche (Mustervergleich / Pattern Matching)
-  * `A` [Z-Algorithmus (Z Algorithm)](src/algorithms/string/z-algorithm) - Teilstringsuche (Mustervergleich / Pattern Matching)
-  * `A` [Rabin-Karp-Algorithmus (Rabin Karp Algorithm)](src/algorithms/string/rabin-karp) - Teilstringsuche
-  * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring)
-  * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching)
-* **Suchen**
-  * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search)
-  * `B` [Sprungsuche (Jump Search)](src/algorithms/search/jump-search) (oder Blocksuche) - Suche im sortierten Array
-  * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search) - Suche in einem sortierten Array
-  * `B` [Interpolationssuche (Interpolation Search)](src/algorithms/search/interpolation-search) - Suche in gleichmäßig verteilt sortiertem Array
-* **Sortieren**
-  * `B` [Bubblesort (Bubble Sort)](src/algorithms/sorting/bubble-sort)
-  * `B` [Selectionsort (Selection Sort)](src/algorithms/sorting/selection-sort)
-  * `B` [Einfügesortierenmethode (Insertion Sort)](src/algorithms/sorting/insertion-sort)
-  * `B` [Haldensortierung (Heap Sort)](src/algorithms/sorting/heap-sort)
-  * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort) - in-place und non-in-place Implementierungen
-  * `B` [Shellsort (Shellsort)](src/algorithms/sorting/shell-sort)
-  * `B` [Countingsort (Counting Sort)](src/algorithms/sorting/counting-sort)
-  * `B` [Fachverteilen (Radix Sort)](src/algorithms/sorting/radix-sort)
-* **Verkettete Liste (Linked List)**
-  * `B` [Gerade Traversierung (Straight Traversal)](src/algorithms/linked-list/traversal)
-  * `B` [Umgekehrte Traversierung (Reverse Traversal)](src/algorithms/linked-list/reverse-traversal)
-* **Bäume**
-  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/tree/breadth-first-search) (BFS)
-* **Graphen**
-  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen
-  * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus
-  * `A` [Bellman-Ford-Algorithmus (Bellman-Ford Algorithm)](src/algorithms/graph/bellman-ford) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus
-  * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden
-  * `A` [Zykluserkennung (Detect Cycle)](src/algorithms/graph/detect-cycle) - Sowohl für gerichtete als auch für ungerichtete Graphen (DFS- und Disjoint-Set-basierte Versionen)
-  * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen
-  * `A` [Topologische Sortierung (Topological Sorting)](src/algorithms/graph/topological-sorting) - DFS-Verfahren
-  * `A` [Artikulationspunkte (Articulation Points)](src/algorithms/graph/articulation-points) - Algorithmus von Tarjan (Tarjan's algorithm) (DFS basiert)
-  * `A` [Brücke (Bridges)](src/algorithms/graph/bridges) - DFS-basierter Algorithmus
-  * `A` [Eulerkreisproblem (Eulerian Path and Eulerian Circuit)](src/algorithms/graph/eulerian-path) - Algorithmus von Fleury (Fleury's algorithm) - Jede Kante genau einmal durchlaufen.
-  * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen.
-  * `A` [Starke Zusammenhangskomponente (Strongly Connected Components)](src/algorithms/graph/strongly-connected-components) - Kosarajus Algorithmus
-  * `A` [Problem des Handlungsreisenden (Travelling Salesman Problem)](src/algorithms/graph/travelling-salesman) - Kürzestmögliche Route, die jede Stadt besucht und zur Ausgangsstadt zurückkehrt
-* **Kryptographie**
-  * `B` [Polynomiale Streuwertfunktion(Polynomial Hash)](src/algorithms/cryptography/polynomial-hash) - Rollierende Streuwert-Funktion basierend auf Polynom
-  * `B` [Schienenzaun Chiffre (Rail Fence Cipher)](src/algorithms/cryptography/rail-fence-cipher) - Ein Transpositionsalgorithmus zur Verschlüsselung von Nachrichten
-  * `B` [Caesar-Verschlüsselung (Caesar Cipher)](src/algorithms/cryptography/caesar-cipher) - Einfache Substitutions-Chiffre
-  * `B` [Hill-Chiffre (Hill Cipher)](src/algorithms/cryptography/hill-cipher) - Substitutionschiffre basierend auf linearer Algebra
-* **Maschinelles Lernen**
-  * `B` [Künstliches Neuron (NanoNeuron)](https://github.com/trekhleb/nano-neuron) - 7 einfache JS-Funktionen, die veranschaulichen, wie Maschinen tatsächlich lernen können (Vorwärts-/Rückwärtspropagation)
-  * `B` [Nächste-Nachbarn-Klassifikation (k-NN)](src/algorithms/ml/knn) - k-nächste-Nachbarn-Algorithmus
-  * `B` [k-Means (k-Means)](src/algorithms/ml/k-means) - k-Means-Algorithmus
-* **Image Processing**
-  * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung
-* **Unkategorisiert**
-  * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Rotationsmatrix (Square Matrix Rotation)](src/algorithms/uncategorized/square-matrix-rotation) - In-Place-Algorithmus
-  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) - Backtracking, dynamische Programmierung (Top-down + Bottom-up) und gierige Beispiele
-  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths) - Backtracking, dynamische Programmierung und Pascalsches Dreieck basierte Beispiele
-  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)
-  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)
-  * `B` [Beste Zeit zum Kaufen/Verkaufen von Aktien (Best Time To Buy Sell Stocks)](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - Beispiele für "Teile und Herrsche" und Beispiele für den One-Pass-Algorithmus
-  * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens)
-  * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour)
-
-### Algorithmen nach Paradigma
-
-Ein algorithmisches Paradigma ist eine generische Methode oder ein Ansatz, der dem Entwurf einer Klasse von Algorithmen zugrunde liegt. Es ist eine Abstraktion, die höher ist als der Begriff des Algorithmus. Genauso wie ein Algorithmus eine Abstraktion ist, die höher ist als ein Computerprogramm.
-
-* **Brachiale Gewalt (Brute Force)** - schaut sich alle Möglichkeiten an und wählt die beste Lösung aus
-  * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search)
-  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)
-  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)
-  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray)
-  * `A` [Problem des Handlungsreisenden (Travelling Salesman Problem)](src/algorithms/graph/travelling-salesman) - Kürzestmögliche Route, die jede Stadt besucht und zur Ausgangsstadt zurückkehrt
-  * `A` [Diskrete Fourier-Transformation (Discrete Fourier Transform)](src/algorithms/math/fourier-transform) - Eine Funktion der Zeit (ein Signal) in die Frequenzen zerlegen, aus denen sie sich zusammensetzt
-* **Gierig (Greedy)** - Wählt die beste Option zum aktuellen Zeitpunkt, ohne Rücksicht auf die Zukunft
-  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)
-  * `A` [Rucksackproblem (Unbound Knapsack Problem)](src/algorithms/sets/knapsack-problem)
-  * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus
-  * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen
-  * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen
-* **Teile und herrsche** - Das Problem in kleinere Teile aufteilen und diese Teile dann lösen
-  * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search)
-  * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle)
-  * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort)
-  * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.)
-  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)
-  * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering)
-  * `B` [Beste Zeit zum Kaufen/Verkaufen von Aktien (Best Time To Buy Sell Stocks)](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - Beispiele für "Teile und Herrsche" und Beispiele für den One-Pass-Algorithmus
-  * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen)
-  * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen)
-* **Dynamische Programmierung** - Eine Lösung aus zuvor gefundenen Teillösungen aufbauen
-  * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci)
-  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)
-  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths)
-  * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen)
-  * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen)
-  * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung
-  * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen
-  * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring)
-  * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Rucksackproblem (0/1 Knapsack Problem)](src/algorithms/sets/knapsack-problem)
-  * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition)
-  * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray)
-  * `A` [Bellman-Ford-Algorithmus (Bellman-Ford Algorithm)](src/algorithms/graph/bellman-ford) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus
-  * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden
-  * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching)
-* **Zurückverfolgung** - Ähnlich wie bei Brute-Force versuchen Sie, alle möglichen Lösungen zu generieren, aber jedes Mal, wenn Sie die nächste Lösung generieren, testen Sie, ob sie alle Bedingungen erfüllt, und fahren erst dann mit der Generierung weiterer Lösungen fort. Andernfalls gehen Sie zurück und nehmen einen anderen Weg, um eine Lösung zu finden. Normalerweise wird das DFS-Traversal des Zustandsraums verwendet.
-  * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game)
-  * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths)
-  * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge
-  * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen.
-  * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens)
-  * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour)
-  * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden
-* **Verzweigung & Bindung** - Merkt sich die Lösung mit den niedrigsten Kosten, die in jeder Phase der Backtracking-Suche gefunden wurde, und verwendet die Kosten der bisher gefundenen Lösung mit den niedrigsten Kosten als untere Schranke für die Kosten einer Lösung des Problems mit den geringsten Kosten, um Teillösungen zu verwerfen, deren Kosten größer sind als die der bisher gefundenen Lösung mit den niedrigsten Kosten. Normalerweise wird das BFS-Traversal in Kombination mit dem DFS-Traversal des Zustandsraumbaums verwendet.
-
-## So verwendest du dieses Repository
-
-**Alle Abhängigkeiten installieren**
-
-```
-npm install
-```
-
-**ESLint ausführen**
-
-You may want to run it to check code quality.
-
-```
-npm run lint
-```
-
-**Alle Tests ausführen**
-
-```
-npm test
-```
-
-**Tests nach Namen ausführen**
-
-```
-npm test -- 'LinkedList'
-```
-
-**Fehlerbehebung**
-
-Falls das Linting oder Testen fehlschlägt, versuche, den Ordner "node_modules" zu löschen und die npm-Pakete neu zu installieren:
-
-```
-rm -rf ./node_modules
-npm i
-```
-
-**Spielwiese**
-
-Du kannst mit Datenstrukturen und Algorithmen in der Datei `./src/playground/playground.js` herumspielen und
-dir in dieser Datei Tests schreiben `./src/playground/__test__/playground.test.js`.
-
-Dann führe einfach folgenden Befehl aus, um zu testen, ob dein Spielwiesencode wie erwartet funktioniert:
-
-```
-npm test -- 'playground'
-```
-
-## Nützliche Informationen
-
-### Referenzen
-
-[▶ Datenstrukturen und Algorithmen auf YouTube(Englisch)](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### O-Notation (_Big O Notation_)
-
-Die O-Notation wird verwendet, um Algorithmen danach zu klassifizieren, wie ihre Laufzeit oder ihr Platzbedarf mit zunehmender Eingabegröße wächst. In der folgenden Tabelle finden Sie die häufigsten Wachstumsordnungen von Algorithmen, die in Big-O-Notation angegeben sind.
-
-![O-Notation Graphen](./assets/big-o-graph.png)
-
-Quelle: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Nachfolgend finden Sie eine Liste einiger der am häufigsten verwendeten Big O-Notationen und deren Leistungsvergleiche für unterschiedliche Größen der Eingabedaten.
-
-| Big O Notation | Berechnungen für 10 Elemente | Berechnungen für 100 Elemente | Berechnungen für 1000 Elemente |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------ |
-| **O(1)**       | 1                            | 1                             | 1                              |
-| **O(log N)**   | 3                            | 6                             | 9                              |
-| **O(N)**       | 10                           | 100                           | 1000                           |
-| **O(N log N)** | 30                           | 600                           | 9000                           |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                        |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                      |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                     |
-
-### Komplexität von Datenstrukturoperationen
-
-| Datenstruktur          | Zugriff auf | Suche  | Einfügen | Löschung | Kommentare                                                      |
-| ---------------------- | :---------: | :----: | :------: | :------: | :-------------------------------------------------------------- |
-| **Array**              |      1      |   n    |    n     |    n     |                                                                 |
-| **Stack**              |      n      |   n    |    1     |    1     |                                                                 |
-| **Queue**              |      n      |   n    |    1     |    1     |                                                                 |
-| **Linked List**        |      n      |   n    |    1     |    n     |                                                                 |
-| **Hash Table**         |      -      |   n    |    n     |    n     | Im Falle einer perfekten Hash-Funktion wären die Kosten O(1)    |
-| **Binary Search Tree** |      n      |   n    |    n     |    n     | Im Falle eines ausgeglichenen Baumes wären die Kosten O(log(n)) |
-| **B-Tree**             |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |
-| **Red-Black Tree**     |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |
-| **AVL Tree**           |   log(n)    | log(n) |  log(n)  |  log(n)  |                                                                 |
-| **Bloom Filter**       |      -      |   1    |    1     |    -     | Falschpostive sind bei der Suche möglichen                      |
-
-### Komplexität von Array-Sortieralgorithmen
-
-| Name               |    Bester     |      Durchschnitt       |        Schlechtester        | Speicher | Stabil | Kommentar                                                                  |
-| ------------------ | :-----------: | :---------------------: | :-------------------------: | :------: | :----: | :------------------------------------------------------------------------- |
-| **Bubble sort**    |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |   JA   |                                                                            |
-| **Insertion sort** |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |   Ja   |                                                                            |
-| **Selection sort** | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |    1     |  Nein  |                                                                            |
-| **Heap sort**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |    1     |  Nein  |                                                                            |
-| **Merge sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |    n     |   Ja   |                                                                            |
-| **Quick sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n<sup>2</sup>        |  log(n)  |  Nein  | Quicksort wird normalerweise in-place mit O(log(n)) Stapelplatz ausgeführt |
-| **Shell sort**     | n&nbsp;log(n) | abhängig von Spaltfolge | n&nbsp;(log(n))<sup>2</sup> |    1     |  Nein  |                                                                            |
-| **Counting sort**  |     n + r     |          n + r          |            n + r            |  n + r   |   Ja   | r - größte Zahl im Array                                                   |
-| **Radix sort**     |    n \* k     |         n \* k          |           n \* k            |  n + k   |   Ja   | k - Länge des längsten Schlüssels                                          |
-
-## Projekt-Unterstützer
-
-> Du kannst dieses Projekt unterstützen über ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-[Leute, die dieses Projekt unterstützen](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
-
diff --git a/README.en-EN.md b/README.en-EN.md
new file mode 100644
index 0000000000..01d38dcd6d
--- /dev/null
+++ b/README.en-EN.md
@@ -0,0 +1,349 @@
+# JavaScript Algorithms and Data Structures
+
+[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
+[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
+![repo size](https://img.shields.io/github/repo-size/trekhleb/javascript-algorithms.svg)
+
+This repository contains JavaScript based examples of many
+popular algorithms and data structures.
+
+Each algorithm and data structure has its own separate README
+with related explanations and links for further reading (including ones to YouTube videos).
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+[Source - Original Repository](https://github.com/trekhleb/javascript-algorithms)
+
+_☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production._
+
+## Data Structures
+
+A data structure is a particular way of organizing and storing data in a computer so that it can
+be accessed and modified efficiently. More precisely, a data structure is a collection of data
+values, the relationships among them, and the functions or operations that can be applied to the data.
+
+`B` - Beginner, `A` - Advanced
+
+- `B` [Linked List](src/data-structures/linked-list)
+- `B` [Doubly Linked List](src/data-structures/doubly-linked-list)
+- `B` [Queue](src/data-structures/queue)
+- `B` [Stack](src/data-structures/stack)
+- `B` [Hash Table](src/data-structures/hash-table)
+- `B` [Heap](src/data-structures/heap) - max and min heap versions
+- `B` [Priority Queue](src/data-structures/priority-queue)
+- `A` [Trie](src/data-structures/trie)
+- `A` [Tree](src/data-structures/tree)
+  - `A` [Binary Search Tree](src/data-structures/tree/binary-search-tree)
+  - `A` [AVL Tree](src/data-structures/tree/avl-tree)
+  - `A` [Red-Black Tree](src/data-structures/tree/red-black-tree)
+  - `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples
+  - `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
+- `A` [Graph](src/data-structures/graph) (both directed and undirected)
+- `A` [Disjoint Set](src/data-structures/disjoint-set) - a union–find data structure or merge–find set
+- `A` [Bloom Filter](src/data-structures/bloom-filter)
+- `A` [LRU Cache](src/data-structures/lru-cache/) - Least Recently Used (LRU) cache
+
+## Algorithms
+
+An algorithm is an unambiguous specification of how to solve a class of problems. It is
+a set of rules that precisely define a sequence of operations.
+
+`B` - Beginner, `A` - Advanced
+
+### Algorithms by Topic
+
+- **Math**
+  - `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.
+  - `B` [Binary Floating Point](src/algorithms/math/binary-floating-point) - binary representation of the floating-point numbers.
+  - `B` [Factorial](src/algorithms/math/factorial)
+  - `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions
+  - `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem
+  - `B` [Primality Test](src/algorithms/math/primality-test) (trial division method)
+  - `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
+  - `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM)
+  - `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit
+  - `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms)
+  - `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
+  - `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them
+  - `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion
+  - `B` [Fast Powering](src/algorithms/math/fast-powering)
+  - `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation
+  - `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.)
+  - `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices
+  - `A` [Integer Partition](src/algorithms/math/integer-partition)
+  - `A` [Square Root](src/algorithms/math/square-root) - Newton's method
+  - `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
+  - `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up
+- **Sets**
+  - `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets
+  - `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
+  - `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise, backtracking, and cascading solutions)
+  - `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
+  - `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
+  - `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
+  - `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
+  - `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)
+  - `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones
+  - `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - "Brute Force" and "Dynamic Programming" (Kadane's) versions
+  - `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
+- **Strings**
+  - `B` [Hamming Distance](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
+  - `B` [Palindrome](src/algorithms/string/palindrome) - check if the string is the same in reverse
+  - `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
+  - `A` [Knuth–Morris–Pratt Algorithm](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - substring search (pattern matching)
+  - `A` [Z Algorithm](src/algorithms/string/z-algorithm) - substring search (pattern matching)
+  - `A` [Rabin Karp Algorithm](src/algorithms/string/rabin-karp) - substring search
+  - `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
+  - `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
+- **Searches**
+  - `B` [Linear Search](src/algorithms/search/linear-search)
+  - `B` [Jump Search](src/algorithms/search/jump-search) (or Block Search) - search in sorted array
+  - `B` [Binary Search](src/algorithms/search/binary-search) - search in sorted array
+  - `B` [Interpolation Search](src/algorithms/search/interpolation-search) - search in uniformly distributed sorted array
+- **Sorting**
+  - `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)
+  - `B` [Selection Sort](src/algorithms/sorting/selection-sort)
+  - `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)
+  - `B` [Heap Sort](src/algorithms/sorting/heap-sort)
+  - `B` [Merge Sort](src/algorithms/sorting/merge-sort)
+  - `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations
+  - `B` [Shellsort](src/algorithms/sorting/shell-sort)
+  - `B` [Counting Sort](src/algorithms/sorting/counting-sort)
+  - `B` [Radix Sort](src/algorithms/sorting/radix-sort)
+  - `B` [Bucket Sort](src/algorithms/sorting/bucket-sort)
+- **Linked Lists**
+  - `B` [Straight Traversal](src/algorithms/linked-list/traversal)
+  - `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)
+- **Trees**
+  - `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
+  - `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)
+- **Graphs**
+  - `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
+  - `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)
+  - `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
+  - `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest paths to all graph vertices from single vertex
+  - `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest paths to all graph vertices from single vertex
+  - `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices
+  - `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions)
+  - `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
+  - `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method
+  - `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based)
+  - `A` [Bridges](src/algorithms/graph/bridges) - DFS based algorithm
+  - `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once
+  - `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
+  - `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
+  - `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
+- **Cryptography**
+  - `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial
+  - `B` [Rail Fence Cipher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages
+  - `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher
+  - `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra
+- **Machine Learning**
+  - `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)
+  - `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm
+  - `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm
+- **Image Processing**
+  - `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
+- **Statistics**
+  - `B` [Weighted Random](src/algorithms/statistics/weighted-random) - select the random item from the list based on items' weights
+- **Evolutionary algorithms**
+  - `A` [Genetic algorithm](https://github.com/trekhleb/self-parking-car-evolution) - example of how the genetic algorithm may be applied for training the self-parking cars
+- **Uncategorized**
+  - `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
+  - `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
+  - `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
+  - `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
+  - `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
+  - `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions)
+  - `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples
+  - `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
+  - `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
+
+### Algorithms by Paradigm
+
+An algorithmic paradigm is a generic method or approach which underlies the design of a class
+of algorithms. It is an abstraction higher than the notion of an algorithm, just as an
+algorithm is an abstraction higher than a computer program.
+
+- **Brute Force** - look at all the possibilities and selects the best solution
+  - `B` [Linear Search](src/algorithms/search/linear-search)
+  - `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
+  - `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
+  - `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
+  - `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
+  - `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up
+- **Greedy** - choose the best option at the current time, without any consideration for the future
+  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
+  - `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)
+  - `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest path to all graph vertices
+  - `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
+  - `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
+- **Divide and Conquer** - divide the problem into smaller parts and then solve those parts
+  - `B` [Binary Search](src/algorithms/search/binary-search)
+  - `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
+  - `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
+  - `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
+  - `B` [Merge Sort](src/algorithms/sorting/merge-sort)
+  - `B` [Quicksort](src/algorithms/sorting/quick-sort)
+  - `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
+  - `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
+  - `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes
+  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
+  - `B` [Fast Powering](src/algorithms/math/fast-powering)
+  - `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples
+  - `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
+  - `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
+  - `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
+- **Dynamic Programming** - build up a solution using previously found sub-solutions
+  - `B` [Fibonacci Number](src/algorithms/math/fibonacci)
+  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
+  - `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
+  - `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
+  - `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
+  - `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
+  - `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
+  - `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
+  - `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
+  - `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
+  - `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)
+  - `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)
+  - `A` [Integer Partition](src/algorithms/math/integer-partition)
+  - `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
+  - `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest path to all graph vertices
+  - `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices
+  - `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
+- **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate next solution you test
+  if it satisfies all conditions, and only then continue generating subsequent solutions. Otherwise, backtrack, and go on a
+  different path of finding a solution. Normally the DFS traversal of state-space is being used.
+  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
+  - `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
+  - `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
+  - `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
+  - `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
+  - `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
+  - `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
+- **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking
+  search, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of
+  a least-cost solution to the problem, in order to discard partial solutions with costs larger than the
+  lowest-cost solution found so far. Normally BFS traversal in combination with DFS traversal of state-space
+  tree is being used.
+
+## How to use this repository
+
+**Install all dependencies**
+
+```
+npm install
+```
+
+**Run ESLint**
+
+You may want to run it to check code quality.
+
+```
+npm run lint
+```
+
+**Run all tests**
+
+```
+npm test
+```
+
+**Run tests by name**
+
+```
+npm test -- 'LinkedList'
+```
+
+**Troubleshooting**
+
+If linting or testing is failing, try to delete the `node_modules` folder and re-install npm packages:
+
+```
+rm -rf ./node_modules
+npm i
+```
+
+Also make sure that you're using a correct Node version (`>=16`). If you're using [nvm](https://github.com/nvm-sh/nvm) for Node version management you may run `nvm use` from the root folder of the project and the correct version will be picked up.
+
+**Playground**
+
+You may play with data-structures and algorithms in `./src/playground/playground.js` file and write
+tests for it in `./src/playground/__test__/playground.test.js`.
+
+Then just simply run the following command to test if your playground code works as expected:
+
+```
+npm test -- 'playground'
+```
+
+## Useful Information
+
+### References
+
+- [▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [✍🏻 Data Structure Sketches](https://okso.app/showcase/data-structures)
+
+### Big O Notation
+
+_Big O notation_ is used to classify algorithms according to how their running time or space requirements grow as the input size grows.
+On the chart below you may find most common orders of growth of algorithms specified in Big O notation.
+
+![Big O graphs](./assets/big-o-graph.png)
+
+Source: [Big O Cheat Sheet](http://bigocheatsheet.com/).
+
+Below is the list of some of the most used Big O notations and their performance comparisons against different sizes of the input data.
+
+| Big O Notation | Type        | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements |
+| -------------- | ----------- | ---------------------------- | ----------------------------- | ------------------------------ |
+| **O(1)**       | Constant    | 1                            | 1                             | 1                              |
+| **O(log N)**   | Logarithmic | 3                            | 6                             | 9                              |
+| **O(N)**       | Linear      | 10                           | 100                           | 1000                           |
+| **O(N log N)** | n log(n)    | 30                           | 600                           | 9000                           |
+| **O(N^2)**     | Quadratic   | 100                          | 10000                         | 1000000                        |
+| **O(2^N)**     | Exponential | 1024                         | 1.26e+29                      | 1.07e+301                      |
+| **O(N!)**      | Factorial   | 3628800                      | 9.3e+157                      | 4.02e+2567                     |
+
+### Data Structure Operations Complexity
+
+| Data Structure         | Access | Search | Insertion | Deletion | Comments                                             |
+| ---------------------- | :----: | :----: | :-------: | :------: | :--------------------------------------------------- |
+| **Array**              |   1    |   n    |     n     |    n     |                                                      |
+| **Stack**              |   n    |   n    |     1     |    1     |                                                      |
+| **Queue**              |   n    |   n    |     1     |    1     |                                                      |
+| **Linked List**        |   n    |   n    |     1     |    n     |                                                      |
+| **Hash Table**         |   -    |   n    |     n     |    n     | In case of perfect hash function costs would be O(1) |
+| **Binary Search Tree** |   n    |   n    |     n     |    n     | In case of balanced tree costs would be O(log(n))    |
+| **B-Tree**             | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **Red-Black Tree**     | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **AVL Tree**           | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **Bloom Filter**       |   -    |   1    |     1     |    -     | False positives are possible while searching         |
+
+### Array Sorting Algorithms Complexity
+
+| Name               |     Best      |         Average         |            Worst            | Memory | Stable | Comments                                                      |
+| ------------------ | :-----------: | :---------------------: | :-------------------------: | :----: | :----: | :------------------------------------------------------------ |
+| **Bubble sort**    |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |  Yes   |                                                               |
+| **Insertion sort** |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |  Yes   |                                                               |
+| **Selection sort** | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |   No   |                                                               |
+| **Heap sort**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   1    |   No   |                                                               |
+| **Merge sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   n    |  Yes   |                                                               |
+| **Quick sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n<sup>2</sup>        | log(n) |   No   | Quicksort is usually done in-place with O(log(n)) stack space |
+| **Shell sort**     | n&nbsp;log(n) | depends on gap sequence | n&nbsp;(log(n))<sup>2</sup> |   1    |   No   |                                                               |
+| **Counting sort**  |     n + r     |          n + r          |            n + r            | n + r  |  Yes   | r - biggest number in array                                   |
+| **Radix sort**     |    n \* k     |         n \* k          |           n \* k            | n + k  |  Yes   | k - length of longest key                                     |
+
+## Project Backers
+
+> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).
+
+[Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`
+
+## Author
+
+[@trekhleb](https://trekhleb.dev)
+
+A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.es-ES.md b/README.es-ES.md
deleted file mode 100644
index d79baf6022..0000000000
--- a/README.es-ES.md
+++ /dev/null
@@ -1,304 +0,0 @@
-# Algoritmos y Estructuras de Datos en JavaScript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Este repositorio contiene ejemplos basados en JavaScript de muchos
-algoritmos y estructuras de datos populares.
-
-Cada algoritmo y estructura de datos tiene su propio LÉAME con explicaciones relacionadas y
-enlaces para lecturas adicionales (incluyendo algunas a vídeos de YouTube).
-
-_Léelo en otros idiomas:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación,
-y **no** para ser usado en producción.*
-
-## Estructuras de Datos
-
-Una estructura de datos es una forma particular de organizar y almacenar datos en un ordenador para que puedan accederse
-y modificarse de forma eficiente. Más concretamente, una estructura de datos es un conjunto de valores
-de datos, las relaciones entre ellos y las funciones u operaciones que se pueden aplicar a
-los datos.
-
-`P` - Principiante, `A` - Avanzado
-
-* `P` [Lista enlazada](src/data-structures/linked-list)
-* `P` [Lista doblemente enlazada](src/data-structures/doubly-linked-list)
-* `P` [Cola](src/data-structures/queue)
-* `P` [Pila](src/data-structures/stack)
-* `P` [Tabla hash](src/data-structures/hash-table)
-* `P` [Heap](src/data-structures/heap) - versiones máx y mín
-* `P` [Cola de prioridad](src/data-structures/priority-queue)
-* `A` [Trie](src/data-structures/trie)
-* `A` [Árbol](src/data-structures/tree)
-  * `A` [Árbol de búsqueda binaria](src/data-structures/tree/binary-search-tree)
-  * `A` [Árbol AVL](src/data-structures/tree/avl-tree)
-  * `A` [Árbol Rojo-Negro](src/data-structures/tree/red-black-tree)
-  * `A` [Árbol de segmentos](src/data-structures/tree/segment-tree) - con ejemplos de consultas de rango mín/máx/suma
-  * `A` [Árbol de Fenwick](src/data-structures/tree/fenwick-tree) (Árbol binario indexado)
-* `A` [Grafo](src/data-structures/graph) (dirigido y no dirigido)
-* `A` [Conjuntos disjuntos](src/data-structures/disjoint-set)
-* `A` [Filtro de Bloom](src/data-structures/bloom-filter)
-
-## Algoritmos
-
-Un algoritmo es una especificación inequívoca de cómo resolver una clase de problemas. Es un conjunto de reglas que
-definen con precisión una secuencia de operaciones.
-
-`P` - Principiante, `A` - Avanzado
-
-### Algoritmos por Tema
-
-* **Matemáticas**
-  * `P` [Manipulación de bits](src/algorithms/math/bits) - asignar/obtener/actualizar/limpiar bits, multiplicación/división por dos, hacer negativo, etc.
-  * `P` [Factorial](src/algorithms/math/factorial)
-  * `P` [Número de Fibonacci](src/algorithms/math/fibonacci)
-  * `P` [Prueba de primalidad](src/algorithms/math/primality-test) (método de división de prueba)
-  * `P` [Algoritmo de Euclides](src/algorithms/math/euclidean-algorithm) - calcular el Máximo común divisor (MCD)
-  * `P` [Mínimo común múltiplo](src/algorithms/math/least-common-multiple) (MCM)
-  * `P` [Criba de Eratóstenes](src/algorithms/math/sieve-of-eratosthenes) - encontrar todos los números primos hasta un límite dado
-  * `P` [Es una potencia de dos?](src/algorithms/math/is-power-of-two) - comprobar si el número es una potencia de dos (algoritmos ingenuos y de bits)
-  * `P` [Triángulo de Pascal](src/algorithms/math/pascal-triangle)
-  * `P` [Números complejos](src/algorithms/math/complex-number) - números complejos y operaciones con ellos
-  * `P` [Radianes & Grados](src/algorithms/math/radian) - conversión de radianes a grados y viceversa
-  * `P` [Exponenciación rápida](src/algorithms/math/fast-powering)
-  * `A` [Partición entera](src/algorithms/math/integer-partition)
-  * `A` [Algoritmo π de Liu Hui](src/algorithms/math/liu-hui) - aproximar el cálculo de  π basado en polígonos de N lados
-  * `A` [Transformada discreta de Fourier](src/algorithms/math/fourier-transform) - descomponer una función de tiempo (señal) en las frecuencias que la componen
-* **Conjuntos**
-  * `P` [Producto cartesiano](src/algorithms/sets/cartesian-product) - producto de múltiples conjuntos
-  * `P` [Permutación de Fisher–Yates](src/algorithms/sets/fisher-yates) - permutación aleatoria de una secuencia finita
-  * `A` [Conjunto potencia](src/algorithms/sets/power-set) - todos los subconjuntos de un conjunto
-  * `A` [Permutaciones](src/algorithms/sets/permutations) (con y sin repeticiones)
-  * `A` [Combinaciones](src/algorithms/sets/combinations) (con y sin repeticiones)
-  * `A` [Subsecuencia común más larga](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Subsecuencia creciente más larga](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Supersecuencia común más corta](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Problema de la mochila](src/algorithms/sets/knapsack-problem) - "0/1" y "sin límite"
-  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray) - versiones de "fuerza bruta" y "programación dinámica" (de Kadane)
-  * `A` [Suma combinada](src/algorithms/sets/combination-sum) - encuentra todas las combinaciones que forman una suma específica
-* **Cadenas de caracteres**
-  * `P` [Distancia de Hamming](src/algorithms/string/hamming-distance) - número de posiciones en las que los símbolos son diferentes
-  * `A` [Distancia de Levenshtein](src/algorithms/string/levenshtein-distance) - distancia mínima de edición entre dos secuencias
-  * `A` [Algoritmo Knuth-Morris-Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritmo KMP) - búsqueda de subcadenas (coincidencia de patrones)
-  * `A` [Algoritmo Z](src/algorithms/string/z-algorithm) - búsqueda de subcadenas (coincidencia de patrones)
-  * `A` [Algoritmo de Rabin Karp](src/algorithms/string/rabin-karp) - búsqueda de subcadenas
-  * `A` [Subcadena común más larga](src/algorithms/string/longest-common-substring)
-  * `A` [Coincidencia por expresiones regulares](src/algorithms/string/regular-expression-matching)
-* **Búsquedas**
-  * `P` [Búsqueda lineal](src/algorithms/search/linear-search)
-  * `P` [Búsqueda de salto](src/algorithms/search/jump-search) (o Búsqueda de bloque) - búsqueda en una lista ordenada
-  * `P` [Búsqueda binaria](src/algorithms/search/binary-search) - búsqueda en una lista ordenada
-  * `P` [Búsqueda por interpolación](src/algorithms/search/interpolation-search) - búsqueda en una lista ordenada uniformemente distribuida
-* **Ordenamiento**
-  * `P` [Ordenamiento de burbuja](src/algorithms/sorting/bubble-sort)
-  * `P` [Ordenamiento por selección](src/algorithms/sorting/selection-sort)
-  * `P` [Ordenamiento por inserción](src/algorithms/sorting/insertion-sort)
-  * `P` [Ordenamiento por Heap](src/algorithms/sorting/heap-sort)
-  * `P` [Ordenamiento por mezcla](src/algorithms/sorting/merge-sort)
-  * `P` [Quicksort](src/algorithms/sorting/quick-sort) - implementaciones in situ y no in situ
-  * `P` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `P` [Ordenamiento por cuentas](src/algorithms/sorting/counting-sort)
-  * `P` [Ordenamiento Radix](src/algorithms/sorting/radix-sort)
-* **Listas enlazadas**
-  * `P` [Recorrido directo](src/algorithms/linked-list/traversal)
-  * `P` [Recorrido inverso](src/algorithms/linked-list/reverse-traversal)
-* **Árboles**
-  * `P` [Búsqueda en profundidad](src/algorithms/tree/depth-first-search) (DFS)
-  * `P` [Búsqueda en anchura](src/algorithms/tree/breadth-first-search) (BFS)
-* **Grafos**
-  * `P` [Búsqueda en profundidad](src/algorithms/graph/depth-first-search) (DFS)
-  * `P` [Búsqueda en anchura](src/algorithms/graph/breadth-first-search) (BFS)
-  * `P` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado
-  * `A` [Algoritmo de Dijkstra](src/algorithms/graph/dijkstra) - encontrar los caminos más cortos a todos los vértices del grafo desde un solo vértice
-  * `A` [Algoritmo de Bellman-Ford](src/algorithms/graph/bellman-ford) - encontrar los caminos más cortos a todos los vértices del grafo desde un solo vértice
-  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - encontrar los caminos más cortos entre todos los pares de vértices
-  * `A` [Detectar ciclos](src/algorithms/graph/detect-cycle) - para grafos dirigidos y no dirigidos (versiones basadas en DFS y conjuntos disjuntos)
-  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado
-  * `A` [Ordenamiento topológico](src/algorithms/graph/topological-sorting) - método DFS
-  * `A` [Puntos de articulación](src/algorithms/graph/articulation-points) - algoritmo de Tarjan (basado en DFS)
-  * `A` [Puentes](src/algorithms/graph/bridges) - algoritmo basado en DFS
-  * `A` [Camino euleriano y circuito euleriano](src/algorithms/graph/eulerian-path) - algoritmo de Fleury - visitar cada arista exactamente una vez
-  * `A` [Ciclo hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - visitar cada vértice exactamente una vez
-  * `A` [Componentes fuertemente conexos](src/algorithms/graph/strongly-connected-components) - algoritmo de Kosaraju
-  * `A` [Problema del viajante](src/algorithms/graph/travelling-salesman) - la ruta más corta posible que visita cada ciudad y vuelve a la ciudad de origen
-* **Criptografía**
-  * `P` [Hash polinomial](src/algorithms/cryptography/polynomial-hash) - función de hash rodante basada en polinomio
-* **Sin categoría**
-  * `P` [Torre de Hanói](src/algorithms/uncategorized/hanoi-tower)
-  * `P` [Rotación de matriz cuadrada](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in situ
-  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game) - ejemplos de backtracking, programación dinámica (de arriba hacia abajo + de abajo hacia arriba) y voraces
-  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths) - ejemplos de backtracking, programación dinámica y basados en el Triángulo de Pascal
-  * `P` [Terrazas pluviales](src/algorithms/uncategorized/rain-terraces) - el problema de la retención del agua de lluvia (programación dinámica y fuerza bruta)
-  * `A` [Problema de las N Reinas](src/algorithms/uncategorized/n-queens)
-  * `A` [Problema del caballo (Knight tour)](src/algorithms/uncategorized/knight-tour)
-
-### Algoritmos por paradigma
-
-Un paradigma algorítmico es un método o enfoque genérico que subyace al diseño de una clase de algoritmos.
-Es una abstracción superior a la noción de algoritmo, del mismo modo que un algoritmo es una abstracción superior a un programa de ordenador.
-
-* **Fuerza Bruta** - mira todas las posibilidades y selecciona la mejor solución
-  * `P` [Búsqueda lineal](src/algorithms/search/linear-search)
-  * `P` [Terrazas pluviales](src/algorithms/uncategorized/rain-terraces) - el problema de la retención del agua de lluvia
-  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray)
-  * `A` [Problema del viajante](src/algorithms/graph/travelling-salesman) - la ruta más corta posible que visita cada ciudad y vuelve a la ciudad de origen
-  * `A` [Transformada discreta de Fourier](src/algorithms/math/fourier-transform) - descomponer una función de tiempo (señal) en las frecuencias que la componen
-* **Voraces** - escoge la mejor opción en el momento actual, sin ninguna consideración sobre el futuro
-  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)
-  * `A` [Problema de la mochila sin límite](src/algorithms/sets/knapsack-problem)
-  * `A` [Algoritmo de Dijkstra](src/algorithms/graph/dijkstra) - encontrar los caminos más cortos a todos los vértices del grafo desde un solo vértice
-  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado
-  * `A` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - encontrar el árbol de cubrimiento mínimo (MST) para un grafo no dirigido ponderado
-* **Divide y Vencerás** - divide el problema en partes más pequeñas y luego resuelve esas partes
-  * `P` [Búsqueda binaria](src/algorithms/search/binary-search)
-  * `P` [Torre de Hanói](src/algorithms/uncategorized/hanoi-tower)
-  * `P` [Triángulo de Pascal](src/algorithms/math/pascal-triangle)
-  * `P` [Algoritmo de Euclides](src/algorithms/math/euclidean-algorithm) - calcular el Máximo Común Divisor (MCD)
-  * `P` [Ordenamiento por mezcla](src/algorithms/sorting/merge-sort)
-  * `P` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `P` [Búsqueda en profundidad (árboles)](src/algorithms/tree/depth-first-search) - (DFS)
-  * `P` [Búsqueda en profundidad (grafos)](src/algorithms/graph/depth-first-search) - (DFS)
-  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)
-  * `P` [Exponenciación rápida](src/algorithms/math/fast-powering)
-  * `A` [Permutaciones](src/algorithms/sets/permutations) - (con y sin repeticiones)
-  * `A` [Combinaciones](src/algorithms/sets/combinations) - (con y sin repeticiones)
-* **Programación Dinámica** - construye una solución usando sub-soluciones previamente encontradas
-  * `P` [Número de Fibonacci](src/algorithms/math/fibonacci)
-  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)
-  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths)
-  * `P` [Terrazas pluviales](src/algorithms/uncategorized/rain-terraces) - el problema de la retención del agua de lluvia
-  * `A` [Distancia de Levenshtein](src/algorithms/string/levenshtein-distance) - distancia mínima de edición entre dos secuencias
-  * `A` [Subsecuencia común más larga](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Subcadena común más larga](src/algorithms/string/longest-common-substring)
-  * `A` [Subsecuencia creciente más larga](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Supersecuencia común más corta](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Problema de la mochila 0/1](src/algorithms/sets/knapsack-problem)
-  * `A` [Partición entera](src/algorithms/math/integer-partition)
-  * `A` [Máximo subarreglo](src/algorithms/sets/maximum-subarray)
-  * `A` [Algoritmo de Bellman-Ford](src/algorithms/graph/bellman-ford) - encontrar los caminos más cortos a todos los vértices del grafo desde un solo vértice
-  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - encontrar los caminos más cortos entre todos los pares de vértices
-  * `A` [Coincidencia por expresiones regulares](src/algorithms/string/regular-expression-matching)
-* **De Retorceso (Backtracking)** - De manera similar a la fuerza bruta, trata de generar todas las soluciones posibles, pero cada vez que genere la siguiente solución, comprueba si cumple con todas las condiciones, y sólo entonces continúa generando soluciones posteriores. De lo contrario, retrocede y sigue un camino diferente para encontrar una solución. Normalmente se utiliza un recorrido en profundidad (DFS) del espacio de estados.
-  * `P` [Juego de los saltos](src/algorithms/uncategorized/jump-game)
-  * `P` [Caminos únicos](src/algorithms/uncategorized/unique-paths)
-  * `P` [Conjunto potencia](src/algorithms/sets/power-set) - todos los subconjuntos de un conjunto
-  * `A` [Ciclo hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - visitar cada vértice exactamente una vez
-  * `A` [Problema de las N Reinas](src/algorithms/uncategorized/n-queens)
-  * `A` [Problema del caballo (Knight tour)](src/algorithms/uncategorized/knight-tour)
-  * `A` [Suma combinada](src/algorithms/sets/combination-sum) - encuentra todas las combinaciones que forman una suma específica
-* **Ramas y Límites** - recuerda la solución de menor costo encontrada en cada etapa de la búsqueda de rastreo, y utilizar el costo de la solución de menor costo encontrada hasta el momento como un límite inferior del costo de una solución de menor costo para el problema, a fin de descartar soluciones parciales con costos mayores que la solución de menor costo encontrada hasta el momento. Normalmente se utiliza un recorrido BFS en combinación con un recorrido DFS del árbol del espacio de estados.
-
-## Cómo usar este repositorio
-
-**Instalar las dependencias**
-
-```
-npm install
-```
-
-**Correr ESLint**
-
-Es posible que desee ejecutarlo para comprobar la calidad del código.
-
-```
-npm run lint
-```
-
-**Correr los tests**
-
-```
-npm test
-```
-
-**Correr tests por nombre**
-
-```
-npm test -- 'LinkedList'
-```
-
-**Campo de juegos**
-
-Puede jugar con estructuras de datos y algoritmos en el archivo `./src/playground/playground.js` y escribir
-pruebas para ello en `./src/playground/__test__/playground.test.js`.
-
-A continuación, simplemente ejecute el siguiente comando para comprobar si el código funciona como se espera:
-
-```
-npm test -- 'playground'
-```
-
-## Información útil
-
-### Referencias
-
-[▶ Estructuras de datos y algoritmos en YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Notación O Grande
-
-Orden de crecimiento de los algoritmos especificados en la notación O grande.
-
-![Gráficas de Notación O grande ](./assets/big-o-graph.png)
-
-Fuente: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-A continuación se muestra la lista de algunas de las notaciones de Big O más utilizadas y sus comparaciones de rendimiento
-frente a diferentes tamaños de los datos de entrada.
-
-| Notación O grande | Cálculos para 10 elementos | Cálculos para 100 elementos | Cálculos para 1000 elementos |
-| ----------------- | -------------------------- | --------------------------- | ---------------------------- |
-| **O(1)**          | 1                          | 1                           | 1                            |
-| **O(log N)**      | 3                          | 6                           | 9                            |
-| **O(N)**          | 10                         | 100                         | 1000                         |
-| **O(N log N)**    | 30                         | 600                         | 9000                         |
-| **O(N^2)**        | 100                        | 10000                       | 1000000                      |
-| **O(2^N)**        | 1024                       | 1.26e+29                    | 1.07e+301                    |
-| **O(N!)**         | 3628800                    | 9.3e+157                    | 4.02e+2567                   |
-
-### Complejidad de las operaciones de estructuras de datos
-
-| Estructura de Datos            | Accesso | Busqueda | Inserción | Borrado | Comentarios                                                     |
-| ------------------------------ | :-----: | :------: | :-------: | :-----: | :-------------------------------------------------------------- |
-| **Colección**                  |    1    |    n     |     n     |    n    |                                                                 |
-| **Stack**                      |    n    |    n     |     1     |    1    |                                                                 |
-| **Cola**                       |    n    |    n     |     1     |    1    |                                                                 |
-| **Lista enlazada**             |    n    |    n     |     1     |    1    |                                                                 |
-| **Tabla hash**                 |    -    |    n     |     n     |    n    | En caso de función hash perfecta los costos serían O(1)         |
-| **Búsqueda por Árbol binario** |    n    |    n     |     n     |    n    | En el caso de un árbol equilibrado, los costos serían O(log(n)) |
-| **Árbol B**                    | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |
-| **Árbol Rojo-Negro**           | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |
-| **Árbol AVL**                  | log(n)  |  log(n)  |  log(n)   | log(n)  |                                                                 |
-| **Filtro de Bloom**            |    -    |    1     |     1     |    -    | Falsos positivos son posibles durante la búsqueda               |
-
-### Complejidad de algoritmos de ordenamiento de arreglos
-
-| Nombre                           | Mejor         | Promedio                | Pero                        | Memorya | Estable | Comentarios                                                   |
-| -------------------------------- | :-----------: | :---------------------: | :-------------------------: | :-----: | :-----: | :------------------------------------------------------------ |
-| **Ordenamiento de burbuja**      |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |  Si     |                                                               |
-| **Ordenamiento por inserción**   |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |  Si     |                                                               |
-| **Ordenamiento por selección**   | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |   1     |   No    |                                                               |
-| **Ordenamiento por Heap**        | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   1     |   No    |                                                               |
-| **Ordenamiento por mezcla**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   n     |  Si     |                                                               |
-| **Quicksort**                    | n&nbsp;log(n) |      n&nbsp;log(n)      |        n<sup>2</sup>        | log(n)  |   No    | Quicksort utiliza O(log(n)) de espacio en el stack         |
-| **Shellsort**                    | n&nbsp;log(n) | depende de la secuencia de huecos | n&nbsp;(log(n))<sup>2</sup> |   1   |   No   |                                                               |
-| **Ordenamiento por cuentas**     |     n + r     |          n + r          |            n + r            | n + r   |  Si     | r - mayor número en el arreglo                                |
-| **Ordenamiento Radix**           |    n \* k     |         n \* k          |           n \* k            | n + k   |  Si     | k - largo de la llave más larga                                     |
-
-> ℹ️ Algunos otros [proyectos](https://trekhleb.dev/projects/) y [artículos](https://trekhleb.dev/blog/) sobre JavaScript y algoritmos en [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.fr-FR.md b/README.fr-FR.md
deleted file mode 100644
index 469a4f52d9..0000000000
--- a/README.fr-FR.md
+++ /dev/null
@@ -1,298 +0,0 @@
-# Algorithmes et Structures de Données en JavaScript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Ce dépôt contient des exemples d'implémentation en JavaScript de plusieurs
-algorithmes et structures de données populaires.
-
-Chaque algorithme et structure de donnée possède son propre README contenant
-les explications détaillées et liens (incluant aussi des vidéos Youtube) pour
-complément d'informations.
-
-_Lisez ceci dans d'autres langues:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## Data Structures
-
-Une structure de données est une manière spéciale d'organiser et de stocker
-des données dans un ordinateur de manière à ce que l'on puisse accéder à
-cette information et la modifier de manière efficiente. De manière plus
-spécifique, une structure de données est un ensemble composé d'une collection
-de valeurs, des relations entre ces valeurs ainsi que d'un ensemble de
-fonctions ou d'opérations pouvant être appliquées sur ces données.
-
-`B` - Débutant, `A` - Avancé
-
-- `B` [Liste Chaînée](src/data-structures/linked-list)
-- `B` [Liste Doublement Chaînée](src/data-structures/doubly-linked-list)
-- `B` [Queue](src/data-structures/queue)
-- `B` [Pile](src/data-structures/stack)
-- `B` [Table de Hachage](src/data-structures/hash-table)
-- `B` [Tas](src/data-structures/heap)
-- `B` [Queue de Priorité](src/data-structures/priority-queue)
-- `A` [Trie](src/data-structures/trie)
-- `A` [Arbre](src/data-structures/tree)
-  - `A` [Arbre de recherche Binaire](src/data-structures/tree/binary-search-tree)
-  - `A` [Arbre AVL](src/data-structures/tree/avl-tree)
-  - `A` [Arbre Red-Black](src/data-structures/tree/red-black-tree)
-  - `A` [Arbre de Segments](src/data-structures/tree/segment-tree) - avec exemples de requêtes de type min/max/somme sur intervalles
-  - `A` [Arbre de Fenwick](src/data-structures/tree/fenwick-tree) (Arbre Binaire Indexé)
-- `A` [Graphe](src/data-structures/graph) (orienté et non orienté)
-- `A` [Ensembles Disjoints](src/data-structures/disjoint-set)
-- `A` [Filtre de Bloom](src/data-structures/bloom-filter)
-
-## Algorithmes
-
-Un algorithme est une démarche non ambigüe expliquant comment résoudre une
-classe de problèmes. C'est un ensemble de règles décrivant de manière précise
-une séquence d'opérations.
-
-`B` - Débutant, `A` - Avancé
-
-### Algorithmes par topic
-
-- **Math**
-  - `B` [Manipulation de Bit](src/algorithms/math/bits/README.fr-FR.md) - définir/obtenir/mettre à jour/effacer les bits, multiplication/division par deux, négativiser etc.
-  - `B` [Factorielle](src/algorithms/math/factorial/README.fr-FR.md)
-  - `B` [Nombre de Fibonacci](src/algorithms/math/fibonacci/README.fr-FR.md)
-  - `B` [Test de Primalité](src/algorithms/math/primality-test) (méthode du test de division)
-  - `B` [Algorithme d'Euclide](src/algorithms/math/euclidean-algorithm/README.fr-FR.md) - calcule le Plus Grand Commun Diviseur (PGCD)
-  - `B` [Plus Petit Commun Multiple](src/algorithms/math/least-common-multiple) (PPCM)
-  - `B` [Crible d'Eratosthène](src/algorithms/math/sieve-of-eratosthenes) - trouve tous les nombres premiers inférieurs à une certaine limite
-  - `B` [Puissance de Deux](src/algorithms/math/is-power-of-two) - teste si un nombre donné est une puissance de deux (algorithmes naif et basé sur les opérations bit-à-bit)
-  - `B` [Triangle de Pascal](src/algorithms/math/pascal-triangle)
-  - `B` [Nombre complexe](src/algorithms/math/complex-number/README.fr-FR.md) - nombres complexes et opérations de bases
-  - `A` [Partition Entière](src/algorithms/math/integer-partition)
-  - `A` [Approximation de π par l'algorithme de Liu Hui](src/algorithms/math/liu-hui) - approximation du calcul de π basé sur les N-gons
-  - `B` [Exponentiation rapide](src/algorithms/math/fast-powering/README.fr-FR.md)
-  - `A` [Transformée de Fourier Discrète](src/algorithms/math/fourier-transform/README.fr-FR.md) - décomposer une fonction du temps (un signal) en fréquences qui la composent
-- **Ensembles**
-  - `B` [Produit Cartésien](src/algorithms/sets/cartesian-product) - produit de plusieurs ensembles
-  - `B` [Mélange de Fisher–Yates](src/algorithms/sets/fisher-yates) - permulation aléatoire d'une séquence finie
-  - `A` [Ensemble des parties d'un ensemble](src/algorithms/sets/power-set) - tous les sous-ensembles d'un ensemble
-  - `A` [Permutations](src/algorithms/sets/permutations) (avec et sans répétitions)
-  - `A` [Combinaisons](src/algorithms/sets/combinations) (avec et sans répétitions)
-  - `A` [Plus Longue Sous-séquence Commune](src/algorithms/sets/longest-common-subsequence)
-  - `A` [Plus Longue Sous-suite strictement croissante](src/algorithms/sets/longest-increasing-subsequence)
-  - `A` [Plus Courte Super-séquence Commune](src/algorithms/sets/shortest-common-supersequence)
-  - `A` [Problème du Sac à Dos](src/algorithms/sets/knapsack-problem) - versions "0/1" et "Sans Contraintes"
-  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray) - versions "Force Brute" et "Programmation Dynamique" (Kadane)
-  - `A` [Somme combinatoire](src/algorithms/sets/combination-sum) - trouve toutes les combinaisons qui forment une somme spécifique
-- **Chaînes de Caractères**
-  - `B` [Distance de Hamming](src/algorithms/string/hamming-distance) - nombre de positions auxquelles les symboles sont différents
-  - `A` [Distance de Levenshtein](src/algorithms/string/levenshtein-distance) - distance minimale d'édition entre deux séquences
-  - `A` [Algorithme de Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algorithme KMP) - recherche de sous-chaîne (pattern matching)
-  - `A` [Algorithme Z](src/algorithms/string/z-algorithm) - recherche de sous-chaîne (pattern matching)
-  - `A` [Algorithme de Rabin Karp](src/algorithms/string/rabin-karp) - recherche de sous-chaîne
-  - `A` [Plus Longue Sous-chaîne Commune](src/algorithms/string/longest-common-substring)
-  - `A` [Expression Régulière](src/algorithms/string/regular-expression-matching)
-- **Recherche**
-  - `B` [Recherche Linéaire](src/algorithms/search/linear-search)
-  - `B` [Jump Search](src/algorithms/search/jump-search) Recherche par saut (ou par bloc) - recherche dans une liste triée
-  - `B` [Recherche Binaire](src/algorithms/search/binary-search) - recherche dans une liste triée
-  - `B` [Recherche par Interpolation](src/algorithms/search/interpolation-search) - recherche dans une liste triée et uniformément distribuée
-- **Tri**
-  - `B` [Tri Bullet](src/algorithms/sorting/bubble-sort)
-  - `B` [Tri Sélection](src/algorithms/sorting/selection-sort)
-  - `B` [Tri Insertion](src/algorithms/sorting/insertion-sort)
-  - `B` [Tri Par Tas](src/algorithms/sorting/heap-sort)
-  - `B` [Tri Fusion](src/algorithms/sorting/merge-sort)
-  - `B` [Tri Rapide](src/algorithms/sorting/quick-sort) - implémentations _in-place_ et _non in-place_
-  - `B` [Tri Shell](src/algorithms/sorting/shell-sort)
-  - `B` [Tri Comptage](src/algorithms/sorting/counting-sort)
-  - `B` [Tri Radix](src/algorithms/sorting/radix-sort)
-- **Arbres**
-  - `B` [Parcours en Profondeur](src/algorithms/tree/depth-first-search) (DFS)
-  - `B` [Parcours en Largeur](src/algorithms/tree/breadth-first-search) (BFS)
-- **Graphes**
-  - `B` [Parcours en Profondeur](src/algorithms/graph/depth-first-search) (DFS)
-  - `B` [Parcours en Largeur](src/algorithms/graph/breadth-first-search) (BFS)
-  - `B` [Algorithme de Kruskal](src/algorithms/graph/kruskal) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé
-  - `A` [Algorithme de Dijkstra](src/algorithms/graph/dijkstra) - trouver tous les plus courts chemins partant d'un noeud vers tous les autres noeuds dans un graphe
-  - `A` [Algorithme de Bellman-Ford](src/algorithms/graph/bellman-ford) - trouver tous les plus courts chemins partant d'un noeud vers tous les autres noeuds dans un graphe
-  - `A` [Algorithme de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - trouver tous les plus courts chemins entre toutes les paires de noeuds dans un graphe
-  - `A` [Détection de Cycle](src/algorithms/graph/detect-cycle) - pour les graphes dirigés et non dirigés (implémentations basées sur l'algorithme de Parcours en Profondeur et sur les Ensembles Disjoints)
-  - `A` [Algorithme de Prim](src/algorithms/graph/prim) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé
-  - `A` [Tri Topologique](src/algorithms/graph/topological-sorting) - méthode DFS
-  - `A` [Point d'Articulation](src/algorithms/graph/articulation-points) - algorithme de Tarjan (basé sur l'algorithme de Parcours en Profondeur)
-  - `A` [Bridges](src/algorithms/graph/bridges) - algorithme basé sur le Parcours en Profondeur
-  - `A` [Chemin Eulérien et Circuit Eulérien](src/algorithms/graph/eulerian-path) - algorithme de Fleury - visite chaque arc exactement une fois
-  - `A` [Cycle Hamiltonien](src/algorithms/graph/hamiltonian-cycle) - visite chaque noeud exactement une fois
-  - `A` [Composants Fortements Connexes](src/algorithms/graph/strongly-connected-components) - algorithme de Kosaraju
-  - `A` [Problème du Voyageur de Commerce](src/algorithms/graph/travelling-salesman) - chemin le plus court visitant chaque cité et retournant à la cité d'origine
-- **Non catégorisé**
-  - `B` [Tours de Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  - `B` [Rotation de Matrice Carrée](src/algorithms/uncategorized/square-matrix-rotation) - algorithme _in place_
-  - `B` [Jump Game](src/algorithms/uncategorized/jump-game) - retour sur trace, programmation dynamique (haut-bas + bas-haut) et exemples gourmands
-  - `B` [Chemins Uniques](src/algorithms/uncategorized/unique-paths) - retour sur trace, programmation dynamique (haut-bas + bas-haut) et exemples basés sur le Triangle de Pascal
-  - `A` [Problème des N-Dames](src/algorithms/uncategorized/n-queens)
-  - `A` [Problème du Cavalier](src/algorithms/uncategorized/knight-tour)
-
-### Algorithmes par Paradigme
-
-Un paradigme algorithmique est une méthode générique ou une approche qui
-sous-tend la conception d'une classe d'algorithmes. C'est une abstraction
-au-dessus de la notion d'algorithme, tout comme l'algorithme est une abstraction
-supérieure à un programme informatique.
-
-- **Force Brute** - cherche parmi toutes les possibilités et retient la meilleure
-  - `B` [Recherche Linéaire](src/algorithms/search/linear-search)
-  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray)
-  - `A` [Problème du Voyageur de Commerce](src/algorithms/graph/travelling-salesman) - chemin le plus court visitant chaque cité et retournant à la cité d'origine
-- **Gourmand** - choisit la meilleure option à l'instant courant, sans tenir compte de la situation future
-  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  - `A` [Problème du Sac à Dos Sans Contraintes](src/algorithms/sets/knapsack-problem)
-  - `A` [Algorithme de Dijkstra](src/algorithms/graph/dijkstra) - trouver tous les plus courts chemins partant d'un noeud vers tous les autres noeuds dans un graphe
-  - `A` [Algorithme de Prim](src/algorithms/graph/prim) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé
-  - `A` [Algorithme de Kruskal](src/algorithms/graph/kruskal) - trouver l'arbre couvrant de poids minimal sur un graphe pondéré non dirigé
-- **Diviser et Régner** - divise le problème en sous problèmes (plus simples) et résoud ces sous problèmes
-  - `B` [Recherche Binaire](src/algorithms/search/binary-search)
-  - `B` [Tours de Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  - `B` [Triangle de Pascal](src/algorithms/math/pascal-triangle)
-  - `B` [Algorithme d'Euclide](src/algorithms/math/euclidean-algorithm) - calcule le Plus Grand Commun Diviseur (PGCD)
-  - `B` [Tri Fusion](src/algorithms/sorting/merge-sort)
-  - `B` [Tri Rapide](src/algorithms/sorting/quick-sort)
-  - `B` [Arbre de Parcours en Profondeur](src/algorithms/tree/depth-first-search) (DFS)
-  - `B` [Graphe de Parcours en Profondeur](src/algorithms/graph/depth-first-search) (DFS)
-  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  - `A` [Permutations](src/algorithms/sets/permutations) (avec et sans répétitions)
-  - `A` [Combinations](src/algorithms/sets/combinations) (avec et sans répétitions)
-- **Programmation Dynamique** - construit une solution en utilisant les solutions précédemment trouvées
-  - `B` [Nombre de Fibonacci](src/algorithms/math/fibonacci)
-  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  - `B` [Chemins Uniques](src/algorithms/uncategorized/unique-paths)
-  - `A` [Distance de Levenshtein](src/algorithms/string/levenshtein-distance) - distance minimale d'édition entre deux séquences
-  - `A` [Plus Longue Sous-séquence Commune](src/algorithms/sets/longest-common-subsequence)
-  - `A` [Plus Longue Sous-chaîne Commune](src/algorithms/string/longest-common-substring)
-  - `A` [Plus Longue Sous-suite strictement croissante](src/algorithms/sets/longest-increasing-subsequence)
-  - `A` [Plus Courte Super-séquence Commune](src/algorithms/sets/shortest-common-supersequence)
-  - `A` [Problème de Sac à Dos](src/algorithms/sets/knapsack-problem)
-  - `A` [Partition Entière](src/algorithms/math/integer-partition)
-  - `A` [Sous-partie Maximum](src/algorithms/sets/maximum-subarray)
-  - `A` [Algorithme de Bellman-Ford](src/algorithms/graph/bellman-ford) - trouver tous les plus courts chemins partant d'un noeud vers tous les autres noeuds dans un graphe
-  - `A` [Algorithme de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - trouver tous les plus courts chemins entre toutes les paires de noeuds dans un graphe
-  - `A` [Expression Régulière](src/algorithms/string/regular-expression-matching)
-- **Retour sur trace** - de même que la version "Force Brute", essaie de générer toutes les solutions possibles, mais pour chaque solution générée, on teste si elle satisfait toutes les conditions, et seulement ensuite continuer à générer des solutions ultérieures. Sinon, l'on revient en arrière, et l'on essaie un
-  chemin différent pour tester d'autres solutions. Normalement, la traversée en profondeur de l'espace d'états est utilisée.
-  - `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  - `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  - `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
-  - `A` [Problème des N-Dames](src/algorithms/uncategorized/n-queens)
-  - `A` [Problème du Cavalier](src/algorithms/uncategorized/knight-tour)
-  - `A` [Somme combinatoire](src/algorithms/sets/combination-sum) - trouve toutes les combinaisons qui forment une somme spécifique
-- **Séparation et Evaluation** - pemet de retenir une solution à moindre coût dans un ensemble. Pour chaque étape, l'on garde une trace de la solution la moins coûteuse trouvée jusqu'à présent en tant que borne inférieure du coût. Cela afin d'éliminer les solutions partielles dont les coûts sont plus élevés que celui de la solution actuelle retenue. Normalement, la traversée en largeur en combinaison avec la traversée en profondeur de l'espace d'états de l'arbre est utilisée.
-
-## Comment utiliser ce dépôt
-
-**Installer toutes les dépendances**
-
-```
-npm install
-```
-
-**Exécuter ESLint**
-
-Vous pouvez l'installer pour tester la qualité du code.
-
-```
-npm run lint
-```
-
-**Exécuter tous les tests**
-
-```
-npm test
-```
-
-**Exécuter les tests par nom**
-
-```
-npm test -- 'LinkedList'
-```
-
-**Tests personnalisés**
-
-Vous pouvez manipuler les structures de données et algorithmes présents dans ce
-dépôt avec le fichier `./src/playground/playground.js` et écrire vos propres
-tests dans file `./src/playground/__test__/playground.test.js`.
-
-Vous pourrez alors simplement exécuter la commande suivante afin de tester si
-votre code fonctionne comme escompté
-
-```
-npm test -- 'playground'
-```
-
-## Informations Utiles
-
-### Références
-
-[▶ Structures de Données et Algorithmes sur YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Notation Grand O
-
-Comparaison de la performance d'algorithmes en notation Grand O.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-Source: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Voici la liste de certaines des notations Grand O les plus utilisées et de leurs
-comparaisons de performance suivant différentes tailles pour les données d'entrée.
-
-| Notation Grand O | Opérations pour 10 éléments | Opérations pour 100 éléments | Opérations pour 1000 éléments |
-| ---------------- | --------------------------- | ---------------------------- | ----------------------------- |
-| **O(1)**         | 1                           | 1                            | 1                             |
-| **O(log N)**     | 3                           | 6                            | 9                             |
-| **O(N)**         | 10                          | 100                          | 1000                          |
-| **O(N log N)**   | 30                          | 600                          | 9000                          |
-| **O(N^2)**       | 100                         | 10000                        | 1000000                       |
-| **O(2^N)**       | 1024                        | 1.26e+29                     | 1.07e+301                     |
-| **O(N!)**        | 3628800                     | 9.3e+157                     | 4.02e+2567                    |
-
-### Complexité des Opérations suivant les Structures de Données
-
-| Structure de donnée            | Accès  | Recherche | Insertion | Suppression | Commentaires                                                               |
-| ------------------------------ | :----: | :-------: | :-------: | :---------: | :------------------------------------------------------------------------- |
-| **Liste**                      |   1    |     n     |     n     |      n      |                                                                            |
-| **Pile**                       |   n    |     n     |     1     |      1      |                                                                            |
-| **Queue**                      |   n    |     n     |     1     |      1      |                                                                            |
-| **Liste Liée**                 |   n    |     n     |     1     |      1      |                                                                            |
-| **Table de Hachage**           |   -    |     n     |     n     |      n      | Dans le cas des fonctions de hachage parfaites, les couts seraient de O(1) |
-| **Arbre de Recherche Binaire** |   n    |     n     |     n     |      n      | Dans le cas des arbre équilibrés, les coûts seraient de O(log(n))          |
-| **Arbre B**                    | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |
-| **Arbre Red-Black**            | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |
-| **Arbre AVL**                  | log(n) |  log(n)   |  log(n)   |   log(n)    |                                                                            |
-| **Filtre de Bloom**            |   -    |     1     |     1     |      -      | Les faux positifs sont possibles lors de la recherche                      |
-
-### Complexité des Algorithmes de Tri de Liste
-
-| Nom               |   Meilleur    |        Moyenne         |            Pire             | Mémoire | Stable | Commentaires                                                                         |
-| ----------------- | :-----------: | :--------------------: | :-------------------------: | :-----: | :----: | :----------------------------------------------------------------------------------- |
-| **Tri Bulle**     |       n       |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Oui   |                                                                                      |
-| **Tri Insertion** |       n       |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Oui   |                                                                                      |
-| **Tri Sélection** | n<sup>2</sup> |     n<sup>2</sup>      |        n<sup>2</sup>        |    1    |  Non   |                                                                                      |
-| **Tri par Tas**   | n&nbsp;log(n) |     n&nbsp;log(n)      |        n&nbsp;log(n)        |    1    |  Non   |                                                                                      |
-| **Merge sort**    | n&nbsp;log(n) |     n&nbsp;log(n)      |        n&nbsp;log(n)        |    n    |  Oui   |                                                                                      |
-| **Tri Rapide**    | n&nbsp;log(n) |     n&nbsp;log(n)      |        n<sup>2</sup>        | log(n)  |  Non   | le Tri Rapide est généralement effectué _in-place_ avec une pile de taille O(log(n)) |
-| **Tri Shell**     | n&nbsp;log(n) | dépend du gap séquence | n&nbsp;(log(n))<sup>2</sup> |    1    |  Non   |                                                                                      |
-| **Tri Comptage**  |     n + r     |         n + r          |            n + r            |  n + r  |  Oui   | r - le plus grand nombre dans la liste                                               |
-| **Tri Radix**     |    n \* k     |         n \* k         |           n \* k            |  n + k  |  Non   | k - longueur du plus long index                                                      |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.id-ID.md b/README.id-ID.md
deleted file mode 100644
index b204f2a8f8..0000000000
--- a/README.id-ID.md
+++ /dev/null
@@ -1,309 +0,0 @@
-# Algoritme dan Struktur Data Javascript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Repositori ini berisi contoh-contoh algoritme dan struktur data yang populer menggunakan JavaScript.
-
-Setiap algoritma dan struktur data memiliki README-nya tersendiri dengan penjelasan yang berkaitan dan tautan untuk bacaan lebih lanjut (termasuk tautan menuju video YouTube).
-
-_Baca ini dalam bahasa yang lain:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-_☝ Perhatikan bahwa proyek ini hanya dimaksudkan untuk tujuan pembelajaran dan riset, dan **tidak** dimaksudkan untuk digunakan sebagai produksi._
-
-## Struktur Data
-
-Struktur data adalah cara tertentu untuk mengatur dan menyimpan data dalam komputer sehingga dapat diakses dan diubah secara efisien. Lebih tepatnya, struktur data adalah kumpulan dari nilai data, relasi di antara data-data, dan fungsi atau operasi yang dapat diterapkan pada data.
-
-`P` - Pemula, `L` - Lanjutan
-
-- `P` [Senarai Berantai](src/data-structures/linked-list)
-- `P` [Senarai Berantai Ganda](src/data-structures/doubly-linked-list)
-- `P` [Antrean](src/data-structures/queue)
-- `P` [Tumpukan](src/data-structures/stack)
-- `P` [Tabel Hash](src/data-structures/hash-table)
-- `P` [_Heap_](src/data-structures/heap) - versi _heap_ maksimum dan minimum
-- `P` [Antrean Prioritas](src/data-structures/priority-queue)
-- `L` [_Trie_](src/data-structures/trie)
-- `L` [Pohon](src/data-structures/tree)
-  - `L` [Pohon Telusur Biner](src/data-structures/tree/binary-search-tree)
-  - `L` [_AVL Tree_](src/data-structures/tree/avl-tree)
-  - `L` [Pohon Merah Hitam](src/data-structures/tree/red-black-tree)
-  - `L` [_Segment Tree_](src/data-structures/tree/segment-tree) - dengan contoh min/max/sum range query
-  - `L` [Pohon Fenwick](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-- `L` [Graf](src/data-structures/graph) (directed dan undirected)
-- `L` [_Disjoint Set_](src/data-structures/disjoint-set)
-- `L` [_Bloom Filter_](src/data-structures/bloom-filter)
-
-## Algoritma
-
-Algoritma adalah sebuah perincian yang jelas tentang cara untuk memecahkan suatu masalah. Ia adalah sekumpulan aturan yang menjelaskan secara tepat urutan-urutan dari sebuah operasi.
-
-`P` - Pemula, `L` - Lanjutan
-
-### Algoritma Berdasarkanan Topik
-
-- **Matematika**
-  - `P` [Manipulasi Bit](src/algorithms/math/bits) - menetapkan/mendapatkan/memperbarui/menghapus bit, perkalian/pembagian dengan angka 2, membuat bilangan negatif dan lain-lain.
-  - `P` [Faktorial](src/algorithms/math/Faktorial)
-  - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci) - versi klasik dan bentuk tertutup
-  - `P` [Faktor Prima](src/algorithms/math/prime-factors) - menemukan faktor prima dan menghitungnya menggunakan teorema Hardy-Ramanujan
-  - `P` [Pengujian Bilangan Prima](src/algorithms/math/primality-test) (metode _trial division_)
-  - `P` [Algoritma Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB)
-  - `P` [_Least Common Multiple_](src/algorithms/math/least-common-multiple) (LCM)
-  - `P` [_Sieve of Eratosthenes_](src/algorithms/math/sieve-of-eratosthenes) - menemukan semua bilangan prima hingga batas yang ditentukan
-  - `P` [_Is Power of Two_](src/algorithms/math/is-power-of-two) - mengecek apakah sebuah bilangan adalah hasil dari pangkat dua (algoritma _naive_ dan _bitwise_)
-  - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle)
-  - `P` [Bilangan Kompleks](src/algorithms/math/complex-number) - bilangan kompleks dengan operasi dasarnya
-  - `P` [Radian & Derajat](src/algorithms/math/radian) - konversi radian ke derajat dan sebaliknya
-  - `P` [_Fast Powering_](src/algorithms/math/fast-powering)
-  - `P` [Metode Horner](src/algorithms/math/horner-method) - evaluasi polinomial
-  - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition)
-  - `L` [Akar Pangkat Dua](src/algorithms/math/square-root) - metode Newton
-  - `L` [Algoritma π Liu Hui](src/algorithms/math/liu-hui) - perkiraan perhitungan π berdasarkan segibanyak
-  - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya
-- **Himpunan**
-  - `P` [Produk Kartesian](src/algorithms/sets/cartesian-product) - hasil dari beberapa himpunan
-  - `P` [Pengocokan Fisher–Yates](src/algorithms/sets/fisher-yates) - permutasi acak dari sebuah urutan terhingga
-  - `L` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan
-  - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan)
-  - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan)
-  - `L` [_Longest Common Subsequence_](src/algorithms/sets/longest-common-subsequence) (LCS)
-  - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence)
-  - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  - `L` [Permasalahan Knapsack](src/algorithms/sets/knapsack-problem) - "0/1" dan yang tidak "dibatasi"
-  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray) - "_Brute Force_" dan "Pemrograman Dinamis" versi Kadane
-  - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu
-- **String**
-  - `P` [Jarak Hamming](src/algorithms/string/hamming-distance) - jumlah posisi di mana ditemukan simbol-simbol yang berbeda
-  - `L` [Algoritma Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan
-  - `L` [Algoritma Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritma KMP) - pencarian substring (pencocokan pola)
-  - `L` [Algoritma Z](src/algorithms/string/z-algorithm) - pencarian substring (pencocokan pola)
-  - `L` [Algoritma Rabin Karp](src/algorithms/string/rabin-karp) - pencarian substring
-  - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring)
-  - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching)
-- **Pencarian**
-  - `P` [Pencarian Linier](src/algorithms/search/linear-search)
-  - `P` [Pencarian Lompat](src/algorithms/search/jump-search) (atau Block Search) - pencarian di larik tersortir
-  - `P` [Pencarian Biner](src/algorithms/search/binary-search) - pencarian di larik tersortir
-  - `P` [Pencarian Interpolasi](src/algorithms/search/interpolation-search) - pencarian di larik tersortir yang terdistribusi seragam
-- **Penyortiran**
-  - `P` [Sortir Gelembung](src/algorithms/sorting/bubble-sort)
-  - `P` [Sortir Seleksi](src/algorithms/sorting/selection-sort)
-  - `P` [Sortir Sisipan](src/algorithms/sorting/insertion-sort)
-  - `P` [Sortir _Heap_](src/algorithms/sorting/heap-sort)
-  - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort)
-  - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort) - implementasi _in-place_ dan _non-in-place_
-  - `P` [Sortir Shell](src/algorithms/sorting/shell-sort)
-  - `P` [Sortir Perhitungan](src/algorithms/sorting/counting-sort)
-  - `P` [Sortir Akar](src/algorithms/sorting/radix-sort)
-- **Senarai Berantai**
-  - `P` [Lintas Lurus](src/algorithms/linked-list/traversal)
-  - `P` [Lintas Terbalik](src/algorithms/linked-list/reverse-traversal)
-- **Pohon**
-  - `P` [Pencarian Kedalaman Pertama](src/algorithms/tree/depth-first-search) (DFS)
-  - `P` [Pencarian Luas Pertama](src/algorithms/tree/breadth-first-search) (BFS)
-- **Graf**
-  - `P` [Pencarian Kedalaman Pertama](src/algorithms/graph/depth-first-search) (DFS)
-  - `P` [Pencarian Luas Pertama](src/algorithms/graph/breadth-first-search) (BFS)
-  - `P` [Algoritma Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot
-  - `L` [Algoritma Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal
-  - `L` [Algoritma Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal
-  - `L` [Algoritma Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut
-  - `L` [Mendeteksi Siklus](src/algorithms/graph/detect-cycle) - untuk graf berarah dan tidak berarah (berdasarkan versi DFS dan _Disjoint Set_)
-  - `L` [ALgoritma Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot
-  - `L` [Sortir Topologi](src/algorithms/graph/topological-sorting) - metode DFS
-  - `L` [Poin Artikulasi](src/algorithms/graph/articulation-points) - Algoritma Tarjan (berdasarkan DFS)
-  - `L` [Jembatan](src/algorithms/graph/bridges) - Algoritma berdasarkan DFS
-  - `L` [Jalur dan Sirkuit Eulerian](src/algorithms/graph/eulerian-path) - Algoritma Fleury - Mengunjungi setiap tepinya tepat satu kali
-  - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali
-  - `L` [Komponen yang Terkoneksi dengan Kuat](src/algorithms/graph/strongly-connected-components) - Algoritma Kosaraju
-  - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal
-- **Kriptografi**
-  - `P` [Polinomial Hash](src/algorithms/cryptography/polynomial-hash) - fungsi rolling hash berdasarkan polinomial
-  - `P` [Sandi Caesar](src/algorithms/cryptography/caesar-cipher) - sandi pengganti sederhana
-- **Pembelajaran Mesin**
-  - `P` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 fungsi JS sederhana yang mengilustrasikan bagaimana mesin-mesin dapat benar-benar belajar (perambatan maju/mundur)
-- **Tidak Dikategorikan**
-  - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  - `P` [Perputaran Matriks Persegi](src/algorithms/uncategorized/square-matrix-rotation) - algoritma _in-place_
-  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) - runut-balik, pemrograman dinamis (atas ke bawah + bawah ke atas) and contoh-contoh _greedy_
-  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths) - runut-balik, pemrograman dinamis and contoh-contoh beradsarkan Segitiga Pascal
-  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_ (versi pemrograman dinamis and _brute force_)
-  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga (4 solusi)
-  - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens)
-  - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour)
-
-### Algoritma Berdasarkan Paradigma
-
-Paradigma algoritmik adalah sebuah metode atau pendekatan umum yang mendasari desain sebuah tingkatan algoritma. Paradigma algoritmik merupakan abstraksi yang lebih tinggi dari gagasan sebuah algoritma, seperti halnya sebuah algoritma merupakan abstraksi yang lebih tinggi dari sebuah program komputer.
-
-- **_Brute Force_** - melihat ke semua kemungkinan dan memilih solusi yang terbaik
-  - `P` [Pencarian Linier](src/algorithms/search/linear-search)
-  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_
-  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga
-  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray)
-  - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal
-  - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya
-- **_Greedy_** - memilih pilihan terbaik pada saat ini tanpa mempertimbangkan masa yang akan datang
-  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)
-  - `L` [Permasalahan Knapsack yang Tidak Dibatasi](src/algorithms/sets/knapsack-problem)
-  - `L` [Algoritma Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal
-  - `L` [Algoritma Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot
-  - `L` [Algoritma Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot
-- **Memecah dan Menaklukkan** - membagi masalah menjadi bagian-bagian yang kecil, lalu memcahkan bagian-bagian tersebut
-  - `P` [Pencarian Biner](src/algorithms/search/binary-search)
-  - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle)
-  - `P` [Algoritma Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB)
-  - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort)
-  - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort)
-  - `P` [Pencarian Kedalaman Pertama untuk Pohon](src/algorithms/tree/depth-first-search) (DFS)
-  - `P` [Pencarian Kedalaman Pertama untuk Graf](src/algorithms/graph/depth-first-search) (DFS)
-  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)
-  - `P` [_Fast Powering_](src/algorithms/math/fast-powering)
-  - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan)
-  - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan)
-- **Pemrograman Dinamis** - membangun sebuah solusi menggunakan upasolusi yang ditemukan sebelumnya
-  - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci)
-  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)
-  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths)
-  - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_
-  - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga
-  - `L` [Algoritma Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan
-  - `L` [_Longest Common Subsquence_](src/algorithms/sets/longest-common-subsequence) (LCS)
-  - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring)
-  - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence)
-  - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence)
-  - `L` [Permasalahan Knapsack 0/1](src/algorithms/sets/knapsack-problem)
-  - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition)
-  - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray)
-  - `L` [Algoritma Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal
-  - `L` [Algoritma Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut
-  - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching)
-- **Runut-balik** - sama halnya dengan _brute force_, algoritma ini mencoba untuk menghasilkan segala kemungkinan solusi, tetapi setiap kali anda menghasilkan solusi selanjutnya, anda akan menguji apakah solusi tersebut memenuhi semua kondisi dan setelah itu baru akan menghasilkan solusi berikutnya. Apabila tidak, maka akan merunut-balik dan mencari solusi di jalur yang berbeda. Biasanya menggunakan lintas DFS dari ruang keadaan.
-  - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game)
-  - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths)
-  - `P` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan
-  - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali
-  - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens)
-  - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu
-- **_Mencabang dan Membatasi_** - digunakan untuk membuang solusi parsial dengan biaya yang lebih besar dari solusi dengan biaya yang terendah yang ditemukan sejauh ini dengan cara mengingat solusi dengan biaya terendah yang ditemukan pada setiap tahap dari pencarian runut-balik dan menggunakan biaya dari solusi dengan biaya terendah sejauh ini sebagai batas bawah pada biaya dari solusi dengan biaya yang paling sedikit untuk permasalahannya. Biasanya menggunakan lintas BFS yang berkombinasi dengan lintas DFS dari pohon ruang keadaan.
-
-## Cara menggunakan repositori ini
-
-**Meng-_install_ semua dependensi**
-
-```
-npm install
-```
-
-**Menjalankan ESLint**
-
-Anda dapat menjalankannya untuk memeriksa kualitas kode.
-
-```
-npm run lint
-```
-
-**Menjalankan semua tes**
-
-```
-npm test
-```
-
-**Menjalankan tes berdasarkan nama**
-
-```
-npm test -- 'LinkedList'
-```
-
-**_Playground_**
-
-Anda dapat bermain dengan algoritma dan struktur data di _file_ `./src/playground/playground.js` dan menuliskan tesnya di `./src/playground/__test__/playground.test.js`.
-
-Lalu, hanya tinggal menjalankan perintah berikut untuk mengetes apakah kode _playground_ anda bekerja sesuai dengan keinginan:
-
-```
-npm test -- 'playground'
-```
-
-## Informasi Bermanfaat
-
-### Referensi
-
-[▶ Algoritma dan Struktur Data di YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Notasi _Big O_
-
-Notasi _Big O_ digunakan untuk mengklasifikasikan algoritma berdasarkan durasi atau ruang yang dibutuhkan seiring bertambahnya _input_. Pada grafik dibawah, anda dapat menemukan urutan pertumbuhan yang paling umum dari algoritma yang ditentukan dalam notasi _Big O_.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-Sumber: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Di bawah ini adalah daftar dari beberapa notasi _Big O_ yang sering digunakan dan perbandingan kinerjanya terhadap berbagai ukuran _input data_.
-
-| Notasi _Big O_ | Komputasi untuk 10 elemen | Komputasi untuk 100 elemen | Komputasi untuk 1000 elemen |
-| -------------- | ------------------------- | -------------------------- | --------------------------- |
-| **O(1)**       | 1                         | 1                          | 1                           |
-| **O(log N)**   | 3                         | 6                          | 9                           |
-| **O(N)**       | 10                        | 100                        | 1000                        |
-| **O(N log N)** | 30                        | 600                        | 9000                        |
-| **O(N^2)**     | 100                       | 10000                      | 1000000                     |
-| **O(2^N)**     | 1024                      | 1.26e+29                   | 1.07e+301                   |
-| **O(N!)**      | 3628800                   | 9.3e+157                   | 4.02e+2567                  |
-
-### Kompleksitas Operasi Struktur Data
-
-| Struktur Data                                | Akses  | Pencarian | Penyisipan | Penghapusan | Keterangan                                               |
-| -------------------------------------------- | :----: | :-------: | :--------: | :---------: | :------------------------------------------------------- |
-| **Array (Larik)**                            |   1    |     n     |     n      |      n      |                                                          |
-| **Stack (Tumpukan)**                         |   n    |     n     |     1      |      1      |                                                          |
-| **Queue (Antrean)**                          |   n    |     n     |     1      |      1      |                                                          |
-| **Linked List (Senarai Berantai)**           |   n    |     n     |     1      |      n      |                                                          |
-| **Hash Table**                               |   -    |     n     |     n      |      n      | Apabila fungsi hash sempurna, biayanya akan menjadi O(1) |
-| **Binary Search Tree (Pohon Telusur Biner)** |   n    |     n     |     n      |      n      | Apabila pohon seimbang, biayanya akan menjadi O(log(n))  |
-| **B-Tree**                                   | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |
-| **Red-Black Tree (Pohon Merah-Hitam)**       | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |
-| **AVL Tree**                                 | log(n) |  log(n)   |   log(n)   |   log(n)    |                                                          |
-| **Bloom Filter**                             |   -    |     1     |     1      |      -      | Positif palsu dimungkinkan saat pencarian                |
-
-### Kompleksitas Algoritma Sortir Larik
-
-| Nama                                   |    Terbaik    |          Rata-rata           |          Terburuk           | Memori | Stabil | Keterangan                                                                        |
-| -------------------------------------- | :-----------: | :--------------------------: | :-------------------------: | :----: | :----: | :-------------------------------------------------------------------------------- |
-| **Bubble sort (Sortir Gelembung)**     |       n       |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    |   Ya   |                                                                                   |
-| **Insertion sort (Sortir Sisipan)**    |       n       |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    |   Ya   |                                                                                   |
-| **Selection sort (Sortir Seleksi)**    | n<sup>2</sup> |        n<sup>2</sup>         |        n<sup>2</sup>        |   1    | Tidak  |                                                                                   |
-| **Heap sort (Sortir _Heap_)**          | n&nbsp;log(n) |        n&nbsp;log(n)         |        n&nbsp;log(n)        |   1    | Tidak  |                                                                                   |
-| **Merge Sort (Sortir Gabungan)**       | n&nbsp;log(n) |        n&nbsp;log(n)         |        n&nbsp;log(n)        |   n    |   Ya   |                                                                                   |
-| **Quick sort (Sortir Cepat)**          | n&nbsp;log(n) |        n&nbsp;log(n)         |        n<sup>2</sup>        | log(n) | Tidak  | Sortir Cepat biasanya dilakukan secara _in-place_ dengan O(log(n)) ruang tumpukan |
-| **Shell sort (Sortir Shell)**          | n&nbsp;log(n) | tergantung pada jarak urutan | n&nbsp;(log(n))<sup>2</sup> |   1    | Tidak  |                                                                                   |
-| **Counting sort (Sortir Perhitungan)** |     n + r     |            n + r             |            n + r            | n + r  |   Ya   | r - angka terbesar dalam larik                                                    |
-| **Radix sort (Sortir Akar)**           |    n \* k     |            n \* k            |           n \* k            | n + k  |   Ya   | k - panjang dari kunci terpanjang                                                 |
-
-## Pendukung Proyek
-
-> Anda dapat mendukung proyek ini via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) atau ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-[Orang-orang yang mendukung proyek ini](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.it-IT.md b/README.it-IT.md
deleted file mode 100644
index 6ac47fa5bc..0000000000
--- a/README.it-IT.md
+++ /dev/null
@@ -1,302 +0,0 @@
-# Algoritmi e Strutture Dati in Javascript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Questa repository contiene esempi in Javascript dei più popolari algoritmi e strutture dati .
-
-Ogni algortimo e struttura dati ha il suo README separato e la relative spiegazioni e i link per ulteriori approfondimenti (compresi quelli su YouTube).
-
-_Leggilo in altre lingue:_
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.*
-
-## Strutture Dati
-
-Una struttura dati è un particolare modo di organizzare e memorizzare i dati in un computer che  permeta di accedervi e modificarli in modo efficiente. Più precisamente, una struttura dati è una raccolta di dati, le relazioni tra di essi e le funzioni o operazioni che possono essere applicate ai dati.
-
-`P` - Principiante, `A` - Avanzato
-
-* `P` [Lista Concatenata](src/data-structures/linked-list)
-* `P` [Doppia Lista Concatenata](src/data-structures/doubly-linked-list)
-* `P` [Coda](src/data-structures/queue)
-* `P` [Pila](src/data-structures/stack)
-* `P` [Hash Table](src/data-structures/hash-table)
-* `P` [Heap](src/data-structures/heap) - versione massimo e minimo heap
-* `P` [Coda di priorità](src/data-structures/priority-queue)
-* `A` [Trie](src/data-structures/trie)
-* `A` [Albero](src/data-structures/tree)
-  * `A` [Albero binario di ricerca](src/data-structures/tree/binary-search-tree)
-  * `A` [Albero AVL](src/data-structures/tree/avl-tree)
-  * `A` [RB Albero](src/data-structures/tree/red-black-tree)
-  * `A` [Albero Segmentato](src/data-structures/tree/segment-tree) - con  min/max/sum esempi di query
-  * `A` [Albero di Fenwick](src/data-structures/tree/fenwick-tree) (Albero binario indicizzato)
-* `A` [Grafo](src/data-structures/graph) (direzionale e unidirezionale)
-* `A` [Set Disgiunto](src/data-structures/disjoint-set)
-* `A` [Filtro Bloom](src/data-structures/bloom-filter)
-
-## Algoritmi
-
-Un algoritmo è una specifica univoca per risolvere una classe di problemi. È
-un insieme di regole che definiscono con precisione una sequenza di operazioni.
-
-`P` - Principiante, `A` - Avanzato
-
-### Algoritmi per Topic
-
-* **Matematica**
-  * `P` [Manipolazione dei Bit](src/algorithms/math/bits) - set/get/update/clear bits, moltiplicazione/divisione per due, gestire numeri negativi etc.
-  * `P` [Fattoriale](src/algorithms/math/factorial)
-  * `P` [Numeri di Fibonacci](src/algorithms/math/fibonacci) - classico e forma chiusa
-  * `P` [Test di Primalità](src/algorithms/math/primality-test) (metodo del divisore)
-  * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - trova il massimo comune divisore (MCD)
-  * `P` [Minimo Comune Multiplo](src/algorithms/math/least-common-multiple) (MCM)
-  * `P` [Crivello di Eratostene](src/algorithms/math/sieve-of-eratosthenes) - trova i numeri i primi fino al limite indicato
-  * `P` [Potenza di due](src/algorithms/math/is-power-of-two) - controlla se il numero è una potenza di due
-  * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle)
-  * `P` [Numeri Complessi](src/algorithms/math/complex-number) - numeri complessi e operazioni
-  * `P` [Radiante & Gradi](src/algorithms/math/radian) - conversione da radiante a gradi e viceversa
-  * `P` [Potenza di un Numero](src/algorithms/math/fast-powering)
-  * `A` [Partizione di un Intero](src/algorithms/math/integer-partition)
-  * `A` [Radice Quadrata](src/algorithms/math/square-root) - Metodo di Newton
-  * `A` [Algoritmo di Liu Hui π](src/algorithms/math/liu-hui) - calcolare π usando un poligono
-  * `A` [Trasformata Discreta di Fourier ](src/algorithms/math/fourier-transform) -decomporre una funzione di tempo (un segnale) nelle frequenze che lo compongono
-* **Set**
-  * `P` [Prodotto Cartesiano](src/algorithms/sets/cartesian-product) - moltiplicazione multipla di set
-  * `P` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - permutazione casuale di un sequenza finita
-  * `A` [Power Set](src/algorithms/sets/power-set) - tutti i sottoinsiemi di un set (soluzioni bitwise e backtracking)
-  * `A` [Permutazioni](src/algorithms/sets/permutations) (con e senza ripetizioni)
-  * `A` [Combinazioni](src/algorithms/sets/combinations) (con e senza ripetizioni)
-  * `A` [Massima Sottosequenza Comune](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Massima Sottosequenza Crescente](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Minima Sottosequenza Diffusa](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem) - "0/1" e "Senza Restrizioni"
-  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) - "Brute Force" e "Programmazione Dinamica" versione Kadane
-  * `A` [Somma di Combinazioni](src/algorithms/sets/combination-sum) - ricerca di tutte le combinazioni di una somma
-* **String**
-  * `P` [Distanza di Hamming](src/algorithms/string/hamming-distance) - numero di posizioni in cui i caratteri sono diversi
-  * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - numero minimo di modifiche per rendere uguali due stringhe
-  * `A` [Algoritmo di Knuth-Morris-Pratt](src/algorithms/string/knuth-morris-pratt) (KMP) - ricerca nella sottostringa (pattern matching)
-  * `A` [Algoritmo Z](src/algorithms/string/z-algorithm) - ricerca nella sottostringa (pattern matching)
-  * `A` [Algoritmo di Rabin Karp ](src/algorithms/string/rabin-karp) - ricerca nella sottostringa
-  * `A` [Sottostringa Comune più lunga](src/algorithms/string/longest-common-substring)
-  * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching)
-* **Searches**
-  * `P` [Ricerca Sequenziale](src/algorithms/search/linear-search)
-  * `P` [Ricerca a Salti](src/algorithms/search/jump-search) (o Ricerca a Blocchi) - per la ricerca in array ordinati
-  * `P` [Ricerca Binari](src/algorithms/search/binary-search) - per la ricerca in array ordinati
-  * `P` [Ricerca Interpolata](src/algorithms/search/interpolation-search) - per la ricerca in un array ordinato uniformemente distibuito
-* **Sorting**
-  * `P` [Bubble Sort](src/algorithms/sorting/bubble-sort)
-  * `P` [Selection Sort](src/algorithms/sorting/selection-sort)
-  * `P` [Insertion Sort](src/algorithms/sorting/insertion-sort)
-  * `P` [Heap Sort](src/algorithms/sorting/heap-sort)
-  * `P` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `P` [Quicksort](src/algorithms/sorting/quick-sort) - con e senza allocazione di ulteriore memoria
-  * `P` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `P` [Counting Sort](src/algorithms/sorting/counting-sort)
-  * `P` [Radix Sort](src/algorithms/sorting/radix-sort)
-* **Lista Concatenatas**
-  * `P` [Attraversamento Lista Concatenata](src/algorithms/linked-list/traversal)
-  * `P` [Attraversamento Lista Concatenata nel senso Contrario](src/algorithms/linked-list/reverse-traversal)
-* **Alberi**
-  * `P` [Ricerca in Profondità su Alberi](src/algorithms/tree/depth-first-search) (DFS)
-  * `P` [Ricerca in Ampiezza su Alberi](src/algorithms/tree/breadth-first-search) (BFS)
-* **Grafi**
-  * `P` [Ricerca in Profondità su Grafi](src/algorithms/graph/depth-first-search) (DFS)
-  * `P` [Breadth-First Search su Grafi](src/algorithms/graph/breadth-first-search) (BFS)
-  * `P` [Algoritmo di Kruskal](src/algorithms/graph/kruskal) - ricerca dell'Albero con Minima Distanza (MST) per grafi pesati unidirezionali
-  * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice
-  * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice
-  * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) -  ricerca dei percorsi più brevi tra tutte le coppie di vertici
-  * `A` [Rivelamento dei Cicli](src/algorithms/graph/detect-cycle) - per grafici diretti e non diretti (basate su partizioni DFS e Disjoint Set)
-  * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca dell'Albero Ricoprente Minimo (MST) per grafi unidirezionali pesati
-  * `A` [Ordinamento Topologico](src/algorithms/graph/topological-sorting) - metodo DFS
-  * `A` [Punti di Articolazione](src/algorithms/graph/articulation-points) - Algoritmo di Tarjan (basato su DFS)
-  * `A` [Bridges](src/algorithms/graph/bridges) - basato su DFS
-  * `A` [Cammino Euleriano e Circuito Euleriano](src/algorithms/graph/eulerian-path) - Algoritmo di Fleury - Visita ogni margine esattamente una volta
-  * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - Visita ad ogni vertice solo una volta
-  * `A` [Componenti Fortemente Connessa](src/algorithms/graph/strongly-connected-components) - algoritmo di Kosaraju
-  * `A` [Problema del Commesso Viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale
-* **Crittografia**
-  * `P` [Hash Polinomiale](src/algorithms/cryptography/polynomial-hash) - Una funzione hash di rolling basata sul polinomio
-* **Senza categoria**
-  * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `P` [Rotazione Matrice Quadrata](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in memoria
-  * `P` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, programmazione dinamica (top-down + bottom-up) ed esempre di greeedy
-  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) - backtracking, programmazione dinamica and l'esempio del Triangolo di Pascal
-  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola(versione con programmazione dinamica e brute force)
-  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta(4 soluzioni)
-  * `A` [Rompicapo delle Otto Regine](src/algorithms/uncategorized/n-queens)
-  * `A` [Percorso del Cavallo](src/algorithms/uncategorized/knight-tour)
-
-### Modelli di Algoritmi
-
- Un modello di algoritmo è un generico metodo o approcio che sta alla base della progettazione di una classe di algoritmi.
- Si tratta di un'astrazione ancora più alta di un algoritmo, proprio come un algoritmo è un'astrazione di un programma del computer.
-
-* **Brute Force** - controlla tutte le possibilità e seleziona la migliore
-  * `P` [Ricerca Lineare](src/algorithms/search/linear-search)
-  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola
-  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta
-  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray)
-  * `A` [Problema del commesso viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale
-  * `A` [Trasformata Discreta di Fourier](src/algorithms/math/fourier-transform) - scomporre la funzione (segnale) del tempo in frequenze che la compongono
-* **Greedy** - scegliere l'opzione migliore al momento d'eleborazione dell'algoritmo, senza alcuna considerazione per il futuro
-  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem)
-  * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca del percorso più breve tra tutti i vertici del grafo
-  * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca del Minimo Albero Ricoprente per grafi pesati e unidirezionali
-  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-* **Divide e Conquista** - divide il problema in piccole parti e risolve ogni parte
-  * `P` [Ricerca Binaria](src/algorithms/search/binary-search)
-  * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle)
-  * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * `P` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `P` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `P` [Albero per Ricerca in Profondità](src/algorithms/tree/depth-first-search) (DFS)
-  * `P` [Grafo per Ricerca in Profondità](src/algorithms/graph/depth-first-search) (DFS)
-  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `P` [Algoritmo di Elevamento a Potenza](src/algorithms/math/fast-powering)
-  * `A` [Permutazioni](src/algorithms/sets/permutations) (con o senza ripetizioni)
-  * `A` [Combinazioni](src/algorithms/sets/combinations) (con o senza ripetizioni)
-* **Programmazione Dinamica** - creare una soluzione utilizzando le sub-solution trovate in precedenza
-  * `P` [Numero di Fibonacci](src/algorithms/math/fibonacci)
-  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths)
-  * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola
-  * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta
-  * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - minima variazione tra due sequenze
-  * `A` [La Più Lunga Frequente SottoSequenza](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [La Più Lunga Frequente SubString](src/algorithms/string/longest-common-substring)
-  * `A` [La Più Lunga SottoSequenza Crescente](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [La Più Corta e Frequente SuperSequenza](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Problema dello zaino](src/algorithms/sets/knapsack-problem)
-  * `A` [Partizione di un Intero](src/algorithms/math/integer-partition)
-  * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray)
-  * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca del percorso più breve per tutti i vertici del grafo
-  * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca del percorso più breve tra tutte le coppie di vertici
-  * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching)
-* **Backtracking** -  come la brute force, provate a generare tutte le soluzioni possibili, ma ogni volta che generate la prossima soluzione testate se soddisfa tutte le condizioni e solo allora continuare a generare soluzioni successive. Altrimenti, fate marcia indietro, e andate su un percorso diverso per trovare una soluzione. Normalmente si utilizza l'algoritmo DFS.
-  * `P` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths)
-  * `P` [Power Set](src/algorithms/sets/power-set) - tutti i subset di un set
-  * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - visita di tutti i vertici solamente una volta
-  * `A` [Problema di N-Queens](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  * `A` [Combinazioni di una Somma](src/algorithms/sets/combination-sum) - trovare tutte le combinazioni che compongono una somma
-* **Branch & Bound** - ricordatevi che la soluzione meno costosa trovata ad ogni step durante il backtracking e
-il costo di usare la soluzione meno costosa trovata fino al limite inferiore al costo minimo della soluzione al problema,
-al fine di scartare soluzioni parziali con costi maggiori della soluzione meno costosa trovata .
-Di solito si usa BFS trasversale in combinazione con DFS trasversale .
-
-## Come usare questa repository
-
-**Installare tutte le dipendenze**
-```
-npm install
-```
-
-**Eseguire ESLint**
-
-Potresti usarlo per controllare la qualità del codice.
-
-```
-npm run lint
-```
-
-**Eseguire tutti i test**
-```
-npm test
-```
-
-**Eseguire un test tramite il nome**
-```
-npm test -- 'LinkedList'
-```
-
-**Playground**
-
-Se vuoi puoi giocare le strutture dati e gli algoritmi nel file ./src/playground/playground.js` e
-scrivere test nel file `./src/playground/__test__/playground.test.js`.
-
-Poi puoi semplicemente eseguire il seguente comando per testare quello che hai scritto :
-
-```
-npm test -- 'playground'
-```
-
-## Informazioni Utili
-
-### Bibliografia
-
-[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Notazione Big O
-
-* La notazione Big O* è usata per classificare algoritmi in base al tempo di esecuzione o ai
-requisiti di spazio che crescono in base alla crescita dell'input .
-Nella grafico qua sotto puoi trovare gli ordini di crescita più comuni degli algoritmi usando la notazione Big O.
-
-![Grafi Big O ](./assets/big-o-graph.png)
-
-Riferimento: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Nella tabella qua sotto ci sono riportate la lista delle notazioni Big O più usate e delle loro prestazioni comparate tra differenti grandezze d'input .
-
-| Notazione Big O | Computazione con 10 elementi | Computazione con 100 elementi | Computazione con 1000 elementi  |
-| --------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**        | 1                            | 1                             | 1                               |
-| **O(log N)**    | 3                            | 6                             | 9                               |
-| **O(N)**        | 10                           | 100                           | 1000                            |
-| **O(N log N)**  | 30                           | 600                           | 9000                            |
-| **O(N^2)**      | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**      | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**       | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Complessità delle Operazion sulle Strutture Dati
-
-| Struttura Dati          | Accesso   | Ricerca   | Inserimento | Rimozione | Commenti  |
-| ----------------------- | :-------: | :-------: | :--------:  | :-------: | :-------- |
-| **Array**               | 1         | n         | n           | n         |           |
-| **Pila**                | n         | n         | 1           | 1         |           |
-| **Coda**                | n         | n         | 1           | 1         |           |
-| **Lista Concatenata**   | n         | n         | 1           | n         |           |
-| **Tabella Hash**        | -         | n         | n           | n         | Nel caso di una funzione di hashing perfetta il costo sarebbe O(1)|
-| **Binary Search Tree**  | n         | n         | n           | n         | Nel caso di albero bilanciato il costo sarebbe O(log(n)) |
-| **B-Tree**              | log(n)    | log(n)    | log(n)      | log(n)    |           |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)      | log(n)    |           |
-| **Albero AVL**          | log(n)    | log(n)    | log(n)      | log(n)    |           |
-| **Bloom Filter**        | -         | 1         | 1           | -         | Falsi positivi sono possibili durante la ricerca |
-
-### Complessità degli Algoritmi di Ordinamento di Array
-
-| Nome                  | Milgiore        | Media               | Perggiore           | Memoria   | Stabile   | Commenti  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        | Quicksort viene eseguito in memoria solitamente con una pila di O(log(n)) |
-| **Shell sort**        | n&nbsp;log(n)   | dipende dagli spazi vuoti nella sequenza  | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - numero più grande nell'array |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - lunghezza della chiave più grande |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.ja-JP.md b/README.ja-JP.md
deleted file mode 100644
index e10bb94083..0000000000
--- a/README.ja-JP.md
+++ /dev/null
@@ -1,301 +0,0 @@
-# JavaScriptアルゴリズムとデータ構造
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-このリポジトリには、JavaScriptベースの一般的なアルゴリズムとデータ構造に関する多数のサンプルが含まれています。
-
-
-各アルゴリズムとデータ構造には独自のREADMEがあります。
-関連する説明、そして参考資料 (YouTube動画)も含まれています。
-
-_Read this in other languages:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## データ構造
-
-データ構造は、データ値、データ値との間の関係、
-そして、データを扱うことができる関数と演算の集合で、
-データを特定の方法で構成して保存することで、より効率的に
-アクセスして変更することができます。
-
-`B` - 初心者, `A` - 上級
-
-* `B` [リンクされたリスト](src/data-structures/linked-list)
-* `B` [二重リンクリスト](src/data-structures/doubly-linked-list)
-* `B` [キュー](src/data-structures/queue)
-* `B` [スタック](src/data-structures/stack)
-* `B` [ハッシュ表](src/data-structures/hash-table)
-* `B` [ヒープ](src/data-structures/heap) - max and min heap versions
-* `B` [優先度キュー](src/data-structures/priority-queue)
-* `A` [トライ](src/data-structures/trie)
-* `A` [ツリー](src/data-structures/tree)
-  * `A` [バイナリ検索ツリー](src/data-structures/tree/binary-search-tree)
-  * `A` [AVLツリー](src/data-structures/tree/avl-tree)
-  * `A` [赤黒のツリー](src/data-structures/tree/red-black-tree)
-  * `A` [セグメントツリー](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples
-  * `A` [フェンウィック・ツリー](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-* `A` [グラフ](src/data-structures/graph) (both directed and undirected)
-* `A` [分離集合](src/data-structures/disjoint-set)
-* `A` [ブルームフィルタ](src/data-structures/bloom-filter)
-
-## アルゴリズム
-
-アルゴリズムとは、問題のクラスをどのように解決するかの明確な仕様です。
-一連の操作を正確に定義する一連のルールです。
-
-`B` - 初心者, `A` - 上級
-
-### トピック別アルゴリズム
-
-* **数学**
-  * `B` [ビット操作](src/algorithms/math/bits) - set/get/update/clear bits, 2つの乗算/除算, 否定的にする. 等
-  * `B` [因果関係](src/algorithms/math/factorial)
-  * `B` [フィボナッチ数](src/algorithms/math/fibonacci) - クラシックとクローズドフォームのバージョン
-  * `B` [素数性テスト](src/algorithms/math/primality-test) (trial division 方法)
-  * `B` [ユークリッドアルゴリズム](src/algorithms/math/euclidean-algorithm) - 最大公約数を計算する (GCD)
-  * `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [エラトステネスのふるい](src/algorithms/math/sieve-of-eratosthenes) - 与えられた限度まですべての素数を見つける
-  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - 数値が2の累乗であるかどうかを調べる（単純なアルゴリズムとビットごとのアルゴリズム）
-  * `B` [パスカルの三角形](src/algorithms/math/pascal-triangle)
-  * `B` [複素数](src/algorithms/math/complex-number) - 複素数とその基本演算
-  * `B` [ラジアン＆度](src/algorithms/math/radian) - 度数と逆方向の変換に対するラジアン
-  * `B` [高速電力供給](src/algorithms/math/fast-powering)
-  * `A` [整数パーティション](src/algorithms/math/integer-partition)
-  * `A` [Liu Hui π アルゴリズム](src/algorithms/math/liu-hui) - N-gonsに基づく近似π計算
-  * `A` [離散フーリエ変換](src/algorithms/math/fourier-transform) - 時間（信号）の関数をそれを構成する周波数に分解する
-* **セット**
-  * `B` [デカルト積 ](src/algorithms/sets/cartesian-product) - 複数の積の積
-  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - 有限シーケンスのランダム置換
-  * `A` [パワーセット](src/algorithms/sets/power-set) - セットのすべてのサブセット（ビットごとのソリューションとバックトラッキングソリューション）
-  * `A` [順列](src/algorithms/sets/permutations) （繰り返しの有無にかかわらず）
-  * `A` [組み合わせ](src/algorithms/sets/combinations) （繰返しあり、繰返しなし）
-  * `A` [最長共通部分列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [最長増加サブシーケンス](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [最短共通スーパーシーケンス](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [ナップザック問題 ](src/algorithms/sets/knapsack-problem) - 「0/1」と「非結合」問題
-  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray) - 「ブルートフォース」と「ダイナミックプログラミング」（Kadane's版）
-  * `A` [組み合わせ合計](src/algorithms/sets/combination-sum) - 特定の合計を構成するすべての組み合わせを見つける
-* **文字列**
-  * `B` [ハミング距離](src/algorithms/string/hamming-distance) - シンボルが異なる位置の数
-  * `A` [レーベンシュタイン距離](src/algorithms/string/levenshtein-distance) - 2つのシーケンス間の最小編集距離
-  * `A` [Knuth-Morris-Prattアルゴリズム](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - 部分文字列検索 (pattern matching)
-  * `A` [Z アルゴリズム](src/algorithms/string/z-algorithm) - 部分文字列検索 (pattern matching)
-  * `A` [Rabin Karpアルゴリズム](src/algorithms/string/rabin-karp) - 部分文字列検索
-  * `A` [最長共通部分文字列](src/algorithms/string/longest-common-substring)
-  * `A` [正規表現マッチング](src/algorithms/string/regular-expression-matching)
-* **検索**
-  * `B` [リニアサーチ](src/algorithms/search/linear-search)
-  * `B` [ジャンプ検索](src/algorithms/search/jump-search) (Jump Search) - ソートされた配列で検索
-  * `B` [バイナリ検索](src/algorithms/search/binary-search) - ソートされた配列で検索
-  * `B` [補間探索](src/algorithms/search/interpolation-search) - 一様分布のソート配列で検索する
-* **並べ替え**
-  * `B` [バブルソート](src/algorithms/sorting/bubble-sort)
-  * `B` [選択ソート](src/algorithms/sorting/selection-sort)
-  * `B` [挿入ソート](src/algorithms/sorting/insertion-sort)
-  * `B` [ヒープソート](src/algorithms/sorting/heap-sort)
-  * `B` [マージソート](src/algorithms/sorting/merge-sort)
-  * `B` [クイックソート](src/algorithms/sorting/quick-sort) -インプレースおよび非インプレース・インプリメンテーション
-  * `B` [シェルソート](src/algorithms/sorting/shell-sort)
-  * `B` [並べ替えを数える](src/algorithms/sorting/counting-sort)
-  * `B` [基数ソート](src/algorithms/sorting/radix-sort)
-* **リンクされたリスト**
-  * `B` [ストレートトラバーサル](src/algorithms/linked-list/traversal)
-  * `B` [逆方向のトラバーサル](src/algorithms/linked-list/reverse-traversal)
-* **ツリー**
-  * `B` [深度優先検索](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [幅優先検索](src/algorithms/tree/breadth-first-search) (BFS)
-* **グラフ**
-  * `B` [深度優先検索](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [幅優先検索](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー（MST）の発見
-  * `A` [Dijkstraアルゴリズム](src/algorithms/graph/dijkstra) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける
-  * `A` [Bellman-Fordアルゴリズム](src/algorithms/graph/bellman-ford) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける
-  * `A` [Floyd-Warshallアルゴリズム](src/algorithms/graph/floyd-warshall) - すべての頂点ペア間の最短経路を見つける
-  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - 有向グラフと無向グラフの両方（DFSおよびディスジョイントセットベースのバージョン）
-  * `A` [プリムのアルゴリズム](src/algorithms/graph/prim) - 重み付き無向グラフの最小スパニングツリー（MST）の発見
-  * `A` [トポロジカルソート](src/algorithms/graph/topological-sorting) - DFSメソッド
-  * `A` [アーティキュレーションポイント](src/algorithms/graph/articulation-points) - Tarjanのアルゴリズム（DFSベース）
-  * `A` [ブリッジ ](src/algorithms/graph/bridges) - DFSベースのアルゴリズム
-  * `A` [オイラーパスとオイラー回路](src/algorithms/graph/eulerian-path) - フルリーアルゴリズム - すべてのエッジを正確に1回訪問する
-  * `A` [ハミルトニアンサイクル](src/algorithms/graph/hamiltonian-cycle) - すべての頂点を正確に1回訪問する
-  * `A` [強連結成分](src/algorithms/graph/strongly-connected-components) - コサラジュのアルゴリズム
-  * `A` [トラベリングセールスマン問題](src/algorithms/graph/travelling-salesman) - 各都市を訪問し、起点都市に戻る最短経路
-* **暗号**
-  * `B` [多項式ハッシュ](src/algorithms/cryptography/polynomial-hash) - 関数多項式に基づくハッシュ関数
-* **未分類**
-  * `B` [ハノイの塔](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [正方行列回転](src/algorithms/uncategorized/square-matrix-rotation) - インプレイスアルゴリズム
-  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game) - バックトラック、ダイナミックプログラミング（トップダウン+ボトムアップ）、欲張りの例
-  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths) - バックトラック、動的プログラミング、PascalのTriangleベースの例
-  * `B` [レインテラス](src/algorithms/uncategorized/rain-terraces) - トラップ雨水問題（ダイナミックプログラミングとブルートフォースバージョン）
-  * `B` [再帰的階段](src/algorithms/uncategorized/recursive-staircase) - 上に到達する方法の数を数える（4つのソリューション）
-  * `A` [N-クイーンズ問題](src/algorithms/uncategorized/n-queens)
-  * `A` [ナイトツアー](src/algorithms/uncategorized/knight-tour)
-
-### Paradigmによるアルゴリズム
-
-アルゴリズムパラダイムは、あるクラスのアルゴリズムの設計の基礎をなす一般的な方法またはアプローチである。それは、アルゴリズムがコンピュータプログラムよりも高い抽象であるのと同様に、アルゴリズムの概念よりも高い抽象である。
-* **ブルートフォース** - すべての可能性を見て最適なソリューションを選択する
-  * `B` [線形探索](src/algorithms/search/linear-search)
-  * `B` [レインテラス](src/algorithms/uncategorized/rain-terraces) - 雨水問題
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - 先頭に到達する方法の数を数えます
-  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray)
-  * `A` [旅行セールスマン問題](src/algorithms/graph/travelling-salesman) - 各都市を訪れ、起点都市に戻る最短ルート
-  * `A` [離散フーリエ変換](src/algorithms/math/fourier-transform) - 時間（信号）の関数をそれを構成する周波数に分解する
-* **欲張り** - 未来を考慮することなく、現時点で最適なオプションを選択する
-  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)
-  * `A` [結合されていないナップザック問題](src/algorithms/sets/knapsack-problem)
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - すべてのグラフ頂点への最短経路を見つける
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - 重み付き無向グラフの最小スパニングツリー（MST）を見つける
-  * `A` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー（MST）を見つける
-* **分割と征服** - 問題をより小さな部分に分割し、それらの部分を解決する
-  * `B` [バイナリ検索](src/algorithms/search/binary-search)
-  * `B` [ハノイの塔](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [パスカルの三角形](src/algorithms/math/pascal-triangle)
-  * `B` [ユークリッドアルゴリズム](src/algorithms/math/euclidean-algorithm) - GCD（Greatest Common Divisor）を計算する
-  * `B` [マージソート](src/algorithms/sorting/merge-sort)
-  * `B` [クイックソート](src/algorithms/sorting/quick-sort)
-  * `B` [ツリーの深さ優先検索](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [グラフの深さ優先検索](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)
-  * `B` [高速電力供給](src/algorithms/math/fast-powering)
-  * `A` [順列](src/algorithms/sets/permutations) （繰り返しの有無にかかわらず）
-  * `A` [組み合わせ](src/algorithms/sets/combinations)（繰返しあり、繰返しなし）
-* **動的プログラミング** - 以前に発見されたサブソリューションを使用してソリューションを構築する
-  * `B` [フィボナッチ数](src/algorithms/math/fibonacci)
-  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)
-  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths)
-  * `B` [雨テラス](src/algorithms/uncategorized/rain-terraces) - トラップ雨水問題
-  * `B` [再帰的階段](src/algorithms/uncategorized/recursive-staircase) - 上に到達する方法の数を数える
-  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - 2つのシーケンス間の最小編集距離
-  * `A` [最長共通部分列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [最長共通部分文字列](src/algorithms/string/longest-common-substring)
-  * `A` [最長増加サブシーケンス](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [最短共通共通配列](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1ナップザック問題](src/algorithms/sets/knapsack-problem)
-  * `A` [整数パーティション](src/algorithms/math/integer-partition)
-  * `A` [最大サブアレイ](src/algorithms/sets/maximum-subarray)
-  * `A` [Bellman-Fordアルゴリズム](src/algorithms/graph/bellman-ford) - すべてのグラフ頂点への最短経路を見つける
-  * `A` [Floyd-Warshallアルゴリズム](src/algorithms/graph/floyd-warshall) - すべての頂点ペア間の最短経路を見つける
-  * `A` [正規表現マッチング](src/algorithms/string/regular-expression-matching)
-* **バックトラッキング** - ブルートフォースと同様に、可能なすべてのソリューションを生成しようとしますが、
-  次のソリューションを生成するたびにすべての条件を満たすかどうかをテストし、それ以降は引き続きソリューションを生成します。
-  それ以外の場合は、バックトラックして、解決策を見つける別の経路に進みます。
-  通常、状態空間のDFSトラバーサルが使用されています。
-  * `B` [ジャンプゲーム](src/algorithms/uncategorized/jump-game)
-  * `B` [ユニークなパス](src/algorithms/uncategorized/unique-paths)
-  * `B` [パワーセット](src/algorithms/sets/power-set) - セットのすべてのサブセット
-  * `A` [ハミルトニアンサイクル](src/algorithms/graph/hamiltonian-cycle) - すべての頂点を正確に1回訪問する
-  * `A` [N-クイーンズ問題](src/algorithms/uncategorized/n-queens)
-  * `A` [ナイトツアー](src/algorithms/uncategorized/knight-tour)
-  * `A` [組み合わせ合計](src/algorithms/sets/combination-sum) - 特定の合計を構成するすべての組み合わせを見つける
-* **ブランチ＆バウンド** - バックトラック検索の各段階で見つかった最もコストの低いソリューションを覚えておいて、最もコストの低いソリューションのコストを使用します。これまでに発見された最もコストの低いソリューションよりも大きなコストで部分ソリューションを破棄するように指示します。通常、状態空間ツリーのDFSトラバーサルと組み合わせたBFSトラバーサルが使用されています。
-
-## このリポジトリの使い方
-
-**すべての依存関係をインストールする**
-```
-npm install
-```
-
-**ESLintを実行する**
-
-これを実行してコードの品質をチェックすることができます。
-
-```
-npm run lint
-```
-
-**すべてのテストを実行する**
-```
-npm test
-```
-
-**名前でテストを実行する**
-```
-npm test -- 'LinkedList'
-```
-
-**playground**
-
-データ構造とアルゴリズムを `./src/playground/playground.js` ファイルで再生し、
-それに対するテストを書くことができ `./src/playground/__test__/playground.test.js`.
-
-次に、次のコマンドを実行して、遊び場コードが正常に動作するかどうかをテストします。
-
-```
-npm test -- 'playground'
-```
-
-## 有用な情報
-
-### 参考文献
-
-[▶ データ構造とアルゴリズム on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### ビッグO表記
-
-*Big O表記法は* 入力サイズが大きくなるにつれて実行時間やスペース要件がどのように増加するかに応じてアルゴリズムを分類するために使用されます。下のチャートでは、Big O表記で指定されたアルゴリズムの成長の最も一般的な順序を見つけることができます。
-
-![Big Oグラフ](./assets/big-o-graph.png)
-
-出典: [Big Oチートシート](http://bigocheatsheet.com/).
-
-以下は、最も使用されているBig O表記のリストと、入力データのさまざまなサイズに対するパフォーマンス比較です。
-
-| Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### データ構造操作の複雑さ
-
-| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Array**               | 1         | n         | n         | n         |           |
-| **Stack**               | n         | n         | 1         | 1         |           |
-| **Queue**               | n         | n         | 1         | 1         |           |
-| **Linked List**         | n         | n         | 1         | 1         |           |
-| **Hash Table**          | -         | n         | n         | n         | In case of perfect hash function costs would be O(1) |
-| **Binary Search Tree**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bloom Filter**        | -         | 1         | 1         | -         | False positives are possible while searching |
-
-### 配列の並べ替えアルゴリズムの複雑さ
-
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        | Quicksort is usually done in-place with O(log(n)) stack space |
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.ko-KR.md b/README.ko-KR.md
deleted file mode 100644
index b48c43aa56..0000000000
--- a/README.ko-KR.md
+++ /dev/null
@@ -1,282 +0,0 @@
-# JavaScript 알고리즘 및 자료 구조
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-이 저장소에는 많이 알려진 알고리즘 및 자료 구조의 Javascript 기반 예제를 담고 있습니다.
-
-각 알고리즘과 자료 구조에 대해 연관되어 있는 설명이 README에 작성되어 있으며,
-링크를 통해 더 자세한 설명을 만날 수 있습니다. (관련된 YouTube 영상도 포함).
-
-_Read this in other languages:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## 자료 구조
-
-자료 구조는 데이터를 특정 방식으로 구성하고 저장함으로써 더 효율적으로
-접근하고 수정할 수 있게 해줍니다. 간단히 말해, 자료 구조는 데이터 값들,
-데이터 간의 관계, 그리고 데이터를 다룰 수 있는 함수와 작업의 모임입니다.
-
-
-`B` - 입문자, `A` - 숙련자
-
-* `B` [연결 리스트](src/data-structures/linked-list)
-* `B` [이중 연결 리스트](src/data-structures/doubly-linked-list)
-* `B` [큐](src/data-structures/queue)
-* `B` [스택](src/data-structures/stack)
-* `B` [해시 테이블](src/data-structures/hash-table)
-* `B` [힙](src/data-structures/heap)
-* `B` [우선순위 큐](src/data-structures/priority-queue)
-* `A` [트라이](src/data-structures/trie)
-* `A` [트리](src/data-structures/tree)
-  * `A` [이진 탐색 트리](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL 트리](src/data-structures/tree/avl-tree)
-  * `A` [Red-Black 트리](src/data-structures/tree/red-black-tree)
-  * `A` [세그먼트 트리](src/data-structures/tree/segment-tree) - min/max/sum range 쿼리 예제.
-  * `A` [Fenwick 트리](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-* `A` [그래프](src/data-structures/graph) (유방향, 무방향)
-* `A` [서로소 집합](src/data-structures/disjoint-set)
-* `A` [블룸 필터](src/data-structures/bloom-filter)
-
-## 알고리즘
-
-알고리즘은 어떤 종류의 문제를 풀 수 있는 정확한 방법이며,
-일련의 작업을 정확하게 정의해 놓은 규칙들입니다.
-
-`B` - 입문자, `A` - 숙련자
-
-### 주제별 알고리즘
-
-* **Math**
-  * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, 2의 곱 / 나누기, 음수로 만들기 etc.
-  * `B` [팩토리얼](src/algorithms/math/factorial)
-  * `B` [피보나치 수](src/algorithms/math/fibonacci)
-  * `B` [소수 판별](src/algorithms/math/primality-test) (trial division 방식)
-  * `B` [유클리드 호제법](src/algorithms/math/euclidean-algorithm) - 최대공약수 (GCD)
-  * `B` [최소 공배수](src/algorithms/math/least-common-multiple) - LCM
-  * `B` [에라토스테네스의 체](src/algorithms/math/sieve-of-eratosthenes) - 특정수 이하의 모든 소수 찾기
-  * `B` [2의 거듭제곱 판별법](src/algorithms/math/is-power-of-two) - 어떤 수가 2의 거듭제곱인지 판별 (naive 와 bitwise 알고리즘)
-  * `B` [파스칼 삼각형](src/algorithms/math/pascal-triangle)
-  * `A` [자연수 분할](src/algorithms/math/integer-partition)
-  * `A` [리우 후이 π 알고리즘](src/algorithms/math/liu-hui) - N-각형을 기반으로 π 근사치 구하기
-* **Sets**
-  * `B` [카티지언 프로덕트](src/algorithms/sets/cartesian-product) - 곱집합
-  * `B` [Fisher–Yates 셔플](src/algorithms/sets/fisher-yates) - 유한 시퀀스의 무작위 순열
-  * `A` [멱집합](src/algorithms/sets/power-set) - 집합의 모든 부분집합
-  * `A` [순열](src/algorithms/sets/permutations) (반복 유,무)
-  * `A` [조합](src/algorithms/sets/combinations) (반복 유,무)
-  * `A` [최장 공통 부분수열](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [최장 증가 수열](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [배낭 문제](src/algorithms/sets/knapsack-problem) - "0/1" 과 "Unbound"
-  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray) - "브루트 포스" 과 "동적 계획법" (Kadane's) 버전
-  * `A` [조합 합](src/algorithms/sets/combination-sum) - 특정 합을 구성하는 모든 조합 찾기
-* **Strings**
-  * `B` [해밍 거리](src/algorithms/string/hamming-distance) - 심볼이 다른 위치의 갯수
-  * `A` [편집 거리](src/algorithms/string/levenshtein-distance) - 두 시퀀스 간위 최소 편집거리
-  * `A` [커누스-모리스-프랫 알고리즘](src/algorithms/string/knuth-morris-pratt) (KMP 알고리즘) - 부분 문자열 탐색 (패턴 매칭)
-  * `A` [Z 알고리즘](src/algorithms/string/z-algorithm) - 부분 문자열 탐색 (패턴 매칭)
-  * `A` [라빈 카프 알고리즘](src/algorithms/string/rabin-karp) - 부분 문자열 탐색
-  * `A` [최장 공통 부분 문자열](src/algorithms/string/longest-common-substring)
-  * `A` [정규 표현식 매칭](src/algorithms/string/regular-expression-matching)
-* **Searches**
-  * `B` [선형 탐색](src/algorithms/search/linear-search)
-  * `B` [점프 탐색](src/algorithms/search/jump-search) (or Block Search) - 정렬된 배열에서 탐색
-  * `B` [이진 탐색](src/algorithms/search/binary-search) - 정렬된 배열에서 탐색
-  * `B` [보간 탐색](src/algorithms/search/interpolation-search) - 균등한 분포를 이루는 정렬된 배열에서 탐색
-* **Sorting**
-  * `B` [거품 정렬](src/algorithms/sorting/bubble-sort)
-  * `B` [선택 정렬](src/algorithms/sorting/selection-sort)
-  * `B` [삽입 정렬](src/algorithms/sorting/insertion-sort)
-  * `B` [힙 정렬](src/algorithms/sorting/heap-sort)
-  * `B` [병합 정렬](src/algorithms/sorting/merge-sort)
-  * `B` [퀵 정렬](src/algorithms/sorting/quick-sort) - 제자리(in-place)와 제자리가 아닌(non-in-place) 구현
-  * `B` [셸 정렬](src/algorithms/sorting/shell-sort)
-  * `B` [계수 정렬](src/algorithms/sorting/counting-sort)
-  * `B` [기수 정렬](src/algorithms/sorting/radix-sort)
-* **Trees**
-  * `B` [깊이 우선 탐색](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [너비 우선 탐색](src/algorithms/tree/breadth-first-search) (BFS)
-* **Graphs**
-  * `B` [깊이 우선 탐색](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [너비 우선 탐색](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [크루스칼 알고리즘](src/algorithms/graph/kruskal) - 최소 신장 트리 찾기 (MST) 무방향 가중 그래프
-  * `A` [다익스트라 알고리즘](src/algorithms/graph/dijkstra) - 한 점에서 다른 모든 점까지 최단 거리 찾기
-  * `A` [벨만-포드 알고리즘](src/algorithms/graph/bellman-ford) - 한 점에서 다른 모든 점까지 최단 거리 찾기
-  * `A` [플로이드-워셜 알고리즘](src/algorithms/graph/floyd-warshall) - 모든 종단 간의 최단거리 찾기
-  * `A` [사이클 탐지](src/algorithms/graph/detect-cycle) - 유방향, 무방향 그래프 (DFS 와 Disjoint Set 에 기반한 버전)
-  * `A` [프림 알고리즘](src/algorithms/graph/prim) - 무방향 가중치 그래프에서 최소 신장 트리 (MST) 찾기
-  * `A` [위상 정렬](src/algorithms/graph/topological-sorting) - DFS 방식
-  * `A` [단절점](src/algorithms/graph/articulation-points) - 타잔의 알고리즘 (DFS 기반)
-  * `A` [단절선](src/algorithms/graph/bridges) - DFS 기반 알고리즘
-  * `A` [오일러 경로 와 오일러 회로](src/algorithms/graph/eulerian-path) - Fleury의 알고리즘 - 모든 엣지를 한번만 방문
-  * `A` [해밀턴 경로](src/algorithms/graph/hamiltonian-cycle) - 모든 꼭짓점을 한번만 방문
-  * `A` [강결합 컴포넌트](src/algorithms/graph/strongly-connected-components) - Kosaraju의 알고리즘
-  * `A` [외판원 문제](src/algorithms/graph/travelling-salesman) - 각 도시를 다 방문하고 다시 출발점으로 돌아오는 최단 경로 찾기
-* **Uncategorized**
-  * `B` [하노이 탑](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [정방 행렬 회전](src/algorithms/uncategorized/square-matrix-rotation) - 제자리(in-place) 알고리즘
-  * `B` [점프 게임](src/algorithms/uncategorized/jump-game) - 백트래킹, 동적계획법 (top-down + bottom-up), 탐욕 알고리즘 예제
-  * `B` [Unique 경로](src/algorithms/uncategorized/unique-paths) - 백트래킹, 동적계획법, 파스칼 삼각형에 기반한 예제
-  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (동적계획법, 브루트포스 버전)
-  * `A` [N-Queens 문제](src/algorithms/uncategorized/n-queens)
-  * `A` [기사의 여행 문제](src/algorithms/uncategorized/knight-tour)
-
-### 패러다임별 알고리즘
-
-알고리즘 패러다임 이란, 알고리즘이 주어진 문제를 해결하기 위해 채택한 기초가 되는 일반적인 방법 혹은 접근법입니다. 알고리즘이 해결하는 문제나 알고리즘의 동작 방식이 완전히 다르더라도,알고리즘의 동작 원칙이 같으면 같은 패러다음을 사용했다고 말할 수 있으며, 주로 알고리즘을 구분하는 기준으로 쓰인다. 알고리즘이 일반적인 컴퓨터의 프로그램에 대한 개념보다 보다 더 추상적인 개념인 것처럼 알고리즘의 패러다임은 명확히 정의된 수학적 실체가 있는 것이 아니기 때문에 그 어떤 알고리즘의 개념보다도 훨씬 추상적인 개념입니다.
-
-* **브루트 포스(Brute Force)** - 가능한 모든 경우를 탐색한 뒤 최적을 찾아내는 방식입니다.
-  * `B` [선형 탐색](src/algorithms/search/linear-search)
-  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray)
-  * `A` [외판원 문제](src/algorithms/graph/travelling-salesman) - 각 도시를 다 방문하고 다시 출발점으로 돌아오는 최단 경로 찾기
-* **탐욕 알고리즘(Greedy)** - 이후를 고려하지 않고 현재 시점에서 가장 최적인 선택을 하는 방식입니다.
-  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)
-  * `A` [쪼갤수 있는 배낭 문제](src/algorithms/sets/knapsack-problem)
-  * `A` [다익스트라 알고리즘](src/algorithms/graph/dijkstra) - 모든 점 까지의 최단거리 찾기
-  * `A` [프림 알고리즘](src/algorithms/graph/prim) - 무방향 가중치 그래프에서 최소 신창 트리 (MST) 찾기
-  * `A` [크루스칼 알고리즘](src/algorithms/graph/kruskal) - 무방향 가중치 그래프에서 최소 신창 트리 (MST) 찾기
-* **분할 정복법(Divide and Conquer)** - 문제를 여러 작은 문제로 분할한 뒤 해결하는 방식입니다.
-  * `B` [이진 탐색](src/algorithms/search/binary-search)
-  * `B` [하노이 탑](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [파스칼 삼각형](src/algorithms/math/pascal-triangle)
-  * `B` [유클리드 호제법](src/algorithms/math/euclidean-algorithm) - 최대공약수 계산 (GCD)
-  * `B` [병합 정렬](src/algorithms/sorting/merge-sort)
-  * `B` [퀵 정렬](src/algorithms/sorting/quick-sort)
-  * `B` [트리 깊이 우선 탐색](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [그래프 깊이 우선 탐색](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)
-  * `A` [순열](src/algorithms/sets/permutations) (반복 유,무)
-  * `A` [조합](src/algorithms/sets/combinations) (반복 유,무)
-* **동적 계획법(Dynamic Programming)** - 이전에 찾은 결과를 이용하여 최종적으로 해결하는 방식입니다.
-  * `B` [피보나치 수](src/algorithms/math/fibonacci)
-  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `A` [편집 거리](src/algorithms/string/levenshtein-distance) - 두 시퀀스 간의 최소 편집 거리
-  * `A` [최장 공통 부분 수열](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [최장 공통 부분 문자열](src/algorithms/string/longest-common-substring)
-  * `A` [최장 증가 수열](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1 배낭 문제](src/algorithms/sets/knapsack-problem)
-  * `A` [자연수 분할](src/algorithms/math/integer-partition)
-  * `A` [최대 구간합](src/algorithms/sets/maximum-subarray)
-  * `A` [벨만-포드 알고리즘](src/algorithms/graph/bellman-ford) - 모든 점 까지의 최단 거리 찾기
-  * `A` [플로이드-워셜 알고리즘](src/algorithms/graph/floyd-warshall) - 모든 종단 간의 최단거리 찾기
-  * `A` [정규 표현식 매칭](src/algorithms/string/regular-expression-matching)
-* **백트래킹(Backtracking)** - 모든 가능한 경우를 고려한다는 점에서 브루트 포스와 유사합니다. 하지만 다음 단계로 넘어갈때 마다 모든 조건을 만족했는지 확인하고 진행합니다. 만약 조건을 만족하지 못했다면 뒤로 돌아갑니다 (백트래킹). 그리고 다른 경로를 선택합니다. 보통 상태를  유지한 DFS 탐색을 많이 사용합니다.
-  * `B` [점프 게임](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `A` [해밀턴 경로](src/algorithms/graph/hamiltonian-cycle) - 모든 점을 한번씩 방문
-  * `A` [N-Queens 문제](src/algorithms/uncategorized/n-queens)
-  * `A` [기사의 여행](src/algorithms/uncategorized/knight-tour)
-  * `A` [조합 합](src/algorithms/sets/combination-sum) - 특정 합을 구성하는 모든 조합 찾기
-* **분기 한정법** - 백트래킹으로 찾은 각 단계의 최소 비용이 드는 해를 기억해 두고 있다가, 이 비용을 이용해서 더 낮은 최적의 해를 찾습니다. 기억해둔 최소 비용들을 이용해 더 높은 비용이 드는 해결법을 탐색 안함으로써 불필요한 시간 소모를 줄입니다. 보통 상태 공간 트리의 DFS 탐색을 이용한 BFS 탐색 방식에서 사용됩니다.
-
-## 이 저장소의 사용법
-
-**모든 종속 모듈들 설치**
-```
-npm install
-```
-
-**ESLint 실행**
-
-코드의 품질을 확인 할 수 있습니다.
-
-```
-npm run lint
-```
-
-**모든 테스트 실행**
-```
-npm test
-```
-
-**이름을 통해 특정 테스트 실행**
-```
-npm test -- 'LinkedList'
-```
-
-**Playground**
-
- `./src/playground/playground.js` 파일을 통해 자료 구조와 알고리즘을 작성하고 `./src/playground/__test__/playground.test.js`에 테스트를 작성할 수 있습니다.
-
-그리고 간단하게 아래 명령어를 통해 의도한대로 동작하는지 확인 할 수 있습니다.:
-
-```
-npm test -- 'playground'
-```
-
-## 유용한 정보
-
-### 참고
-
-[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Big O 표기
-
-Big O 표기로 표시한 알고리즘의 증가 양상입니다.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-Source: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-아래는 가장 많이 사용되는 Big O 표기와 입력 데이터 크기에 따른 성능을 비교한 표입니다.
-
-| Big O 표기 | 10 개 일때 | 100 개 일때 | 1000 개 일때  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### 자료 구조 작업별 복잡도
-
-| 자료 구조                 | 접근       | 검색      | 삽입       | 삭제      | 비고       |
-| ------------------------ | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **배열**                  | 1         | n         | n         | n         |           |
-| **스택**                  | n         | n         | 1         | 1         |           |
-| **큐**                    | n         | n         | 1         | 1         |           |
-| **연결 리스트**            | n         | n         | 1         | 1         |           |
-| **해시 테이블**            | -         | n         | n         | n         | 완벽한 해시 함수의 경우 O(1) |
-| **이진 탐색 트리**          | n         | n         | n         | n         | 균형 트리의 경우 O(log(n)) |
-| **B-트리**                | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Red-Black 트리**        | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **AVL 트리**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bloom Filter**          | -         | 1         | 1         | -         | 거짓 양성이 탐색 중 발생 가능 |
-
-### 정렬 알고리즘 복잡도
-
-| 이름                   | 최적            | 평균                 | 최악                | 메모리     | 동일값 순서유지    | 비고       |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :--------------: | :-------- |
-| **거품 정렬**          | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes              |           |
-| **삽입 정렬**          | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes              |           |
-| **선택 정렬**          | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No               |           |
-| **힙 정렬**            | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No               |           |
-| **병합 정렬**          | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes              |           |
-| **퀵 정렬**            | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No               | 퀵 정렬은 보통 제자리(in-place)로 O(log(n)) 스택공간으로 수행됩니다. |
-| **셸 정렬**            | n&nbsp;log(n)   | 간격 순서에 영향을 받습니다.   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
-| **계수 정렬**          | n + r           | n + r               | n + r               | n + r     | Yes              | r - 배열내 가장 큰 수 |
-| **기수 정렬**          | n * k           | n * k               | n * k               | n + k     | Yes              | k - 키값의 최대 길이 |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.md b/README.md
index e06cfb9075..e6d9c76dbb 100644
--- a/README.md
+++ b/README.md
@@ -1,374 +1,348 @@
-# JavaScript Algorithms and Data Structures
-
-> 🇺🇦 UKRAINE [IS BEING ATTACKED](https://war.ukraine.ua/) BY RUSSIAN ARMY. CIVILIANS ARE GETTING KILLED. RESIDENTIAL AREAS ARE GETTING BOMBED.
-> - Help Ukraine via:
->   - [Serhiy Prytula Charity Foundation](https://prytulafoundation.org/en/)
->   - [Come Back Alive Charity Foundation](https://savelife.in.ua/en/donate-en/)
->   - [National Bank of Ukraine](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi)
-> - More info on [war.ukraine.ua](https://war.ukraine.ua/) and [MFA of Ukraine](https://twitter.com/MFA_Ukraine)
-
-<hr/>
+# Thuật toán và Cấu trúc Dữ liệu JavaScript
 
 [![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
 [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
 ![repo size](https://img.shields.io/github/repo-size/trekhleb/javascript-algorithms.svg)
 
-This repository contains JavaScript based examples of many
-popular algorithms and data structures.
-
-Each algorithm and data structure has its own separate README
-with related explanations and links for further reading (including ones
-to YouTube videos).
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türkçe_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Note that this project is meant to be used for learning and researching purposes
-only, and it is **not** meant to be used for production.*
-
-## Data Structures
-
-A data structure is a particular way of organizing and storing data in a computer so that it can
-be accessed and modified efficiently. More precisely, a data structure is a collection of data
-values, the relationships among them, and the functions or operations that can be applied to
-the data.
-
-`B` - Beginner, `A` - Advanced
-
-* `B` [Linked List](src/data-structures/linked-list)
-* `B` [Doubly Linked List](src/data-structures/doubly-linked-list)
-* `B` [Queue](src/data-structures/queue)
-* `B` [Stack](src/data-structures/stack)
-* `B` [Hash Table](src/data-structures/hash-table)
-* `B` [Heap](src/data-structures/heap) - max and min heap versions
-* `B` [Priority Queue](src/data-structures/priority-queue)
-* `A` [Trie](src/data-structures/trie)
-* `A` [Tree](src/data-structures/tree)
-  * `A` [Binary Search Tree](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL Tree](src/data-structures/tree/avl-tree)
-  * `A` [Red-Black Tree](src/data-structures/tree/red-black-tree)
-  * `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples
-  * `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-* `A` [Graph](src/data-structures/graph) (both directed and undirected)
-* `A` [Disjoint Set](src/data-structures/disjoint-set) - a union–find data structure or merge–find set
-* `A` [Bloom Filter](src/data-structures/bloom-filter)
-* `A` [LRU Cache](src/data-structures/lru-cache/) - Least Recently Used (LRU) cache
-
-## Algorithms
-
-An algorithm is an unambiguous specification of how to solve a class of problems. It is
-a set of rules that precisely define a sequence of operations.
-
-`B` - Beginner, `A` - Advanced
-
-### Algorithms by Topic
-
-* **Math**
-  * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.
-  * `B` [Binary Floating Point](src/algorithms/math/binary-floating-point) - binary representation of the floating-point numbers.
-  * `B` [Factorial](src/algorithms/math/factorial)
-  * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions
-  * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem
-  * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method)
-  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit
-  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms)
-  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
-  * `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them
-  * `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion
-  * `B` [Fast Powering](src/algorithms/math/fast-powering)
-  * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation
-  * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.)
-  * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices
-  * `A` [Integer Partition](src/algorithms/math/integer-partition)
-  * `A` [Square Root](src/algorithms/math/square-root) - Newton's method
-  * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
-  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up
-* **Sets**
-  * `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets
-  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
-  * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bitwise, backtracking, and cascading solutions)
-  * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
-  * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
-  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - "Brute Force" and "Dynamic Programming" (Kadane's) versions
-  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
-* **Strings**
-  * `B` [Hamming Distance](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
-  * `B` [Palindrome](src/algorithms/string/palindrome) - check if the string is the same in reverse
-  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
-  * `A` [Knuth–Morris–Pratt Algorithm](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - substring search (pattern matching)
-  * `A` [Z Algorithm](src/algorithms/string/z-algorithm) - substring search (pattern matching)
-  * `A` [Rabin Karp Algorithm](src/algorithms/string/rabin-karp) - substring search
-  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
-  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
-* **Searches**
-  * `B` [Linear Search](src/algorithms/search/linear-search)
-  * `B` [Jump Search](src/algorithms/search/jump-search) (or Block Search) - search in sorted array
-  * `B` [Binary Search](src/algorithms/search/binary-search) - search in sorted array
-  * `B` [Interpolation Search](src/algorithms/search/interpolation-search) - search in uniformly distributed sorted array
-* **Sorting**
-  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)
-  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)
-  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)
-  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations
-  * `B` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)
-  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)
-  * `B` [Bucket Sort](src/algorithms/sorting/bucket-sort)
-* **Linked Lists**
-  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)
-  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)
-* **Trees**
-  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)
-* **Graphs**
-  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest paths to all graph vertices from single vertex
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest paths to all graph vertices from single vertex
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices
-  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions)
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method
-  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based)
-  * `A` [Bridges](src/algorithms/graph/bridges) - DFS based algorithm
-  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
-  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
-* **Cryptography**
-  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial
-  * `B` [Rail Fence Cipher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages
-  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher
-  * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra
-* **Machine Learning**
-  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)
-  * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm
-  * `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm
-* **Image Processing**
-  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
-* **Statistics**
-  * `B` [Weighted Random](src/algorithms/statistics/weighted-random) - select the random item from the list based on items' weights
-* **Evolutionary algorithms**
-  * `A` [Genetic algorithm](https://github.com/trekhleb/self-parking-car-evolution) - example of how the genetic algorithm may be applied for training the self-parking cars
-* **Uncategorized**
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions)
-  * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-
-### Algorithms by Paradigm
-
-An algorithmic paradigm is a generic method or approach which underlies the design of a class
-of algorithms. It is an abstraction higher than the notion of an algorithm, just as an
-algorithm is an abstraction higher than a computer program.
-
-* **Brute Force** - look at all the possibilities and selects the best solution
-  * `B` [Linear Search](src/algorithms/search/linear-search)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
-  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up
-* **Greedy** - choose the best option at the current time, without any consideration for the future
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest path to all graph vertices
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-* **Divide and Conquer** - divide the problem into smaller parts and then solve those parts
-  * `B` [Binary Search](src/algorithms/search/binary-search)
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
-  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Fast Powering](src/algorithms/math/fast-powering)
-  * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples
-  * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
-  * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-* **Dynamic Programming** - build up a solution using previously found sub-solutions
-  * `B` [Fibonacci Number](src/algorithms/math/fibonacci)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
-  * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
-  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
-  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
-  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Integer Partition](src/algorithms/math/integer-partition)
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest path to all graph vertices
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices
-  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
-* **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate next solution you test
-if it satisfies all conditions, and only then continue generating subsequent solutions. Otherwise, backtrack, and go on a
-different path of finding a solution. Normally the DFS traversal of state-space is being used.
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - find all combinations that form specific sum
-* **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking
-search, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of
-a least-cost solution to the problem, in order to discard partial solutions with costs larger than the
-lowest-cost solution found so far. Normally BFS traversal in combination with DFS traversal of state-space
-tree is being used.
-
-## How to use this repository
-
-**Install all dependencies**
+Kho lưu trữ này chứa các ví dụ dựa trên JavaScript
+về nhiều thuật toán và cấu trúc dữ liệu phổ biến.
+
+Mỗi thuật toán và cấu trúc dữ liệu đều có một tệp README
+riêng với các giải thích liên quan và các liên kết để đọc thêm (bao gồm cả các video trên YouTube).
+
+_Đọc tài liệu này bằng ngôn ngữ khác:_ [_English_](README.en-EN.md)
+
+[Nguồn - Kho lưu trữ gốc](https://github.com/trekhleb/javascript-algorithms)
+
+_☝ Lưu ý rằng dự án này chỉ được sử dụng cho mục đích học tập và nghiên cứu, **không** dùng cho sản xuất._
+
+## Data Structures - Cấu trúc dữ liệu
+
+Cấu trúc dữ liệu là một cách đặc biệt để tổ chức và lưu trữ dữ liệu trong máy tính sao cho có thể truy cập và sửa đổi hiệu quả.
+Một cách chính xác hơn, cấu trúc dữ liệu là tập hợp các giá trị dữ liệu,
+các mối quan hệ giữa chúng, và các hàm hoặc thao tác có thể được áp dụng cho dữ liệu.
+
+`B` - Người mới bắt đầu, `A` - Nâng cao
+
+- `B` [Linked List - Danh sách liên kết](src/data-structures/linked-list)
+- `B` [Doubly Linked List - Danh sách liên kết kép](src/data-structures/doubly-linked-list)
+- `B` [Queue - Hàng đợi](src/data-structures/queue)
+- `B` [Stack - Ngăn xếp](src/data-structures/stack)
+- `B` [Hash Table - Bảng băm](src/data-structures/hash-table)
+- `B` [Heap - Đống](src/data-structures/heap) - các phiên bản đống lớn nhất và nhỏ nhất
+- `B` [Priority Queue - Hàng đợi ưu tiên](src/data-structures/priority-queue)
+- `A` [Trie](src/data-structures/trie)
+- `A` [Tree - Cây](src/data-structures/tree)
+  - `A` [Binary Search Tree - Cây tìm kiếm nhị phân](src/data-structures/tree/binary-search-tree)
+  - `A` [AVL Tree - Cây AVL](src/data-structures/tree/avl-tree)
+  - `A` [Red-Black Tree - Cây đỏ đen](src/data-structures/tree/red-black-tree)
+  - `A` [Segment Tree - Cây phân đoạn](src/data-structures/tree/segment-tree) - với các ví dụ truy vấn phạm vi tìm min/max/tổng
+  - `A` [Fenwick Tree (Binary Indexed Tree) - Cây Fenwick (Cây chỉ số nhị phân)](src/data-structures/tree/fenwick-tree)
+- `A` [Graph - Đồ thị](src/data-structures/graph) (cả hai loại có hướng và không hướng)
+- `A` [Disjoint Set - Tập hợp rời rạc](src/data-structures/disjoint-set) - cấu trúc dữ liệu hợp nhất–tìm kiếm hoặc tập hợp hợp nhất–tìm kiếm
+- `A` [Bloom Filter - Bộ lọc Bloom](src/data-structures/bloom-filter)
+- `A` [LRU Cache - Bộ nhớ cache LRU (Least Recently Used)](src/data-structures/lru-cache)
+
+## Algorithms - Thuật toán
+
+Thuật toán là một đặc tả không mơ hồ về cách giải quyết một lớp vấn đề.
+Đó là một tập hợp các quy tắc xác định chính xác một chuỗi các thao tác.
+
+`B` - Người mới bắt đầu, `A` - Nâng cao
+
+### Algorithms by Topic - Thuật toán theo Chủ đề
+
+- **Math - Toán học**
+  - `B` [Bit Manipulation - Thao tác bit](src/algorithms/math/bits) - đặt/lấy/cập nhật/xóa bit, nhân/chia cho hai, làm số âm, v.v.
+  - `B` [Binary Floating Point - Điểm nổi nhị phân](src/algorithms/math/binary-floating-point) - biểu diễn nhị phân của các số dấu phẩy động.
+  - `B` [Factorial - Giai thừa](src/algorithms/math/factorial)
+  - `B` [Fibonacci Number - Số Fibonacci](src/algorithms/math/fibonacci) - phiên bản cổ điển và phiên bản công thức đóng
+  - `B` [Prime Factors - Thừa số nguyên tố](src/algorithms/math/prime-factors) - tìm thừa số nguyên tố và đếm chúng bằng định lý Hardy-Ramanujan
+  - `B` [Primality Test - Kiểm tra số nguyên tố](src/algorithms/math/primality-test) (phương pháp chia thử)
+  - `B` [Euclidean Algorithm - Thuật toán Euclide](src/algorithms/math/euclidean-algorithm) - tính Ước số chung lớn nhất (GCD)
+  - `B` [Least Common Multiple - Bội số chung nhỏ nhất](src/algorithms/math/least-common-multiple) (LCM)
+  - `B` [Sieve of Eratosthenes - Rây Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - tìm tất cả các số nguyên tố đến bất kỳ giới hạn nào được đưa ra
+  - `B` [Is Power of Two - Kiểm tra lũy thừa của hai](src/algorithms/math/is-power-of-two) - kiểm tra xem số có phải là lũy thừa của hai không (thuật toán ngây thơ và thuật toán bit)
+  - `B` [Pascal's Triangle - Tam giác Pascal](src/algorithms/math/pascal-triangle)
+  - `B` [Complex Number - Số phức](src/algorithms/math/complex-number) - các số phức và các phép toán cơ bản với chúng
+  - `B` [Radian & Degree - Radian và Độ](src/algorithms/math/radian) - chuyển đổi radian sang độ và ngược lại
+  - `B` [Fast Powering - Luỹ thừa nhanh](src/algorithms/math/fast-powering)
+  - `B` [Horner's method - Phương pháp Horner](src/algorithms/math/horner-method) - đánh giá đa thức
+  - `B` [Matrices - Ma trận](src/algorithms/math/matrix) - ma trận và các thao tác cơ bản với ma trận (nhân, chuyển vị, v.v.)
+  - `B` [Euclidean Distance - Khoảng cách Euclide](src/algorithms/math/euclidean-distance) - khoảng cách giữa hai điểm/vectơ/ma trận
+  - `A` [Integer Partition - Phân chia số nguyên](src/algorithms/math/integer-partition)
+  - `A` [Square Root - Căn bậc hai](src/algorithms/math/square-root) - phương pháp Newton
+  - `A` [Liu Hui π Algorithm - Thuật toán π Liu Hui](src/algorithms/math/liu-hui) - tính gần đúng π dựa trên N-gons
+  - `A` [Discrete Fourier Transform - Biến đổi Fourier rời rạc](src/algorithms/math/fourier-transform) - phân tích một hàm thời gian (tín hiệu) thành các tần số tạo thành nó
+- **Sets - Tập hợp**
+  - `B` [Cartesian Product - Tích Descartes](src/algorithms/sets/cartesian-product) - sản phẩm của nhiều tập hợp
+  - `B` [Fisher–Yates Shuffle - Xáo trộn Fisher–Yates](src/algorithms/sets/fisher-yates) - hoán vị ngẫu nhiên của một chuỗi hữu hạn
+  - `A` [Power Set - Tập lực lượng](src/algorithms/sets/power-set) - tất cả các tập con của một tập hợp (các giải pháp dựa trên bit, backtracking và dâng trào)
+  - `A` [Permutations - Hoán vị](src/algorithms/sets/permutations) (có và không có lặp lại)
+  - `A` [Combinations - Tổ hợp](src/algorithms/sets/combinations) (có và không có lặp lại)
+  - `A` [Longest Common Subsequence - Chuỗi con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)
+  - `A` [Longest Increasing Subsequence - Chuỗi tăng dài nhất](src/algorithms/sets/longest-increasing-subsequence)
+  - `A` [Shortest Common Supersequence - Chuỗi chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence) (SCS)
+  - `A` [Knapsack Problem - Bài toán ba lô](src/algorithms/sets/knapsack-problem) - các phiên bản "0/1" và "Không giới hạn"
+  - `A` [Maximum Subarray - Mảng con lớn nhất](src/algorithms/sets/maximum-subarray) - các phiên bản "Vét cạn" và "Quy hoạch động" (Kadane)
+  - `A` [Combination Sum - Tổng các tổ hợp](src/algorithms/sets/combination-sum) - tìm tất cả các tổ hợp tạo thành tổng cụ thể
+- **Strings - Chuỗi**
+  - `B` [Hamming Distance - Khoảng cách Hamming](src/algorithms/string/hamming-distance) - số lượng vị trí mà các ký tự khác nhau
+  - `B` [Palindrome - Chuỗi đối xứng](src/algorithms/string/palindrome) - kiểm tra xem chuỗi có giống nhau khi đảo ngược không
+  - `A` [Levenshtein Distance - Khoảng cách Levenshtein](src/algorithms/string/levenshtein-distance) - khoảng cách chỉnh sửa tối thiểu giữa hai chuỗi
+  - `A` [Knuth–Morris–Pratt Algorithm (KMP Algorithm) - Thuật toán Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) - tìm kiếm chuỗi con (so khớp mẫu)
+  - `A` [Z Algorithm - Thuật toán Z](src/algorithms/string/z-algorithm) - tìm kiếm chuỗi con (so khớp mẫu)
+  - `A` [Rabin Karp Algorithm - Thuật toán Rabin Karp](src/algorithms/string/rabin-karp) - tìm kiếm chuỗi con
+  - `A` [Longest Common Substring - Chuỗi con chung dài nhất](src/algorithms/string/longest-common-substring)
+  - `A` [Regular Expression Matching - So khớp biểu thức chính quy](src/algorithms/string/regular-expression-matching)
+- **Searches - Tìm kiếm**
+  - `B` [Linear Search - Tìm kiếm tuyến tính](src/algorithms/search/linear-search)
+  - `B` [Jump Search (or Block Search) - Tìm kiếm nhảy (hoặc Tìm kiếm khối)](src/algorithms/search/jump-search) - tìm kiếm trong mảng đã sắp xếp
+  - `B` [Binary Search - Tìm kiếm nhị phân](src/algorithms/search/binary-search) - tìm kiếm trong mảng đã sắp xếp
+  - `B` [Interpolation Search - Tìm kiếm nội suy](src/algorithms/search/interpolation-search) - tìm kiếm trong mảng đã sắp xếp phân bố đều
+- **Sorting - Sắp xếp**
+  - `B` [Bubble Sort - Sắp xếp nổi bọt](src/algorithms/sorting/bubble-sort)
+  - `B` [Selection Sort - Sắp xếp chọn](src/algorithms/sorting/selection-sort)
+  - `B` [Insertion Sort - Sắp xếp chèn](src/algorithms/sorting/insertion-sort)
+  - `B` [Heap Sort - Sắp xếp đống](src/algorithms/sorting/heap-sort)
+  - `B` [Merge Sort - Sắp xếp trộn](src/algorithms/sorting/merge-sort)
+  - `B` [Quicksort - Sắp xếp nhanh](src/algorithms/sorting/quick-sort) - các phiên bản tại chỗ và không tại chỗ
+  - `B` [Shellsort - Sắp xếp Shell](src/algorithms/sorting/shell-sort)
+  - `B` [Counting Sort - Sắp xếp đếm](src/algorithms/sorting/counting-sort)
+  - `B` [Radix Sort - Sắp xếp theo cơ số](src/algorithms/sorting/radix-sort)
+  - `B` [Bucket Sort - Sắp xếp thùng](src/algorithms/sorting/bucket-sort)
+- **Linked Lists - Danh sách liên kết**
+  - `B` [Straight Traversal - Duyệt thẳng](src/algorithms/linked-list/traversal)
+  - `B` [Reverse Traversal - Duyệt ngược](src/algorithms/linked-list/reverse-traversal)
+- **Trees - Cây**
+  - `B` [Depth-First Search - Tìm kiếm theo chiều sâu](src/algorithms/tree/depth-first-search) (DFS)
+  - `B` [Breadth-First Search - Tìm kiếm theo chiều rộng](src/algorithms/tree/breadth-first-search) (BFS)
+- **Graphs - Đồ thị**
+  - `B` [Depth-First Search - Tìm kiếm theo chiều sâu](src/algorithms/graph/depth-first-search) (DFS)
+  - `B` [Breadth-First Search - Tìm kiếm theo chiều rộng](src/algorithms/graph/breadth-first-search) (BFS)
+  - `B` [Kruskal’s Algorithm - Thuật toán Kruskal](src/algorithms/graph/kruskal) - tìm Cây bao trùm tối thiểu (MST) cho đồ thị vô hướng có trọng số
+  - `A` [Dijkstra Algorithm - Thuật toán Dijkstra](src/algorithms/graph/dijkstra) - tìm đường đi ngắn nhất đến tất cả các đỉnh đồ thị từ một đỉnh
+  - `A` [Bellman-Ford Algorithm - Thuật toán Bellman-Ford](src/algorithms/graph/bellman-ford) - tìm đường đi ngắn nhất đến tất cả các đỉnh đồ thị từ một đỉnh
+  - `A` [Floyd-Warshall Algorithm - Thuật toán Floyd-Warshall](src/algorithms/graph/floyd-warshall) - tìm đường đi ngắn nhất giữa tất cả các cặp đỉnh
+  - `A` [Detect Cycle - Phát hiện chu trình](src/algorithms/graph/detect-cycle) - cho cả đồ thị có hướng và không hướng (các phiên bản dựa trên DFS và Tập hợp rời rạc)
+  - `A` [Prim’s Algorithm - Thuật toán Prim](src/algorithms/graph/prim) - tìm Cây bao trùm tối thiểu (MST) cho đồ thị vô hướng có trọng số
+  - `A` [Topological Sorting - Sắp xếp topo](src/algorithms/graph/topological-sorting) - phương pháp DFS
+  - `A` [Articulation Points - Điểm nối](src/algorithms/graph/articulation-points) - thuật toán Tarjan (dựa trên DFS)
+  - `A` [Bridges - Cầu](src/algorithms/graph/bridges) - thuật toán dựa trên DFS
+  - `A` [Eulerian Path and Eulerian Circuit - Đường đi Euler và Chu trình Euler](src/algorithms/graph/eulerian-path) - thuật toán Fleury - ghé thăm mỗi cạnh một lần
+  - `A` [Hamiltonian Cycle - Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - ghé thăm mỗi đỉnh một lần
+  - `A` [Strongly Connected Components - Thành phần liên thông mạnh](src/algorithms/graph/strongly-connected-components) - thuật toán Kosaraju
+  - `A` [Travelling Salesman Problem - Bài toán người bán hàng du lịch](src/algorithms/graph/travelling-salesman) - tuyến đường ngắn nhất có thể ghé thăm mỗi thành phố và trở về thành phố xuất phát
+- **Cryptography - Mật mã học**
+  - `B` [Polynomial Hash - Băm đa thức](src/algorithms/cryptography/polynomial-hash) - hàm băm dựa trên đa thức
+  - `B` [Rail Fence Cipher - Mật mã hàng rào](src/algorithms/cryptography/rail-fence-cipher) - thuật toán mật mã hoán vị để mã hóa tin nhắn
+  - `B` [Caesar Cipher - Mật mã Caesar](src/algorithms/cryptography/caesar-cipher) - mật mã thay thế đơn giản
+  - `B` [Hill Cipher - Mật mã Hill](src/algorithms/cryptography/hill-cipher) - mật mã thay thế dựa trên đại số tuyến tính
+- **Machine Learning - Máy học**
+  - `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 hàm JS đơn giản minh họa cách máy móc có thể học hỏi thực sự (lan truyền tiến/lùi)
+  - `B` [k-NN - k-Nearest Neighbors](src/algorithms/ml/knn) - thuật toán phân loại k láng giềng gần nhất
+  - `B` [k-Means - k-Means](src/algorithms/ml/k-means) - thuật toán phân cụm k-Means
+- **Image Processing - Xử lý ảnh**
+  - `B` [Seam Carving - Cắt chỉnh sửa nội dung](src/algorithms/image-processing/seam-carving) - thuật toán thay đổi kích thước ảnh nhận thức nội dung
+- **Statistics - Thống kê**
+  - `B` [Weighted Random - Ngẫu nhiên có trọng số](src/algorithms/statistics/weighted-random) - chọn mục ngẫu nhiên từ danh sách dựa trên trọng số của các mục
+- **Evolutionary algorithms - Thuật toán tiến hóa**
+  - `A` [Genetic algorithm - Thuật toán di truyền](https://github.com/trekhleb/self-parking-car-evolution) - ví dụ về cách áp dụng thuật toán di truyền để huấn luyện xe tự đỗ
+- **Uncategorized - Không phân loại**
+  - `B` [Tower of Hanoi - Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)
+  - `B` [Square Matrix Rotation - Xoay ma trận vuông](src/algorithms/uncategorized/square-matrix-rotation) - thuật toán tại chỗ
+  - `B` [Jump Game - Trò chơi nhảy](src/algorithms/uncategorized/jump-game) - các ví dụ về vét cạn, quy hoạch động (trên xuống + dưới lên) và tham lam
+  - `B` [Unique Paths - Đường đi độc đáo](src/algorithms/uncategorized/unique-paths) - các ví dụ về vét cạn, quy hoạch động và Tam giác Pascal
+  - `B` [Rain Terraces - Mái hiên mưa](src/algorithms/uncategorized/rain-terraces) - bài toán mắc kẹt nước mưa (quy hoạch động và các phiên bản vét cạn)
+  - `B` [Recursive Staircase - Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách để đạt đến đỉnh (4 giải pháp)
+  - `B` [Best Time To Buy Sell Stocks - Thời điểm tốt nhất để mua bán cổ phiếu](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - chia để trị và các ví dụ một lần
+  - `A` [N-Queens Problem - Bài toán N quân hậu](src/algorithms/uncategorized/n-queens)
+  - `A` [Knight's Tour - Chuyến du lịch của hiệp sĩ](src/algorithms/uncategorized/knight-tour)
+
+### Algorithms by Paradigm - Thuật toán theo Mô hình
+
+Một mô hình thuật toán là một phương pháp chung hoặc cách tiếp cận chung chung cho thiết kế một loạt thuật toán.
+Nó là một trừu tượng cao hơn so với khái niệm thuật toán,
+giống như thuật toán là một trừu tượng cao hơn so với chương trình máy tính.
+
+- **Brute Force - Vét cạn** - xem xét tất cả các khả năng và chọn giải pháp tốt nhất
+  - `B` [Linear Search - Tìm kiếm tuyến tính](src/algorithms/search/linear-search)
+  - `B` [Rain Terraces - Mái hiên mưa](src/algorithms/uncategorized/rain-terraces) - bài toán mắc kẹt nước mưa
+  - `B` [Recursive Staircase - Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách để đạt đến đỉnh
+  - `A` [Maximum Subarray - Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)
+  - `A` [Travelling Salesman Problem - Bài toán người bán hàng du lịch](src/algorithms/graph/travelling-salesman) - tuyến đường ngắn nhất có thể ghé thăm mỗi thành phố và trở về thành phố xuất phát
+  - `A` [Discrete Fourier Transform - Biến đổi Fourier rời rạc](src/algorithms/math/fourier-transform) - phân tích một hàm thời gian (tín hiệu) thành các tần số tạo thành nó
+- **Greedy - Tham lam** - chọn giải pháp tốt nhất tại thời điểm hiện tại, mà không cần xem xét đến tương lai
+  - `B` [Jump Game - Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
+  - `A` [Unbound Knapsack Problem - Bài toán ba lô không giới hạn](src/algorithms/sets/knapsack-problem)
+  - `A` [Dijkstra Algorithm - Thuật toán Dijkstra](src/algorithms/graph/dijkstra) - tìm đường đi ngắn nhất đến tất cả các đỉnh đồ thị
+  - `A` [Prim’s Algorithm - Thuật toán Prim](src/algorithms/graph/prim) - tìm Cây bao trùm tối thiểu (MST) cho đồ thị vô hướng có trọng số
+  - `A` [Kruskal’s Algorithm - Thuật toán Kruskal](src/algorithms/graph/kruskal) - tìm Cây bao trùm tối thiểu (MST) cho đồ thị vô hướng có trọng số
+- **Divide and Conquer - Chia để trị** - chia vấn đề thành các phần nhỏ hơn và sau đó giải quyết những phần đó
+  - `B` [Binary Search - Tìm kiếm nhị phân](src/algorithms/search/binary-search)
+  - `B` [Tower of Hanoi - Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)
+  - `B` [Pascal's Triangle - Tam giác Pascal](src/algorithms/math/pascal-triangle)
+  - `B` [Euclidean Algorithm - Thuật toán Euclide](src/algorithms/math/euclidean-algorithm) - tính Ước số chung lớn nhất (GCD)
+  - `B` [Merge Sort - Sắp xếp trộn](src/algorithms/sorting/merge-sort)
+  - `B` [Quicksort - Sắp xếp nhanh](src/algorithms/sorting/quick-sort)
+  - `B` [Tree Depth-First Search - Tìm kiếm theo chiều sâu cây](src/algorithms/tree/depth-first-search) (DFS)
+  - `B` [Graph Depth-First Search - Tìm kiếm theo chiều sâu đồ thị](src/algorithms/graph/depth-first-search) (DFS)
+  - `B` [Matrices - Ma trận](src/algorithms/math/matrix) - tạo và duyệt các ma trận có hình dạng khác nhau
+  - `B` [Jump Game - Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
+  - `B` [Fast Powering - Luỹ thừa nhanh](src/algorithms/math/fast-powering)
+  - `B` [Best Time To Buy Sell Stocks - Thời điểm tốt nhất để mua bán cổ phiếu](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - chia để trị và các ví dụ một lần
+  - `A` [Permutations - Hoán vị](src/algorithms/sets/permutations) (có và không có lặp lại)
+  - `A` [Combinations - Tổ hợp](src/algorithms/sets/combinations) (có và không có lặp lại)
+  - `A` [Maximum Subarray - Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)
+- **Dynamic Programming - Quy hoạch động** - xây dựng giải pháp sử dụng các tiểu giải pháp đã tìm thấy trước đó
+  - `B` [Fibonacci Number - Số Fibonacci](src/algorithms/math/fibonacci)
+  - `B` [Jump Game - Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
+  - `B` [Unique Paths - Đường đi độc đáo](src/algorithms/uncategorized/unique-paths)
+  - `B` [Rain Terraces - Mái hiên mưa](src/algorithms/uncategorized/rain-terraces) - bài toán mắc kẹt nước mưa
+  - `B` [Recursive Staircase - Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách để đạt đến đỉnh
+  - `B` [Seam Carving - Cắt chỉnh sửa nội dung](src/algorithms/image-processing/seam-carving) - thuật toán thay đổi kích thước ảnh nhận thức nội dung
+  - `A` [Levenshtein Distance - Khoảng cách Levenshtein](src/algorithms/string/levenshtein-distance) - khoảng cách chỉnh sửa tối thiểu giữa hai chuỗi
+  - `A` [Longest Common Subsequence - Chuỗi con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)
+  - `A` [Longest Common Substring - Chuỗi con chung dài nhất](src/algorithms/string/longest-common-substring)
+  - `A` [Longest Increasing Subsequence - Chuỗi tăng dài nhất](src/algorithms/sets/longest-increasing-subsequence)
+  - `A` [Shortest Common Supersequence - Chuỗi chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence)
+  - `A` [0/1 Knapsack Problem - Bài toán ba lô 0/1](src/algorithms/sets/knapsack-problem)
+  - `A` [Integer Partition - Phân chia số nguyên](src/algorithms/math/integer-partition)
+  - `A` [Maximum Subarray - Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)
+  - `A` [Bellman-Ford Algorithm - Thuật toán Bellman-Ford](src/algorithms/graph/bellman-ford) - tìm đường đi ngắn nhất đến tất cả các đỉnh đồ thị
+  - `A` [Floyd-Warshall Algorithm - Thuật toán Floyd-Warshall](src/algorithms/graph/floyd-warshall) - tìm đường đi ngắn nhất giữa tất cả các cặp đỉnh
+  - `A` [Regular Expression Matching - So khớp biểu thức chính quy](src/algorithms/string/regular-expression-matching)
+- **Backtracking** - tương tự như vét cạn, thử tạo ra tất cả các giải pháp có thể, nhưng mỗi lần bạn tạo ra giải pháp tiếp theo,
+  bạn kiểm tra xem nó có đáp ứng tất cả các điều kiện không và chỉ sau đó mới tiếp tục tạo ra các giải pháp tiếp theo.
+  Nếu không, quay lại và đi theo một hướng khác để tìm giải pháp. Thường thì duyệt không gian trạng thái bằng DFS được sử dụng.
+- `B` [Jump Game - Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
+- `B` [Unique Paths - Đường đi độc đáo](src/algorithms/uncategorized/unique-paths)
+- `B` [Power Set - Tập lực lượng](src/algorithms/sets/power-set) - tất cả các tập con của một tập hợp
+- `A` [Hamiltonian Cycle - Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - Ghé thăm mỗi đỉnh một lần
+- `A` [N-Queens Problem - Bài toán N quân hậu](src/algorithms/uncategorized/n-queens)
+- `A` [Knight's Tour - Chuyến du lịch của hiệp sĩ](src/algorithms/uncategorized/knight-tour)
+- `A` [Combination Sum - Tổng các tổ hợp](src/algorithms/sets/combination-sum) - tìm tất cả các tổ hợp tạo thành tổng cụ thể
+- **Branch & Bound** - nhớ giải pháp có chi phí thấp nhất tìm thấy ở mỗi giai đoạn của quá trình backtracking,
+  và sử dụng chi phí của giải pháp có chi phí thấp nhất tìm thấy cho đến nay làm ranh giới dưới
+  về chi phí của giải pháp ít chi phí nhất cho vấn đề,
+  để loại bỏ các giải pháp một phần có chi phí lớn hơn giải pháp có chi phí thấp nhất tìm thấy cho đến nay.
+  Thường thì duyệt không gian trạng thái cây bằng BFS kết hợp với duyệt DFS được sử dụng.
+
+## How to use this repository - Cách sử dụng kho lưu trữ này
+
+**Install all dependencies - Cài đặt tất cả các phụ thuộc**
 
 ```
 npm install
 ```
 
-**Run ESLint**
+**Run ESLint - Chạy ESLint**
 
-You may want to run it to check code quality.
+Bạn có thể muốn chạy nó để kiểm tra chất lượng mã.
 
 ```
 npm run lint
 ```
 
-**Run all tests**
+**Run all tests - Chạy tất cả các bài kiểm tra**
 
 ```
 npm test
 ```
 
-**Run tests by name**
+**Run tests by name - Chạy các bài kiểm tra theo tên**
 
 ```
 npm test -- 'LinkedList'
 ```
 
-**Troubleshooting**
+**Troubleshooting - Khắc phục sự cố**
 
-If linting or testing is failing, try to delete the `node_modules` folder and re-install npm packages:
+Nếu việc linting hoặc kiểm tra thất bại, hãy thử xóa thư mục `node_modules` và cài đặt lại các gói npm:
 
 ```
 rm -rf ./node_modules
 npm i
 ```
 
-Also make sure that you're using a correct Node version (`>=16`). If you're using [nvm](https://github.com/nvm-sh/nvm) for Node version management you may run `nvm use` from the root folder of the project and the correct version will be picked up.
+Cũng đảm bảo rằng bạn đang sử dụng phiên bản Node đúng (`>=16`). Nếu bạn đang sử dụng [nvm](https://github.com/nvm-sh/nvm) để quản lý phiên bản Node, bạn có thể chạy `nvm use` từ thư mục gốc của dự án và phiên bản đúng sẽ được chọn.
 
-**Playground**
+**Playground - Sân chơi**
 
-You may play with data-structures and algorithms in `./src/playground/playground.js` file and write
-tests for it in `./src/playground/__test__/playground.test.js`.
+Bạn có thể chơi với các cấu trúc dữ liệu và thuật toán trong tệp `./src/playground/playground.js`
+và viết các bài kiểm tra cho nó trong `./src/playground/__test__/playground.test.js`.
 
-Then just simply run the following command to test if your playground code works as expected:
+Sau đó chỉ cần chạy lệnh sau để kiểm tra xem mã sân chơi của bạn có hoạt động như mong đợi hay không:
 
 ```
 npm test -- 'playground'
 ```
 
-## Useful Information
+## Useful Information - Thông tin hữu ích
 
-### References
+### References - Tài liệu tham khảo
 
-- [▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [✍🏻 Data Structure Sketches](https://okso.app/showcase/data-structures)
+- [▶ Cấu trúc dữ liệu và Thuật toán trên YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [✍🏻 Bản vẽ Cấu trúc dữ liệu](https://okso.app/showcase/data-structures)
 
-### Big O Notation
+### Big O Notation - Ký hiệu Big O
 
-*Big O notation* is used to classify algorithms according to how their running time or space requirements grow as the input size grows.
-On the chart below you may find most common orders of growth of algorithms specified in Big O notation.
+_Ký hiệu Big O_ được sử dụng để phân loại các thuật toán theo cách thời gian chạy hoặc yêu cầu không gian của chúng tăng lên như thế nào khi kích thước đầu vào tăng lên.
+Trên biểu đồ dưới đây, bạn có thể tìm thấy các trật tự tăng trưởng phổ biến nhất của các thuật toán được chỉ định trong ký hiệu Big O.
 
-![Big O graphs](./assets/big-o-graph.png)
+![Biểu đồ Big O](./assets/big-o-graph.png)
 
-Source: [Big O Cheat Sheet](http://bigocheatsheet.com/).
+Nguồn: [Big O Cheat Sheet](http://bigocheatsheet.com/).
 
-Below is the list of some of the most used Big O notations and their performance comparisons against different sizes of the input data.
+Dưới đây là danh sách một số ký hiệu Big O phổ biến nhất và so sánh hiệu suất của chúng đối với các kích thước dữ liệu đầu vào khác nhau.
 
-| Big O Notation | Type        | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements  |
-| -------------- | ----------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | Constant    | 1                            | 1                             | 1                               |
-| **O(log N)**   | Logarithmic | 3                            | 6                             | 9                               |
-| **O(N)**       | Linear      | 10                           | 100                           | 1000                            |
-| **O(N log N)** | n log(n)    | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | Quadratic   | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | Exponential | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | Factorial   | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
+| Big O Notation | Type        | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements |
+| -------------- | ----------- | ---------------------------- | ----------------------------- | ------------------------------ |
+| **O(1)**       | Constant    | 1                            | 1                             | 1                              |
+| **O(log N)**   | Logarithmic | 3                            | 6                             | 9                              |
+| **O(N)**       | Linear      | 10                           | 100                           | 1000                           |
+| **O(N log N)** | n log(n)    | 30                           | 600                           | 9000                           |
+| **O(N^2)**     | Quadratic   | 100                          | 10000                         | 1000000                        |
+| **O(2^N)**     | Exponential | 1024                         | 1.26e+29                      | 1.07e+301                      |
+| **O(N!)**      | Factorial   | 3628800                      | 9.3e+157                      | 4.02e+2567                     |
 
 ### Data Structure Operations Complexity
 
-| Data Structure          | Access    | Search    | Insertion | Deletion  | Comments  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Array**               | 1         | n         | n         | n         |           |
-| **Stack**               | n         | n         | 1         | 1         |           |
-| **Queue**               | n         | n         | 1         | 1         |           |
-| **Linked List**         | n         | n         | 1         | n         |           |
-| **Hash Table**          | -         | n         | n         | n         | In case of perfect hash function costs would be O(1) |
-| **Binary Search Tree**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bloom Filter**        | -         | 1         | 1         | -         | False positives are possible while searching |
+| Data Structure         | Access | Search | Insertion | Deletion | Comments                                             |
+| ---------------------- | :----: | :----: | :-------: | :------: | :--------------------------------------------------- |
+| **Array**              |   1    |   n    |     n     |    n     |                                                      |
+| **Stack**              |   n    |   n    |     1     |    1     |                                                      |
+| **Queue**              |   n    |   n    |     1     |    1     |                                                      |
+| **Linked List**        |   n    |   n    |     1     |    n     |                                                      |
+| **Hash Table**         |   -    |   n    |     n     |    n     | In case of perfect hash function costs would be O(1) |
+| **Binary Search Tree** |   n    |   n    |     n     |    n     | In case of balanced tree costs would be O(log(n))    |
+| **B-Tree**             | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **Red-Black Tree**     | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **AVL Tree**           | log(n) | log(n) |  log(n)   |  log(n)  |                                                      |
+| **Bloom Filter**       |   -    |   1    |     1     |    -     | False positives are possible while searching         |
 
 ### Array Sorting Algorithms Complexity
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        | Quicksort is usually done in-place with O(log(n)) stack space |
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |
+| Name               |     Best      |         Average         |            Worst            | Memory | Stable | Comments                                                      |
+| ------------------ | :-----------: | :---------------------: | :-------------------------: | :----: | :----: | :------------------------------------------------------------ |
+| **Bubble sort**    |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |  Yes   |                                                               |
+| **Insertion sort** |       n       |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |  Yes   |                                                               |
+| **Selection sort** | n<sup>2</sup> |      n<sup>2</sup>      |        n<sup>2</sup>        |   1    |   No   |                                                               |
+| **Heap sort**      | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   1    |   No   |                                                               |
+| **Merge sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n&nbsp;log(n)        |   n    |  Yes   |                                                               |
+| **Quick sort**     | n&nbsp;log(n) |      n&nbsp;log(n)      |        n<sup>2</sup>        | log(n) |   No   | Quicksort is usually done in-place with O(log(n)) stack space |
+| **Shell sort**     | n&nbsp;log(n) | depends on gap sequence | n&nbsp;(log(n))<sup>2</sup> |   1    |   No   |                                                               |
+| **Counting sort**  |     n + r     |          n + r          |            n + r            | n + r  |  Yes   | r - biggest number in array                                   |
+| **Radix sort**     |    n \* k     |         n \* k          |           n \* k            | n + k  |  Yes   | k - length of longest key                                     |
 
-## Project Backers
+## Project Backers - Nhà tài trợ dự án
 
-> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb).
+> Bạn có thể hỗ trợ dự án này qua ❤️️ [GitHub](https://github.com/sponsors/trekhleb) hoặc ❤️️ [Patreon](https://www.patreon.com/trekhleb).
 
-[Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`
+[Những người đang tài trợ cho dự án này](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`
 
-## Author
+## Author - Tác giả
 
 [@trekhleb](https://trekhleb.dev)
 
-A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
+Thêm một số [dự án](https://trekhleb.dev/projects/) và [bài viết](https://trekhleb.dev/blog/) về JavaScript và thuật toán tại [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.pl-PL.md b/README.pl-PL.md
deleted file mode 100644
index 52ba75a5e4..0000000000
--- a/README.pl-PL.md
+++ /dev/null
@@ -1,294 +0,0 @@
-# JavaScript Algorytmy i Struktury Danych
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-To repozytorium zawiera wiele przykładów JavaScript opartych na
-znanych algorytmach i strukturach danych.
-
-Każdy algorytm i struktura danych zawiera osobny plik README
-wraz z powiązanymi wyjaśnieniami i odnośnikami do dalszego czytania
-(włącznie z tymi do YouTube videos).
-
-_Read this in other languages:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/)
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## Struktury Danych
-
-Struktura danych to sposób uporządkowania i przechowywania informacji w
-komputerze żeby mogłaby być sprawnie dostępna i efektywnie zmodyfikowana.
-Dokładniej, struktura danych jest zbiorem wartości danych, relacjami
-pomiędzy nimi, zadaniami lub działaniami, które mogą dotyczyć danych.
-
-`B` - Początkujący, `A` - Zaawansowany
-
-* `B` [Lista](src/data-structures/linked-list)
-* `B` [Lista Dwukierunkowa](src/data-structures/doubly-linked-list)
-* `B` [Kolejka](src/data-structures/queue)
-* `B` [Stos](src/data-structures/stack)
-* `B` [Tabela Skrótu](src/data-structures/hash-table)
-* `B` [Sterta](src/data-structures/heap)
-* `B` [Kolejka Priorytetowa](src/data-structures/priority-queue)
-* `A` [Trie](src/data-structures/trie)
-* `A` [Drzewo](src/data-structures/tree)
-  * `A` [Wyszukiwanie Binarne](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL Drzewo](src/data-structures/tree/avl-tree)
-  * `A` [Drzewa czerwono-czarne](src/data-structures/tree/red-black-tree)
-  * `A` [Drzewo Segmentu](src/data-structures/tree/segment-tree) - z przykładami zapytań o min / max / sumie sum
-  * `A` [Drzewo Fenwicka](src/data-structures/tree/fenwick-tree) (Drzewo Indeksowane Binarnie)
-* `A` [Graf](src/data-structures/graph) (zarówno skierowane i nieukierunkowane)
-* `A` [Rozłączny Zestaw](src/data-structures/disjoint-set)
-* `A` [Filtr Blooma](src/data-structures/bloom-filter)
-
-## Algorytmy
-
-Algorytm jest to skończony ciąg jasno zdefiniowanych czynności, koniecznych
-do wykonania pewnego rodzaju zadań. Sposób postępowania prowadzący do
-rozwiązania problemu.
-
-`B` - Początkujący, `A` - Zaawansowany
-
-### Algorytmy według tematu
-
-* **Matematyka**
-  * `B` [Manipulacja Bitami](src/algorithms/math/bits) - ustaw / uzyskaj / aktualizuj / usuwaj bity, mnożenie / dzielenie przez dwa, tworzenie negatywów itp.
-  * `B` [Silnia](src/algorithms/math/factorial)
-  * `B` [Ciąg Fibonacciego](src/algorithms/math/fibonacci)
-  * `B` [Test Pierwszorzędności](src/algorithms/math/primality-test) (metoda podziału na próby)
-  * `B` [Algorytm Euclideana](src/algorithms/math/euclidean-algorithm) - obliczyć Największy Wspólny Dzielnik (GCD)
-  * `B` [Najmniejsza Wspólna Wielokrotność](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [Sito Eratosthenes-a](src/algorithms/math/sieve-of-eratosthenes) - znajdowanie wszystkich liczb pierwszych do określonego limitu
-  * `B` [Jest Potęgą Dwójki](src/algorithms/math/is-power-of-two) - sprawdź, czy liczba jest potęgą dwóch (algorytmy naiwne i bitowe)
-  * `B` [Trójkąt Pascala](src/algorithms/math/pascal-triangle)
-  * `A` [Partycja Całkowita](src/algorithms/math/integer-partition)
-  * `A` [Algorytm Liu Huia](src/algorithms/math/liu-hui) - przybliżone obliczenia na podstawie N-gonów
-* **Zestawy**
-  * `B` [Produkt Kartezyjny](src/algorithms/sets/cartesian-product) - wynik wielu zestawów
-  * `B` [Przetasowanie Fisher Yates-a](src/algorithms/sets/fisher-yates) - losowa permutacja kończącej się serii
-  * `A` [Zestaw Zasilający](src/algorithms/sets/power-set) - podzbiór wszystkich serii
-  * `A` [Permutacje](src/algorithms/sets/permutations) (z albo bez powtórzeń)
-  * `A` [Kombinacje](src/algorithms/sets/combinations) (z albo bez powtórzeń)
-  * `A` [Najdłuższa Wspólna Podsekwencja](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Najdłuższa Wzrostająca Podsekwencja](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Najkrótsza Wspólna Supersekwencja](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Problem Knapsacka](src/algorithms/sets/knapsack-problem) - "0/1" i "Rozwiązany"
-  * `A` [Maksymalna Podtablica](src/algorithms/sets/maximum-subarray) - "Metoda Siłowa" i "Dynamiczne Programowanie" (Kadane-a) wersje
-  * `A` [Suma Kombinacji](src/algorithms/sets/combination-sum) -
-znajdź wszystkie kombinacje, które tworzą określoną sumę
-* **Łańcuchy**
-  * `B` [Odległość Hamminga](src/algorithms/string/hamming-distance) - liczba pozycji, w których symbole są różne
-  * `A` [Odległość Levenshteina](src/algorithms/string/levenshtein-distance) - minimalna odległość edycji między dwiema sekwencjami
-  * `A` [Algorytm Knuth–Morris–Pratta](src/algorithms/string/knuth-morris-pratt) (Algorytm KMP) - dopasowywanie wzorców (dopasowywanie wzorców)
-  * `A` [Algorytm Z](src/algorithms/string/z-algorithm) - szukanie podłańcucha(dopasowywanie wzorców)
-  * `A` [Algorytm Rabin Karpa](src/algorithms/string/rabin-karp) - szukanie podłańcucha
-  * `A` [Najdłuższa Wspólna Podłańcucha](src/algorithms/string/longest-common-substring)
-  * `A` [Dopasowanie Wyrażeń Regularnych](src/algorithms/string/regular-expression-matching)
-* **Szukanie**
-  * `B` [Wyszukiwanie Liniowe](src/algorithms/search/linear-search)
-  * `B` [Jump Search](src/algorithms/search/jump-search) (lub Przeszukiwanie Bloku) - szukaj w posortowanej tablicy
-  * `B` [Wyszukiwanie Binarne](src/algorithms/search/binary-search) - szukaj w posortowanej tablicy
-  * `B` [Wyszukiwanie Interpolacyjne](src/algorithms/search/interpolation-search) - szukaj w równomiernie rozłożonej, posortowanej tablicy
-* **Sortowanie**
-  * `B` [Sortowanie bąbelkowe](src/algorithms/sorting/bubble-sort)
-  * `B` [Sortowanie przez wymiane](src/algorithms/sorting/selection-sort)
-  * `B` [Sortowanie przez wstawianie](src/algorithms/sorting/insertion-sort)
-  * `B` [Sortowanie stogowe](src/algorithms/sorting/heap-sort)
-  * `B` [Sortowanie przez scalanie](src/algorithms/sorting/merge-sort)
-  * `B` [Sortowanie szybkie](src/algorithms/sorting/quick-sort) - wdrożenia w miejscu i nie na miejscu
-  * `B` [Sortowanie Shella](src/algorithms/sorting/shell-sort)
-  * `B` [Sortowanie przez zliczanie](src/algorithms/sorting/counting-sort)
-  * `B` [Sortowanie pozycyjne](src/algorithms/sorting/radix-sort)
-* **Drzewa**
-  * `B` [Przeszukiwanie w głąb](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Przeszukiwanie wszerz](src/algorithms/tree/breadth-first-search) (BFS)
-* **Grafy**
-  * `B` [Przeszukiwanie w głąb](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Przeszukiwanie wszerz](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Algorytm Kruskala](src/algorithms/graph/kruskal) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu
-  * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) - znajdowanie  najkrótszej ścieżki z pojedynczego źródła w grafie
-  * `A` [Algorytm Bellmana-Forda](src/algorithms/graph/bellman-ford) - znajdowanie najkrótszych ścieżek do wszystkich wierzchołków wykresu z jednego wierzchołka
-  * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) - znajdź najkrótsze ścieżki między wszystkimi parami wierzchołków
-  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - zarówno dla wykresów skierowanych, jak i nieukierunkowanych(wersje oparte na DFS i Rozłączny Zestaw)
-  * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu
-  * `A` [Sortowanie Topologiczne](src/algorithms/graph/topological-sorting) - metoda DFS
-  * `A` [Punkty Artykulacji](src/algorithms/graph/articulation-points) - Algorytm Tarjana (oparty o DFS)
-  * `A` [Mosty](src/algorithms/graph/bridges) - Oparty na algorytmie DFS
-  * `A` [Ścieżka Euleriana i Obwód Euleriana](src/algorithms/graph/eulerian-path) - Algorytm Fleurya - Odwiedź każdą krawędź dokładnie raz
-  * `A` [Cykl Hamiltoniana](src/algorithms/graph/hamiltonian-cycle) - Odwiedź każdy wierzchołek dokładnie raz
-  * `A` [Silnie Połączone Komponenty](src/algorithms/graph/strongly-connected-components) - Algorytm Kosaraja
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - najkrótsza ścieżka która odwiedza każde miasto i wraca miasta początkującego
-* **Niezkategorizowane**
-  * `B` [Wieża Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Kwadratowa Matryca Obrotu](src/algorithms/uncategorized/square-matrix-rotation) - algorytm w miejscu
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - cofanie, dynamiczne programowanie (od góry do dołu + od dołu do góry) i przykłady chciwego
-  * `B` [Unikatowe Ścieżki](src/algorithms/uncategorized/unique-paths) - cofanie, dynamiczne programowanie i przykłady oparte na Trójkącie Pascala
-  * `A` [Problem N-Queens](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-
-### Algorytmy według paradygmatu
-
-Paradygmat algorytmiczny jest ogólną metodą lub podejściem, które jest
-podstawą projektowania klasy algorytmów. Jest abstrakcją wyższą niż
-pojęcie algorytmu, podobnie jak algorytm jest abstrakcją wyższą niż
-program komputerowy.
-
-* **Metoda Siłowa** - Sprawdza wszystkie możliwosci i wybiera  najlepsze rozwiązanie.
-  * `B` [Wyszukiwanie Liniowe](src/algorithms/search/linear-search)
-  * `A` [Maksymalna Podtablica](src/algorithms/sets/maximum-subarray)
-  * `A` [Problem z Podróżującym Sprzedawcą](src/algorithms/graph/travelling-salesman) - najkrótsza możliwa trasa, która odwiedza każde miasto i wraca do miasta początkowego
-* **Chciwy** - wybierz najlepszą opcję w obecnym czasie, bez względu na przyszłość
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Niezwiązany Problem Knapsacka ](src/algorithms/sets/knapsack-problem)
-  * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) -
-znalezienie najkrótszej ścieżki do wszystkich wierzchołków grafu
-  * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu
-  * `A` [Algorytm Kruskala](src/algorithms/graph/kruskal) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu
-* **Dziel i Zwyciężaj** - podziel problem na mniejsze części, a następnie rozwiąż te części
-  * `B` [Wyszukiwanie Binarne](src/algorithms/search/binary-search)
-  * `B` [Wieża Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Trójkąt Pascala](src/algorithms/math/pascal-triangle)
-  * `B` [Algorytm Euclideana](src/algorithms/math/euclidean-algorithm) - obliczyć Największy Wspólny Dzielnik(GCD)
-  * `B` [Sortowanie przez scalanie](src/algorithms/sorting/merge-sort)
-  * `B` [Szybkie Sortowanie](src/algorithms/sorting/quick-sort)
-  * `B` [Drzewo Przeszukiwania W Głąb](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Graf Przeszukiwania W Głąb](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Permutacje](src/algorithms/sets/permutations) (z albo bez powtórzeń)
-  * `A` [Kombinacje](src/algorithms/sets/combinations) (z albo bez powtórzeń)
-* **Programowanie Dynamiczne** - zbuduj rozwiązanie, korzystając z wcześniej znalezionych podrzędnych rozwiązań
-  * `B` [Ciąg Fibonacciego](src/algorithms/math/fibonacci)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unikatowe Scieżki](src/algorithms/uncategorized/unique-paths)
-  * `A` [Dystans Levenshteina](src/algorithms/string/levenshtein-distance) - minimalna odległość edycji między dwiema sekwencjami
-  * `A` [Najdłuższa Wspólna Podsekwencja](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Najdłuższa Wspólna Podłańcucha](src/algorithms/string/longest-common-substring)
-  * `A` [Najdłuższa Wzrostająca Podsekwencja](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Najkrótsza Wspólna Supersekwencja](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1 Problem Knapsacka](src/algorithms/sets/knapsack-problem)
-  * `A` [Partycja Całkowita](src/algorithms/math/integer-partition)
-  * `A` [Maksymalne Podtablice](src/algorithms/sets/maximum-subarray)
-  * `A` [Algorytm Bellman-Forda](src/algorithms/graph/bellman-ford) - znalezienie najkrótszej ścieżki wszystkich wierzchołków wykresu
-  * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) -
-znajdź najkrótsze ścieżki między wszystkimi parami wierzchołków
-  * `A` [Dopasowanie Wyrażeń Regularnych](src/algorithms/string/regular-expression-matching)
-* **Algorytm z nawrotami** - podobny do metody siłowej, próbuje wygenerować wszystkie możliwe rozwiązania, jednak za każdym razem generujesz następne rozwiązanie które testujesz
-jeżeli zaspokaja wszystkie warunki, tylko wtedy generuje kolejne rozwiązania. W innym wypadku, cofa sie, i podąża inna ścieżka znaleźenia rozwiązania. Zazwyczaj, używane jest przejście przez Przeszukiwania W Głąb(DFS) przestrzeni stanów.
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unikatowe Scieżki](src/algorithms/uncategorized/unique-paths)
-  * `A` [Cykl Hamiltoniana](src/algorithms/graph/hamiltonian-cycle) - Odwiedź każdy wierzchołek dokładnie raz
-  * `A` [Problem N-Queens](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  * `A` [Zestaw Sumy](src/algorithms/sets/combination-sum) - znajduje wszystkie zestawy które tworzą określoną sumę
-* **Metoda Podziału i Ograniczeń** - Pamięta o niskonakładowym rozwiązaniu znalezionym na każdym etapie szukania nawrotu,
-używa kosztu niskonakładowego kosztu, które dotychczas zostało znalezione jako niska granica najmniejszego kosztu
-do rozwiązanie problemu, aby odrzucić cząstkowe rozwiązania o kosztach większych niż niskonakładowe
-rozwiązanie znalezione do tej pory.
-Zazwyczan trajektoria BFS, w połączeniu z trajektorią Przeszukiwania W Głąb (DFS) drzewa przestrzeni stanów jest użyte.
-
-## Jak używać repozytorium
-
-**Zainstaluj wszystkie zależnosci**
-```
-npm install
-```
-
-**Uruchom ESLint**
-
-Możesz to uruchomić aby sprawdzić jakość kodu.
-
-```
-npm run lint
-```
-
-**Uruchom wszystkie testy**
-```
-npm test
-```
-
-**Uruchom testy używając określonej nazwy**
-```
-npm test -- 'LinkedList'
-```
-
-**Playground**
-
-Możesz pociwiczyć ze strukturą danych i algorytmami w `./src/playground/playground.js` zakartotekuj i napisz
-testy do tego w `./src/playground/__test__/playground.test.js`.
-
-Następnie uruchom następującą komendę w celu przetestowania czy twoje kod działa według oczekiwań:
-
-```
-npm test -- 'playground'
-```
-
-## Pomocne informacje
-
-### Źródła
-
-[â–¶ Struktury Danych i Algorytmy na YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Big O Notacja
-
-Kolejność wzrastania algorytmów według Big O notacji.
-
-![Big O grafy](./assets/big-o-graph.png)
-
-Źródło: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Poniżej umieszczamy listę najbardziej używanych Big O notacji i ich porównania wydajności do róznych rozmiarów z wprowadzonych danych.
-
-| Big O notacja  | Obliczenia na 10 elementów   | Obliczenia na 100 elementów   | Obliczenia na 1000 elementów    |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Złożoność operacji struktury danych
-
-| Struktura Danych                | Dostęp    | Szukaj    | Umieszczanie | Usuwanie  | Komentarze   |
-| ------------------------------- | :-------: | :-------: | :----------: | :-------: | :----------- |
-| **Szereg**                      | 1         | n         | n            | n         |              |
-| **Sterta**                      | n         | n         | 1            | 1         |              |
-| **Kolejka**                     | n         | n         | 1            | 1         |              |
-| **Lista Powiązana**             | n         | n         | 1            | 1         |              |
-| **Tablica funkcji mieszanej**   | -         | n         | n            | n         | W wypadku idealnej funkcji skrótu koszt mógłby sie równać O(1) |
-| **Binarne Drzewo Poszukiwań**   | n         | n         | n            | n         | W przypadku zrównoważonych kosztów drzew byłoby O(log(n)) |
-| **B-Drzewo**                    | log(n)    | log(n)    | log(n)       | log(n)    |              |
-| **Drzewa czerwono-czarne**      | log(n)    | log(n)    | log(n)       | log(n)    |              |
-| **AVL Drzewo**                  | log(n)    | log(n)    | log(n)       | log(n)    |              |
-| **Filtr Blooma**                | -         | 1         | 1            | -         | Fałszywe dotatnie są możliwe podczas wyszukiwania |
-
-### Sortowanie Tablic Złożoności Algorytmów
-
-| Nazwa                               | Najlepszy       | Średni              | Najgorszy           | Pamięć    | Stabilność  | Komentarze  |
-| ----------------------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :---------: | :---------- |
-| **Sortowanie bąbelkowe**            | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes         |             |
-| **Sortowanie przez wstawianie**     | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes         |             |
-| **Sortowanie przez wybieranie**     | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No          |             |
-| **Sortowanie przez kopcowanie**     | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No          |             |
-| **Sortowanie przez scalanie**       | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes         |             |
-| **Szybkie sortowanie**              | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No          | Szybkie sortowanie jest zazwyczaj robione w miejsce O(log(n)) stosu przestrzeni |
-| **Sortowanie Shella**               | n&nbsp;log(n)   | zależy od luki w układzie   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
-| **Sortowanie przez zliczanie**      | n + r           | n + r               | n + r               | n + r     | Yes         | r - największy numer w tablicy|
-| **Sortowanie Radix**                | n * k           | n * k               | n * k               | n + k     | Yes         | k -długość najdłuższego klucza |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.pt-BR.md b/README.pt-BR.md
deleted file mode 100644
index a937e8c0bf..0000000000
--- a/README.pt-BR.md
+++ /dev/null
@@ -1,302 +0,0 @@
-# Estrutura de Dados e Algoritmos em JavaScript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Este repositório contém exemplos baseados em JavaScript de muitos
-algoritmos e estruturas de dados populares.
-
-Cada algoritmo e estrutura de dados possui seu próprio README
-com explicações relacionadas e links para leitura adicional (incluindo
-vídeos para YouTube)
-
-_Leia isto em outros idiomas:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/)
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## Estrutura de Dados
-
-Uma estrutura de dados é uma maneira particular de organizar e armazenar dados em um computador para que ele possa
-ser acessado e modificado de forma eficiente. Mais precisamente, uma estrutura de dados é uma coleção de valores de dados, as relações entre eles e as funções ou operações que podem ser aplicadas aos dados.
-
-`B` - Iniciante, `A` - Avançado
-
-* `B` [Lista Encadeada (Linked List)](src/data-structures/linked-list/README.pt-BR.md)
-* `B` [Lista Duplamente Ligada (Doubly Linked List)](src/data-structures/doubly-linked-list/README.pt-BR.md)
-* `B` [Fila (Queue)](src/data-structures/queue/README.pt-BR.md)
-* `B` [Pilha (Stack)](src/data-structures/stack/README.pt-BR.md)
-* `B` [Tabela de Hash (Hash Table)](src/data-structures/hash-table/README.pt-BR.md)
-* `B` [Heap](src/data-structures/heap/README.pt-BR.md) - versões de heap máximo e mínimo
-* `B` [Fila de Prioridade (Priority Queue)](src/data-structures/priority-queue/README.pt-BR.md)
-* `A` [Árvore de Prefixos (Trie)](src/data-structures/trie/README.pt-BR.md)
-* `A` [Árvore (Tree)](src/data-structures/tree/README.pt-BR.md)
-  * `A` [Árvore de Pesquisa Binária (Binary Search Tree)](src/data-structures/tree/binary-search-tree/README.pt-BR.md)
-  * `A` [Árvore AVL (AVL Tree)](src/data-structures/tree/avl-tree/README.pt-BR.md)
-  * `A` [Árvore Rubro-Negra (Red-Black Tree)](src/data-structures/tree/red-black-tree/README.pt-BR.md)
-  * `A` [Árvore de Segmento (Segment Tree)](src/data-structures/tree/segment-tree/README.pt-BR.md) - com exemplos de consultas min / max / sum range
-  * `A` [Árvore Fenwick (Fenwick Tree)](src/data-structures/tree/fenwick-tree/README.pt-BR.md) (Árvore indexada binária)
-* `A` [Grafo (Graph)](src/data-structures/graph/README.pt-BR.md) (ambos dirigidos e não direcionados)
-* `A` [Conjunto Disjunto (Disjoint Set)](src/data-structures/disjoint-set/README.pt-BR.md)
-* `A` [Filtro Bloom (Bloom Filter)](src/data-structures/bloom-filter/README.pt-BR.md)
-
-## Algoritmos
-
-Um algoritmo é uma especificação inequívoca de como resolver uma classe de problemas. Isto é
-um conjunto de regras que define precisamente uma sequência de operações.
-
-`B` - Iniciante, `A` - Avançado
-
-### Algoritmos por Tópico
-
-* **Matemática**
-  * `B` [Manipulação Bit](src/algorithms/math/bits) - set/get/update/clear bits, multiplicação / divisão por dois, tornar negativo etc.
-  * `B` [Fatorial](src/algorithms/math/factorial)
-  * `B` [Número de Fibonacci](src/algorithms/math/fibonacci)
-  * `B` [Teste de Primalidade](src/algorithms/math/primality-test) (método de divisão experimental)
-  * `B` [Algoritmo Euclidiano](src/algorithms/math/euclidean-algorithm) - Calcular o Máximo Divisor Comum (MDC)
-  * `B` [Mínimo Múltiplo Comum](src/algorithms/math/least-common-multiple) Calcular o Mínimo Múltiplo Comum (MMC)
-  * `B` [Peneira de Eratóstenes](src/algorithms/math/sieve-of-eratosthenes) - Encontrar todos os números primos até um determinado limite
-  * `B` [Potência de Dois](src/algorithms/math/is-power-of-two) - Verifique se o número é a potência de dois (algoritmos ingênuos e bit a bit)
-  * `B` [Triângulo de Pascal](src/algorithms/math/pascal-triangle)
-  * `B` [Número Complexo](src/algorithms/math/complex-number) - Números complexos e operações básicas com eles
-  * `A` [Partição Inteira](src/algorithms/math/integer-partition)
-  * `A` [Algoritmo Liu Hui π](src/algorithms/math/liu-hui) - Cálculos aproximados de π baseados em N-gons
-* **Conjuntos**
-  * `B` [Produto Cartesiano](src/algorithms/sets/cartesian-product) - Produto de vários conjuntos
-  * `B` [Permutações de Fisher–Yates](src/algorithms/sets/fisher-yates) - Permutação aleatória de uma sequência finita
-  * `A` [Potência e Conjunto](src/algorithms/sets/power-set) - Todos os subconjuntos de um conjunto
-  * `A` [Permutações](src/algorithms/sets/permutations) (com e sem repetições)
-  * `A` [Combinações](src/algorithms/sets/combinations) (com e sem repetições)
-  * `A` [Mais Longa Subsequência Comum](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Maior Subsequência Crescente](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Supersequência Comum Mais Curta](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem) - "0/1" e "Não consolidado"
-  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray) - "Força bruta" e "Programação Dinâmica", versões de Kadane
-  * `A` [Soma de Combinação](src/algorithms/sets/combination-sum) - Encontre todas as combinações que formam uma soma específica
-* **Cadeia de Caracteres**
-  * `B` [Distância de Hamming](src/algorithms/string/hamming-distance) - Número de posições em que os símbolos são diferentes
-  * `B` [Palíndromos](src/algorithms/string/palindrome) - Verifique se a cadeia de caracteres (string) é a mesma ao contrário
-  * `A` [Distância Levenshtein](src/algorithms/string/levenshtein-distance) - Distância mínima de edição entre duas sequências
-  * `A` [Algoritmo Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritmo KMP) - Pesquisa de substring (correspondência de padrão)
-  * `A` [Z Algorithm](src/algorithms/string/z-algorithm) - Pesquisa de substring (correspondência de padrão)
-  * `A` [Algoritmo de Rabin Karp](src/algorithms/string/rabin-karp) - Pesquisa de substring
-  * `A` [Substring Comum Mais Longa](src/algorithms/string/longest-common-substring)
-  * `A` [Expressões Regulares Correspondentes](src/algorithms/string/regular-expression-matching)
-* **Buscas**
-  * `B` [Busca Linear (Linear Search)](src/algorithms/search/linear-search)
-  * `B` [Busca por Saltos (Jump Search)](src/algorithms/search/jump-search) - Pesquisa em matriz ordenada
-  * `B` [Busca Binária (Binary Search)](src/algorithms/search/binary-search) - Pesquisa em matriz ordenada
-  * `B` [Busca por Interpolação (Interpolation Search)](src/algorithms/search/interpolation-search) - Pesquisa em matriz classificada uniformemente distribuída
-* **Classificação**
-  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)
-  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)
-  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)
-  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - Implementações local e não local
-  * `B` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)
-  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)
-* **Árvores**
-  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/tree/breadth-first-search) (BFS)
-* **Grafos**
-  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - Encontrando Árvore Mínima de Abrangência (MST) para grafo conexo com pesos
-  * `A` [Algoritmo de Dijkstra](src/algorithms/graph/dijkstra) - Encontrar caminhos mais curtos para todos os vértices do grafo a partir de um único vértice
-  * `A` [Algoritmo de Bellman-Ford](src/algorithms/graph/bellman-ford) - Encontrar caminhos mais curtos para todos os vértices do grafo a partir de um único vértice
-  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - Encontrar caminhos mais curtos entre todos os pares de vértices
-  * `A` [Detectar Ciclo](src/algorithms/graph/detect-cycle) - Para grafos direcionados e não direcionados (versões baseadas em DFS e Conjunto Disjuntivo)
-  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - Encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado
-  * `A` [Ordenação Topológica](src/algorithms/graph/topological-sorting) - Métodos DFS
-  * `A` [Pontos de Articulação](src/algorithms/graph/articulation-points) - O algoritmo de Tarjan (baseado em DFS)
-  * `A` [Pontes](src/algorithms/graph/bridges) - Algoritmo baseado em DFS
-  * `A` [Caminho e Circuito Euleriano](src/algorithms/graph/eulerian-path) - Algoritmo de Fleury - Visite todas as bordas exatamente uma vez
-  * `A` [Ciclo Hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - Visite todas as bordas exatamente uma vez
-  * `A` [Componentes Fortemente Conectados](src/algorithms/graph/strongly-connected-components) - Algoritmo de Kosaraju
-  * `A` [Problema do Caixeiro Viajante](src/algorithms/graph/travelling-salesman) - Rota mais curta possível que visita cada cidade e retorna à cidade de origem
-* **Criptografia**
-  * `B` [Hash Polinomial](src/algorithms/cryptography/polynomial-hash) - Função de hash de rolagem baseada em polinômio
-* **Sem categoria**
-  * `B` [Torre de Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Rotação de Matriz Quadrada](src/algorithms/uncategorized/square-matrix-rotation) - Algoritmo no local
-  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game) - Backtracking, programação dinâmica (top-down + bottom-up) e exemplos gananciosos
-  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths) - Backtracking, programação dinâmica e exemplos baseados no triângulo de Pascal
-  * `B` [Terraços de Chuva](src/algorithms/uncategorized/rain-terraces) - Problema de retenção da água da chuva (programação dinâmica e versões de força bruta)
-  * `A` [Problema das N-Rainhas](src/algorithms/uncategorized/n-queens)
-  * `A` [Passeio do Cavaleiro](src/algorithms/uncategorized/knight-tour)
-
-### Algoritmos por Paradigma
-
-Um paradigma algorítmico é um método ou abordagem genérica subjacente ao design de uma classe
-de algoritmos. É uma abstração maior do que a noção de um algoritmo, assim como
-algoritmo é uma abstração maior que um programa de computador.
-
-* **Força bruta** - Pense em todas as possibilidades e escolha a melhor solução
-  * `B` [Busca Linear (Linear Search)](src/algorithms/search/linear-search)
-  * `B` [Terraços de Chuva](src/algorithms/uncategorized/rain-terraces) - Problema de retenção de água da chuva (programação dinâmica e versões de força bruta)
-  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray)
-  * `A` [Problema do Caixeiro Viajante](src/algorithms/graph/travelling-salesman) - Rota mais curta possível que visita cada cidade e retorna à cidade de origem
-* **Ganância** - Escolha a melhor opção no momento, sem qualquer consideração pelo futuro
-  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)
-  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem)
-  * `A` [Algoritmo de Dijkstra](src/algorithms/graph/dijkstra) - Encontrar caminhos mais curtos para todos os vértices do grafo a partir de um único vértice
-  * `A` [Algoritmo de Prim](src/algorithms/graph/prim) - Encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado
-  * `A` [Algoritmo de Kruskal](src/algorithms/graph/kruskal) - Encontrando Árvore Mínima de Abrangência (MST) para grafo conexo com pesos
-* **Dividir e Conquistar** - Dividir o problema em partes menores e então resolver essas partes
-  * `B` [Busca Binária (Binary Search)](src/algorithms/search/binary-search)
-  * `B` [Torre de Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Triângulo de Pascal](src/algorithms/math/pascal-triangle)
-  * `B` [Algoritmo Euclidiano](src/algorithms/math/euclidean-algorithm) - Calcular o Máximo Divisor Comum (MDC)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `B` [Busca em Profundidade (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Busca em Largura (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)
-  * `A` [Permutações](src/algorithms/sets/permutations) (com e sem repetições)
-  * `A` [Combinações](src/algorithms/sets/combinations) (com e sem repetições)
-* **Programação Dinâmica** - Criar uma solução usando sub-soluções encontradas anteriormente
-  * `B` [Número de Fibonacci](src/algorithms/math/fibonacci)
-  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)
-  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths)
-  * `B` [Terraços de Chuva](src/algorithms/uncategorized/rain-terraces) - Trapping problema da água da chuva
-  * `A` [Distância Levenshtein](src/algorithms/string/levenshtein-distance) - Distância mínima de edição entre duas sequências
-  * `A` [Mais Longa Subsequência Comum](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Substring Comum Mais Longa](src/algorithms/string/longest-common-substring)
-  * `A` [Maior Subsequência Crescente](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Supersequência Comum Mais Curta](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Problema da Mochila](src/algorithms/sets/knapsack-problem)
-  * `A` [Partição Inteira](src/algorithms/math/integer-partition)
-  * `A` [Subarray Máximo](src/algorithms/sets/maximum-subarray)
-  * `A` [Algoritmo de Bellman-Ford](src/algorithms/graph/bellman-ford) - Encontrar caminhos mais curtos para todos os vértices do grafo a partir de um único vértice
-  * `A` [Algoritmo de Floyd-Warshall](src/algorithms/graph/floyd-warshall) - Encontrar caminhos mais curtos entre todos os pares de vértices
-  * `A` [Expressões Regulares Correspondentes](src/algorithms/string/regular-expression-matching)
-* **Backtracking** - Da mesma forma que a força bruta, tente gerar todas as soluções possíveis, mas, cada vez que você gerar a próxima solução será necessário testar se a mesma satisfaz todas as condições, e só então continuará a gerar as soluções subsequentes. Caso contrário, volte atrás e siga um caminho diferente para encontrar uma solução. Normalmente, a passagem DFS do espaço de estados está sendo usada.
-  * `B` [Jogo do Salto](src/algorithms/uncategorized/jump-game)
-  * `B` [Caminhos Únicos](src/algorithms/uncategorized/unique-paths)
-  * `A` [Ciclo Hamiltoniano](src/algorithms/graph/hamiltonian-cycle) - Visite todos os vértices exatamente uma vez
-  * `A` [Problema das N-Rainhas](src/algorithms/uncategorized/n-queens)
-  * `A` [Passeio do Cavaleiro](src/algorithms/uncategorized/knight-tour)
-  * `A` [Soma de Combinação](src/algorithms/sets/combination-sum) - Encontre todas as combinações que formam uma soma específica
-* **Branch & Bound** - Lembre-se da solução de menor custo encontrada em cada etapa do retrocesso, pesquisar e usar o custo da solução de menor custo encontrada até o limite inferior do custo de
-solução de menor custo para o problema, a fim de descartar soluções parciais com custos maiores que o
-solução de menor custo encontrada até o momento. Normalmente, a travessia BFS em combinação com a passagem DFS do espaço de estados
-árvore está sendo usada
-
-## Como usar este repositório
-
-**Instalar todas as dependências**
-```
-npm install
-```
-
-**Executar o ESLint**
-
-Você pode querer executá-lo para verificar a qualidade do código.
-
-```
-npm run lint
-```
-
-**Execute todos os testes**
-```
-npm test
-```
-
-**Executar testes por nome**
-```
-npm test -- 'LinkedList'
-```
-**Solução de problemas**
-
-Caso o linting ou o teste estejam falhando, tente excluir a pasta node_modules e reinstalar os pacotes npm:
-```
-rm -rf ./node_modules
-npm i
-```
-
-Verifique também se você está usando uma versão correta do Node (>=14.16.0). Se você estiver usando [nvm](https://github.com/nvm-sh/nvm) para gerenciamento de versão do Node, você pode executar `nvm use` a partir da pasta raiz do projeto e a versão correta será escolhida.
-
-**Playground**
-
-Você pode brincar com estruturas de dados e algoritmos no arquivo `./src/playground/playground.js` e escrever
-testes para isso em `./src/playground/__test__/playground.test.js`.
-
-Em seguida, basta executar o seguinte comando para testar se o código do seu playground funciona conforme o esperado:
-
-```
-npm test -- 'playground'
-```
-
-## Informação útil
-
-### Referências
-
-- [▶ Estruturas de Dados e Algoritmos no YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [✍🏻 Esboços de Estruturas de Dados](https://okso.app/showcase/data-structures)
-
-### Notação Big O
-
-A notação Big O é usada para classificar algoritmos de acordo com a forma como seu tempo de execução ou requisitos de espaço crescem à medida que o tamanho da entrada aumenta. No gráfico abaixo você pode encontrar as ordens mais comuns de crescimento de algoritmos especificados na notação Big O.
-
-![Notação Big-O](./assets/big-o-graph.png)
-
-Fonte: [Notação Big-O Dicas](http://bigocheatsheet.com/).
-
-Abaixo está a lista de algumas das notações Big O mais usadas e suas comparações de desempenho em relação aos diferentes tamanhos dos dados de entrada.
-
-| Notação Big-O  | Cálculos para 10 elementos   | Cálculos para 100 elementos   | Cálculos para 1000 elementos    |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Complexidade de operações de estrutura de dados
-
-| Estrutura de dados      | Acesso    | Busca     | Inserção  | Eliminação | Comentários |
-| ----------------------- | :-------: | :-------: | :-------: | :-------:  | :--------   |
-| **Array**               | 1         | n         | n         | n          |             |
-| **Stack**               | n         | n         | 1         | 1          |             |
-| **Queue**               | n         | n         | 1         | 1          |             |
-| **Linked List**         | n         | n         | 1         | 1          |             |
-| **Hash Table**          | -         | n         | n         | n          | Em caso de uma função hash perfeita, os custos seriam O(1) |
-| **Binary Search Tree**  | n         | n         | n         | n          | No caso de custos de árvore equilibrados seria O(log(n))
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)     |             |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)     |             |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)     |             |
-| **Bloom Filter**        | -         | 1         | 1         | -          | Falsos positivos são possíveis durante a pesquisa |
-
-### Complexidade dos Algoritmos de Ordenação de Matrizes
-
-| Nome                  | Melhor          | Média               | Pior                | Mémoria   | Estável   | Comentários |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :--------   |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |             |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |             |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Não       |             |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Não       |             |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Sim       |             |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Não       | O Quicksort geralmente é feito no local com espaço de pilha O(log(n)) |
-| **Shell sort**        | n&nbsp;log(n)   | depende da sequência de lacunas | n&nbsp;(log(n))<sup>2</sup>     | 1      | Não    |                   |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Sim       | r - maior número na matriz          |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Sim       | k - comprimento da chave mais longa |
-
-> ℹ️ Outros [projetos](https://trekhleb.dev/projects/) e [artigos](https://trekhleb.dev/blog/) sobre JavaScript e algoritmos em [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.ru-RU.md b/README.ru-RU.md
deleted file mode 100644
index 541e1d2703..0000000000
--- a/README.ru-RU.md
+++ /dev/null
@@ -1,320 +0,0 @@
-# Алгоритмы и структуры данных на JavaScript
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-В этом репозитории содержатся базовые JavaScript-примеры многих популярных алгоритмов и структур данных.
-
-Для каждого алгоритма и структуры данных есть свой файл README с соответствующими пояснениями и ссылками на материалы для дальнейшего изучения (в том числе и ссылки на видеоролики в YouTube).
-
-_Читать на других языках:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).*
-
-## Структуры данных
-
-Структура данных (англ. data structure) — программная единица, позволяющая хранить и обрабатывать множество однотипных и/или логически связанных данных в вычислительной технике. Для добавления, поиска, изменения и удаления данных структура данных предоставляет некоторый набор функций, составляющих её интерфейс.
-
-`B` - Базовый уровень, `A` - Продвинутый уровень
-
-* `B` [Связный список](src/data-structures/linked-list)
-* `B` [Двунаправленный связный список](src/data-structures/doubly-linked-list)
-* `B` [Очередь](src/data-structures/queue)
-* `B` [Стек](src/data-structures/stack)
-* `B` [Хеш-таблица](src/data-structures/hash-table)
-* `B` [Куча](src/data-structures/heap) — максимальная и минимальная версии
-* `B` [Очередь с приоритетом](src/data-structures/priority-queue)
-* `A` [Префиксное дерево](src/data-structures/trie)
-* `A` [Деревья](src/data-structures/tree)
-  * `A` [Двоичное дерево поиска](src/data-structures/tree/binary-search-tree)
-  * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree)
-  * `A` [Красно-чёрное дерево](src/data-structures/tree/red-black-tree)
-  * `A` [Дерево отрезков](src/data-structures/tree/segment-tree) — для минимума, максимума и суммы отрезков
-  * `A` [Дерево Фенвика](src/data-structures/tree/fenwick-tree) (двоичное индексированное дерево)
-* `A` [Граф](src/data-structures/graph) (ориентированный и неориентированный)
-* `A` [Система непересекающихся множеств](src/data-structures/disjoint-set)
-* `A` [Фильтр Блума](src/data-structures/bloom-filter)
-
-## Алгоритмы
-
-Алгоритм — конечная совокупность точно заданных правил решения некоторого класса задач или набор инструкций, описывающих порядок действий исполнителя для решения некоторой задачи.
-
-`B` - Базовый уровень, `A` - Продвинутый уровень
-
-### Алгоритмы по тематике
-
-* **Математика**
-  * `B` [Битовые манипуляции](src/algorithms/math/bits) — получение/запись/сброс/обновление битов, умножение/деление на 2, сделать отрицательным и т.п.
-  * `B` [Двоичное число с плавающей запятой](src/algorithms/math/binary-floating-point) - двоичное представление чисел с плавающей запятой
-  * `B` [Факториал](src/algorithms/math/factorial)
-  * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci) — классическое решение, решение в замкнутой форме
-  * `B` [Простые множители](src/algorithms/math/prime-factors) - нахождение простых множителей и их подсчёт с использованием теоремы Харди-Рамануджана
-  * `B` [Тест простоты](src/algorithms/math/primality-test) (метод пробного деления)
-  * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД)
-  * `B` [Наименьшее общее кратное](src/algorithms/math/least-common-multiple) (НОК)
-  * `B` [Решето Эратосфена](src/algorithms/math/sieve-of-eratosthenes) — нахождение всех простых чисел до некоторого целого числа n
-  * `B` [Степень двойки](src/algorithms/math/is-power-of-two) — является ли число степенью двойки (простое и побитовое решения)
-  * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle)
-  * `B` [Комплексные числа](src/algorithms/math/complex-number) — комплексные числа, базовые операции над ними
-  * `B` [Радианы и градусы](src/algorithms/math/radian) — конвертирование радианов в градусы и наоборот
-  * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering)
-  * `B` [Схема Горнера](src/algorithms/math/horner-method) - оценка полиномов
-  * `B` [Матрицы](src/algorithms/math/matrix) - матрицы и основные операции с матрицами (умножение, транспонирование и т.д.)
-  * `B` [Евклидово расстояние](src/algorithms/math/euclidean-distance) - расстояние между двумя точками/векторами/матрицами
-  * `A` [Разбиение числа](src/algorithms/math/integer-partition)
-  * `A` [Квадратный корень](src/algorithms/math/square-root) — метод Ньютона
-  * `A` [Алгоритм Лю Хуэя](src/algorithms/math/liu-hui) — расчёт числа π с заданной точностью методом вписанных правильных многоугольников
-  * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие
-* **Множества**
-  * `B` [Декартово произведение](src/algorithms/sets/cartesian-product) — результат перемножения множеств
-  * `B` [Тасование Фишера — Йетса](src/algorithms/sets/fisher-yates) — создание случайных перестановок конечного множества
-  * `A` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества (побитовый поиск и поиск с возвратом)
-  * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений)
-  * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений)
-  * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence)
-  * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Наименьшая общая супер-последовательность](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Задача о рюкзаке](src/algorithms/sets/knapsack-problem) — "0/1" и "неограниченный" рюкзаки
-  * `A` [Максимальный под-массив](src/algorithms/sets/maximum-subarray) — метод полного перебора и алгоритм Кадане
-  * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу
-* **Алгоритмы работы со строками**
-  * `B` [Расстояние Хэмминга](src/algorithms/string/hamming-distance) — число позиций, в которых соответствующие символы различны
-  * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями
-  * `A` [Алгоритм Кнута — Морриса — Пратта](src/algorithms/string/knuth-morris-pratt) — поиск подстроки (сопоставление с шаблоном)
-  * `A` [Z-функция](src/algorithms/string/z-algorithm) — поиск подстроки (сопоставление с шаблоном)
-  * `A` [Алгоритм Рабина — Карпа](src/algorithms/string/rabin-karp) — поиск подстроки
-  * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring)
-  * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching)
-* **Алгоритмы поиска**
-  * `B` [Линейный поиск](src/algorithms/search/linear-search)
-  * `B` [Поиск с перескоком](src/algorithms/search/jump-search) (поиск блоков) — поиск в упорядоченном массиве
-  * `B` [Двоичный поиск](src/algorithms/search/binary-search) — поиск в упорядоченном массиве
-  * `B` [Интерполяционный поиск](src/algorithms/search/interpolation-search) — поиск в равномерно распределённом упорядоченном массиве.
-* **Алгоритмы сортировки**
-  * `B` [Сортировка пузырьком](src/algorithms/sorting/bubble-sort)
-  * `B` [Сортировка выбором](src/algorithms/sorting/selection-sort)
-  * `B` [Сортировка вставками](src/algorithms/sorting/insertion-sort)
-  * `B` [Пирамидальная сортировка (сортировка кучей)](src/algorithms/sorting/heap-sort)
-  * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort)
-  * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort) — с использованием дополнительной памяти и без её использования
-  * `B` [Сортировка Шелла](src/algorithms/sorting/shell-sort)
-  * `B` [Сортировка подсчётом](src/algorithms/sorting/counting-sort)
-  * `B` [Поразрядная сортировка](src/algorithms/sorting/radix-sort)
-* **Связный список**
-  * `B` [Прямой обход](src/algorithms/linked-list/traversal)
-  * `B` [Обратный обход](src/algorithms/linked-list/reverse-traversal)
-* **Деревья**
-  * `B` [Поиск в глубину](src/algorithms/tree/depth-first-search)
-  * `B` [Поиск в ширину](src/algorithms/tree/breadth-first-search)
-* **Графы**
-  * `B` [Поиск в глубину](src/algorithms/graph/depth-first-search)
-  * `B` [Поиск в ширину](src/algorithms/graph/breadth-first-search)
-  * `B` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа
-  * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных
-  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — нахождение кратчайших путей от одной из вершин графа до всех остальных
-  * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших расстояний между всеми вершинами графа
-  * `A` [Задача нахождения цикла](src/algorithms/graph/detect-cycle) — для ориентированных и неориентированных графов (на основе поиска в глубину и системы непересекающихся множеств)
-  * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа
-  * `A` [Топологическая сортировка](src/algorithms/graph/topological-sorting) — на основе поиска в глубину
-  * `A` [Шарниры (разделяющие вершины)](src/algorithms/graph/articulation-points) — алгоритм Тарьяна (на основе поиска в глубину)
-  * `A` [Мосты](src/algorithms/graph/bridges) — на основе поиска в глубину
-  * `A` [Эйлеров путь и Эйлеров цикл](src/algorithms/graph/eulerian-path) — алгоритм Флёри (однократное посещение каждой вершины)
-  * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз
-  * `A` [Компоненты сильной связности](src/algorithms/graph/strongly-connected-components) — алгоритм Косарайю
-  * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город
-* **Криптография**
-  * `B` [Полиноминальный хэш](src/algorithms/cryptography/polynomial-hash) — функция кольцевого хэша, основанная на полиноме
-  * `B` [Шифр ​​ограждения рельсов](src/algorithms/cryptography/rail-fence-cipher) - алгоритм транспозиционного шифра для кодирования сообщений
-  * `B` [Шифр Цезаря](src/algorithms/cryptography/caesar-cipher) - простой подстановочный шифр
-  * `B` [Шифр Хилла](src/algorithms/cryptography/hill-cipher) - подстановочный шифр на основе линейной алгебры
-* **Машинное обучение**
-  * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) — 7 простых JavaScript функций, отображающих способности машины к обучению (прямое и обратное распространение)
-  * `B` [k-NN](src/algorithms/ml/knn) - алгоритм классификации k-ближайших соседей
-  * `B` [k-Means](src/algorithms/ml/k-means) - алгоритм кластеризации по методу k-средних
-* **Обработка изображений**
-  * `B` [Резьба по шву](src/algorithms/image-processing/seam-carving) - алгоритм изменения размера изображения с учетом содержания
-* **Статистика**
-  * `B` [Взвешенная случайность](src/algorithms/statistics/weighted-random) - выбор случайного элемента из списка на основе веса элементов
-* **Эволюционные алгоритмы**
-  * `A` [Генетический алгоритм](https://github.com/trekhleb/self-parking-car-evolution) - пример применения генетического алгоритма для обучения самопаркующихся автомобилей
-* **Прочие алгоритмы**
-  * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Поворот квадратной матрицы](src/algorithms/uncategorized/square-matrix-rotation) — используется дополнительная память
-  * `B` [Прыжки](src/algorithms/uncategorized/jump-game) — на основе бэктрекинга, динамического программирования (сверху-вниз + снизу-вверх) и жадных алгоритмов
-  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) — на основе бэктрекинга, динамического программирования и треугольника Паскаля
-  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) — на основе перебора и динамического программирования
-  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы (4 способа)
-  * `B` [Лучшее время для покупки и продажи акций](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - примеры "разделяй и властвуй" и в один проход
-  * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens)
-  * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour)
-
-### Алгоритмы по парадигме программирования
-
-Парадигма программирования — общий метод или подход, лежащий в основе целого класса алгоритмов. Понятие "парадигма программирования" является более абстрактным по отношению к понятию "алгоритм", которое в свою очередь является более абстрактным по отношению к понятию "компьютерная программа".
-
-* **Алгоритмы полного перебора** — поиск лучшего решения исчерпыванием всевозможных вариантов
-  * `B` [Линейный поиск](src/algorithms/search/linear-search)
-  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces)
-  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы
-  * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray)
-  * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город
-  * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие
-* **Жадные алгоритмы** — принятие локально оптимальных решений с учётом допущения об оптимальности конечного решения
-  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)
-  * `A` [Задача о неограниченном рюкзаке](src/algorithms/sets/knapsack-problem)
-  * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных
-  * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа
-  * `A` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа
-* **Разделяй и властвуй** — рекурсивное разбиение решаемой задачи на более мелкие
-  * `B` [Двоичный поиск](src/algorithms/search/binary-search)
-  * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle)
-  * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД)
-  * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort)
-  * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort)
-  * `B` [Поиск в глубину (дерево)](src/algorithms/tree/depth-first-search)
-  * `B` [Поиск в глубину (граф)](src/algorithms/graph/depth-first-search)
-  * `B` [Матрицы](src/algorithms/math/matrix) - генерирование и обход матриц различной формы
-  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)
-  * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering)
-  * `B` [Лучшее время для покупки и продажи акций](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - примеры "разделяй и властвуй" и в один проход
-  * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений)
-  * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений)
-* **Динамическое программирование** — решение общей задачи конструируется на основе ранее найденных решений подзадач
-  * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci)
-  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)
-  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths)
-  * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces)
-  * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы
-  * `B` [Резьба по шву](src/algorithms/image-processing/seam-carving) - алгоритм изменения размера изображения с учетом содержания
-  * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями
-  * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence)
-  * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring)
-  * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Наименьшая общая суперпоследовательность](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Рюкзак 0-1](src/algorithms/sets/knapsack-problem)
-  * `A` [Разбиение числа](src/algorithms/math/integer-partition)
-  * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray)
-  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — поиск кратчайшего пути во взвешенном графе
-  * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших путей от одной из вершин графа до всех остальных
-  * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching)
-* **Поиск с возвратом (бэктрекинг)** — при поиске решения многократно делается попытка расширить текущее частичное решение. Если расширение невозможно, то происходит возврат к предыдущему более короткому частичному решению, и делается попытка его расширить другим возможным способом. Обычно используется обход пространства состояний в глубину.
-  * `B` [Прыжки](src/algorithms/uncategorized/jump-game)
-  * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths)
-  * `B` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества
-  * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз
-  * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens)
-  * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour)
-  * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу
-* **Метод ветвей и границ** — основан на упорядоченном переборе решений и рассмотрении только тех из них, которые являются перспективными (по тем или иным признакам) и отбрасывании бесперспективных множеств решений. Обычно используется обход в ширину в совокупности с обходом дерева пространства состояний в глубину.
-
-## Как использовать этот репозиторий
-
-**Установка всех зависимостей**
-```
-npm install
-```
-
-**Запуск ESLint**
-
-Эта команда может потребоваться вам для проверки качества кода.
-
-```
-npm run lint
-```
-
-**Запуск всех тестов**
-
-```
-npm test
-```
-
-**Запуск определённого теста**
-
-```
-npm test -- 'LinkedList'
-```
-
-**Песочница**
-
-Вы можете экспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js`
-(файл `./src/playground/__test__/playground.test.js` предназначен для написания тестов).
-
-Для проверки работоспособности вашего кода используйте команду:
-
-```
-npm test -- 'playground'
-```
-
-## Полезная информация
-
-### Ссылки
-
-[▶ О структурах данных и алгоритмах](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Нотация «О» большое
-
-*Нотация «О» большое* используется для классификации алгоритмов в соответствии с ростом времени выполнения и затрачиваемой памяти при увеличении размера входных данных. На диаграмме ниже представлены общие порядки роста алгоритмов в соответствии с нотацией «О» большое.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-Источник: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Ниже представлены часто используемые обозначения в нотации «О» большое, а также сравнение их производительностей на различных размерах входных данных.
-
-| Нотация «О» большое | 10 элементов | 100 элементов | 1000 элементов |
-| ------------------- | ------------ | ------------- | -------------- |
-| **O(1)**            | 1            | 1             | 1              |
-| **O(log N)**        | 3            | 6             | 9              |
-| **O(N)**            | 10           | 100           | 1000           |
-| **O(N log N)**      | 30           | 600           | 9000           |
-| **O(N^2)**          | 100          | 10000         | 1000000        |
-| **O(2^N)**          | 1024         | 1.26e+29      | 1.07e+301      |
-| **O(N!)**           | 3628800      | 9.3e+157      | 4.02e+2567     |
-
-### Сложности операций в структурах данных
-
-| Структура данных           | Получение | Поиск     | Вставка   | Удаление  | Комментарии |
-| -------------------------- | :-------: | :-------: | :-------: | :-------: | :---------- |
-| **Массив**                 | 1         | n         | n         | n         |             |
-| **Стек**                   | n         | n         | 1         | 1         |             |
-| **Очередь**                | n         | n         | 1         | 1         |             |
-| **Связный список**         | n         | n         | 1         | n         |             |
-| **Хеш-таблица**            | -         | n         | n         | n         | Для идеальной хеш-функции — O(1) |
-| **Двоичное дерево поиска** | n         | n         | n         | n         | В сбалансированном дереве — O(log(n)) |
-| **B-дерево**               | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Красно-чёрное дерево**   | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **АВЛ-дерево**             | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Фильтр Блума**           | -         | 1         | 1         | -         | Возможно получение ложно-положительного срабатывания |
-
-### Сложности алгоритмов сортировки
-
-| Наименование               | Лучший случай | Средний случай | Худший случай | Память | Устойчивость | Комментарии |
-| -------------------------- | :-----------: | :------------: | :-----------: | :----: | :----------: | :---------- |
-| **Сортировка пузырьком**   | n             | n<sup>2</sup>  | n<sup>2</sup> | 1      | Да           |             |
-| **Сортировка вставками**   | n             | n<sup>2</sup>  | n<sup>2</sup> | 1      | Да           |             |
-| **Сортировка выбором**     | n<sup>2</sup> | n<sup>2</sup>  | n<sup>2</sup> | 1      | Нет          |             |
-| **Сортировка кучей**       | n&nbsp;log(n) | n&nbsp;log(n)  | n&nbsp;log(n) | 1      | Нет          |             |
-| **Сортировка слиянием**    | n&nbsp;log(n) | n&nbsp;log(n)  | n&nbsp;log(n) | n      | Да           |             |
-| **Быстрая сортировка**     | n&nbsp;log(n) | n&nbsp;log(n)  | n<sup>2</sup> | log(n) | Нет          | Быстрая сортировка обычно выполняется с использованием O(log(n)) дополнительной памяти |
-| **Сортировка Шелла**       | n&nbsp;log(n) | зависит от выбранных шагов | n&nbsp;(log(n))<sup>2</sup>  | 1      | Нет          |           |
-| **Сортировка подсчётом**   | n + r         | n + r          | n + r         | n + r  | Да           | r — наибольшее число в массиве |
-| **Поразрядная сортировка** | n * k         | n * k          | n * k         | n + k  | Да           | k — длина самого длинного ключа |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.tr-TR.md b/README.tr-TR.md
deleted file mode 100644
index 805bf7b431..0000000000
--- a/README.tr-TR.md
+++ /dev/null
@@ -1,323 +0,0 @@
-# JavaScript Algoritmalar ve Veri Yapıları
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Bu repository popüler algoritmaların ve veri yapılarının birçoğunun Javascript tabanlı örneklerini bulundurur.
-
-Her bir algoritma ve veri yapısı kendine
-ait açıklama ve videoya sahip README dosyası içerir.
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış
-olup üretim için **yapılmamıştır**.*
-
-## Veri Yapıları
-
-Bir veri yapısı, verileri bir bilgisayarda organize etmenin ve depolamanın belirli bir yoludur, böylece
-verimli bir şekilde erişilebilir ve değiştirilebilir. Daha iyi ifadeyle, bir veri yapısı bir veri koleksiyonudur,
-aralarındaki ilişkiler, ve işlevler veya işlemler
-veriye uygulanabilir.
-
-`B` - Başlangıç, `A` - İleri Seviye
-
-* `B` [Bağlantılı Veri Yapısı](src/data-structures/linked-list)
-* `B` [Çift Yönlü Bağlı Liste](src/data-structures/doubly-linked-list)
-* `B` [Kuyruk](src/data-structures/queue)
-* `B` [Yığın](src/data-structures/stack)
-* `B` [Hash Table](src/data-structures/hash-table)
-* `B` [Heap](src/data-structures/heap) - max and min heap versions
-* `B` [Öncelikli Kuyruk](src/data-structures/priority-queue)
-* `A` [Trie](src/data-structures/trie)
-* `A` [Ağaç](src/data-structures/tree)
-  * `A` [İkili Arama Ağaçları](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL Tree](src/data-structures/tree/avl-tree)
-  * `A` [Red-Black Tree](src/data-structures/tree/red-black-tree)
-  * `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples
-  * `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-* `A` [Graph](src/data-structures/graph) (both directed and undirected)
-* `A` [Disjoint Set](src/data-structures/disjoint-set)
-* `A` [Bloom Filter](src/data-structures/bloom-filter)
-
-## Algoritmalar
-
-Bir algoritma, bir problem sınıfının nasıl çözüleceğine dair kesin bir tanımlamadır.
-Bir işlem dizisini açık olarak tanımlayan kurallar dizisidir.
-
-
-`B` - Başlangıç, `A` - İleri Seviye
-
-### Konusuna göre Algoritma
-
-* **Matematik**
-  * `B` [Bit Manipülasyonu](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.
-  * `B` [İkili Kayan Nokta](src/algorithms/math/binary-floating-point) - kayan noktalı sayıların ikilik sistemde gösterimi.
-  * `B` [Faktöriyel](src/algorithms/math/factorial)
-  * `B` [Fibonacci Sayısı](src/algorithms/math/fibonacci) - klasik ve kapalı-form versiyonları
-  * `B` [Asallık Testi](src/algorithms/math/primality-test) (deneyerek bölüm metodu)
-  * `B` [Öklid Algoritması](src/algorithms/math/euclidean-algorithm) - En büyük ortak bölen hesaplama (EBOB)
-  * `B` [En küçük Ortak Kat](src/algorithms/math/least-common-multiple) (EKOK)
-  * `B` [Eratosten Kalburu](src/algorithms/math/sieve-of-eratosthenes) - belirli bir sayıya kadarki asal sayıları bulma
-  * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - sayı ikinin katı mı sorgusu (naive ve bitwise algoritmaları)
-  * `B` [Paskal Üçgeni](src/algorithms/math/pascal-triangle)
-  * `B` [Karmaşık Sayılar](src/algorithms/math/complex-number) - karmaşık sayılar ve karmaşık sayılar ile temel işlemler
-  * `B` [Radyan & Derece](src/algorithms/math/radian) - radyandan dereceye çeviri ve tersine çeviri
-  * `B` [Fast Powering](src/algorithms/math/fast-powering)
-  * `B` [Horner's method](src/algorithms/math/horner-method) - polinomal ifadelerin değerlendirilmesi
-  * `B` [Matrices](src/algorithms/math/matrix) - matrisler ve basit matris operasyonları (çarpım, tersçapraz, vb.)
-  * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - iki nokta/vektör/matris arasındaki mesafe
-  * `A` [Tamsayı Bölümü](src/algorithms/math/integer-partition)
-  * `A` [Karekök](src/algorithms/math/square-root) - Newton yöntemi
-  * `A` [Liu Hui π Algoritması](src/algorithms/math/liu-hui) - N-gons'a göre yaklaşık π hesabı
-  * `A` [Ayrık Fourier Dönüşümü](src/algorithms/math/fourier-transform) - bir zaman fonksiyonunu (sinyal) içerdiği frekanslara ayırın
-* **Setler**
-  * `B` [Kartezyen Ürün](src/algorithms/sets/cartesian-product) - birden fazla kümenin çarpımı
-  * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - sonlu bir dizinin rastgele permütasyonu
-  * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set (bit düzeyinde ve geri izleme yöntemleri)
-  * `A` [Permütasyonlar](src/algorithms/sets/permutations)(tekrarlı ve tekrarsız)
-  * `A` [Kombinasyonlar](src/algorithms/sets/combinations) (tekrarlı ve tekrarsız)
-  * `A` [En Uzun Ortak Altdizi](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [En Uzun Artan Altdizi](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [En Kısa Ortak Üst Sıra](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - "0-1 sırt çantası problemi" ve "Sınırsız sırt çantası problemi"
-  * `A` [Maksimum Altdizi](src/algorithms/sets/maximum-subarray) - "Kaba Kuvvet" ve "Dinamik Programlara" (Kadane'nin) versiyonu
-  * `A` [Kombinasyon Toplamı](src/algorithms/sets/combination-sum) - belirli toplamı oluşturan tüm kombinasyonları bulun
-* **Metin**
-  * `B` [Hamming Mesafesi](src/algorithms/string/hamming-distance) - sembollerin farklı olduğu konumların sayısı
-  * `A` [Levenshtein Mesafesi](src/algorithms/string/levenshtein-distance) - iki sekans arasındaki minimum düzenleme mesafesi
-  * `A` [Knuth–Morris–Pratt Algoritması](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - altmetin araması (örüntü eşleme)
-  * `A` [Z Algoritması](src/algorithms/string/z-algorithm) - altmetin araması (desen eşleştirme)
-  * `A` [Rabin Karp Algoritması](src/algorithms/string/rabin-karp) - altmetin araması
-  * `A` [En Uzun Ortak Alt Metin](src/algorithms/string/longest-common-substring)
-  * `A` [Regular Expression Eşleme](src/algorithms/string/regular-expression-matching)
-* **Aramalar**
-  * `B` [Doğrusal Arama](src/algorithms/search/linear-search)
-  * `B` [Jump Search](src/algorithms/search/jump-search) (ya da Block Search) - sıralı dizide arama
-  * `B` [İkili Arama](src/algorithms/search/binary-search) - sıralı dizide arama
-  * `B` [Interpolation Search](src/algorithms/search/interpolation-search) - tekdüze dağıtılmış sıralı dizide arama
-* **Sıralama**
-  * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort)
-  * `B` [Selection Sort](src/algorithms/sorting/selection-sort)
-  * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort)
-  * `B` [Heap Sort](src/algorithms/sorting/heap-sort)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations
-  * `B` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `B` [Counting Sort](src/algorithms/sorting/counting-sort)
-  * `B` [Radix Sort](src/algorithms/sorting/radix-sort)
-* **Bağlantılı Liste**
-  * `B` [Straight Traversal](src/algorithms/linked-list/traversal)
-  * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)
-* **Ağaçlar**
-  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)
-* **Graphs**
-  * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - tek tepe noktasından tüm grafik köşelerine en kısa yolları bulmak
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - tek tepe noktasından tüm grafik köşelerine en kısa yolları bulmak
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - tüm köşe çiftleri arasındaki en kısa yolları bulun
-  * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - hem yönlendirilmiş hem de yönlendirilmemiş grafikler için (DFS ve Ayrık Küme tabanlı sürümler)
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma
-  * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS metodu
-  * `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algoritması (DFS based)
-  * `A` [Bridges](src/algorithms/graph/bridges) - DFS yöntemi ile algoritma
-  * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury'nin algoritması - Her kenara tam olarak bir kez ulaş
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Her köşeyi tam olarak bir kez ziyaret et
-  * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - her şehri ziyaret eden ve başlangıç ​​şehrine geri dönen mümkün olan en kısa rota
-* **Kriptografi**
-  * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - polinom temelinde dönen hash işlevi
-  * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher
-* **Makine Öğrenmesi**
-  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)
-* **Kategoriye Ayrılmayanlar**
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - tepeye ulaşmanın yollarını sayma (4 çözüm)
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-
-### Algoritmik Paradigma
-
-Algoritmik paradigma, bir sınıfın tasarımının altında yatan genel bir yöntem veya yaklaşımdır.
-Algoritma dizayn tekniği olarak düşünülebilir. Her bir altproblemi (subproblem) asıl problemle
-benzerlik gösteren problemlere uygulanabilir.
-
-* **Brute Force** - mümkün olan tüm çözümleri tara ve en iyisini seç
-  * `B` [Doğrusal Arama](src/algorithms/search/linear-search)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - tepeye çıkmanın yollarını hesapla
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - her şehri ziyaret eden ve başlangıç şehrine geri dönen mümkün olan en kısa rota
-  * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - bir zaman fonksiyonunu (bir sinyal) onu oluşturan frekanslara ayırır
-* **Açgözlü** - geleceği düşünmeden şu an için en iyi seçeneği seçin
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - tüm grafik köşelerine giden en kısa yolu bulmak
-  * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma
-  * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - ağırlıklı yönlendirilmemiş grafik için Minimum Yayılma Ağacı'nı (MST) bulma
-* **Böl ve Fethet** - sorunu daha küçük parçalara bölün ve sonra bu parçaları çözün
-  * `B` [Binary Search](src/algorithms/search/binary-search)
-  * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
-  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * `B` [Merge Sort](src/algorithms/sorting/merge-sort)
-  * `B` [Quicksort](src/algorithms/sorting/quick-sort)
-  * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Fast Powering](src/algorithms/math/fast-powering)
-  * `A` [Permutations](src/algorithms/sets/permutations) (tekrarlı ve tekrarsız)
-  * `A` [Combinations](src/algorithms/sets/combinations) (tekrarlı ve tekrarsız)
-* **Dinamik Programlama** - önceden bulunan alt çözümleri kullanarak bir çözüm oluşturmak
-  * `B` [Fibonacci Sayısı](src/algorithms/math/fibonacci)
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Eşsiz Yol](src/algorithms/uncategorized/unique-paths)
-  * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
-  * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - zirveye ulaşmanın yollarının sayısını sayın
-  * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - iki sekans arasındaki minimum düzenleme mesafesi
-  * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
-  * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem)
-  * `A` [Integer Partition](src/algorithms/math/integer-partition)
-  * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
-  * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - tüm grafik köşelerine giden en kısa yolu bulmak
-  * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - tüm köşe çiftleri arasındaki en kısa yolları bulun
-  * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching)
-* **Backtracking** - brute forceye benzer, mümkün tüm sonuçları tara, ancak bir sonraki çözümü her ürettiğinizde test edersiniz
-tüm koşulları karşılıyorsa ve ancak o zaman sonraki çözümleri üretmeye devam edin. Aksi takdirde, geri dönün ve farklı bir çözüm arayın(?).
-Normally the DFS traversal of state-space is being used.
-  * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
-  * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
-  * `B` [Power Set](src/algorithms/sets/power-set) - all subsets of a set
-  * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Her köşeyi tam olarak bir kez ziyaret edin
-  * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
-  * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
-  * `A` [Combination Sum](src/algorithms/sets/combination-sum) - belirli toplamı oluşturan tüm kombinasyonları bulun
-* **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking
-search, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of
-a least-cost solution to the problem, in order to discard partial solutions with costs larger than the
-lowest-cost solution found so far. Normally BFS traversal in combination with DFS traversal of state-space
-tree is being used.
-
-## Repository'in Kullanımı
-
-**Bütün dependencyleri kurun**
-```
-npm install
-```
-
-**ESLint'i başlatın**
-
-Bunu kodun kalitesini kontrol etmek amacı ile çalıştırabilirsin.
-
-```
-npm run lint
-```
-
-**Bütün testleri çalıştır**
-```
-npm test
-```
-
-**Testleri ismine göre çalıştır**
-```
-npm test -- 'LinkedList'
-```
-
-**Deneme Alanı**
-
-data-structures ve algorithms içerisinde `./src/playground/playground.js`
-yazarak `./src/playground/__test__/playground.test.js` için test edebilirsin.
-
-
-Ardından basitçe alttaki komutu girerek kodunun beklendiği gibi çalışıp çalışmadığını test edebilirsin:
-
-```
-npm test -- 'playground'
-```
-
-## Yararlı Bilgiler
-
-### Referanslar
-
-[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Big O Notation
-
-* Big O notation *, algoritmaları, girdi boyutu büyüdükçe çalışma süresi veya alan gereksinimlerinin nasıl arttığına göre sınıflandırmak için kullanılır.
-Aşağıdaki grafikte, Big O gösteriminde belirtilen algoritmaların en yaygın büyüme sıralarını bulabilirsiniz.
-
-![Big O graphs](./assets/big-o-graph.png)
-
-Kaynak: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Altta Big O notations ve farklı input boyutlarına karşın yapılmış performans karşılaştırması listelenmektedir.
-
-| Big O Notation | 10 Element için hesaplama | 100 Element için hesaplama | 1000 Element için hesaplama  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Veri Yapısı İşlem Karmaşıklığı
-
-| Veri Yapısı          | Access    | Search    | Insertion | Deletion  | Comments  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Dizi**               | 1         | n         | n         | n         |           |
-| **Yığın**               | n         | n         | 1         | 1         |           |
-| **Sıralı**               | n         | n         | 1         | 1         |           |
-| **Bağlantılı Liste**         | n         | n         | 1         | n         |           |
-| **Yığın Tablo**          | -         | n         | n         | n         | Kusursuz hash fonksiyonu durumunda sonuç O(1) |
-| **İkili Arama Ağacı**  | n         | n         | n         | n         | In case of balanced tree costs would be O(log(n)) |
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Red-Black Tree**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bloom Filter**        | -         | 1         | 1         | -         | Arama esnasında yanlış sonuçlar çıkabilir |
-
-### Dizi Sıralama Algoritmaları Karmaşıklığı
-
-| İsim                  | En İyi            | Ortalama             | En Kötü               | Hafıza    | Kararlı    | Yorumlar  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Evet       |           |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Evet       |           |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Hayır        |           |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Hayır        |           |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Evet       |           |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Hayır        | Hızlı sıralama genellikle O(log(n)) yığın alanıyla yapılır |
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Hayır         |           |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Evet       | r - dizideki en büyük sayı |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Evet       | k - en uzun key'in uzunluğu |
-
-## Projeyi Destekleme
-
-Bu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.uk-UA.md b/README.uk-UA.md
deleted file mode 100644
index dd129b2c3c..0000000000
--- a/README.uk-UA.md
+++ /dev/null
@@ -1,310 +0,0 @@
-# Алгоритми JavaScript та структури даних
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Даний репозиторій приклади багатьох популярних алгоритмів та структур даних на основі JavaScript.
-
-Кожен алгоритм та структура даних має свій окремий README-файл із відповідними поясненнями та посиланнями для подальшого вивчення (включаючи посилання на відео на YouTube).
-
-_Вивчення матеріалу на інших мовах:_
-[_English_](README.md),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*☝ Зверніть увагу! Даний проект призначений лише для навчальних та дослідницьких цілей, і він **не** призначений для виробництва (продакшн).*
-
-## Структури даних
-
-Структура даних (в програмуванні) - це спосіб організації даних в комп'ютерах. Часто разом зі структурою даних пов'язується і специфічний перелік операцій, що можуть бути виконаними над даними, організованими в таку структуру.
-Точніше, структура даних - це сукупність даних цінності, взаємозв'язки між ними та функції або операції, до яких можна застосувати дані.
-
-`B` - Початківець, `A` - Просунутий рівень
-
-* `B` [Зв'язаний список](src/data-structures/linked-list)
-* `B` [Двобічно зв'язаний список](src/data-structures/doubly-linked-list)
-* `B` [Черга](src/data-structures/queue)
-* `B` [Стек](src/data-structures/stack)
-* `B` [Геш-таблиця](src/data-structures/hash-table)
-* `B` [Купа, стіс або піраміда](src/data-structures/heap) - max and min heap versions
-* `B` [Черга з пріоритетом](src/data-structures/priority-queue)
-* `A` [Префіксне дерево](src/data-structures/trie)
-* `A` [Дерево](src/data-structures/tree)
-  * `A` [Двійкове дерево пошуку](src/data-structures/tree/binary-search-tree)
-  * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree)
-  * `A` [Червоно-чорне дерево](src/data-structures/tree/red-black-tree)
-  * `A` [Дерево відрізків](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples
-  * `A` [Дерево Фенвіка](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree)
-* `A` [Граф (абстрактний тип даних)](src/data-structures/graph) (both directed and undirected)
-* `A` [Система неперетинних множин](src/data-structures/disjoint-set)
-* `A` [Фільтр Блума](src/data-structures/bloom-filter)
-
-
-## Алгоритми
-
-Алгоритм - це однозначна специфікація способу вирішення класу задач. Це набір правил, які точно визначають послідовність операцій.
-
-`B` - Початківець, `A` - Просунутий рівень
-
-### Алгоритми за тематикою
-
-* **Математика**
-  * `B` [Бітова маніпуляція](src/algorithms/math/bits) - встановити / отримати / оновити / очистити біти, множення / ділення на два, робити від’ємними тощо
-  * `B` [Факторіал](src/algorithms/math/factorial)
-  * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії
-  * `B` [Основні фактори](src/algorithms/math/prime-factors) - пошук простих множників і підрахунок їх за допомогою теореми Харді-Рамануджана
-  * `B` [Тест простоти](src/algorithms/math/primality-test) (метод пробного поділу)
-  * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД)
-  * `B` [Найменше спільне кратне](src/algorithms/math/least-common-multiple) (НСК)
-  * `B` [Решето Ератосфена](src/algorithms/math/sieve-of-eratosthenes) - алгоритм знаходження всіх простих чисел менших деякого цілого числа *n*
-  * `B` [Піднесення до степеня](src/algorithms/math/is-power-of-two) - перевірити, чи є число ступенем двох (просте та побітове рішення)
-  * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle)
-  * `B` [Комплексне число](src/algorithms/math/complex-number) - комплексні числа та основні операції з ними
-  * `B` [Радіани & Градуси](src/algorithms/math/radian) - перетворення радіанів у градуси та навпаки
-  * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering)
-  * `B` [Схема Горнера](src/algorithms/math/horner-method) - поліноміальна оцінка
-  * `A` [Розбиття числа](src/algorithms/math/integer-partition)
-  * `A` [Метод дотичних (метод Ньютона)](src/algorithms/math/square-root) - метод наближеного знаходження кореня дійсного рівняння
-  * `A` [Алгоритм Лю Хуея](src/algorithms/math/liu-hui) - розрахунок числа π з заданою точністю методом вписаних правильних багатокутників
-  * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові
-* **Множина**
-  * `B` [Декартів добуток множин](src/algorithms/sets/cartesian-product) - множина усіх можливих впорядкованих пар
-  * `B` [Тасування Фішера - Єйтса](src/algorithms/sets/fisher-yates) - створення випадкових перестановок кінцевого безлічі
-  * `A` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення)
-  * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без)
-  * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без)
-  * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence)
-  * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений"
-  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray) - метод «Грубої сили» та алгоритм Кадана
-  * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму
-* **Алгоритми роботи з рядками**
-  * `B` [Відстань Геммінга](src/algorithms/string/hamming-distance) - число позицій, у яких відповідні цифри двох двійкових слів однакової довжини різні
-  * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків)
-  * `A` [Алгоритм Кнута — Морріса — Пратта](src/algorithms/string/knuth-morris-pratt) пошук підрядків (узгодження шаблонів)
-  * `A` [Z-функція](src/algorithms/string/z-algorithm) - пошук підрядків (зіставлення зразків)
-  * `A` [Алгоритм Рабіна — Карпа](src/algorithms/string/rabin-karp) - алгоритм пошуку рядка
-  * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring)
-  * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching)
-* **Алгоритми пошуку**
-  * `B` [Лінійний пошук](src/algorithms/search/linear-search)
-  * `B` [Пошук блоків](src/algorithms/search/jump-search) - пошук у відсортованому масиві
-  * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві
-  * `B` [Інтерполяційний алгоритм пошуку](src/algorithms/search/interpolation-search) - алгоритм для пошуку за заданим ключем в індексованому масиві, який впорядкований за значенням ключів
-* **Алгоритми сортування**
-  * `B` [Сортування бульбашкою](src/algorithms/sorting/bubble-sort)
-  * `B` [Сортування вибором](src/algorithms/sorting/selection-sort)
-  * `B` [Сортування включенням](src/algorithms/sorting/insertion-sort)
-  * `B` [Пірамідальне сортування](src/algorithms/sorting/heap-sort)
-  * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort)
-  * `B` [Швидке сортування](src/algorithms/sorting/quick-sort)
-  * `B` [Сортування Шелла](src/algorithms/sorting/shell-sort)
-  * `B` [Сортування підрахунком](src/algorithms/sorting/counting-sort)
-  * `B` [Сортування за розрядами](src/algorithms/sorting/radix-sort)
-* **Зв’язані списки**
-  * `B` [Прямий обхід](src/algorithms/linked-list/traversal)
-  * `B` [Зворотний обхід](src/algorithms/linked-list/reverse-traversal)
-* **Дерева**
-  * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search)
-  * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search)
-* **Графи**
-  * `B` [Пошук у глибину](src/algorithms/graph/depth-first-search)
-  * `B` [Пошук у ширину](src/algorithms/graph/breadth-first-search)
-  * `B` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа
-  * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин
-  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) -  алгоритм пошуку найкоротшого шляху в зваженому графі
-  * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) -  знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів)
-  * `A` [Циклічний граф](src/algorithms/graph/detect-cycle) - граф, що складається з єдиного циклу, або, іншими словами, деякого числа вершин, з'єднаних замкнутим ланцюгом.
-  * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа
-  * `A` [Топологічне сортування](src/algorithms/graph/topological-sorting) - впорядковування вершин безконтурного орієнтованого графа згідно з частковим порядком, визначеним ребрами цього графу на множині його вершин
-  * `A` [Алгоритм Тар'яна](src/algorithms/graph/articulation-points) - алгоритм пошуку компонент сильної зв'язності в орієнтованому графі, що працює за лінійний час
-  * `A` [Міст (теорія графів)](src/algorithms/graph/bridges)
-  * `A` [Ейлерів ланцюг](src/algorithms/graph/eulerian-path) - ланцюг у графі, який проходить кожне ребро рівно один раз
-  * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз
-  * `A` [Компонента сильної зв'язності графа](src/algorithms/graph/strongly-connected-components) - Алгоритм Косараджу - алгоритм для знаходження компонент сильної зв’язності орієнтованого графу
-  * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу
-* **Криптографія**
-  * `B` [Хеш-функція](src/algorithms/cryptography/polynomial-hash) - функція, що перетворює вхідні дані будь-якого (як правило великого) розміру в дані фіксованого розміру.
-  * `B` [Шифр Цезаря (шифр зсуву)](src/algorithms/cryptography/caesar-cipher) - симетричний моноалфавітний алгоритм шифрування, в якому кожна буква відкритого тексту заміняється на ту, що віддалена від неї в алфавіті на сталу кількість позицій
-  * `B` [Шифр Гілла](src/algorithms/cryptography/hill-cipher) - поліграмний шифр підстановки, заснований на лінійній алгебрі
-* **Машинне навчання**
-  * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) - 7 простих функцій JS, які ілюструють, як машини насправді можуть навчатися (пряме та зворотнє поширення)
-  * `B` [Метод k-найближчих сусідів](src/algorithms/ml/knn) - простий непараметричний класифікаційний метод, де для класифікації об'єктів у рамках простору властивостей використовуються відстані (зазвичай евклідові), пораховані до усіх інших об'єктів
-  * `B` [Кластеризація методом к–середніх](src/algorithms/ml/knn) - популярний метод кластеризації, — впорядкування множини об'єктів в порівняно однорідні групи.
-* **Без категорії**
-  * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Поворот квадратної матриці](src/algorithms/uncategorized/square-matrix-rotation)
-  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади
-  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля
-  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили)
-  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення)
-  * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens)
-  * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour)
-
-### Парадигма програмування
-
-Парадиигма програмува́ння — це система ідей і понять, які визначають стиль написання комп'ютерних програм, а також спосіб мислення програміста. Це спосіб концептуалізації, що визначає організацію обчислень і структурування роботи, яку виконує комп'ютер.
-
-* **Метод «грубої сили» або повний перебір** - метод рішення криптографічної задачі шляхом перебору всіх можливих варіантів ключа
-  * `B` [Лінійний пошук](src/algorithms/search/linear-search)
-  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - задача про дощові тераси
-  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини
-  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray)
-  * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу
-  * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові
-* **"Жадібні" алгоритми** - простий і прямолінійний евристичний алгоритм, який приймає найкраще рішення, виходячи з наявних на кожному етапі даних, не зважаючи на можливі наслідки, сподіваючись урешті-решт отримати оптимальний розв'язок
-  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади
-  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений"
-  * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин
-  * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа
-  * `A` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа
-* **Розділяй і володарюй** - важлива парадигма розробки алгоритмів, що полягає в рекурсивному розбитті розв'язуваної задачі на дві або більше підзадачі того ж типу, але меншого розміру, і комбінуванні їх розв'язків для отримання відповіді до вихідного завдання. Розбиття виконуються доти, поки всі підзавдання не стануть елементарними.
-  * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві
-  * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle)
-  * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД)
-  * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort)
-  * `B` [Швидке сортування](src/algorithms/sorting/quick-sort)
-  * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search)
-  * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search)
-  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади
-  * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering)
-  * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без)
-  * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без)
-* **Динамічне програмування** - розділ математики, який присвячено теорії і методам розв'язання багатокрокових задач оптимального управління
-  * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії
-  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади
-  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля
-  * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили)
-  * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення)
-  * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків)
-  * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence)
-  * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring)
-  * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений"
-  * `A` [Розбиття числа](src/algorithms/math/integer-partition)
-  * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray)
-  * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) -  алгоритм пошуку найкоротшого шляху в зваженому графі
-  * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) -  знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів)
-  * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching)
-* **Пошук із зворотом** - подібно до грубої сили, намагайтеся генерувати всі можливі рішення, але кожного разу, коли ви створюєте наступне рішення, тестуєте чи він задовольняє всім умовам, і лише потім продовжуєте генерувати наступні рішення. В іншому випадку поверніться назад і рухайтесь далі іншим шляхом пошуку рішення.
-  * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади
-  * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля
-  * `B` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення)
-  * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз
-  * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens)
-  * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour)
-  * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму
-* **Метод гілок і меж** - один з поширених методів дискретної оптимізації. Метод працює на дереві рішень та визначає принципи роботи конкретних алгоритмів пошуку розв'язків, тобто, є мета-алгоритмом. Для різних задач комбінаторної оптимізації створюють спеціалізовані алгоритми гілок та меж.
-
-## Як користуватися цим репозиторієм
-
-**Встановіть усі залежності**
-```
-npm install
-```
-
-**Запустіть ESLint**
-
-Запустіть для перевірки якості коду
-
-```
-npm run lint
-```
-
-**Запустіть усі тести**
-```
-npm test
-```
-
-**Запустіть тести за назвою**
-```
-npm test -- 'LinkedList'
-```
-
-**Ігрище**
-
-Ви можете побавитись зі структурами даних та алгоритмами в файлі `./src/playground/playground.js` та писати тести до них в даному файлі `./src/playground/__test__/playground.test.js`.
-
-Для перевірки, чи працює ваш код належним чином запустіть команду:
-
-```
-npm test -- 'playground'
-```
-
-## Корисна інформація
-
-### Список літератури
-
-[▶ Структури даних та алгоритми на YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Асимптотична нотація великого О (нотація Ландау)
-
-*Асимптотична нотація великого О (нотація Ландау)* розповсюджена математична нотація для формального запису асимптотичної поведінки функцій. Широко вживається в теорії складності обчислень, інформатиці та математиці.
-![Асимптотична нотація великого О](./assets/big-o-graph.png)
-
-Джерело: [Асимптотична нотація великого О](http://bigocheatsheet.com/).
-
-Нижче наведено список деяких найбільш часто використовуваних позначень нотації Ландаута їх порівняння продуктивності з різними розмірами вхідних даних.
-
-| Нотація Ландау | Обчислення для 10 елементів | Обчислення для 100 елементів | Обчислення для 1000 елементів  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Складність операцій в структурі даних
-
-| Структура даних        | Доступ    | Пошук    | Вставка | Видалення  | Коментарі  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Масив**               | 1         | n         | n         | n         |           |
-| **Купа**               | n         | n         | 1         | 1         |           |
-| **Черга**               | n         | n         | 1         | 1         |           |
-| **Зв’язаний список**         | n         | n         | 1         | n         |           |
-| **Хеш-таблиця**          | -         | n         | n         | n         | У разі ідеальної хеш-функції - O(1) |
-| **Бінарне дерево пошуку**  | n         | n         | n         | n         | У разі збалансованого дерева витрати становитимуть O (log (n)) |
-| **Б-дерево**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Червоно-чорне дерево**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **АВЛ-дерево**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Фільтр Блума**        | -         | 1         | 1         | -         | Під час пошуку можливі помилкові спрацьовування |
-
-### Складність алгоритмів сортування масивів
-
-| Назва                  | Найкращий            | Середній             | Найгірший               | Пам'ять    | Стабільність    | Коментарі  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Сортування бульбашкою**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Так       |           |
-| **Сортування включенням**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Так       |           |
-| **Сортування вибором**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Ні        |           |
-| **Пірамідальне сортування**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Ні        |           |
-| **Сортування злиттям**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Так       |           |
-| **Швидке сортування**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Ні        | Швидке сортування зазвичай виконується на місці з використанням O (log (n)) додаткової пам'яті |
-| **Сортування Шелла**        | n&nbsp;log(n)   | залежить від послідовності проміжків   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Ні         |           |
-| **Сортування підрахунком**     | n + r           | n + r               | n + r               | n + r     | Так       | Де r - найбільше число в масиві |
-| **Сортування за розрядами**        | n * k           | n * k               | n * k               | n + k     | Так       | Де k - довжина найдовшого ключа |
-
-## Патронати проекту
-
-> Ви можете підтримати цей проект через ❤️️ [GitHub](https://github.com/sponsors/trekhleb) або ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-[Люди, які підтримують цей проект](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1`
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.vi-VN.md b/README.vi-VN.md
deleted file mode 100644
index a5cbb72e07..0000000000
--- a/README.vi-VN.md
+++ /dev/null
@@ -1,328 +0,0 @@
-# JavaScript Thuật Toán và Cấu Trúc Dữ Liệu
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-Repository này bao gồm nhiều ví dụ thuật toán và cấu trúc dữ liệu phổ biến
-dựa trên Javascript.
-
-Mối thuật toán và cấu trúc dữ liệu có README riêng với những lý giải và links
-liên quan để đọc thêm (bao gồm cả những videos trên Youtube).
-
-_Đọc bằng ngôn ngữ khác:_
-[_English_](README.md),
-[_简体中文_](README.zh-CN.md),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md)
-
-*☝ Dự án này chỉ được sử dụng cho mục đích học tập và nghiên cứu, **không** được dùng
-cho mục đích thương mại.*
-
-## Cấu Trúc Dữ Liệu
-
-Cấu trúc dữ liệu là một cách cụ thể để tổ chức và lưu trữ dữ liệu trong máy tính để nó có thể
-được truy cập và sửa đổi một cách hiệu quả. Chính xác hơn, cấu trúc dữ liệu là một tập hợp
-các giá trị dữ liệu, các mối quan hệ giữa chúng và các hàm hoặc phép toán có thể được áp dụng
-cho dữ liệu.
-
-`B` - Cơ bản, `A` - Nâng cao
-
-* `B` [Danh sách liên kết](src/data-structures/linked-list)
-* `B` [Danh sách liên kết đôi](src/data-structures/doubly-linked-list)
-* `B` [Hàng đợi](src/data-structures/queue)
-* `B` [Ngăn xếp](src/data-structures/stack)
-* `B` [Bảng băm](src/data-structures/hash-table)
-* `B` [Đống](src/data-structures/heap) - max và min heap
-* `B` [Hàng đợi ưu tiên](src/data-structures/priority-queue)
-* `A` [Cây tiền tố](src/data-structures/trie)
-* `A` [Cây](src/data-structures/tree)
-  * `A` [Cây tìm kiếm nhị phân](src/data-structures/tree/binary-search-tree)
-  * `A` [Cây AVL](src/data-structures/tree/avl-tree)
-  * `A` [Cây đỏ đen](src/data-structures/tree/red-black-tree)
-  * `A` [Cây phân đoạn](src/data-structures/tree/segment-tree) - với các ví dụ truy vấn phạm vi nhỏ nhất/lớn nhất/tổng
-  * `A` [CÂy Fenwick](src/data-structures/tree/fenwick-tree) (Cây chỉ mục nhị phân)
-* `A` [Đồ thị](src/data-structures/graph) (có hướng và vô hướng)
-* `A` [Tập hợp không giao nhau](src/data-structures/disjoint-set)
-* `A` [Bộ lọc Bloom](src/data-structures/bloom-filter)
-
-## Thuật Toán
-
-Thuật toán là một đặc tả rõ ràng về cách giải quyết một lớp vấn đề. Nó là một tập hợp các
-quy tắc xác định chính xác một chuỗi phép toán.
-
-`B` - Cơ bản, `A` - Nâng cao
-
-### Thuật toán theo chủ đề
-
-* **Toán**
-  * `B` [Thao tác bit](src/algorithms/math/bits) - đặt/lấy/cập nhật/xóa bit, nhân/chia 2, đổi dấu âm,...
-  * `B` [Giai thừa](src/algorithms/math/factorial)
-  * `B` [Số Fibonacci](src/algorithms/math/fibonacci) - cổ điển và dạng đóng
-  * `B` [Thừa số nguyên tố](src/algorithms/math/prime-factors) - tìm và đếm thừa số nguyên tố sử dụng định luật Hardy-Ramanujan's
-  * `B` [Kiểm tra tính nguyên tố](src/algorithms/math/primality-test) (phân chia thử nghiệm)
-  * `B` [Thuật toán Euclid](src/algorithms/math/euclidean-algorithm) - tính ước số chung lớn nhất (GCD)
-  * `B` [Bội số chung nhỏ nhất](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [Sàng số nguyên tố](src/algorithms/math/sieve-of-eratosthenes) - tìm tất cả các số nguyên tố trong bất kỳ phạm vi nhất định nào
-  * `B` [Xác định lũy thừa của 2](src/algorithms/math/is-power-of-two) - kiểm tra xem số có phải là lũy thừa của 2 hay không (thuật toán nguyên bản và theo bit)
-  * `B` [Tam giác Pascal](src/algorithms/math/pascal-triangle)
-  * `B` [Số phức](src/algorithms/math/complex-number) - số phức và các phép toán cơ bản với số phức
-  * `B` [Radian & độ](src/algorithms/math/radian) - chuyển đổi giữa đơn vị radian và độ
-  * `B` [Tính nhanh lũy thừa](src/algorithms/math/fast-powering)
-  * `B` [Phương pháp Horner's](src/algorithms/math/horner-method) - tính giá trị đa thức
-  * `B` [Ma trận](src/algorithms/math/matrix) - ma trận và các phép toán cơ bản (phép nhân, phép chuyển vị,...)
-  * `B` [Khoảng cách Euclid](src/algorithms/math/euclidean-distance) - khoảng cách giữa hai điểm/véc-tơ/ma trận
-  * `A` [Phân hoạch](src/algorithms/math/integer-partition)
-  * `A` [Căn bậc hai](src/algorithms/math/square-root) - phương pháp Newton
-  * `A` [Thuật cắt đường tròn - Lưu Huy](src/algorithms/math/liu-hui) - phép tính gần đúng số π dựa vào đa giác
-  * `A` [Biến đổi Fourier rời rạc](src/algorithms/math/fourier-transform) - phân giải tín hiệu thời gian thành các tần số tạo nên tín hiệu đó
-* **Tập hợp**
-  * `B` [Tích Đề-các](src/algorithms/sets/cartesian-product) - tích của nhiều tập hợp
-  * `B` [Thuật toán xáo trộn](src/algorithms/sets/fisher-yates) - dãy hữu hạn hoán vị ngẫu nhiên
-  * `A` [Tập lũy thừa](src/algorithms/sets/power-set) - tập hợp chứa tất cả các tập con (theo bit và quay lui)
-  * `A` [Hoán vị](src/algorithms/sets/permutations) (lặp và không lặp)
-  * `A` [Tổ hợp](src/algorithms/sets/combinations) (lặp và không lặp)
-  * `A` [Dãy con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Dãy con chung tăng dần dài nhất](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Dãy con chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [Bài toán xếp ba lô](src/algorithms/sets/knapsack-problem) - dạng 0-1 và không bị chặn
-  * `A` [Mảng con lớn nhất](src/algorithms/sets/maximum-subarray) - phiên bản vét cạn và quy hoạch động (Kadane)
-  * `A` [Tổ hợp của tổng](src/algorithms/sets/combination-sum) - tìm tất cả các tổ hợp tạo thành tổng cụ thể 
-* **Chuỗi**
-  * `B` [Khoảng cách Hamming](src/algorithms/string/hamming-distance) - số các vị trí các ký hiệu khác nhau 
-  * `A` [Khoảng cách Levenshtein](src/algorithms/string/levenshtein-distance) - khoảng cách thay đổi nhỏ nhất giữa hai chuỗi ký tự
-  * `A` [Thuật toán Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (thuật toán KMP) - tìm chuỗi con (đối sánh mẫu) 
-  * `A` [Thuật toán Z](src/algorithms/string/z-algorithm) - tìm chuỗi con (đối sánh mẫu)
-  * `A` [Thuật toán Rabin Karp](src/algorithms/string/rabin-karp) - tìm chuỗi con
-  * `A` [Xâu con chung dài nhất](src/algorithms/string/longest-common-substring)
-  * `A` [Phối biểu thức chính quy](src/algorithms/string/regular-expression-matching)
-* **Tìm kiếm**
-  * `B` [Tìm kiếm tuyến tính](src/algorithms/search/linear-search)
-  * `B` [Tìm kiếm nhảy](src/algorithms/search/jump-search) (tìm khối) - tìm kiếm trong mảng đã sắp xếp 
-  * `B` [Tìm kiếm nhị phân](src/algorithms/search/binary-search) - tìm kiếm trong mảng đã sắp xếp 
-  * `B` [Tìm kiếm nội suy ](src/algorithms/search/interpolation-search) - Tìm kiếm strong mảng có thứ tự được phân phối đồng nhất
-* **Sắp xếp**
-  * `B` [Sắp xếp nổi bọt](src/algorithms/sorting/bubble-sort)
-  * `B` [Sắp xếp chọn](src/algorithms/sorting/selection-sort)
-  * `B` [Sắp xếp chèn](src/algorithms/sorting/insertion-sort)
-  * `B` [Sắp xếp vun đống](src/algorithms/sorting/heap-sort)
-  * `B` [Sắp xếp trộn](src/algorithms/sorting/merge-sort)
-  * `B` [Sắp xếp nhanh](src/algorithms/sorting/quick-sort) - Tại chỗ và không tại chỗ
-  * `B` [Shellsort](src/algorithms/sorting/shell-sort)
-  * `B` [Sắp xếp đếm](src/algorithms/sorting/counting-sort)
-  * `B` [Sắp xếp theo cơ số](src/algorithms/sorting/radix-sort)
-* **Danh sách liên kết**
-  * `B` [Di chuyển chính hướng](src/algorithms/linked-list/traversal)
-  * `B` [Di chuyển ngược hướng](src/algorithms/linked-list/reverse-traversal)
-* **Cây**
-  * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS)
-* **Đồ thị**
-  * `B` [Tìm kiếm theo chiều sâu](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Tìm kiếm theo chiều rộng](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [Thuật toán Kruskal](src/algorithms/graph/kruskal) - tìm cây bao trùm nhỏ nhất (MST) cho đồ thị vô hướng có trọng số
-  * `A` [Thuật toán Dijkstra Algorithm](src/algorithms/graph/dijkstra) - tìm những đường ngắn nhất từ một định tới tất cả các đỉnh
-  * `A` [Thuật toán Bellman-Ford](src/algorithms/graph/bellman-ford) - tìm những đường ngắn nhất từ một đỉnh tới tất cả các đỉnh của đồ thị
-  * `A` [Thuật toán Floyd-Warshall](src/algorithms/graph/floyd-warshall) - tìm những đường ngắn nhất giữa tất cả các cặp đỉnh
-  * `A` [Phát hiện vòng](src/algorithms/graph/detect-cycle) - cho cả đồ thị có hướng và vô hướng (dựa trên DFS và tập không giao)
-  * `A` [Thuật toán Prim](src/algorithms/graph/prim) - tìm cây bao trùm nhỏ nhất (MST) cho đồ thị vô hướng có trọng số
-  * `A` [Sắp xếp tô pô](src/algorithms/graph/topological-sorting) - phương pháp DFS
-  * `A` [Điểm khớp](src/algorithms/graph/articulation-points) - Thuật toán Tarjan (dựa trên DFS)
-  * `A` [Cầu nối](src/algorithms/graph/bridges) - dựa trên DFS
-  * `A` [Đường đi Euler và Chu trình Euler](src/algorithms/graph/eulerian-path) - thuật toán Fleury - đi qua các cạnh chỉ một lần duy nhất
-  * `A` [Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - đi qua các đỉnh chỉ một lần duy nhất
-  * `A` [Các thành phần kết nối chặt](src/algorithms/graph/strongly-connected-components) - Thuật toán Kosaraju
-  * `A` [Bài toán người bán hàng](src/algorithms/graph/travelling-salesman) - tuyến đường ngắn nhất có thể đến thăm từng thành phố và trở về thành phố gốc
-* **Mật mã học**
-  * `B` [Băm đa thức](src/algorithms/cryptography/polynomial-hash) - lăn hàm băm dựa trên đa thức 
-  * `B` [Mật mã hàng rào đường sắt](src/algorithms/cryptography/rail-fence-cipher) - một thuật toán mật mã chuyển vị để mã hóa thông điệp 
-  * `B` [Mật mã Caesar](src/algorithms/cryptography/caesar-cipher) - mật mã chuyển vị đơn giản
-  * `B` [Mật mã Hill](src/algorithms/cryptography/hill-cipher) - mật mã chuyển vị đơn giản dựa trên đại số tuyến tính
-* **Học máy**
-  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 hàm JS đơn giản minh họa cách máy tính thực sự có thể học (truyền thuận / truyền ngược) 
-  * `B` [k-NN](src/algorithms/ml/knn) - thuật toán phân loại k láng giềng gần nhất
-  * `B` [k-Means](src/algorithms/ml/k-means) - thuật toán phân cụm k-Means
-* **Khác**
-  * `B` [Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Xoay ma trận vuông](src/algorithms/uncategorized/square-matrix-rotation) - thuật toán tại chỗ
-  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game) - ví dụ quay lui, quy hoạch động (từ trên xuống + từ dưới lên), dynamic programming (top-down + bottom-up) và tham lam
-  * `B` [Các đường đi đặc trưng duy nhất](src/algorithms/uncategorized/unique-paths) - ví dụ quay lui, quy hoạch động và tam giác Pascal
-  * `B` [Thu thập nước mưa](src/algorithms/uncategorized/rain-terraces) - bài toán bẫy nước mưa (phiên bản quy hoạch động và vét cạn)
-  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh (4 lời giải)
-  * `B` [Thời điểm tốt nhất để mua bán cổ phiếu ](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - ví dụ chia để trị và một đường chuyền
-  * `A` [Bài toán n quân hậu](src/algorithms/uncategorized/n-queens)
-  * `A` [Mã đi tuần](src/algorithms/uncategorized/knight-tour)
-
-### Thuật toán theo mẫu hình
-
-Mẫu hình thuật toán là một phương pháp hoặc cách tiếp cận chung làm cơ sở cho việc thiết kế một
-lớp thuật toán. Nó là một sự trừu tượng cao hơn khái niệm về một thuật toán, cũng giống như
-một thuật toán là một sự trừu tượng cao hơn một chương trình máy tính. 
-
-* **Vét cạn** - xem xét tất cả các khả năng và chọn giải pháp tốt nhất 
-  * `B` [Tìm kiếm tuyến tính](src/algorithms/search/linear-search)
-  * `B` [Thu thập nước mưa](src/algorithms/uncategorized/rain-terraces) - bài toán bẫy nước mưa
-  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh
-  * `A` [Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)
-  * `A` [Bài toán người bán hàng](src/algorithms/graph/travelling-salesman) - tuyến đường ngắn nhất có thể đến thăm từng thành phố và trở về thành phố gốc
-  * `A` [Biến đổi Fourier rời rạc](src/algorithms/math/fourier-transform) - phân giải tín hiệu thời gian thành các tần số tạo nên tín hiệu đó
-* **Tham lam** - chọn phương án tốt nhất vào thời điểm hiện tại mà không cần cân nhắc đến tương lai 
-  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
-  * `A` [Bài xếp ba lô không bị chặn](src/algorithms/sets/knapsack-problem)
-  * `A` [Thuật toán Dijkstra](src/algorithms/graph/dijkstra) - tìm những đường ngắn nhất từ một định tới tất cả các đỉnh
-  * `A` [Thuật toán Prim](src/algorithms/graph/prim) - tìm cây bao trùm nhỏ nhất (MST) cho đồ thị vô hướng có trọng số
-  * `A` [Thuật toán Kruskal](src/algorithms/graph/kruskal) - tìm cây bao trùm nhỏ nhất (MST) cho đồ thị vô hướng có trọng số
-* **Chia để trị** - chia vấn đề thành các phần nhỏ hơn rồi giải quyết các phần đó 
-  * `B` [Tìm kiếm nhị phân](src/algorithms/search/binary-search)
-  * `B` [Tháp Hà Nội](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [Tam giác Pascal](src/algorithms/math/pascal-triangle)
-  * `B` [Thuật toán Euclid](src/algorithms/math/euclidean-algorithm) - tính ước số chung lớn nhất
-  * `B` [Sắp xếp trộn](src/algorithms/sorting/merge-sort)
-  * `B` [Sắp xếp nhanh](src/algorithms/sorting/quick-sort)
-  * `B` [Cây tìm kiếm theo chiều sâu](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [Đồ thị tìm kiếm theo chiều sâu](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [Ma trận](src/algorithms/math/matrix) - tạo và duyệt các ma trận có kích thước khác nhau 
-  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
-  * `B` [Tính nhanh lũy thừa](src/algorithms/math/fast-powering)
-  * `B` [Thời điểm tốt nhất để mua bán cổ phiếu](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - ví dụ chia để trị và một đường chuyền
-  * `A` [Hoán vị](src/algorithms/sets/permutations) (lặp và không lặp)
-  * `A` [Tổ hợp](src/algorithms/sets/combinations) (lặp và không lặp)
-* **Quy hoạch động** - xây dựng một giải pháp bằng cách sử dụng các giải pháp phụ đã tìm thấy trước đây
-  * `B` [Số Fibonacci](src/algorithms/math/fibonacci)
-  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
-  * `B` [Đường đi độc nhất](src/algorithms/uncategorized/unique-paths)
-  * `B` [Thu thập nước mưa](src/algorithms/uncategorized/rain-terraces) - bài toán bẫy nước mưa
-  * `B` [Cầu thang đệ quy](src/algorithms/uncategorized/recursive-staircase) - đếm số cách lên đến đỉnh
-  * `A` [Khoảng cách Levenshtein](src/algorithms/string/levenshtein-distance) - khoảng cách thay đổi nhỏ nhất giữa hai chuỗi ký tự
-  * `A` [Dãy con chung dài nhất](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [Xâu con chung dài nhất](src/algorithms/string/longest-common-substring)
-  * `A` [Dãy con chung tăng dần dài nhất](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [Dãy con chung ngắn nhất](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [Bài xếp ba lô dạng 0-1](src/algorithms/sets/knapsack-problem)
-  * `A` [Integer Partition](src/algorithms/math/integer-partition)
-  * `A` [Mảng con lớn nhất](src/algorithms/sets/maximum-subarray)
-  * `A` [Thuật toán Bellman-Ford](src/algorithms/graph/bellman-ford) - tìm những đường ngắn nhất từ một đỉnh tới tất cả các đỉnh của đồ thị
-  * `A` [Thuật toán Floyd-Warshall](src/algorithms/graph/floyd-warshall) - tìm những đường ngắn nhất giữa tất cả các cặp đỉnh
-  * `A` [Phối biểu thức chính quy](src/algorithms/string/regular-expression-matching)
-* **Quay lui** - tương tự như vét cạn, cố tạo ra tất cả các giải pháp có thể, nhưng mỗi lần bạn tạo ra giải pháp tiếp theo,
-bạn sẽ kiểm tra xem nó có thỏa mãn tất cả các điều kiện hay không và chỉ khi thỏa mãn mới tiếp tục tạo ra các giải pháp tiếp theo.
-Nếu không, hãy quay lại và đi trên một con đường khác để tìm ra giải pháp. Thông thường, truyền DFS của không gian trạng thái được sử dụng. 
-  * `B` [Trò chơi nhảy](src/algorithms/uncategorized/jump-game)
-  * `B` [Đường đi độc nhất](src/algorithms/uncategorized/unique-paths)
-  * `B` [Tập lũy thừa](src/algorithms/sets/power-set) - tập hợp chứa tất cả các tập con
-  * `A` [Chu trình Hamilton](src/algorithms/graph/hamiltonian-cycle) - đi qua các đỉnh một lần duy nhất
-  * `A` [Bài toán n quân hậu](src/algorithms/uncategorized/n-queens)
-  * `A` [Mã đi tuần](src/algorithms/uncategorized/knight-tour)
-  * `A` [Tổ hợp của tổng](src/algorithms/sets/combination-sum) - tìm tất cả các tổ hợp tạo thành tổng cụ thể 
-* **Branch & Bound** - ghi nhớ giải pháp chi với phí thấp nhất được tìm thấy ở mỗi giai đoạn của quá trình tìm kiếm quay lui,
-sử dụng chi phí của giải pháp có chi phí thấp nhất được tìm thấy cho đến nay như một giới hạn dưới về chi phí của
-một giải pháp ít chi phí nhân cho bài toán, để loại bỏ các giải pháp từng phần với chi phí lớn hơn giải pháp chi phí thấp nhất được tìm thấy cho đến nay. 
-Thông thường BFS duyệt kết hợp với duyệt DFS của cây không gian trạng thái đang được sử dụng. 
-
-## Hướng dẫn sử dụng repository
-
-**Cài đặt tất cả các phụ thuộc**
-```
-npm install
-```
-
-**Chạy ESLint**
-
-Bạn có thể muốn chạy nó để kiểm tra chất lượng code. 
-
-```
-npm run lint
-```
-
-**Chạy tất cả các kiểm thử**
-```
-npm test
-```
-
-**Chạy kiểm thử theo tên**
-```
-npm test -- 'LinkedList'
-```
-
-**Sân chơi**
-
-Bạn có thể chơi với các cấu trúc dữ liệu và thuật toán trong tệp `./src/playground/playground.js`
-và viết các bài kiểm thử cho nó ở `./src/playground/__test__/playground.test.js`.
-
-Sau đó, chỉ cần chạy lệnh sau để kiểm tra xem sân chơi của bạn có hoạt động như mong đợi hay không: 
-
-```
-npm test -- 'playground'
-```
-
-## Thông tin hữu ích
-
-### Tham khảo
-
-[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### Kí hiệu O lớn
-
-*Kí hiệu O lớn* được dùng để phân loại thuật toán theo thời gian chạy hoặc yêu cầu không gian gia tăng khi kích thước đầu vào gia tăng.
-Trên biểu đồ bên dưới, bạn có thể tìm thấy hầu hết các thứ tự tăng trưởng phổ biến của các thuật toán được chỉ định trong ký hiệu O lớn. 
-
-![Đồ thị O lớn](./assets/big-o-graph.png)
-
-Nguồn: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-Dưới đây là danh sách một số ký hiệu O lớn thông dụng và so sánh với các kích thước khác nhau của dữ liệu đầu vào.
-
-| Kí hiệu O lớn | Tính toán cho 10 phần tử | Tính toán cho 100 phần tử  | Tính toán cho 1000 phần tử   |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### Độ phức tạp của các phép toán cấu trúc dữ liệu
-
-| Cấu trúc dữ liệu        | Truy cập   | Tìm kiếm    | Chèn | Xóa  | Bình luận  |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- |
-| **Mảng**               | 1         | n         | n         | n         |           |
-| **Ngăn xếp**               | n         | n         | 1         | 1         |           |
-| **Hàng đợi**               | n         | n         | 1         | 1         |           |
-| **Danh sách liên kết**         | n         | n         | 1         | n         |           |
-| **Bảng băm**          | -         | n         | n         | n         | Trong trường hợp hàm băm hoàn hảo, chi phí sẽ là O(1) |
-| **Cây tìm kiếm nhị phân**  | n         | n         | n         | n         | Trong trường hợp cây cân bằng, chi phí sẽ là  O(log(n)) |
-| **Cây B**              | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Cây đỏ đen**      | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Cây AVL**            | log(n)    | log(n)    | log(n)    | log(n)    |           |
-| **Bộ lọc Bloom**        | -         | 1         | 1         | -         | Có thể có kết quả dương tính giả trong khi tìm kiếm  |
-
-### Độ phức tạp của các thuật toán sắp xếp mảng
-
-| Tên                  | Tốt nhất            | Trung bình             | Tệ nhất              | Bộ nhớ    | Ổn định    | Bình luận  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Sắp xếp nổi bọt**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Có       |           |
-| **Sắp xếp chèn**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Có       |           |
-| **Sắp xếp chọn**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Không        |           |
-| **Sắp xếp vun đống**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Không        |           |
-| **Sắp xếp trộn**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Có       |           |
-| **Sắp xếp nhanh**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Không        | Sắp xếp nhanh thường được thực hiện tại chỗ với không gian ngăn xếp O (log (n))  |
-| **Shell sort**        | n&nbsp;log(n)   | phụ thuộc vào khoảng cách dãy   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Không         |           |
-| **Sắp xếp đếm**     | n + r           | n + r               | n + r               | n + r     | Có       | r - số lớn nhất trong mảng |
-| **Sắp xếp theo cơ số**        | n * k           | n * k               | n * k               | n + k     | Có       | k - độ dài của khóa dài nhất |
-
-## Project Backers
-
-> Bạn có thể hỗ trợ dự án này qua ❤️️ [GitHub](https://github.com/sponsors/trekhleb) hoặc ❤️️ [Patreon](https://www.patreon.com/trekhleb).
-
-[Những người đang ủng hộ dự án này](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0`
diff --git a/README.zh-CN.md b/README.zh-CN.md
deleted file mode 100644
index cdef9cabea..0000000000
--- a/README.zh-CN.md
+++ /dev/null
@@ -1,297 +0,0 @@
-# JavaScript 算法与数据结构
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-本仓库包含了多种基于 JavaScript 的算法与数据结构。
-
-每种算法和数据结构都有自己的 README，包含相关说明和链接，以便进一步阅读 (还有 YouTube 视频) 。
-
-_Read this in other languages:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_繁體中文_](README.zh-TW.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-*注意：这个项目仅用于学习和研究，**不是**用于生产环境。*
-
-## 数据结构
-
-数据结构是在计算机中组织和存储数据的一种特殊方式，使得数据可以高效地被访问和修改。更确切地说，数据结构是数据值的集合，表示数据之间的关系，也包括了作用在数据上的函数或操作。
-
-`B` - 初学者， `A` - 进阶
-
-* `B` [链表](src/data-structures/linked-list/README.zh-CN.md)
-* `B` [双向链表](src/data-structures/doubly-linked-list/README.zh-CN.md)
-* `B` [队列](src/data-structures/queue/README.zh-CN.md)
-* `B` [栈](src/data-structures/stack/README.zh-CN.md)
-* `B` [哈希表(散列)](src/data-structures/hash-table/README.zh-CN.md)
-* `B` [堆](src/data-structures/heap/README.zh-CN.md) - 最大堆 & 最小堆
-* `B` [优先队列](src/data-structures/priority-queue/README.zh-CN.md)
-* `A` [字典树](src/data-structures/trie/README.zh-CN.md)
-* `A` [树](src/data-structures/tree/README.zh-CN.md)
-  * `A` [二叉查找树](src/data-structures/tree/binary-search-tree)
-  * `A` [AVL 树](src/data-structures/tree/avl-tree)
-  * `A` [红黑树](src/data-structures/tree/red-black-tree)
-  * `A` [线段树](src/data-structures/tree/segment-tree) - 使用 `最小/最大/总和` 范围查询示例
-  * `A` [树状数组](src/data-structures/tree/fenwick-tree) (二叉索引树)
-* `A` [图](src/data-structures/graph/README.zh-CN.md) (有向图与无向图)
-* `A` [并查集](src/data-structures/disjoint-set)
-* `A` [布隆过滤器](src/data-structures/bloom-filter)
-
-## 算法
-
-算法是如何解决一类问题的明确规范。算法是一组精确定义操作序列的规则。
-
-`B` - 初学者， `A` - 进阶
-
-### 算法主题
-
-* **数学**
-  * `B` [位运算](src/algorithms/math/bits) - set/get/update/clear 位、乘以/除以二进制位 、变负等
-  * `B` [阶乘](src/algorithms/math/factorial/README.zh-CN.md)
-  * `B` [斐波那契数](src/algorithms/math/fibonacci) - `经典` 和 `闭式` 版本
-  * `B` [素数检测](src/algorithms/math/primality-test) (排除法)
-  * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD)
-  * `B` [最小公倍数](src/algorithms/math/least-common-multiple) (LCM)
-  * `B` [素数筛](src/algorithms/math/sieve-of-eratosthenes) - 查找任意给定范围内的所有素数
-  * `B` [判断 2 次方数](src/algorithms/math/is-power-of-two) - 检查数字是否为 2 的幂 (原生和按位算法)
-  * `B` [杨辉三角形](src/algorithms/math/pascal-triangle)
-  * `B` [复数](src/algorithms/math/complex-number) - 复数及其基本运算
-  * `B` [弧度和角](src/algorithms/math/radian) - 弧度与角的相互转换
-  * `B` [快速算次方](src/algorithms/math/fast-powering)
-  * `A` [整数拆分](src/algorithms/math/integer-partition)
-  * `A` [割圆术](src/algorithms/math/liu-hui) - 基于 N-gons 的近似 π 计算
-  * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率
-* **集合**
-  * `B` [笛卡尔积](src/algorithms/sets/cartesian-product) - 多集合结果
-  * `A` [洗牌算法](src/algorithms/sets/fisher-yates) - 随机置换有限序列
-  * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集
-  * `A` [排列](src/algorithms/sets/permutations) (有/无重复)
-  * `A` [组合](src/algorithms/sets/combinations) (有/无重复)
-  * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [最短公共父序列](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * `A` [背包问题](src/algorithms/sets/knapsack-problem) - `0/1` 和 `无边界` 问题
-  * `A` [最大子数列问题](src/algorithms/sets/maximum-subarray) - `BF 算法` 和 `动态规划`
-  * `A` [组合求和](src/algorithms/sets/combination-sum) - 查找形成特定总和的所有组合
-* **字符串**
-  * `B` [汉明距离](src/algorithms/string/hamming-distance) - 符号不同的位置数
-  * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离
-  * `A` [Knuth–Morris–Pratt 算法](src/algorithms/string/knuth-morris-pratt) KMP 算法 - 子串搜索 (模式匹配)
-  * `A` [字符串快速查找](src/algorithms/string/z-algorithm) - 子串搜索 (模式匹配)
-  * `A` [Rabin Karp 算法](src/algorithms/string/rabin-karp) - 子串搜索
-  * `A` [最长公共子串](src/algorithms/string/longest-common-substring)
-  * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching)
-* **搜索**
-  * `B` [线性搜索](src/algorithms/search/linear-search)
-  * `B` [跳转搜索/块搜索](src/algorithms/search/jump-search) - 搜索有序数组
-  * `B` [二分查找](src/algorithms/search/binary-search) - 搜索有序数组
-  * `B` [插值搜索](src/algorithms/search/interpolation-search) - 搜索均匀分布的有序数组
-* **排序**
-  * `B` [冒泡排序](src/algorithms/sorting/bubble-sort)
-  * `B` [选择排序](src/algorithms/sorting/selection-sort)
-  * `B` [插入排序](src/algorithms/sorting/insertion-sort)
-  * `B` [堆排序](src/algorithms/sorting/heap-sort)
-  * `B` [归并排序](src/algorithms/sorting/merge-sort)
-  * `B` [快速排序](src/algorithms/sorting/quick-sort) - in-place (原地) 和 non-in-place 版本
-  * `B` [希尔排序](src/algorithms/sorting/shell-sort)
-  * `B` [计数排序](src/algorithms/sorting/counting-sort)
-  * `B` [基数排序](src/algorithms/sorting/radix-sort)
-* **链表**
-  - `B` [正向遍历](src/algorithms/linked-list/traversal)
-  - `B` [反向遍历](src/algorithms/linked-list/reverse-traversal)
-* **树**
-  * `B` [深度优先搜索](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS)
-* **图**
-  * `B` [深度优先搜索](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [广度优先搜索](src/algorithms/graph/breadth-first-search) (BFS)
-  * `B` [克鲁斯克尔演算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST)
-  * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到图中所有顶点的最短路径
-  * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到图中所有顶点的最短路径
-  * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对 之间的最短路径
-  * `A` [判圈算法](src/algorithms/graph/detect-cycle) - 对于有向图和无向图 (基于 DFS 和不相交集的版本)
-  * `A` [普林演算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST)
-  * `A` [拓扑排序](src/algorithms/graph/topological-sorting) - DFS 方法
-  * `A` [关节点](src/algorithms/graph/articulation-points) - Tarjan 算法 (基于 DFS)
-  * `A` [桥](src/algorithms/graph/bridges) - 基于 DFS 的算法
-  * `A` [欧拉回径与一笔画问题](src/algorithms/graph/eulerian-path) - Fleury 的算法 - 一次访问每个边
-  * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次
-  * `A` [强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju 算法
-  * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市
-* **加密**
-  * `B` [多项式 hash](src/algorithms/cryptography/polynomial-hash) - 基于多项式的 rolling hash 函数
-* **机器学习**
-  * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) -7个简单的JS函数，说明机器如何实际学习（向前/向后传播）
-* **未分类**
-  * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [旋转矩阵](src/algorithms/uncategorized/square-matrix-rotation) - 原地算法
-  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game) - 回溯,、动态编程 (自上而下+自下而上) 和贪婪的例子
-  * `B` [独特(唯一) 路径](src/algorithms/uncategorized/unique-paths) - 回溯、动态编程和基于 Pascal 三角形的例子
-  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱捕雨水问题 (动态编程和暴力版本)
-  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)
-  * `A` [八皇后问题](src/algorithms/uncategorized/n-queens)
-  * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour)
-
-### 算法范式
-
-算法范式是一种通用方法，基于一类算法的设计。这是比算法更高的抽象，就像算法是比计算机程序更高的抽象。
-
-* **BF 算法** - `查找/搜索` 所有可能性并选择最佳解决方案
-  * `B` [线性搜索](src/algorithms/search/linear-search)
-  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 诱导雨水问题
-  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)
-  * `A` [最大子数列](src/algorithms/sets/maximum-subarray)
-  * `A` [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市
-  * `A` [离散傅里叶变换](src/algorithms/math/fourier-transform) - 把时间信号解析成构成它的频率
-* **贪心法** - 在当前选择最佳选项，不考虑以后情况
-  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)
-  * `A` [背包问题](src/algorithms/sets/knapsack-problem)
-  * `A` [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径
-  * `A` [普里姆算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树 (MST)
-  * `A` [克鲁斯卡尔算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树 (MST)
-* **分治法** - 将问题分成较小的部分，然后解决这些部分
-  * `B` [二分查找](src/algorithms/search/binary-search)
-  * `B` [汉诺塔](src/algorithms/uncategorized/hanoi-tower)
-  * `B` [杨辉三角形](src/algorithms/math/pascal-triangle)
-  * `B` [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数 (GCD)
-  * `B` [归并排序](src/algorithms/sorting/merge-sort)
-  * `B` [快速排序](src/algorithms/sorting/quick-sort)
-  * `B` [树深度优先搜索](src/algorithms/tree/depth-first-search) (DFS)
-  * `B` [图深度优先搜索](src/algorithms/graph/depth-first-search) (DFS)
-  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)
-  * `B` [快速算次方](src/algorithms/math/fast-powering)
-  * `A` [排列](src/algorithms/sets/permutations) (有/无重复)
-  * `A` [组合](src/algorithms/sets/combinations) (有/无重复)
-* **动态规划(Dynamic programming)** - 使用以前找到的子解决方案构建解决方案
-  * `B` [斐波那契数](src/algorithms/math/fibonacci)
-  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)
-  * `B` [独特路径](src/algorithms/uncategorized/unique-paths)
-  * `B` [雨水收集](src/algorithms/uncategorized/rain-terraces) - 疏导雨水问题
-  * `B` [递归楼梯](src/algorithms/uncategorized/recursive-staircase) - 计算有共有多少种方法可以到达顶层 (4 种解题方案)
-  * `A` [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离
-  * `A` [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * `A` [最长公共子串](src/algorithms/string/longest-common-substring)
-  * `A` [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence)
-  * `A` [最短公共子序列](src/algorithms/sets/shortest-common-supersequence)
-  * `A` [0-1背包问题](src/algorithms/sets/knapsack-problem)
-  * `A` [整数拆分](src/algorithms/math/integer-partition)
-  * `A` [最大子数列](src/algorithms/sets/maximum-subarray)
-  * `A` [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径
-  * `A` [弗洛伊德算法](src/algorithms/graph/floyd-warshall) - 找到所有顶点对之间的最短路径
-  * `A` [正则表达式匹配](src/algorithms/string/regular-expression-matching)
-* **回溯法** - 类似于 `BF 算法` 试图产生所有可能的解决方案，但每次生成解决方案测试如果它满足所有条件，那么只有继续生成后续解决方案。否则回溯并继续寻找不同路径的解决方案。
-  * `B` [跳跃游戏](src/algorithms/uncategorized/jump-game)
-  * `B` [独特路径](src/algorithms/uncategorized/unique-paths)
-  * `A` [幂集](src/algorithms/sets/power-set) - 该集合的所有子集
-  * `A` [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次
-  * `A` [八皇后问题](src/algorithms/uncategorized/n-queens)
-  * `A` [骑士巡逻](src/algorithms/uncategorized/knight-tour)
-  * `A` [组合求和](src/algorithms/sets/combination-sum) - 从规定的总和中找出所有的组合
-* **Branch & Bound** - 记住在回溯搜索的每个阶段找到的成本最低的解决方案，并使用到目前为止找到的成本最小值作为下限。以便丢弃成本大于最小值的解决方案。通常，使用 BFS 遍历以及状态空间树的 DFS 遍历。
-
-## 如何使用本仓库
-
-**安装依赖**
-```
-npm install
-```
-
-**运行 ESLint**
-
-检查代码质量
-
-```
-npm run lint
-```
-
-**执行测试**
-
-```
-npm test
-```
-
-**按照名称执行测试**
-```
-npm test -- 'LinkedList'
-```
-
-**Playground**
-
-你可以在 `./src/playground/playground.js` 文件中操作数据结构与算法，并在 `./src/playground/__test__/playground.test.js` 中编写测试。
-
-然后，只需运行以下命令来测试你的 Playground 是否无误:
-
-```
-npm test -- 'playground'
-```
-
-## 有用的信息
-
-### 引用
-
-[▶ YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### 大O符号
-
-大O符号中指定的算法的增长顺序。
-
-![Big O graphs](./assets/big-o-graph.png)
-
-源: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-以下是一些最常用的 大O标记法 列表以及它们与不同大小输入数据的性能比较。
-
-| 大O标记法      | 计算10个元素                 | 计算100个元素                 | 计算1000个元素                  |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### 数据结构操作的复杂性
-
-| 数据结构       |  连接  |  查找  |  插入  |  删除  | 备注 |
-| -------------- | :----: | :----: | :----: | :----: | ---- |
-| **数组**       |   1    |   n    |   n    |   n    |      |
-| **栈**         |   n    |   n    |   1    |   1    |      |
-| **队列**       |   n    |   n    |   1    |   1    |      |
-| **链表**       |   n    |   n    |   1    |   1    |      |
-| **哈希表**     |   -    |   n    |   n    |   n    | 在完全哈希函数情况下，复杂度是 O(1） |
-| **二分查找树** |   n    |   n    |   n    |   n    | 在平衡树情况下，复杂度是 O(log(n)) |
-| **B 树**       | log(n) | log(n) | log(n) | log(n) |      |
-| **红黑树**     | log(n) | log(n) | log(n) | log(n) |      |
-| **AVL 树**     | log(n) | log(n) | log(n) | log(n) |      |
-| **布隆过滤器** |   -    |   1    |   1    | - | 存在一定概率的判断错误（误判成存在） |
-
-### 数组排序算法的复杂性
-
-| 名称                  | 最优      | 平均      | 最坏          | 内存      | 稳定      | 备注                  |
-| --------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: | --------------------- |
-| **冒泡排序**          | n         | n^2       | n^2           | 1         | Yes       |                       |
-| **插入排序**          | n         | n^2       | n^2           | 1         | Yes       |                       |
-| **选择排序**          | n^2       | n^2       | n^2           | 1         | No        |                       |
-| **堆排序**            | n log(n)  | n log(n)  | n log(n)      | 1         | No        |                       |
-| **归并排序**          | n log(n)  | n log(n)  | n log(n)      | n         | Yes       |                       |
-| **快速排序**          | n log(n)  | n log(n)  | n^2           | log(n)    | No        | 在 in-place 版本下，内存复杂度通常是 O(log(n)) |
-| **希尔排序**          | n log(n)  | 取决于差距序列   | n (log(n))^2  | 1         | No        |  |
-| **计数排序**          | n + r     | n + r     | n + r         | n + r     | Yes       | r - 数组里最大的数    |
-| **基数排序**          | n * k     | n * k     | n * k         | n + k     | Yes       | k - 最长 key 的升序   |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/README.zh-TW.md b/README.zh-TW.md
deleted file mode 100644
index 20d4381a2a..0000000000
--- a/README.zh-TW.md
+++ /dev/null
@@ -1,227 +0,0 @@
-# JavaScript 演算法與資料結構
-
-[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster)
-[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms)
-
-這個知識庫包含許多 JavaScript 的資料結構與演算法的基礎範例。
-每個演算法和資料結構都有其個別的文件，內有相關的解釋以及更多相關的文章或Youtube影片連結。
-
-_Read this in other languages:_
-[_English_](https://github.com/trekhleb/javascript-algorithms/),
-[_简体中文_](README.zh-CN.md),
-[_한국어_](README.ko-KR.md),
-[_日本語_](README.ja-JP.md),
-[_Polski_](README.pl-PL.md),
-[_Français_](README.fr-FR.md),
-[_Español_](README.es-ES.md),
-[_Português_](README.pt-BR.md),
-[_Русский_](README.ru-RU.md),
-[_Türk_](README.tr-TR.md),
-[_Italiana_](README.it-IT.md),
-[_Bahasa Indonesia_](README.id-ID.md),
-[_Українська_](README.uk-UA.md),
-[_Arabic_](README.ar-AR.md),
-[_Tiếng Việt_](README.vi-VN.md),
-[_Deutsch_](README.de-DE.md)
-
-## 資料結構
-
-資料結構是一個電腦用來組織和排序資料的特定方式，透過這樣的方式資料可以有效率地被讀取以及修改。更精確地說，一個資料結構是一個資料值的集合、彼此間的關係，函數或者運作可以應用於資料上。
-
-* [鏈結串列](src/data-structures/linked-list)
-* [貯列](src/data-structures/queue)
-* [堆疊](src/data-structures/stack)
-* [雜湊表](src/data-structures/hash-table)
-* [堆](src/data-structures/heap)
-* [優先貯列](src/data-structures/priority-queue)
-* [字典樹](src/data-structures/trie)
-* [樹](src/data-structures/tree)
-  * [二元搜尋樹](src/data-structures/tree/binary-search-tree)
-  * [AVL樹](src/data-structures/tree/avl-tree)
-  * [紅黑樹](src/data-structures/tree/red-black-tree)
-* [圖](src/data-structures/graph) (有向跟無向皆包含)
-* [互斥集](src/data-structures/disjoint-set)
-
-## 演算法
-
-演算法是一個如何解決一類問題的非模糊規格。演算法是一個具有精確地定義了一系列運作的規則的集合
-
-### 演算法議題分類
-
-* **數學類**
-  * [階層](src/algorithms/math/factorial)
-  * [費伯納西數列](src/algorithms/math/fibonacci)
-  * [Primality Test](src/algorithms/math/primality-test) (排除法)
-  * [歐幾里得算法](src/algorithms/math/euclidean-algorithm) - 計算最大公因數 (GCD)
-  * [最小公倍數](src/algorithms/math/least-common-multiple) (LCM)
-  * [整數拆分](src/algorithms/math/integer-partition)
-* **集合**
-  * [笛卡爾積](src/algorithms/sets/cartesian-product) - 多個集合的乘積
-  * [冪集合](src/algorithms/sets/power-set) - 所有集合的子集合
-  * [排列](src/algorithms/sets/permutations) (有/無重複)
-  * [组合](src/algorithms/sets/combinations) (有/無重複)
-  * [洗牌算法](src/algorithms/sets/fisher-yates) - 隨機置換一有限序列
-  * [最長共同子序列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence)
-  * [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS)
-  * [背包問題](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones
-  * [最大子序列問題](src/algorithms/sets/maximum-subarray) - 暴力法以及動態編程的(Kadane's)版本
-* **字串**
-  * [萊文斯坦距離](src/algorithms/string/levenshtein-distance) - 兩序列間的最小編輯距離
-  * [漢明距離](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
-  * [KMP 演算法](src/algorithms/string/knuth-morris-pratt) - 子字串搜尋
-  * [Rabin Karp 演算法](src/algorithms/string/rabin-karp) - 子字串搜尋
-  * [最長共通子序列](src/algorithms/string/longest-common-substring)
-* **搜尋**
-  * [二元搜尋](src/algorithms/search/binary-search)
-* **排序**
-  * [氣泡排序](src/algorithms/sorting/bubble-sort)
-  * [選擇排序](src/algorithms/sorting/selection-sort)
-  * [插入排序](src/algorithms/sorting/insertion-sort)
-  * [堆排序](src/algorithms/sorting/heap-sort)
-  * [合併排序](src/algorithms/sorting/merge-sort)
-  * [快速排序](src/algorithms/sorting/quick-sort)
-  * [希爾排序](src/algorithms/sorting/shell-sort)
-* **樹**
-  * [深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS)
-  * [廣度優先搜尋](src/algorithms/tree/breadth-first-search) (BFS)
-* **圖**
-  * [深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS)
-  * [廣度優先搜尋](src/algorithms/graph/breadth-first-search) (BFS)
-  * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑
-  * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - 找到所有圖頂點的最短路徑
-  * [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions)
-  * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * [拓撲排序](src/algorithms/graph/topological-sorting) - DFS method
-  * [關節點](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based)
-  * [橋](src/algorithms/graph/bridges) - DFS based algorithm
-  * [尤拉路徑及尤拉環](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once
-  * [漢彌爾頓環](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
-  * [強連通組件](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm
-  * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
-  * [Floyd-Warshall algorithm](src/algorithms/graph/floyd-warshall) - 一次循环可以找出所有頂點之间的最短路徑
-* **未分類**
-  * [河內塔](src/algorithms/uncategorized/hanoi-tower)
-  * [N-皇后問題](src/algorithms/uncategorized/n-queens)
-  * [騎士走棋盤](src/algorithms/uncategorized/knight-tour)
-
-### 演算法範型
-
-演算法的範型是一個泛用方法或設計一類底層演算法的方式。它是一個比演算法的概念更高階的抽象化，就像是演算法是比電腦程式更高階的抽象化。
-
-* **暴力法** - 尋遍所有的可能解然後選取最好的解
-  * [最大子序列](src/algorithms/sets/maximum-subarray)
-  * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
-* **貪婪法** - choose the best option at the current time, without any consideration for the future
-  * [未定背包問題](src/algorithms/sets/knapsack-problem)
-  * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑
-  * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-  * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph
-* **分治法** - divide the problem into smaller parts and then solve those parts
-  * [二元搜尋](src/algorithms/search/binary-search)
-  * [河內塔](src/algorithms/uncategorized/hanoi-tower)
-  * [歐幾里得演算法](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
-  * [排列](src/algorithms/sets/permutations) (有/無重複)
-  * [组合](src/algorithms/sets/combinations) (有/無重複)
-  * [合併排序](src/algorithms/sorting/merge-sort)
-  * [快速排序](src/algorithms/sorting/quick-sort)
-  * [樹深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS)
-  * [圖深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS)
-* **動態編程** - build up to a solution using previously found sub-solutions
-  * [費伯納西數列](src/algorithms/math/fibonacci)
-  * [萊溫斯坦距離](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
-  * [最長共同子序列](src/algorithms/sets/longest-common-subsequence) (LCS)
-  * [最長共同子字串](src/algorithms/string/longest-common-substring)
-  * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence)
-  * [最短共同子序列](src/algorithms/sets/shortest-common-supersequence)
-  * [0/1背包問題](src/algorithms/sets/knapsack-problem)
-  * [整數拆分](src/algorithms/math/integer-partition)
-  * [最大子序列](src/algorithms/sets/maximum-subarray)
-  * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices
-* **回溯法** - 用類似暴力法來嘗試產生所有可能解，但每次只在能滿足所有測試條件，且只有繼續產生子序列方案來產生的解決方案。否則回溯並尋找不同路徑的解決方案。
-  * [漢彌爾頓迴路](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once
-  * [N-皇后問題](src/algorithms/uncategorized/n-queens)
-  * [騎士走棋盤](src/algorithms/uncategorized/knight-tour)
-* **Branch & Bound**
-
-## 如何使用本知識庫
-
-**安裝所有必須套件**
-
-```
-npm install
-```
-
-**執行所有測試**
-```
-npm test
-```
-
-**以名稱執行該測試**
-```
-npm test -- 'LinkedList'
-```
-**練習場**
-
-你可以透過在`./src/playground/playground.js`裡面的檔案練習資料結構以及演算法，並且撰寫在`./src/playground/__test__/playground.test.js`裡面的測試程式。
-
-接著直接執行下列的指令來測試你練習的 code 是否如預期運作：
-
-```
-npm test -- 'playground'
-```
-
-## 有用的資訊
-
-### 參考
-
-[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
-### 大 O 標記
-
-特別用大 O 標記演算法增長度的排序。
-
-![Big O 表](./assets/big-o-graph.png)
-
-資料來源: [Big O Cheat Sheet](http://bigocheatsheet.com/).
-
-下列列出幾個常用的 Big O 標記以及其不同大小資料量輸入後的運算效能比較。
-
-| Big O 標記     | 10個資料量需花費的時間       | 100個資料量需花費的時間       | 1000個資料量需花費的時間        |
-| -------------- | ---------------------------- | ----------------------------- | ------------------------------- |
-| **O(1)**       | 1                            | 1                             | 1                               |
-| **O(log N)**   | 3                            | 6                             | 9                               |
-| **O(N)**       | 10                           | 100                           | 1000                            |
-| **O(N log N)** | 30                           | 600                           | 9000                            |
-| **O(N^2)**     | 100                          | 10000                         | 1000000                         |
-| **O(2^N)**     | 1024                         | 1.26e+29                      | 1.07e+301                       |
-| **O(N!)**      | 3628800                      | 9.3e+157                      | 4.02e+2567                      |
-
-### 資料結構運作複雜度
-
-| 資料結構                | 存取      | 搜尋      | 插入      | 刪除      |
-| ----------------------- | :-------: | :-------: | :-------: | :-------: |
-| **陣列**                | 1         | n         | n         | n         |
-| **堆疊**                | n         | n         | 1         | 1         |
-| **貯列**                | n         | n         | 1         | 1         |
-| **鏈結串列**            | n         | n         | 1         | 1         |
-| **雜湊表**              | -         | n         | n         | n         |
-| **二元搜尋樹**          | n         | n         | n         | n         |
-| **B-Tree**              | log(n)    | log(n)    | log(n)    | log(n)    |
-| **紅黑樹**              | log(n)    | log(n)    | log(n)    | log(n)    |
-| **AVL Tree**            | log(n)    | log(n)    | log(n)    | log(n)    |
-
-### 陣列排序演算法複雜度
-
-| 名稱                   | 最佳      | 平均      | 最差          | 記憶體    | 穩定      |
-| ---------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: |
-| **氣泡排序**           | n         | n^2       | n^2           | 1         | Yes       |
-| **插入排序**           | n         | n^2       | n^2           | 1         | Yes       |
-| **選擇排序**           | n^2       | n^2       | n^2           | 1         | No        |
-| **Heap 排序**          | n log(n)  | n log(n)  | n log(n)      | 1         | No        |
-| **合併排序**           | n log(n)  | n log(n)  | n log(n)      | n         | Yes       |
-| **快速排序**           | n log(n)  | n log(n)  | n^2           | log(n)    | No        |
-| **希爾排序**           | n log(n)  | 由gap sequence決定   | n (log(n))^2  | 1         | No        |
-
-> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev)
diff --git a/src/algorithms/cryptography/caesar-cipher/README.en-EN.md b/src/algorithms/cryptography/caesar-cipher/README.en-EN.md
new file mode 100644
index 0000000000..1e077a91c5
--- /dev/null
+++ b/src/algorithms/cryptography/caesar-cipher/README.en-EN.md
@@ -0,0 +1,33 @@
+# Caesar Cipher Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In cryptography, a **Caesar cipher**, also known as **Caesar's cipher**, the **shift cipher**, **Caesar's code** or **Caesar shift**, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of `3`, `D` would be replaced by `A`, `E` would become `B`, and so on. The method is named after Julius Caesar, who used it in his private correspondence.
+
+![Caesar Cipher Algorithm](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)
+
+## Example
+
+The transformation can be represented by aligning two alphabets; the cipher alphabet is the plain alphabet rotated left or right by some number of positions. For instance, here is a Caesar cipher using a left rotation of three places, equivalent to a right shift of 23 (the shift parameter is used as the key):
+
+```text
+Plain:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
+Cipher:   XYZABCDEFGHIJKLMNOPQRSTUVW
+```
+
+When encrypting, a person looks up each letter of the message in the "plain" line and writes down the corresponding letter in the "cipher" line.
+
+```text
+Plaintext:  THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
+Ciphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
+```
+
+## Complexity
+
+- Time: `O(|n|)`
+- Space: `O(|n|)`
+
+## References
+
+- [Caesar cipher on Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)
diff --git a/src/algorithms/cryptography/caesar-cipher/README.md b/src/algorithms/cryptography/caesar-cipher/README.md
index d648a62ee9..1b928be9e2 100644
--- a/src/algorithms/cryptography/caesar-cipher/README.md
+++ b/src/algorithms/cryptography/caesar-cipher/README.md
@@ -1,33 +1,33 @@
-# Caesar Cipher Algorithm
+# Thuật toán Mật mã Caesar
 
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md)
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In cryptography, a **Caesar cipher**, also known as **Caesar's cipher**, the **shift cipher**, **Caesar's code** or **Caesar shift**, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of `3`, `D` would be replaced by `A`, `E` would become `B`, and so on. The method is named after Julius Caesar, who used it in his private correspondence.
+Trong mật mã học, **Mật mã Caesar**, còn được gọi là **mã của Caesar**, **mật mã dịch chuyển**, **mã Caesar** hoặc **dịch chuyển Caesar**, là một trong những kỹ thuật mã hóa đơn giản và được biết đến rộng rãi nhất. Đây là một dạng của mật mã thay thế, trong đó mỗi chữ cái trong văn bản gốc được thay thế bởi một chữ cái cách đó một số vị trí nhất định trong bảng chữ cái. Ví dụ, với một dịch chuyển sang trái `3`, `D` sẽ được thay thế bởi `A`, `E` sẽ trở thành `B`, v.v. Phương pháp này được đặt theo tên Julius Caesar, người đã sử dụng nó trong thư từ cá nhân của mình.
 
-![Caesar Cipher Algorithm](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)
+![Thuật toán Mật mã Caesar](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)
 
-## Example
+## Ví dụ
 
-The transformation can be represented by aligning two alphabets; the cipher alphabet is the plain alphabet rotated left or right by some number of positions. For instance, here is a Caesar cipher using a left rotation of three places, equivalent to a right shift of 23 (the shift parameter is used as the key):
+Sự biến đổi này có thể được thể hiện bằng cách căn chỉnh hai bảng chữ cái; bảng chữ cái mã là bảng chữ cái gốc xoay trái hoặc phải một số vị trí nhất định. Ví dụ, đây là một mật mã Caesar sử dụng một xoay trái ba vị trí, tương đương với một dịch chuyển phải 23 (tham số dịch chuyển được sử dụng như là khóa):
 
 ```text
-Plain:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
-Cipher:   XYZABCDEFGHIJKLMNOPQRSTUVW
+Bảng chữ cái gốc:  ABCDEFGHIJKLMNOPQRSTUVWXYZ
+Bảng chữ cái mã:   XYZABCDEFGHIJKLMNOPQRSTUVW
 ```
 
-When encrypting, a person looks up each letter of the message in the "plain" line and writes down the corresponding letter in the "cipher" line.
+Khi mã hóa, người ta tìm từng chữ cái của tin nhắn trong dòng "bảng chữ cái gốc" và viết ra chữ cái tương ứng trong dòng "bảng chữ cái mã".
 
 ```text
-Plaintext:  THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
-Ciphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
+Văn bản gốc:  THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
+Văn bản mã:   QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
 ```
 
-## Complexity
+## Độ phức tạp
 
-- Time: `O(|n|)`
-- Space: `O(|n|)`
+- Thời gian: `O(|n|)`
+- Không gian: `O(|n|)`
 
-## References
+## Tài liệu tham khảo
 
-- [Caesar cipher on Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)
+- [Mật mã Caesar trên Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)
diff --git a/src/algorithms/cryptography/caesar-cipher/README.ru-RU.md b/src/algorithms/cryptography/caesar-cipher/README.ru-RU.md
deleted file mode 100644
index dee4d14cd3..0000000000
--- a/src/algorithms/cryptography/caesar-cipher/README.ru-RU.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Алгоритм шифра Цезаря
-
-В криптографии **шифр Цезаря**, также известный как **шифр сдвига**, **код Цезаря** или **сдвиг Цезаря**, является одним из самых простых и широко известных методов шифрования. Это вид шифра подстановки, в котором каждый символ в открытом тексте заменяется символом, находящимся на некотором постоянном числе позиций левее или правее него в алфавите. Например, в шифре со сдвигом вправо на `3`, `D` была бы заменена на `A`, `E` станет `B`, и так далее. Метод назван в честь Юлия Цезаря, который использовал его в своей личной переписке.
-
-![Алгоритм шифра Цезаря](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)
-
-## Пример
-Это преобразование можно представить как выравнивание двух алфавитов; алфавит шифра - это обычный алфавит, повёрнутый влево или вправо на некоторое количество позиций. Например, здесь приведен шифр Цезаря, использующий поворот влево на три позиции, что эквивалентно сдвигу вправо на 23 (параметр сдвига используется в качестве ключа):
-
-```text
-Обычный:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
-Шифрованный:   XYZABCDEFGHIJKLMNOPQRSTUVW
-```
-
-При шифровании человек просматривает каждую букву сообщения в "открытой" строке и записывает соответствующую букву в "шифрованной" строке.
-
-```text
-Обычный текст:     THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
-Шифрованный текст: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
-```
-
-## Сложность
-
-- Время: `O(|n|)`
-- Пространство: `O(|n|)`
-
-## Ссылки
-
-- [Шифр Цезаря на Wikipedia](https://ru.wikipedia.org/wiki/Шифр_Цезаря)
diff --git a/src/algorithms/cryptography/hill-cipher/README.en-EN.md b/src/algorithms/cryptography/hill-cipher/README.en-EN.md
new file mode 100644
index 0000000000..84c104941c
--- /dev/null
+++ b/src/algorithms/cryptography/hill-cipher/README.en-EN.md
@@ -0,0 +1,98 @@
+# Hill Cipher
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **Hill cipher** is a [polygraphic substitution](https://en.wikipedia.org/wiki/Polygraphic_substitution) cipher based on linear algebra.
+
+Each letter is represented by a number [modulo](https://en.wikipedia.org/wiki/Modular_arithmetic) `26`. Though this is not an essential feature of the cipher, this simple scheme is often used:
+
+| **Letter** | A   | B   | C   | D   | E   | F   | G   | H   | I   | J   | K   | L   | M   | N   | O   | P   | Q   | R   | S   | T   | U   | V   | W   | X   | Y   | Z   |
+| ---------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| **Number** | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   | 8   | 9   | 10  | 11  | 12  | 13  | 14  | 15  | 16  | 17  | 18  | 19  | 20  | 21  | 22  | 23  | 24  | 25  |
+
+## Encryption
+
+To encrypt a message, each block of `n` letters (considered as an `n`-component vector) is multiplied by an invertible `n × n` matrix, against modulus `26`.
+
+The matrix used for encryption is the _cipher key_, and it should be chosen randomly from the set of invertible `n × n` matrices (modulo `26`). The cipher can, of course, be adapted to an alphabet with any number of letters; all arithmetic just needs to be done modulo the number of letters instead of modulo `26`.
+
+Consider the message `ACT`, and the key below (or `GYB/NQK/URP` in letters):
+
+```
+| 6   24   1  |
+| 13  16   10 |
+| 20  17   15 |
+```
+
+Since `A` is`0`, `C` is `2` and `T` is `19`, the message is the vector:
+
+```
+|  0  |
+|  2  |
+|  19 |
+```
+
+Thus, the enciphered vector is given by:
+
+```
+| 6   24   1  |  |  0  |   |  67  |   |  15 |
+| 13  16   10 |  |  2  | = |  222 | ≡ |  14 | (mod 26)
+| 20  17   15 |  |  19 |   |  319 |   |  7  |
+```
+
+which corresponds to a ciphertext of `POH`.
+
+Now, suppose that our message is instead `CAT` (notice how we're using the same letters as in `ACT` here), or:
+
+```
+|  2  |
+|  0  |
+|  19 |
+```
+
+This time, the enciphered vector is given by:
+
+```
+| 6   24   1  |  |  2  |   |  31  |   |  5  |
+| 13  16   10 |  |  0  | = |  216 | ≡ |  8  | (mod 26)
+| 20  17   15 |  |  19 |   |  325 |   |  13 |
+```
+
+which corresponds to a ciphertext of `FIN`. Every letter has changed.
+
+## Decryption
+
+To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. We turn the ciphertext back into a vector, then simply multiply by the inverse matrix of the key matrix (`IFK/VIV/VMI` in letters). (See [matrix inversion](https://en.wikipedia.org/wiki/Matrix_inversion) for methods to calculate the inverse matrix.) We find that, modulo 26, the inverse of the matrix used in the previous example is:
+
+```
+                -1
+| 6   24   1  |                | 8   5    10 |
+| 13  16   10 |    (mod 26) ≡  | 21  8    21 |
+| 20  17   15 |                | 21  12   8  |
+```
+
+Taking the previous example ciphertext of `POH`, we get:
+
+```
+| 8   5    10 |  |  15 |   |  260 |   |  0  |
+| 21  8    21 |  |  14 | = |  574 | ≡ |  2  | (mod 26)
+| 21  12   8  |  |  7  |   |  539 |   |  19 |
+```
+
+which gets us back to `ACT`, as expected.
+
+## Defining the encrypting matrix
+
+Two complications exist in picking the encrypting matrix:
+
+1. Not all matrices have an inverse. The matrix will have an inverse if and only if its [determinant](https://en.wikipedia.org/wiki/Determinant) is not zero.
+2. The determinant of the encrypting matrix must not have any common factors with the modular base.
+
+Thus, if we work modulo `26` as above, the determinant must be nonzero, and must not be divisible by `2` or `13`. If the determinant is `0`, or has common factors with the modular base, then the matrix cannot be used in the Hill cipher, and another matrix must be chosen (otherwise it will not be possible to decrypt). Fortunately, matrices which satisfy the conditions to be used in the Hill cipher are fairly common.
+
+## References
+
+- [Hill cipher on Wikipedia](https://en.wikipedia.org/wiki/Hill_cipher)
+- [Matrix inversion on MathIsFun](https://www.mathsisfun.com/algebra/matrix-inverse.html)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/hill-cipher/)
diff --git a/src/algorithms/cryptography/hill-cipher/README.md b/src/algorithms/cryptography/hill-cipher/README.md
index bf496e2be9..d5fffac245 100644
--- a/src/algorithms/cryptography/hill-cipher/README.md
+++ b/src/algorithms/cryptography/hill-cipher/README.md
@@ -1,20 +1,23 @@
-# Hill Cipher
+# Thuật toán Mật mã Hill
 
-The **Hill cipher** is a [polygraphic substitution](https://en.wikipedia.org/wiki/Polygraphic_substitution) cipher based on linear algebra.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Each letter is represented by a number [modulo](https://en.wikipedia.org/wiki/Modular_arithmetic) `26`. Though this is not an essential feature of the cipher, this simple scheme is often used:
+Mật mã Hill là một loại [mật mã thay thế đa ký tự](https://en.wikipedia.org/wiki/Polygraphic_substitution) dựa trên đại số tuyến tính.
 
-| **Letter** | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
-| ------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
-| **Number** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
+Mỗi chữ cái được biểu diễn bằng một số [theo modulo](https://en.wikipedia.org/wiki/Modular_arithmetic) `26`. Mặc dù đây không phải là tính năng thiết yếu của thuật toán, nhưng đây là một phương án đơn giản thường được sử dụng:
 
-## Encryption
+| **Chữ cái** | A   | B   | C   | D   | E   | F   | G   | H   | I   | J   | K   | L   | M   | N   | O   | P   | Q   | R   | S   | T   | U   | V   | W   | X   | Y   | Z   |
+| ----------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| **Số**      | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   | 8   | 9   | 10  | 11  | 12  | 13  | 14  | 15  | 16  | 17  | 18  | 19  | 20  | 21  | 22  | 23  | 24  | 25  |
 
-To encrypt a message, each block of `n` letters (considered as an `n`-component vector) is multiplied by an invertible `n × n` matrix, against modulus `26`.
+## Mã hóa
 
-The matrix used for encryption is the _cipher key_, and it should be chosen randomly from the set of invertible `n × n` matrices (modulo `26`). The cipher can, of course, be adapted to an alphabet with any number of letters; all arithmetic just needs to be done modulo the number of letters instead of modulo `26`.
+Để mã hóa một thông điệp, mỗi khối `n` chữ cái (xem như một vector `n` thành phần) được nhân với một ma trận `n × n` khả nghịch, với modulo `26`.
 
-Consider the message `ACT`, and the key below (or `GYB/NQK/URP` in letters):
+Ma trận được sử dụng để mã hóa là _khóa mật mã_, và nó nên được chọn ngẫu nhiên từ tập hợp các ma trận `n × n` khả nghịch (theo modulo `26`). Mật mã có thể được điều chỉnh cho bảng chữ cái với bất kỳ số lượng chữ cái nào; tất cả các phép tính chỉ cần được thực hiện theo modulo số lượng chữ cái thay vì modulo `26`.
+
+Xét thông điệp `ACT`, và khóa dưới đây (hoặc `GYB/NQK/URP` bằng chữ):
 
 ```
 | 6   24   1  |
@@ -22,7 +25,7 @@ Consider the message `ACT`, and the key below (or `GYB/NQK/URP` in letters):
 | 20  17   15 |
 ```
 
-Since `A` is`0`, `C` is `2` and `T` is `19`, the message is the vector:
+Vì `A` là `0`, `C` là `2` và `T` là `19`, thông điệp là vector:
 
 ```
 |  0  |
@@ -30,7 +33,7 @@ Since `A` is`0`, `C` is `2` and `T` is `19`, the message is the vector:
 |  19 |
 ```
 
-Thus, the enciphered vector is given by:
+Do đó, vector được mã hóa là:
 
 ```
 | 6   24   1  |  |  0  |   |  67  |   |  15 |
@@ -38,9 +41,9 @@ Thus, the enciphered vector is given by:
 | 20  17   15 |  |  19 |   |  319 |   |  7  |
 ```
 
-which corresponds to a ciphertext of `POH`.
+tương ứng với văn bản mã hóa là `POH`.
 
-Now, suppose that our message is instead `CAT` (notice how we're using the same letters as in `ACT` here), or:
+Bây giờ, giả sử rằng thông điệp của chúng ta là `CAT` (lưu ý là chúng ta đang sử dụng cùng các chữ cái như trong `ACT` ở đây), hoặc:
 
 ```
 |  2  |
@@ -48,7 +51,7 @@ Now, suppose that our message is instead `CAT` (notice how we're using the same
 |  19 |
 ```
 
-This time, the enciphered vector is given by:
+Lần này, vector được mã hóa là:
 
 ```
 | 6   24   1  |  |  2  |   |  31  |   |  5  |
@@ -56,11 +59,11 @@ This time, the enciphered vector is given by:
 | 20  17   15 |  |  19 |   |  325 |   |  13 |
 ```
 
-which corresponds to a ciphertext of `FIN`. Every letter has changed.
+tương ứng với văn bản mã hóa là `FIN`. Mỗi chữ cái đã thay đổi.
 
-## Decryption
+## Giải mã
 
-To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. We turn the ciphertext back into a vector, then simply multiply by the inverse matrix of the key matrix (`IFK/VIV/VMI` in letters). (See [matrix inversion](https://en.wikipedia.org/wiki/Matrix_inversion) for methods to calculate the inverse matrix.) We find that, modulo 26, the inverse of the matrix used in the previous example is:
+Để giải mã thông điệp, mỗi khối được nhân với nghịch đảo của ma trận được sử dụng để mã hóa. Chúng ta chuyển văn bản mã hóa trở lại thành vector, sau đó chỉ đơn giản nhân với ma trận nghịch đảo của ma trận khóa (`IFK/VIV/VMI` bằng chữ). (Xem [nghịch đảo ma trận](https://en.wikipedia.org/wiki/Matrix_inversion) để biết các phương pháp tính ma trận nghịch đảo.) Chúng ta thấy rằng, theo modulo 26, ma trận nghịch đảo của ma trận được sử dụng trong ví dụ trước là:
 
 ```
                 -1
@@ -69,7 +72,7 @@ To decrypt the message, each block is multiplied by the inverse of the matrix us
 | 20  17   15 |                | 21  12   8  |
 ```
 
-Taking the previous example ciphertext of `POH`, we get:
+Lấy ví dụ văn bản mã hóa trước là `POH`, chúng ta có:
 
 ```
 | 8   5    10 |  |  15 |   |  260 |   |  0  |
@@ -77,20 +80,19 @@ Taking the previous example ciphertext of `POH`, we get:
 | 21  12   8  |  |  7  |   |  539 |   |  19 |
 ```
 
-which gets us back to `ACT`, as expected.
+đưa chúng ta trở lại `ACT`, như mong đợi.
 
-## Defining the encrypting matrix
+## Định nghĩa ma trận mã hóa
 
-Two complications exist in picking the encrypting matrix:
+Có hai vấn đề tồn tại trong việc chọn ma trận mã hóa:
 
-1. Not all matrices have an inverse. The matrix will have an inverse if and only if its [determinant](https://en.wikipedia.org/wiki/Determinant) is not zero.
-2. The determinant of the encrypting matrix must not have any common factors with the modular base.
+1. Không phải tất cả các ma trận đều có nghịch đảo. Ma trận sẽ có nghịch đảo nếu và chỉ nếu [định thức](https://en.wikipedia.org/wiki/Determinant) của nó không phải là không.
+2. Định thức của ma trận mã hóa không được có các yếu tố chung với cơ số modulo.
 
-Thus, if we work modulo `26` as above, the determinant must be nonzero, and must not be divisible by `2` or `13`. If the determinant is `0`, or has common factors with the modular base, then the matrix cannot be used in the Hill cipher, and another matrix must be chosen (otherwise it will not be possible to decrypt). Fortunately, matrices which satisfy the conditions to be used in the Hill cipher are fairly common.
+Do đó, nếu chúng ta làm việc theo modulo `26` như trên, định thức phải khác không và không được chia hết cho `2` hoặc `13`. Nếu định thức là `0` hoặc có các yếu tố chung với cơ sở modulo, thì ma trận đó không thể được sử dụng trong mật mã Hill, và một ma trận khác phải được chọn (nếu không sẽ không thể giải mã). May mắn thay, các ma trận đáp ứng điều kiện để sử dụng trong mật mã Hill khá phổ biến.
 
-## References
+## Tài liệu tham khảo
 
-- [Hill cipher on Wikipedia](https://en.wikipedia.org/wiki/Hill_cipher)
-- [Matrix inversion on MathIsFun](https://www.mathsisfun.com/algebra/matrix-inverse.html)
+- [Mật mã Hill trên Wikipedia](https://en.wikipedia.org/wiki/Hill_cipher)
+- [Nghịch đảo ma trận trên MathIsFun](https://www.mathsisfun.com/algebra/matrix-inverse.html)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/hill-cipher/)
-
diff --git a/src/algorithms/cryptography/polynomial-hash/README.en-EN.md b/src/algorithms/cryptography/polynomial-hash/README.en-EN.md
new file mode 100644
index 0000000000..4b2600edde
--- /dev/null
+++ b/src/algorithms/cryptography/polynomial-hash/README.en-EN.md
@@ -0,0 +1,119 @@
+# Polynomial Rolling Hash
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## Hash Function
+
+**Hash functions** are used to map large data sets of elements of an arbitrary
+length (_the keys_) to smaller data sets of elements of a fixed length
+(_the fingerprints_).
+
+The basic application of hashing is efficient testing of equality of keys by
+comparing their fingerprints.
+
+A _collision_ happens when two different keys have the same fingerprint. The way
+in which collisions are handled is crucial in most applications of hashing.
+Hashing is particularly useful in construction of efficient practical algorithms.
+
+## Rolling Hash
+
+A **rolling hash** (also known as recursive hashing or rolling checksum) is a hash
+function where the input is hashed in a window that moves through the input.
+
+A few hash functions allow a rolling hash to be computed very quickly — the new
+hash value is rapidly calculated given only the following data:
+
+- old hash value,
+- the old value removed from the window,
+- and the new value added to the window.
+
+## Polynomial String Hashing
+
+An ideal hash function for strings should obviously depend both on the _multiset_ of
+the symbols present in the key and on the _order_ of the symbols. The most common
+family of such hash functions treats the symbols of a string as coefficients of
+a _polynomial_ with an integer variable `p` and computes its value modulo an
+integer constant `M`:
+
+The _Rabin–Karp string search algorithm_ is often explained using a very simple
+rolling hash function that only uses multiplications and
+additions - **polynomial rolling hash**:
+
+> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = s<sub>0</sub> _ p<sup>k-1</sup> + s<sub>1</sub> _ p<sup>k-2</sup> + ... + s<sub>k</sub> \* p<sup>0</sup>
+
+where `p` is a constant, and _(s<sub>1</sub>, ... , s<sub>k</sub>)_ are the input
+characters.
+
+For example we can convert short strings to key numbers by multiplying digit codes by
+powers of a constant. The three letter word `ace` could turn into a number
+by calculating:
+
+> key = 1 _ 26<sup>2</sup> + 3 _ 26<sup>1</sup> + 5 \* 26<sup>0</sup>
+
+In order to avoid manipulating huge `H` values, all math is done modulo `M`.
+
+> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = (s<sub>0</sub> _ p<sup>k-1</sup> + s<sub>1</sub> _ p<sup>k-2</sup> + ... + s<sub>k</sub> \* p<sup>0</sup>) mod M
+
+A careful choice of the parameters `M`, `p` is important to obtain “good”
+properties of the hash function, i.e., low collision rate.
+
+This approach has the desirable attribute of involving all the characters in the
+input string. The calculated key value can then be hashed into an array index in
+the usual way:
+
+```javascript
+function hash(key, arraySize) {
+  const base = 13;
+
+  let hash = 0;
+  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {
+    const charCode = key.charCodeAt(charIndex);
+    hash += charCode * base ** (key.length - charIndex - 1);
+  }
+
+  return hash % arraySize;
+}
+```
+
+The `hash()` method is not as efficient as it might be. Other than the
+character conversion, there are two multiplications and an addition inside
+the loop. We can eliminate one multiplication by using \*_Horner's method_:
+
+> a<sub>4</sub> _ x<sup>4</sup> + a<sub>3</sub> _ x<sup>3</sup> + a<sub>2</sub> _ x<sup>2</sup> + a<sub>1</sub> _ x<sup>1</sup> + a<sub>0</sub> = (((a<sub>4</sub> _ x + a<sub>3</sub>) _ x + a<sub>2</sub>) _ x + a<sub>1</sub>) _ x + a<sub>0</sub>
+
+In other words:
+
+> H<sub>i</sub> = (P \* H<sub>i-1</sub> + S<sub>i</sub>) mod M
+
+The `hash()` cannot handle long strings because the hashVal exceeds the size of
+int. Notice that the key always ends up being less than the array size.
+In Horner's method we can apply the modulo (%) operator at each step in the
+calculation. This gives the same result as applying the modulo operator once at
+the end, but avoids the overflow.
+
+```javascript
+function hash(key, arraySize) {
+  const base = 13;
+
+  let hash = 0;
+  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {
+    const charCode = key.charCodeAt(charIndex);
+    hash = (hash * base + charCode) % arraySize;
+  }
+
+  return hash;
+}
+```
+
+Polynomial hashing has a rolling property: the fingerprints can be updated
+efficiently when symbols are added or removed at the ends of the string
+(provided that an array of powers of p modulo M of sufficient length is stored).
+The popular Rabin–Karp pattern matching algorithm is based on this property
+
+## References
+
+- [Where to Use Polynomial String Hashing](https://www.mii.lt/olympiads_in_informatics/pdf/INFOL119.pdf)
+- [Hashing on uTexas](https://www.cs.utexas.edu/~mitra/csSpring2017/cs313/lectures/hash.html)
+- [Hash Function on Wikipedia](https://en.wikipedia.org/wiki/Hash_function)
+- [Rolling Hash on Wikipedia](https://en.wikipedia.org/wiki/Rolling_hash)
diff --git a/src/algorithms/cryptography/polynomial-hash/README.md b/src/algorithms/cryptography/polynomial-hash/README.md
index 7355d6649b..6873ba5efc 100644
--- a/src/algorithms/cryptography/polynomial-hash/README.md
+++ b/src/algorithms/cryptography/polynomial-hash/README.md
@@ -1,63 +1,47 @@
-# Polynomial Rolling Hash
+# Băm Đa Thức Cuộn
 
-## Hash Function
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-**Hash functions** are used to map large data sets of elements of an arbitrary 
-length (*the keys*) to smaller data sets of elements of a fixed length
-(*the fingerprints*).
+## Hàm Băm
 
-The basic application of hashing is efficient testing of equality of keys by
-comparing their fingerprints.
+**Hàm băm** được sử dụng để ánh xạ các tập dữ liệu lớn các phần tử có chiều dài tùy ý (_các khóa_) thành các tập dữ liệu nhỏ hơn các phần tử có chiều dài cố định (_các dấu vân tay_).
 
-A *collision* happens when two different keys have the same fingerprint. The way 
-in which collisions are handled is crucial in most applications of hashing. 
-Hashing is particularly useful in construction of efficient practical algorithms.
+Ứng dụng cơ bản của băm là kiểm tra hiệu quả sự bằng nhau của các khóa bằng cách so sánh các dấu vân tay của chúng.
 
-## Rolling Hash
+Một _xung đột_ xảy ra khi hai khóa khác nhau có cùng một dấu vân tay. Cách xử lý các xung đột là rất quan trọng trong hầu hết các ứng dụng của băm. Băm đặc biệt hữu ích trong việc xây dựng các thuật toán thực tiễn hiệu quả.
 
-A **rolling hash** (also known as recursive hashing or rolling checksum) is a hash
-function where the input is hashed in a window that moves through the input.
+## Băm Cuộn
 
-A few hash functions allow a rolling hash to be computed very quickly — the new 
-hash value is rapidly calculated given only the following data:
+**Băm cuộn** (còn được gọi là băm đệ quy hoặc checksum cuộn) là một hàm băm nơi đầu vào được băm trong một cửa sổ di chuyển qua đầu vào.
 
-- old hash value,
-- the old value removed from the window,
-- and the new value added to the window.
+Một số hàm băm cho phép băm cuộn được tính toán rất nhanh — giá trị băm mới được tính nhanh chóng chỉ với dữ liệu sau:
 
-## Polynomial String Hashing
+- giá trị băm cũ,
+- giá trị cũ được loại bỏ khỏi cửa sổ,
+- và giá trị mới được thêm vào cửa sổ.
 
-An ideal hash function for strings should obviously depend both on the *multiset* of
-the symbols present in the key and on the *order* of the symbols. The most common 
-family of such hash functions treats the symbols of a string as coefficients of 
-a *polynomial* with an integer variable `p` and computes its value modulo an 
-integer constant `M`:
+## Băm Chuỗi Đa Thức
 
-The *Rabin–Karp string search algorithm* is often explained using a very simple
-rolling hash function that only uses multiplications and 
-additions - **polynomial rolling hash**:
+Một hàm băm lý tưởng cho chuỗi nên phụ thuộc vào cả _multiset_ của các ký tự có trong khóa và _thứ tự_ của các ký tự. Họ hàm băm phổ biến nhất xử lý các ký tự của một chuỗi như các hệ số của một _đa thức_ với biến số nguyên `p` và tính giá trị của nó theo mô-đun hằng số nguyên `M`:
 
-> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = s<sub>0</sub> * p<sup>k-1</sup> + s<sub>1</sub> * p<sup>k-2</sup> + ... + s<sub>k</sub> * p<sup>0</sup>
+_Thuật toán tìm kiếm chuỗi Rabin–Karp_ thường được giải thích sử dụng một hàm băm cuộn rất đơn giản chỉ sử dụng phép nhân và phép cộng — **băm đa thức cuộn**:
 
-where `p` is a constant, and *(s<sub>1</sub>, ... , s<sub>k</sub>)* are the input
-characters.
+> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = s<sub>0</sub> _ p<sup>k-1</sup> + s<sub>1</sub> _ p<sup>k-2</sup> + ... + s<sub>k</sub> \* p<sup>0</sup>
 
-For example we can convert short strings to key numbers by multiplying digit codes by 
-powers of a constant. The three letter word `ace` could turn into a number 
-by calculating:
+trong đó `p` là hằng số, và _(s<sub>1</sub>, ..., s<sub>k</sub>)_ là các ký tự đầu vào.
 
-> key = 1 * 26<sup>2</sup> + 3 * 26<sup>1</sup> + 5 * 26<sup>0</sup>
+Ví dụ, chúng ta có thể chuyển đổi chuỗi ngắn thành số khóa bằng cách nhân các mã số ký tự với lũy thừa của một hằng số. Từ ba chữ cái `ace` có thể được chuyển thành một số bằng cách tính:
 
-In order to avoid manipulating huge `H` values, all math is done modulo `M`.
+> khóa = 1 _ 26<sup>2</sup> + 3 _ 26<sup>1</sup> + 5 \* 26<sup>0</sup>
 
-> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = (s<sub>0</sub> * p<sup>k-1</sup> + s<sub>1</sub> * p<sup>k-2</sup> + ... + s<sub>k</sub> * p<sup>0</sup>) mod M
+Để tránh xử lý các giá trị `H` quá lớn, tất cả các phép toán đều được thực hiện theo mô-đun `M`.
 
-A careful choice of the parameters `M`, `p` is important to obtain “good”
-properties of the hash function, i.e., low collision rate.
+> H(s<sub>0</sub>, s<sub>1</sub>, ..., s<sub>k</sub>) = (s<sub>0</sub> _ p<sup>k-1</sup> + s<sub>1</sub> _ p<sup>k-2</sup> + ... + s<sub>k</sub> \* p<sup>0</sup>) mod M
 
-This approach has the desirable attribute of involving all the characters in the 
-input string. The calculated key value can then be hashed into an array index in
-the usual way:
+Việc lựa chọn cẩn thận các tham số `M`, `p` là quan trọng để có được các thuộc tính "tốt" của hàm băm, tức là tỷ lệ xung đột thấp.
+
+Cách tiếp cận này có đặc điểm mong muốn là liên quan đến tất cả các ký tự trong chuỗi đầu vào. Giá trị khóa tính toán sau đó có thể được băm thành chỉ số mảng theo cách thông thường:
 
 ```javascript
 function hash(key, arraySize) {
@@ -66,28 +50,22 @@ function hash(key, arraySize) {
   let hash = 0;
   for (let charIndex = 0; charIndex < key.length; charIndex += 1) {
     const charCode = key.charCodeAt(charIndex);
-    hash += charCode * (base ** (key.length - charIndex - 1));
+    hash += charCode * base ** (key.length - charIndex - 1);
   }
 
   return hash % arraySize;
 }
 ```
 
-The `hash()` method is not as efficient as it might be. Other than the 
-character conversion, there are two multiplications and an addition inside 
-the loop. We can eliminate one multiplication by using **Horner's method*:
- 
-> a<sub>4</sub> * x<sup>4</sup> + a<sub>3</sub> * x<sup>3</sup> + a<sub>2</sub> * x<sup>2</sup> + a<sub>1</sub> * x<sup>1</sup> + a<sub>0</sub> = (((a<sub>4</sub> * x + a<sub>3</sub>) * x + a<sub>2</sub>) * x + a<sub>1</sub>) * x + a<sub>0</sub>
+Phương thức `hash()` không hiệu quả như nó có thể. Ngoài việc chuyển đổi ký tự, có hai phép nhân và một phép cộng bên trong vòng lặp. Chúng ta có thể loại bỏ một phép nhân bằng cách sử dụng **phương pháp Horner**:
+
+> a<sub>4</sub> _ x<sup>4</sup> + a<sub>3</sub> _ x<sup>3</sup> + a<sub>2</sub> _ x<sup>2</sup> + a<sub>1</sub> _ x<sup>1</sup> + a<sub>0</sub> = (((a<sub>4</sub> _ x + a<sub>3</sub>) _ x + a<sub>2</sub>) _ x + a<sub>1</sub>) _ x + a<sub>0</sub>
 
-In other words:
+Nói cách khác:
 
-> H<sub>i</sub> = (P * H<sub>i-1</sub> + S<sub>i</sub>) mod M
+> H<sub>i</sub> = (P \* H<sub>i-1</sub> + S<sub>i</sub>) mod M
 
-The `hash()` cannot handle long strings because the hashVal exceeds the size of 
-int. Notice that the key always ends up being less than the array size. 
-In Horner's method we can apply the modulo (%) operator at each step in the 
-calculation. This gives the same result as applying the modulo operator once at 
-the end, but avoids the overflow.
+Phương thức `hash()` không thể xử lý chuỗi dài vì hashVal vượt quá kích thước của int. Lưu ý rằng khóa luôn nhỏ hơn kích thước mảng. Trong phương pháp Horner, chúng ta có thể áp dụng toán tử modulo (%) tại mỗi bước trong tính toán. Điều này cho kết quả giống như áp dụng toán tử modulo một lần ở cuối, nhưng tránh được tràn số.
 
 ```javascript
 function hash(key, arraySize) {
@@ -103,14 +81,11 @@ function hash(key, arraySize) {
 }
 ```
 
-Polynomial hashing has a rolling property: the fingerprints can be updated 
-efficiently when symbols are added or removed at the ends of the string
-(provided that an array of powers of p modulo M of sufficient length is stored).
-The popular Rabin–Karp pattern matching algorithm is based on this property
+Băm đa thức có một tính năng cuộn: các dấu vân tay có thể được cập nhật hiệu quả khi các ký tự được thêm vào hoặc loại bỏ ở các đầu của chuỗi (miễn là một mảng của các lũy thừa của p modulo M có độ dài đủ được lưu trữ). Thuật toán tìm kiếm mẫu Rabin–Karp phổ biến dựa trên tính năng này.
 
-## References
+## Tài liệu tham khảo
 
-- [Where to Use Polynomial String Hashing](https://www.mii.lt/olympiads_in_informatics/pdf/INFOL119.pdf)
-- [Hashing on uTexas](https://www.cs.utexas.edu/~mitra/csSpring2017/cs313/lectures/hash.html)
-- [Hash Function on Wikipedia](https://en.wikipedia.org/wiki/Hash_function)
-- [Rolling Hash on Wikipedia](https://en.wikipedia.org/wiki/Rolling_hash)
+- [Nơi sử dụng Băm Chuỗi Đa Thức](https://www.mii.lt/olympiads_in_informatics/pdf/INFOL119.pdf)
+- [Băm trên uTexas](https://www.cs.utexas.edu/~mitra/csSpring2017/cs313/lectures/hash.html)
+- [Hàm Băm trên Wikipedia](https://en.wikipedia.org/wiki/Hash_function)
+- [Băm Cuộn trên Wikipedia](https://en.wikipedia.org/wiki/Rolling_hash)
diff --git a/src/algorithms/cryptography/rail-fence-cipher/README.en-EN.md b/src/algorithms/cryptography/rail-fence-cipher/README.en-EN.md
new file mode 100644
index 0000000000..0cb19feefc
--- /dev/null
+++ b/src/algorithms/cryptography/rail-fence-cipher/README.en-EN.md
@@ -0,0 +1,31 @@
+# Rail Fence Cipher
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **rail fence cipher** (also called a **zigzag cipher**) is a [transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) in which the message is split across a set of rails on a fence for encoding. The fence is populated with the message's characters, starting at the top left and adding a character on each position, traversing them diagonally to the bottom. Upon reaching the last rail, the direction should then turn diagonal and upwards up to the very first rail in a zig-zag motion. Rinse and repeat until the message is fully disposed across the fence. The encoded message is the result of concatenating the text in each rail, from top to bottom.
+
+From [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), this is what the message `WE ARE DISCOVERED. FLEE AT ONCE` looks like on a `3`-rail fence:
+
+```
+W . . . E . . . C . . . R . . . L . . . T . . . E
+. E . R . D . S . O . E . E . F . E . A . O . C .
+. . A . . . I . . . V . . . D . . . E . . . N . .
+-------------------------------------------------
+             WECRLTEERDSOEEFEAOCAIVDEN
+```
+
+The message can then be decoded by re-creating the encoded fence, with the same traversal pattern, except characters should only be added on one rail at a time. To illustrate that, a dash can be added on the rails that are not supposed to be populated yet. This is what the fence would look like after populating the first rail, the dashes represent positions that were visited but not populated.
+
+```
+W . . . E . . . C . . . R . . . L . . . T . . . E
+. - . - . - . - . - . - . - . - . - . - . - . - .
+. . - . . . - . . . - . . . - . . . - . . . - . .
+```
+
+It's time to start populating the next rail once the number of visited fence positions is equal to the number of characters in the message.
+
+## References
+
+- [Rail Fence Cipher on Wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher)
+- [Rail Fence Cipher Calculator](https://crypto.interactive-maths.com/rail-fence-cipher.html)
diff --git a/src/algorithms/cryptography/rail-fence-cipher/README.md b/src/algorithms/cryptography/rail-fence-cipher/README.md
index d01395f554..d07497fcaf 100644
--- a/src/algorithms/cryptography/rail-fence-cipher/README.md
+++ b/src/algorithms/cryptography/rail-fence-cipher/README.md
@@ -1,8 +1,11 @@
-# Rail Fence Cipher
+# Mật mã Hàng rào Zigzag
 
-The **rail fence cipher** (also called a **zigzag cipher**) is a [transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) in which the message is split across a set of rails on a fence for encoding. The fence is populated with the message's characters, starting at the top left and adding a character on each position, traversing them diagonally to the bottom. Upon reaching the last rail, the direction should then turn diagonal and upwards up to the very first rail in a zig-zag motion. Rinse and repeat until the message is fully disposed across the fence. The encoded message is the result of concatenating the text in each rail, from top to bottom.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-From [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), this is what the message `WE ARE DISCOVERED. FLEE AT ONCE` looks like on a `3`-rail fence:
+**Mật mã hàng rào Zigzag** (còn gọi là **mật mã zigzag**) là một [mật mã hoán vị](https://en.wikipedia.org/wiki/Transposition_cipher) trong đó thông điệp được phân tách trên một tập hợp các hàng rào để mã hóa. Hàng rào được lấp đầy bằng các ký tự của thông điệp, bắt đầu từ góc trên bên trái và thêm một ký tự vào mỗi vị trí, di chuyển chéo xuống dưới. Khi đến hàng cuối cùng, hướng di chuyển sẽ chuyển thành chéo lên trên đến hàng đầu tiên theo một chuyển động zig-zag. Lặp lại quá trình này cho đến khi thông điệp được phân bổ hoàn toàn trên hàng rào. Thông điệp được mã hóa là kết quả của việc nối liền văn bản trên mỗi hàng rào, từ trên xuống dưới.
+
+Từ [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), đây là cách thông điệp `WE ARE DISCOVERED. FLEE AT ONCE` trông như thế nào trên hàng rào `3`-rail:
 
 ```
 W . . . E . . . C . . . R . . . L . . . T . . . E
@@ -12,7 +15,7 @@ W . . . E . . . C . . . R . . . L . . . T . . . E
              WECRLTEERDSOEEFEAOCAIVDEN
 ```
 
-The message can then be decoded by re-creating the encoded fence, with the same traversal pattern, except characters should only be added on one rail at a time. To illustrate that, a dash can be added on the rails that are not supposed to be populated yet. This is what the fence would look like after populating the first rail, the dashes represent positions that were visited but not populated.
+Thông điệp sau đó có thể được giải mã bằng cách tạo lại hàng rào đã mã hóa, với cùng một mô hình di chuyển, ngoại trừ việc các ký tự chỉ được thêm vào một hàng rào mỗi lần. Để minh họa điều đó, dấu gạch ngang có thể được thêm vào các hàng rào chưa được lấp đầy. Đây là cách hàng rào trông sau khi lấp đầy hàng đầu tiên, các dấu gạch ngang đại diện cho các vị trí đã được thăm nhưng chưa được lấp đầy.
 
 ```
 W . . . E . . . C . . . R . . . L . . . T . . . E
@@ -20,9 +23,9 @@ W . . . E . . . C . . . R . . . L . . . T . . . E
 . . - . . . - . . . - . . . - . . . - . . . - . .
 ```
 
-It's time to start populating the next rail once the number of visited fence positions is equal to the number of characters in the message.
+Đã đến lúc bắt đầu lấp đầy hàng rào tiếp theo khi số vị trí hàng rào đã thăm bằng với số lượng ký tự trong thông điệp.
 
-## References
+## Tài liệu tham khảo
 
-- [Rail Fence Cipher on Wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher)
-- [Rail Fence Cipher Calculator](https://crypto.interactive-maths.com/rail-fence-cipher.html)
+- [Mật mã Hàng rào Zigzag trên Wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher)
+- [Máy tính Mật mã Hàng rào Zigzag](https://crypto.interactive-maths.com/rail-fence-cipher.html)
diff --git a/src/algorithms/graph/articulation-points/README.en-EN.md b/src/algorithms/graph/articulation-points/README.en-EN.md
new file mode 100644
index 0000000000..8c8f8358cc
--- /dev/null
+++ b/src/algorithms/graph/articulation-points/README.en-EN.md
@@ -0,0 +1,25 @@
+# Articulation Points (or Cut Vertices)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A vertex in an undirected connected graph is an articulation point
+(or cut vertex) if removing it (and edges through it) disconnects
+the graph. Articulation points represent vulnerabilities in a
+connected network – single points whose failure would split the
+network into 2 or more disconnected components. They are useful for
+designing reliable networks.
+
+For a disconnected undirected graph, an articulation point is a
+vertex removing which increases number of connected components.
+
+![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints.png)
+
+![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints1.png)
+
+![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints21.png)
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/)
+- [YouTube](https://www.youtube.com/watch?v=2kREIkF9UAs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/articulation-points/README.md b/src/algorithms/graph/articulation-points/README.md
index aa6bede7a4..ed013ab96f 100644
--- a/src/algorithms/graph/articulation-points/README.md
+++ b/src/algorithms/graph/articulation-points/README.md
@@ -1,22 +1,25 @@
-# Articulation Points (or Cut Vertices)
+# Điểm khớp nối - Articulation Points (hoặc Cut Vertices)
 
-A vertex in an undirected connected graph is an articulation point
-(or cut vertex) if removing it (and edges through it) disconnects 
-the graph. Articulation points represent vulnerabilities in a 
-connected network – single points whose failure would split the 
-network into 2 or more disconnected components. They are useful for 
-designing reliable networks.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-For a disconnected undirected graph, an articulation point is a 
-vertex removing which increases number of connected components.
+Một đỉnh trong một đồ thị liên thông không hướng là một điểm khớp nối
+(hoặc cut vertex) nếu việc loại bỏ nó (và các cạnh thông qua nó) làm đứt đoạn
+đồ thị. Điểm khớp nối đại diện cho những điểm yếu trong một
+mạng lưới kết nối - những điểm đơn lẻ mà nếu hỏng sẽ chia
+mạng lưới thành 2 hoặc nhiều thành phần không liên thông. Chúng rất hữu ích cho
+việc thiết kế các mạng lưới đáng tin cậy.
 
-![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints.png)
+Đối với một đồ thị không hướng không liên thông, một điểm khớp nối là một
+đỉnh mà việc loại bỏ nó làm tăng số lượng thành phần liên thông.
 
-![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints1.png)
+![Điểm khớp nối](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints.png)
 
-![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints21.png)
+![Điểm khớp nối](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints1.png)
 
-## References
+![Điểm khớp nối](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints21.png)
+
+## Tham khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/)
 - [YouTube](https://www.youtube.com/watch?v=2kREIkF9UAs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/bellman-ford/README.en-EN.md b/src/algorithms/graph/bellman-ford/README.en-EN.md
new file mode 100644
index 0000000000..6d9ced0d5a
--- /dev/null
+++ b/src/algorithms/graph/bellman-ford/README.en-EN.md
@@ -0,0 +1,2 @@
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
diff --git a/src/algorithms/graph/bellman-ford/README.md b/src/algorithms/graph/bellman-ford/README.md
index 9c0922659e..2562d97adb 100644
--- a/src/algorithms/graph/bellman-ford/README.md
+++ b/src/algorithms/graph/bellman-ford/README.md
@@ -1,21 +1,23 @@
-# Bellman–Ford Algorithm
+# Thuật toán Bellman–Ford
 
-The Bellman–Ford algorithm is an algorithm that computes shortest 
-paths from a single source vertex to all of the other vertices 
-in a weighted digraph. It is slower than Dijkstra's algorithm 
-for the same problem, but more versatile, as it is capable of 
-handling graphs in which some of the edge weights are negative 
-numbers.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
+
+Thuật toán Bellman–Ford là một thuật toán tính toán đường đi ngắn nhất
+từ một đỉnh nguồn đơn lẻ đến tất cả các đỉnh khác
+trong một đồ thị có hướng có trọng số. Nó chậm hơn thuật toán Dijkstra
+đối với cùng một vấn đề, nhưng linh hoạt hơn, vì nó có khả năng
+xử lý đồ thị trong đó một số trọng số cạnh là số âm.
 
 ![Bellman-Ford](https://upload.wikimedia.org/wikipedia/commons/2/2e/Shortest_path_Dijkstra_vs_BellmanFord.gif)
 
-## Complexity
+## Độ phức tạp
 
-Worst-case performance `O(|V||E|)`
-Best-case performance	`O(|E|)`
-Worst-case space complexity `O(|V|)`
+Hiệu suất trường hợp tồi nhất `O(|V||E|)`
+Hiệu suất trường hợp tốt nhất `O(|E|)`
+Độ phức tạp không gian trường hợp tồi nhất `O(|V|)`
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm)
-- [On YouTube by Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Wikipedia](https://vi.wikipedia.org/wiki/Thu%E1%BA%ADt_to%C3%A1n_Bellman%E2%80%93Ford)
+- [Trên YouTube bởi Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/breadth-first-search/README.en-EN.md b/src/algorithms/graph/breadth-first-search/README.en-EN.md
new file mode 100644
index 0000000000..75c5100ff0
--- /dev/null
+++ b/src/algorithms/graph/breadth-first-search/README.en-EN.md
@@ -0,0 +1,19 @@
+# Breadth-First Search (BFS)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Breadth-first search (BFS) is an algorithm for traversing,
+searching tree, or graph data structures. It starts at
+the tree root (or some arbitrary node of a graph, sometimes
+referred to as a 'search key') and explores the neighbor
+nodes first, before moving to the next level neighbors.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)
+- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
+- [BFS Visualization](https://www.cs.usfca.edu/~galles/visualization/BFS.html)
diff --git a/src/algorithms/graph/breadth-first-search/README.md b/src/algorithms/graph/breadth-first-search/README.md
index 06073abd8b..0f95dc33ff 100644
--- a/src/algorithms/graph/breadth-first-search/README.md
+++ b/src/algorithms/graph/breadth-first-search/README.md
@@ -1,16 +1,19 @@
-# Breadth-First Search (BFS)
+# Tìm kiếm theo chiều rộng - Breadth-First Search (BFS)
 
-Breadth-first search (BFS) is an algorithm for traversing, 
-searching tree, or graph data structures. It starts at
-the tree root (or some arbitrary node of a graph, sometimes 
-referred to as a 'search key') and explores the neighbor
-nodes first, before moving to the next level neighbors.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)
+Tìm kiếm theo chiều rộng (BFS) là một thuật toán dùng để duyệt,
+tìm kiếm trong cấu trúc dữ liệu cây hoặc đồ thị. Thuật toán bắt đầu từ
+gốc của cây (hoặc một nút tùy ý của đồ thị, đôi khi
+được gọi là 'khóa tìm kiếm') và khám phá các nút lân cận
+đầu tiên, trước khi chuyển sang các nút lân cận ở cấp độ tiếp theo.
 
-## References
+![Minh họa thuật toán](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)
-- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
-- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
-- [BFS Visualization](https://www.cs.usfca.edu/~galles/visualization/BFS.html)
+## Tham khảo
+
+- [Wikipedia](https://vi.wikipedia.org/wiki/T%C3%ACm_ki%E1%BA%BFm_theo_chi%E1%BB%81u_r%E1%BB%99ng)
+- [Duyệt cây (Inorder, Preorder và Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [So sánh BFS và DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
+- [Minh họa BFS](https://www.cs.usfca.edu/~galles/visualization/BFS.html)
diff --git a/src/algorithms/graph/bridges/README.en-EN.md b/src/algorithms/graph/bridges/README.en-EN.md
new file mode 100644
index 0000000000..7a849ac9ed
--- /dev/null
+++ b/src/algorithms/graph/bridges/README.en-EN.md
@@ -0,0 +1,29 @@
+# Bridges in Graph
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In graph theory, a **bridge**, **isthmus**, **cut-edge**, or **cut arc** is an edge
+of a graph whose deletion increases its number of connected components. Equivalently,
+an edge is a bridge if and only if it is not contained in any cycle. A graph is said
+to be bridgeless or isthmus-free if it contains no bridges.
+
+![Bridges in graph](https://upload.wikimedia.org/wikipedia/commons/d/df/Graph_cut_edges.svg)
+
+A graph with 16 vertices and 6 bridges (highlighted in red)
+
+![Bridgeless](https://upload.wikimedia.org/wikipedia/commons/b/bf/Undirected.svg)
+
+An undirected connected graph with no cut edges
+
+![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge1.png)
+
+![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge2.png)
+
+![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge3.png)
+
+## References
+
+- [GeeksForGeeks on YouTube](https://www.youtube.com/watch?v=thLQYBlz2DM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Wikipedia](https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29#Tarjan.27s_Bridge-finding_algorithm)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/bridge-in-a-graph/)
diff --git a/src/algorithms/graph/bridges/README.md b/src/algorithms/graph/bridges/README.md
index 08d919ff96..7d0c7749b1 100644
--- a/src/algorithms/graph/bridges/README.md
+++ b/src/algorithms/graph/bridges/README.md
@@ -1,26 +1,29 @@
-# Bridges in Graph
+# Cầu trong Đồ thị
 
-In graph theory, a **bridge**, **isthmus**, **cut-edge**, or **cut arc** is an edge 
-of a graph whose deletion increases its number of connected components. Equivalently, 
-an edge is a bridge if and only if it is not contained in any cycle. A graph is said 
-to be bridgeless or isthmus-free if it contains no bridges.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-![Bridges in graph](https://upload.wikimedia.org/wikipedia/commons/d/df/Graph_cut_edges.svg)
+Trong lý thuyết đồ thị, một **cầu**, **isthmus**, **cut-edge**, hoặc **cut arc** là một cạnh
+của đồ thị mà việc xóa nó làm tăng số lượng thành phần liên thông của đồ thị. Tương đương,
+một cạnh là một cầu nếu và chỉ nếu nó không nằm trong bất kỳ chu trình nào. Một đồ thị được gọi
+là không có cầu hoặc không có isthmus nếu nó không chứa bất kỳ cầu nào.
 
-A graph with 16 vertices and 6 bridges (highlighted in red)
+![Cầu trong đồ thị](https://upload.wikimedia.org/wikipedia/commons/d/df/Graph_cut_edges.svg)
 
-![Bridgeless](https://upload.wikimedia.org/wikipedia/commons/b/bf/Undirected.svg)
+Một đồ thị với 16 đỉnh và 6 cầu (được tô sáng bằng màu đỏ)
 
-An undirected connected graph with no cut edges
+![Không có cầu](https://upload.wikimedia.org/wikipedia/commons/b/bf/Undirected.svg)
 
-![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge1.png)
+Một đồ thị không hướng liên thông không có cạnh cắt
 
-![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge2.png)
+![Cầu trong đồ thị](https://www.geeksforgeeks.org/wp-content/uploads/Bridge1.png)
 
-![Bridges in graph](https://www.geeksforgeeks.org/wp-content/uploads/Bridge3.png)
+![Cầu trong đồ thị](https://www.geeksforgeeks.org/wp-content/uploads/Bridge2.png)
 
-## References
+![Cầu trong đồ thị](https://www.geeksforgeeks.org/wp-content/uploads/Bridge3.png)
 
-- [GeeksForGeeks on YouTube](https://www.youtube.com/watch?v=thLQYBlz2DM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Wikipedia](https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29#Tarjan.27s_Bridge-finding_algorithm)
+## Tham khảo
+
+- [GeeksForGeeks trên YouTube](https://www.youtube.com/watch?v=thLQYBlz2DM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Wikipedia](<https://vi.wikipedia.org/wiki/C%E1%BA%A7u_(l%C3%BD_thuy%E1%BA%BFt_%C4%91%E1%BB%93_th%E1%BB%8B)>)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/bridge-in-a-graph/)
diff --git a/src/algorithms/graph/depth-first-search/README.en-EN.md b/src/algorithms/graph/depth-first-search/README.en-EN.md
new file mode 100644
index 0000000000..af9466eb69
--- /dev/null
+++ b/src/algorithms/graph/depth-first-search/README.en-EN.md
@@ -0,0 +1,19 @@
+# Depth-First Search (DFS)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Depth-first search (DFS) is an algorithm for traversing or
+searching tree or graph data structures. One starts at
+the root (selecting some arbitrary node as the root in
+the case of a graph) and explores as far as possible
+along each branch before backtracking.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)
+- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
+- [DFS Visualization](https://www.cs.usfca.edu/~galles/visualization/DFS.html)
diff --git a/src/algorithms/graph/depth-first-search/README.md b/src/algorithms/graph/depth-first-search/README.md
index b22a8aa9c8..78b7b26227 100644
--- a/src/algorithms/graph/depth-first-search/README.md
+++ b/src/algorithms/graph/depth-first-search/README.md
@@ -1,16 +1,19 @@
-# Depth-First Search (DFS)
+# Tìm kiếm theo chiều sâu - Depth-First Search (DFS)
 
-Depth-first search (DFS) is an algorithm for traversing or 
-searching tree or graph data structures. One starts at 
-the root (selecting some arbitrary node as the root in 
-the case of a graph) and explores as far as possible 
-along each branch before backtracking.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
+Tìm kiếm theo chiều sâu (DFS) là một thuật toán dùng để duyệt hoặc
+tìm kiếm trong cấu trúc dữ liệu cây hoặc đồ thị. Thuật toán bắt đầu từ
+gốc của cây (chọn một nút tùy ý làm gốc trong
+trường hợp của đồ thị) và khám phá xa nhất có thể
+dọc theo mỗi nhánh trước khi quay lui.
 
-## References
+![Minh họa thuật toán](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)
-- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
-- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
-- [DFS Visualization](https://www.cs.usfca.edu/~galles/visualization/DFS.html)
+## Tham khảo
+
+- [Wikipedia](https://vi.wikipedia.org/wiki/T%C3%ACm_ki%E1%BA%BFm_theo_chi%E1%BB%81u_s%C3%A2u)
+- [Duyệt cây (Inorder, Preorder và Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [So sánh BFS và DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
+- [Minh họa DFS](https://www.cs.usfca.edu/~galles/visualization/DFS.html)
diff --git a/src/algorithms/graph/detect-cycle/README.en-EN.md b/src/algorithms/graph/detect-cycle/README.en-EN.md
new file mode 100644
index 0000000000..510ced6d76
--- /dev/null
+++ b/src/algorithms/graph/detect-cycle/README.en-EN.md
@@ -0,0 +1,63 @@
+# Detect Cycle in Graphs
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In graph theory, a **cycle** is a path of edges and vertices
+wherein a vertex is reachable from itself. There are several
+different types of cycles, principally a **closed walk** and
+a **simple cycle**.
+
+## Definitions
+
+A **closed walk** consists of a sequence of vertices starting
+and ending at the same vertex, with each two consecutive vertices
+in the sequence adjacent to each other in the graph. In a directed graph,
+each edge must be traversed by the walk consistently with its direction:
+the edge must be oriented from the earlier of two consecutive vertices
+to the later of the two vertices in the sequence.
+The choice of starting vertex is not important: traversing the same cyclic
+sequence of edges from different starting vertices produces the same closed walk.
+
+A **simple cycle may** be defined either as a closed walk with no repetitions of
+vertices and edges allowed, other than the repetition of the starting and ending
+vertex, or as the set of edges in such a walk. The two definitions are equivalent
+in directed graphs, where simple cycles are also called directed cycles: the cyclic
+sequence of vertices and edges in a walk is completely determined by the set of
+edges that it uses. In undirected graphs the set of edges of a cycle can be
+traversed by a walk in either of two directions, giving two possible directed cycles
+for every undirected cycle. A circuit can be a closed walk allowing repetitions of
+vertices but not edges; however, it can also be a simple cycle, so explicit
+definition is recommended when it is used.
+
+## Example
+
+![Cycles](https://upload.wikimedia.org/wikipedia/commons/e/e7/Graph_cycle.gif)
+
+A graph with edges colored to illustrate **path** `H-A-B` (green), closed path or
+**walk with a repeated vertex** `B-D-E-F-D-C-B` (blue) and a **cycle with no repeated edge** or
+vertex `H-D-G-H` (red)
+
+### Cycle in undirected graph
+
+![Undirected Cycle](https://www.geeksforgeeks.org/wp-content/uploads/cycleGraph.png)
+
+### Cycle in directed graph
+
+![Directed Cycle](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/cycle.png)
+
+## References
+
+General information:
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Cycle_(graph_theory)>)
+
+Cycles in undirected graphs:
+
+- [Detect Cycle in Undirected Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-undirected-graph/)
+- [Detect Cycle in Undirected Graph Algorithm on YouTube](https://www.youtube.com/watch?v=n_t0a_8H8VY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+
+Cycles in directed graphs:
+
+- [Detect Cycle in Directed Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-in-a-graph/)
+- [Detect Cycle in Directed Graph Algorithm on YouTube](https://www.youtube.com/watch?v=rKQaZuoUR4M&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/detect-cycle/README.md b/src/algorithms/graph/detect-cycle/README.md
index 82641c78a2..2c7dd4e968 100644
--- a/src/algorithms/graph/detect-cycle/README.md
+++ b/src/algorithms/graph/detect-cycle/README.md
@@ -1,60 +1,63 @@
-# Detect Cycle in Graphs
+# Phát hiện chu trình trong Đồ thị
 
-In graph theory, a **cycle** is a path of edges and vertices 
-wherein a vertex is reachable from itself. There are several 
-different types of cycles, principally a **closed walk** and 
-a **simple cycle**.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-## Definitions
+Trong lý thuyết đồ thị, một **chu trình** là một đường đi của các cạnh và đỉnh
+nơi mà một đỉnh có thể đạt được từ chính nó. Có một số
+loại chu trình khác nhau, chủ yếu là một **đường đi kín** và
+một **chu trình đơn giản**.
 
-A **closed walk** consists of a sequence of vertices starting 
-and ending at the same vertex, with each two consecutive vertices
-in the sequence adjacent to each other in the graph. In a directed graph,
-each edge must be traversed by the walk consistently with its direction: 
-the edge must be oriented from the earlier of two consecutive vertices 
-to the later of the two vertices in the sequence. 
-The choice of starting vertex is not important: traversing the same cyclic 
-sequence of edges from different starting vertices produces the same closed walk.
+## Định nghĩa
 
-A **simple cycle may** be defined either as a closed walk with no repetitions of 
-vertices and edges allowed, other than the repetition of the starting and ending 
-vertex, or as the set of edges in such a walk. The two definitions are equivalent 
-in directed graphs, where simple cycles are also called directed cycles: the cyclic 
-sequence of vertices and edges in a walk is completely determined by the set of 
-edges that it uses. In undirected graphs the set of edges of a cycle can be 
-traversed by a walk in either of two directions, giving two possible directed cycles 
-for every undirected cycle. A circuit can be a closed walk allowing repetitions of 
-vertices but not edges; however, it can also be a simple cycle, so explicit 
-definition is recommended when it is used.
+Một **đường đi kín** bao gồm một chuỗi các đỉnh bắt đầu
+và kết thúc tại cùng một đỉnh, với mỗi hai đỉnh liên tiếp
+trong chuỗi kề nhau trong đồ thị. Trong một đồ thị có hướng,
+mỗi cạnh phải được duyệt bởi đường đi một cách nhất quán với hướng của nó:
+cạnh phải được hướng từ đỉnh sớm hơn của hai đỉnh liên tiếp
+đến đỉnh sau của hai đỉnh trong chuỗi.
+Việc chọn đỉnh bắt đầu không quan trọng: việc duyệt cùng một chuỗi chu kỳ
+các cạnh từ các đỉnh bắt đầu khác nhau tạo ra cùng một đường đi kín.
 
-## Example
+Một **chu trình đơn giản** có thể được định nghĩa hoặc là một đường đi kín không cho phép lặp lại
+các đỉnh và cạnh, ngoại trừ việc lặp lại đỉnh bắt đầu và kết thúc,
+hoặc là tập hợp các cạnh trong một đường đi như vậy. Hai định nghĩa là tương đương
+trong đồ thị có hướng, nơi chu trình đơn giản cũng được gọi là chu trình có hướng: chuỗi chu kỳ
+các đỉnh và cạnh trong một đường đi hoàn toàn được xác định bởi tập hợp
+các cạnh mà nó sử dụng. Trong đồ thị không hướng, tập hợp các cạnh của một chu trình có thể
+được duyệt bởi một đường đi theo một trong hai hướng, tạo ra hai chu trình có hướng có thể
+cho mỗi chu trình không hướng. Một mạch có thể là một đường đi kín cho phép lặp lại
+các đỉnh nhưng không phải cạnh; tuy nhiên, nó cũng có thể là một chu trình đơn giản, vì vậy định nghĩa
+rõ ràng được khuyến nghị khi nó được sử dụng.
 
-![Cycles](https://upload.wikimedia.org/wikipedia/commons/e/e7/Graph_cycle.gif)
+## Ví dụ
 
-A graph with edges colored to illustrate **path** `H-A-B` (green), closed path or 
-**walk with a repeated vertex** `B-D-E-F-D-C-B` (blue) and a **cycle with no repeated edge** or 
-vertex `H-D-G-H` (red)
+![Chu trình](https://upload.wikimedia.org/wikipedia/commons/e/e7/Graph_cycle.gif)
 
-### Cycle in undirected graph
+Một đồ thị với các cạnh được tô màu để minh họa **đường đi** `H-A-B` (màu xanh lá), đường đi kín hoặc
+**đường đi với một đỉnh lặp lại** `B-D-E-F-D-C-B` (màu xanh dương) và một **chu trình không lặp lại cạnh** hoặc
+đỉnh `H-D-G-H` (màu đỏ)
 
-![Undirected Cycle](https://www.geeksforgeeks.org/wp-content/uploads/cycleGraph.png)
+### Chu trình trong đồ thị không hướng
 
-### Cycle in directed graph
+![Chu trình không hướng](https://www.geeksforgeeks.org/wp-content/uploads/cycleGraph.png)
 
-![Directed Cycle](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/cycle.png)
+### Chu trình trong đồ thị có hướng
 
-## References
+![Chu trình có hướng](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/cycle.png)
 
-General information:
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Cycle_(graph_theory))
+Thông tin chung:
 
-Cycles in undirected graphs:
+- [Wikipedia](<https://en.wikipedia.org/wiki/Cycle_(graph_theory)>)
 
-- [Detect Cycle in Undirected Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-undirected-graph/)
-- [Detect Cycle in Undirected Graph Algorithm on YouTube](https://www.youtube.com/watch?v=n_t0a_8H8VY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+Chu trình trong đồ thị không hướng:
 
-Cycles in directed graphs:
+- [Phát hiện chu trình trong đồ thị không hướng trên GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-undirected-graph/)
+- [Thuật toán phát hiện chu trình trong đồ thị không hướng trên YouTube](https://www.youtube.com/watch?v=n_t0a_8H8VY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
 
-- [Detect Cycle in Directed Graph on GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-in-a-graph/)
-- [Detect Cycle in Directed Graph Algorithm on YouTube](https://www.youtube.com/watch?v=rKQaZuoUR4M&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+Chu trình trong đồ thị có hướng:
+
+- [Phát hiện chu trình trong đồ thị có hướng trên GeeksForGeeks](https://www.geeksforgeeks.org/detect-cycle-in-a-graph/)
+- [Thuật toán phát hiện chu trình trong đồ thị có hướng trên YouTube](https://www.youtube.com/watch?v=rKQaZuoUR4M&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/dijkstra/README.en-EN.md b/src/algorithms/graph/dijkstra/README.en-EN.md
new file mode 100644
index 0000000000..34dbc69928
--- /dev/null
+++ b/src/algorithms/graph/dijkstra/README.en-EN.md
@@ -0,0 +1,28 @@
+# Dijkstra's Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Dijkstra's algorithm is an algorithm for finding the shortest
+paths between nodes in a graph, which may represent, for example,
+road networks.
+
+The algorithm exists in many variants; Dijkstra's original variant
+found the shortest path between two nodes, but a more common
+variant fixes a single node as the "source" node and finds
+shortest paths from the source to all other nodes in the graph,
+producing a shortest-path tree.
+
+![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)
+
+Dijkstra's algorithm to find the shortest path between `a` and `b`.
+It picks the unvisited vertex with the lowest distance,
+calculates the distance through it to each unvisited neighbor,
+and updates the neighbor's distance if smaller. Mark visited
+(set to red) when done with neighbors.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
+- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/dijkstra/README.ko-KR.md b/src/algorithms/graph/dijkstra/README.ko-KR.md
deleted file mode 100644
index e2595bbe23..0000000000
--- a/src/algorithms/graph/dijkstra/README.ko-KR.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# 다익스트라 알고리즘(Dijkstra's algorithm)
-
-다익스트라 알고리즘은 도로 네트워크 등을 나타낼 수 있는 그래프에서 노드 간의 최단 경로를 찾는 알고리즘입니다.
-
-이 알고리즘은 다양한 형태로 존재합니다. 다익스트라의 원래 형태는 두 노드 간의 최단 경로를 찾았지만, 더 일반적인 형태는 단일 노드를 "소스"노드로 수정하고 그래프의 소스에서 다른 모든 노드까지의 최단 경로를 찾아 최단 경로 트리(shortest-path tree)를 생성합니다.
-
-![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)
-
-`a`와 `b` 사이의 최단 경로를 찾는 다익스트라 알고리즘입니다.
-가장 낮은 거리를 가지며 방문하지 않은 정점(vertex)를 선택하고, 이를 통해 방문하지 않은 각 이웃까지의 거리를 계산하며, 더 작은 경우 이웃의 거리를 업데이트합니다. 이웃에 대한 작업을 마치면 방문한 것으로 표시(빨간색으로 변경)합니다.
-
-## 참조
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
-- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/dijkstra/README.md b/src/algorithms/graph/dijkstra/README.md
index d94e2a3cdf..3d8303481b 100644
--- a/src/algorithms/graph/dijkstra/README.md
+++ b/src/algorithms/graph/dijkstra/README.md
@@ -1,28 +1,27 @@
-# Dijkstra's Algorithm
+# Thuật toán Dijkstra
 
-_Read this in other languages:_
-[_한국어_](README.ko-KR.md)
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-Dijkstra's algorithm is an algorithm for finding the shortest 
-paths between nodes in a graph, which may represent, for example, 
-road networks. 
+Thuật toán Dijkstra là một thuật toán dùng để tìm đường đi ngắn nhất
+giữa các nút trong một đồ thị, ví dụ như mạng lưới đường bộ.
 
-The algorithm exists in many variants; Dijkstra's original variant 
-found the shortest path between two nodes, but a more common 
-variant fixes a single node as the "source" node and finds 
-shortest paths from the source to all other nodes in the graph, 
-producing a shortest-path tree.
+Thuật toán này có nhiều biến thể; biến thể gốc của Dijkstra
+tìm đường đi ngắn nhất giữa hai nút, nhưng một biến thể phổ biến hơn
+đặt một nút duy nhất là nút "nguồn" và tìm
+đường đi ngắn nhất từ nút nguồn đến tất cả các nút khác trong đồ thị,
+tạo ra một cây đường đi ngắn nhất.
 
 ![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif)
 
-Dijkstra's algorithm to find the shortest path between `a` and `b`.
-It picks the unvisited vertex with the lowest distance, 
-calculates the distance through it to each unvisited neighbor, 
-and updates the neighbor's distance if smaller. Mark visited
-(set to red) when done with neighbors.
+Thuật toán Dijkstra để tìm đường đi ngắn nhất giữa `a` và `b`.
+Nó chọn nút chưa được thăm có khoảng cách thấp nhất,
+tính toán khoảng cách thông qua nó đến mỗi láng giềng chưa được thăm,
+và cập nhật khoảng cách của láng giềng nếu nhỏ hơn. Đánh dấu đã thăm
+(đặt thành màu đỏ) khi hoàn thành với các láng giềng.
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
-- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Wikipedia](https://vi.wikipedia.org/wiki/Thu%E1%BA%ADt_to%C3%A1n_Dijkstra)
+- [Trên YouTube bởi Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Trên YouTube bởi Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/eulerian-path/README.en-EN.md b/src/algorithms/graph/eulerian-path/README.en-EN.md
new file mode 100644
index 0000000000..69cb6154f0
--- /dev/null
+++ b/src/algorithms/graph/eulerian-path/README.en-EN.md
@@ -0,0 +1,38 @@
+# Eulerian Path
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In graph theory, an **Eulerian trail** (or **Eulerian path**) is a
+trail in a finite graph which visits every edge exactly once.
+Similarly, an **Eulerian circuit** or **Eulerian cycle** is an
+Eulerian trail which starts and ends on the same vertex.
+
+Euler proved that a necessary condition for the existence of Eulerian
+circuits is that all vertices in the graph have an even degree, and
+stated that connected graphs with all vertices of even degree have
+an Eulerian circuit.
+
+![Eulerian Circuit](https://upload.wikimedia.org/wikipedia/commons/7/72/Labelled_Eulergraph.svg)
+
+Every vertex of this graph has an even degree. Therefore, this is
+an Eulerian graph. Following the edges in alphabetical order gives
+an Eulerian circuit/cycle.
+
+For the existence of Eulerian trails it is necessary that zero or
+two vertices have an odd degree; this means the Königsberg graph
+is not Eulerian. If there are no vertices of odd degree,
+all Eulerian trails are circuits. If there are exactly two vertices
+of odd degree, all Eulerian trails start at one of them and end at
+the other. A graph that has an Eulerian trail but not an Eulerian
+circuit is called semi-Eulerian.
+
+![Königsberg graph](https://upload.wikimedia.org/wikipedia/commons/9/96/K%C3%B6nigsberg_graph.svg)
+
+The Königsberg Bridges multigraph. This multigraph is not Eulerian,
+therefore, a solution does not exist.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Eulerian_path)
+- [YouTube](https://www.youtube.com/watch?v=vvP4Fg4r-Ns&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/eulerian-path/README.md b/src/algorithms/graph/eulerian-path/README.md
index 597a9ef32e..0fc64140cf 100644
--- a/src/algorithms/graph/eulerian-path/README.md
+++ b/src/algorithms/graph/eulerian-path/README.md
@@ -1,35 +1,38 @@
-# Eulerian Path
+# Đường đi Euler
 
-In graph theory, an **Eulerian trail** (or **Eulerian path**) is a 
-trail in a finite graph which visits every edge exactly once.
-Similarly, an **Eulerian circuit** or **Eulerian cycle** is an 
-Eulerian trail which starts and ends on the same vertex.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-Euler proved that a necessary condition for the existence of Eulerian 
-circuits is that all vertices in the graph have an even degree, and 
-stated that connected graphs with all vertices of even degree have 
-an Eulerian circuit.
+Trong lý thuyết đồ thị, một **đường đi Euler** (hoặc **đường đi Euler**) là một
+đường đi trong một đồ thị hữu hạn mà đi qua mỗi cạnh đúng một lần.
+Tương tự, một **chu trình Euler** hoặc **chu trình Euler** là một
+đường đi Euler mà bắt đầu và kết thúc tại cùng một đỉnh.
 
-![Eulerian Circuit](https://upload.wikimedia.org/wikipedia/commons/7/72/Labelled_Eulergraph.svg)
+Euler đã chứng minh rằng một điều kiện cần cho sự tồn tại của chu trình Euler
+là tất cả các đỉnh trong đồ thị đều có bậc chẵn, và
+đã khẳng định rằng các đồ thị liên thông với tất cả các đỉnh có bậc chẵn đều có
+một chu trình Euler.
 
-Every vertex of this graph has an even degree. Therefore, this is 
-an Eulerian graph. Following the edges in alphabetical order gives 
-an Eulerian circuit/cycle.
+![Chu trình Euler](https://upload.wikimedia.org/wikipedia/commons/7/72/Labelled_Eulergraph.svg)
 
-For the existence of Eulerian trails it is necessary that zero or 
-two vertices have an odd degree; this means the Königsberg graph 
-is not Eulerian. If there are no vertices of odd degree, 
-all Eulerian trails are circuits. If there are exactly two vertices 
-of odd degree, all Eulerian trails start at one of them and end at 
-the other. A graph that has an Eulerian trail but not an Eulerian 
-circuit is called semi-Eulerian.
+Mọi đỉnh của đồ thị này đều có bậc chẵn. Do đó, đây là
+một đồ thị Euler. Theo dõi các cạnh theo thứ tự chữ cái cho ta
+một chu trình Euler.
 
-![Königsberg graph](https://upload.wikimedia.org/wikipedia/commons/9/96/K%C3%B6nigsberg_graph.svg)
+Đối với sự tồn tại của các đường đi Euler, điều cần thiết là không có hoặc
+chỉ có hai đỉnh có bậc lẻ; điều này có nghĩa là đồ thị Königsberg
+không phải là Euler. Nếu không có đỉnh nào có bậc lẻ,
+tất cả các đường đi Euler đều là chu trình. Nếu có đúng hai đỉnh
+có bậc lẻ, tất cả các đường đi Euler bắt đầu tại một trong số chúng và kết thúc tại
+đỉnh còn lại. Một đồ thị có đường đi Euler nhưng không có chu trình Euler
+được gọi là bán Euler.
 
-The Königsberg Bridges multigraph. This multigraph is not Eulerian, 
-therefore, a solution does not exist.
+![Đồ thị Königsberg](https://upload.wikimedia.org/wikipedia/commons/9/96/K%C3%B6nigsberg_graph.svg)
 
-## References
+Đồ thị đa cạnh Cầu Königsberg. Đồ thị đa cạnh này không phải là Euler,
+do đó, không tồn tại giải pháp.
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Eulerian_path)
+## Tham khảo
+
+- [Wikipedia](https://vi.wikipedia.org/wiki/%C4%90%C6%B0%E1%BB%9Dng_%C4%91i_Euler)
 - [YouTube](https://www.youtube.com/watch?v=vvP4Fg4r-Ns&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/floyd-warshall/README.en-EN.md b/src/algorithms/graph/floyd-warshall/README.en-EN.md
new file mode 100644
index 0000000000..76373639f7
--- /dev/null
+++ b/src/algorithms/graph/floyd-warshall/README.en-EN.md
@@ -0,0 +1,92 @@
+# Floyd–Warshall Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, the **Floyd–Warshall algorithm** is an algorithm for finding
+shortest paths in a weighted graph with positive or negative edge weights (but
+with no negative cycles). A single execution of the algorithm will find the
+lengths (summed weights) of shortest paths between all pairs of vertices. Although
+it does not return details of the paths themselves, it is possible to reconstruct
+the paths with simple modifications to the algorithm.
+
+## Algorithm
+
+The Floyd–Warshall algorithm compares all possible paths through the graph between
+each pair of vertices. It is able to do this with `O(|V|^3)` comparisons in a graph.
+This is remarkable considering that there may be up to `|V|^2` edges in the graph,
+and every combination of edges is tested. It does so by incrementally improving an
+estimate on the shortest path between two vertices, until the estimate is optimal.
+
+Consider a graph `G` with vertices `V` numbered `1` through `N`. Further consider
+a function `shortestPath(i, j, k)` that returns the shortest possible path
+from `i` to `j` using vertices only from the set `{1, 2, ..., k}` as
+intermediate points along the way. Now, given this function, our goal is to
+find the shortest path from each `i` to each `j` using only vertices
+in `{1, 2, ..., N}`.
+
+![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/f9b75e25063384ccca499c56f9a279abf661ad3b)
+
+![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/34ac7c89bbb18df3fd660225fd38997079e5e513)
+![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/0326d6c14def89269c029da59eba012d0f2edc9d)
+
+This formula is the heart of the Floyd–Warshall algorithm.
+
+## Example
+
+The algorithm above is executed on the graph on the left below:
+
+![Example](https://upload.wikimedia.org/wikipedia/commons/2/2e/Floyd-Warshall_example.svg)
+
+In the tables below `i` is row numbers and `j` is column numbers.
+
+**k = 0**
+
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  3  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  ∞  | −1  |  ∞  |  0  |
+
+**k = 1**
+
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  2  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  ∞  |  −  |  ∞  |  0  |
+
+**k = 2**
+
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  2  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
+
+**k = 3**
+
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  0  |
+| **2** |  4  |  0  |  2  |  4  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
+
+**k = 4**
+
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  | −1  | −2  |  0  |
+| **2** |  4  |  0  |  2  |  4  |
+| **3** |  5  |  1  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
+- [YouTube (by Abdul Bari)](https://www.youtube.com/watch?v=oNI0rf2P9gE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=74)
+- [YouTube (by Tushar Roy)](https://www.youtube.com/watch?v=LwJdNfdLF9s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=75)
diff --git a/src/algorithms/graph/floyd-warshall/README.md b/src/algorithms/graph/floyd-warshall/README.md
index f662861305..4f93879480 100644
--- a/src/algorithms/graph/floyd-warshall/README.md
+++ b/src/algorithms/graph/floyd-warshall/README.md
@@ -1,94 +1,92 @@
-# Floyd–Warshall Algorithm
+# Thuật toán Floyd–Warshall
 
-In computer science, the **Floyd–Warshall algorithm** is an algorithm for finding
-shortest paths in a weighted graph with positive or negative edge weights (but
-with no negative cycles). A single execution of the algorithm will find the 
-lengths (summed weights) of shortest paths between all pairs of vertices. Although 
-it does not return details of the paths themselves, it is possible to reconstruct 
-the paths with simple modifications to the algorithm.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-## Algorithm
+Trong khoa học máy tính, **thuật toán Floyd–Warshall** là một thuật toán dùng để tìm
+đường đi ngắn nhất trong một đồ thị có trọng số dương hoặc âm (nhưng
+không có chu trình âm). Một lần thực hiện thuật toán sẽ tìm ra
+độ dài (tổng trọng số) của đường đi ngắn nhất giữa tất cả các cặp đỉnh. Mặc dù
+nó không trả về chi tiết của các đường đi, nhưng có thể tái tạo
+các đường đi với các thay đổi đơn giản cho thuật toán.
 
-The Floyd–Warshall algorithm compares all possible paths through the graph between 
-each pair of vertices. It is able to do this with `O(|V|^3)` comparisons in a graph.
-This is remarkable considering that there may be up to `|V|^2` edges in the graph, 
-and every combination of edges is tested. It does so by incrementally improving an 
-estimate on the shortest path between two vertices, until the estimate is optimal.
+## Thuật toán
 
-Consider a graph `G` with vertices `V` numbered `1` through `N`. Further consider 
-a function `shortestPath(i, j, k)` that returns the shortest possible path 
-from `i` to `j` using vertices only from the set `{1, 2, ..., k}` as 
-intermediate points along the way. Now, given this function, our goal is to 
-find the shortest path from each `i` to each `j` using only vertices 
-in `{1, 2, ..., N}`.
+Thuật toán Floyd–Warshall so sánh tất cả các đường đi có thể qua đồ thị giữa
+mỗi cặp đỉnh. Nó có thể làm điều này với `O(|V|^3)` so sánh trong một đồ thị.
+Điều này đáng chú ý khi xét rằng có thể có tới `|V|^2` cạnh trong đồ thị,
+và mọi tổ hợp cạnh đều được kiểm tra. Nó làm như vậy bằng cách cải thiện dần dần một
+ước lượng về đường đi ngắn nhất giữa hai đỉnh, cho đến khi ước lượng là tối ưu.
 
-![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/f9b75e25063384ccca499c56f9a279abf661ad3b)
+Xem xét một đồ thị `G` với các đỉnh `V` được đánh số từ `1` đến `N`. Xem xét thêm
+một hàm `shortestPath(i, j, k)` trả về đường đi ngắn nhất có thể
+từ `i` đến `j` sử dụng chỉ các đỉnh từ tập `{1, 2, ..., k}` như
+các điểm trung gian dọc theo đường đi. Bây giờ, với hàm này, mục tiêu của chúng ta là
+tìm đường đi ngắn nhất từ mỗi `i` đến mỗi `j` sử dụng chỉ các đỉnh
+trong `{1, 2, ..., N}`.
 
-![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/34ac7c89bbb18df3fd660225fd38997079e5e513)
-![Recursive Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/0326d6c14def89269c029da59eba012d0f2edc9d)
+![Công thức đệ quy](https://wikimedia.org/api/rest_v1/media/math/render/svg/f9b75e25063384ccca499c56f9a279abf661ad3b)
 
-This formula is the heart of the Floyd–Warshall algorithm.
+![Công thức đệ quy](https://wikimedia.org/api/rest_v1/media/math/render/svg/34ac7c89bbb18df3fd660225fd38997079e5e513)
+![Công thức đệ quy](https://wikimedia.org/api/rest_v1/media/math/render/svg/0326d6c14def89269c029da59eba012d0f2edc9d)
 
-## Example
+Công thức này là trái tim của thuật toán Floyd–Warshall.
 
-The algorithm above is executed on the graph on the left below:
+## Ví dụ
 
-![Example](https://upload.wikimedia.org/wikipedia/commons/2/2e/Floyd-Warshall_example.svg)
+Thuật toán trên được thực hiện trên đồ thị bên trái dưới đây:
 
-In the tables below `i` is row numbers and `j` is column numbers.
+![Ví dụ](https://upload.wikimedia.org/wikipedia/commons/2/2e/Floyd-Warshall_example.svg)
 
+Trong các bảng dưới đây `i` là số hàng và `j` là số cột.
 
 **k = 0**
 
-|       | 1   | 2   | 3   | 4   |
-|:-----:|:---:|:---:|:---:|:---:|
-| **1** |	0   |	∞   |	−2  | ∞   |
-| **2** |	4   |	0   |	3	  | ∞   |
-| **3** |	∞   |	∞   |	0	  | 2   |
-| **4** |	∞   |	−1  | ∞   | 0   |
-
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  3  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  ∞  | −1  |  ∞  |  0  |
 
 **k = 1**
 
-|       | 1   | 2   | 3   | 4   |
-|:-----:|:---:|:---:|:---:|:---:|
-| **1** | 0   | ∞   | −2  | ∞   |
-| **2** | 4   | 0   |  2  | ∞   |
-| **3** | ∞   | ∞   |  0  | 2   |
-| **4** | ∞   | −   |  ∞  | 0   |
-
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  2  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  ∞  |  −  |  ∞  |  0  |
 
 **k = 2**
 
-|       | 1   | 2   | 3   | 4   |
-|:-----:|:---:|:---:|:---:|:---:|
-| **1** |	0   |	∞   |	−2  | ∞   |
-| **2** |	4   |	0   | 2	  | ∞   |
-| **3** |	∞   |	∞	  | 0	  | 2   |
-| **4** |	3   |	−1  | 1   | 0   |
-
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  ∞  |
+| **2** |  4  |  0  |  2  |  ∞  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
 
 **k = 3**
 
-|       | 1   | 2   | 3   | 4   |
-|:-----:|:---:|:---:|:---:|:---:|
-| **1** |	0   |	∞   |	−2  | 0   |
-| **2** |	4   |	0   |	2	  | 4   |
-| **3** |	∞   |	∞   |	0	  | 2   |
-| **4** |	3   |	−1  | 1   | 0   |
-
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  |  ∞  | −2  |  0  |
+| **2** |  4  |  0  |  2  |  4  |
+| **3** |  ∞  |  ∞  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
 
 **k = 4**
 
-|       | 1   | 2   | 3   | 4   |
-|:-----:|:---:|:---:|:---:|:---:|
-| **1** |	0   |	−1  | −2  | 0   |
-| **2** |	4   |	0	  | 2	  | 4   |
-| **3** |	5   |	1	  | 0	  | 2   |
-| **4** |	3   |	−1  | 1   | 0   |
+|       |  1  |  2  |  3  |  4  |
+| :---: | :-: | :-: | :-: | :-: |
+| **1** |  0  | −1  | −2  |  0  |
+| **2** |  4  |  0  |  2  |  4  |
+| **3** |  5  |  1  |  0  |  2  |
+| **4** |  3  | −1  |  1  |  0  |
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
-- [YouTube (by Abdul Bari)](https://www.youtube.com/watch?v=oNI0rf2P9gE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=74)
-- [YouTube (by Tushar Roy)](https://www.youtube.com/watch?v=LwJdNfdLF9s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=75)
+- [Wikipedia](https://vi.wikipedia.org/wiki/Thu%E1%BA%ADt_to%C3%A1n_Floyd%E2%80%93Warshall)
+- [YouTube (bởi Abdul Bari)](https://www.youtube.com/watch?v=oNI0rf2P9gE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=74)
+- [YouTube (bởi Tushar Roy)](https://www.youtube.com/watch?v=LwJdNfdLF9s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=75)
diff --git a/src/algorithms/graph/hamiltonian-cycle/README.en-EN.md b/src/algorithms/graph/hamiltonian-cycle/README.en-EN.md
new file mode 100644
index 0000000000..fee3a4da4d
--- /dev/null
+++ b/src/algorithms/graph/hamiltonian-cycle/README.en-EN.md
@@ -0,0 +1,51 @@
+# Hamiltonian Path
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**Hamiltonian path** (or **traceable path**) is a path in an
+undirected or directed graph that visits each vertex exactly once.
+A **Hamiltonian cycle** (or **Hamiltonian circuit**) is a
+Hamiltonian path that is a cycle. Determining whether such paths
+and cycles exist in graphs is the **Hamiltonian path problem**.
+
+![Hamiltonian cycle](https://upload.wikimedia.org/wikipedia/commons/6/6c/Hamiltonian_path_3d.svg)
+
+One possible Hamiltonian cycle through every vertex of a
+dodecahedron is shown in red – like all platonic solids, the
+dodecahedron is Hamiltonian.
+
+## Naive Algorithm
+
+Generate all possible configurations of vertices and print a
+configuration that satisfies the given constraints. There
+will be `n!` (n factorial) configurations.
+
+```
+while there are untried configurations
+{
+   generate the next configuration
+   if ( there are edges between two consecutive vertices of this
+      configuration and there is an edge from the last vertex to
+      the first ).
+   {
+      print this configuration;
+      break;
+   }
+}
+```
+
+## Backtracking Algorithm
+
+Create an empty path array and add vertex `0` to it. Add other
+vertices, starting from the vertex `1`. Before adding a vertex,
+check for whether it is adjacent to the previously added vertex
+and not already added. If we find such a vertex, we add the
+vertex as part of the solution. If we do not find a vertex
+then we return false.
+
+## References
+
+- [Hamiltonian path on Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path)
+- [Hamiltonian path on YouTube](https://www.youtube.com/watch?v=dQr4wZCiJJ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Hamiltonian cycle on GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-7-hamiltonian-cycle/)
diff --git a/src/algorithms/graph/hamiltonian-cycle/README.md b/src/algorithms/graph/hamiltonian-cycle/README.md
index ccd15481ba..7300987e83 100644
--- a/src/algorithms/graph/hamiltonian-cycle/README.md
+++ b/src/algorithms/graph/hamiltonian-cycle/README.md
@@ -1,29 +1,32 @@
-# Hamiltonian Path
+# Đường đi Hamilton
 
-**Hamiltonian path** (or **traceable path**) is a path in an 
-undirected or directed graph that visits each vertex exactly once. 
-A **Hamiltonian cycle** (or **Hamiltonian circuit**) is a 
-Hamiltonian path that is a cycle. Determining whether such paths 
-and cycles exist in graphs is the **Hamiltonian path problem**.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-![Hamiltonian cycle](https://upload.wikimedia.org/wikipedia/commons/6/6c/Hamiltonian_path_3d.svg)
+**Đường đi Hamilton** (hoặc **đường đi có thể truy vết**) là một đường đi trong một
+đồ thị không hướng hoặc có hướng mà đi qua mỗi đỉnh đúng một lần.
+Một **chu trình Hamilton** (hoặc **chu trình Hamilton**) là một
+đường đi Hamilton tạo thành một chu trình. Xác định xem liệu các đường đi
+và chu trình như vậy có tồn tại trong đồ thị hay không là **bài toán đường đi Hamilton**.
 
-One possible Hamiltonian cycle through every vertex of a 
-dodecahedron is shown in red – like all platonic solids, the 
-dodecahedron is Hamiltonian.
+![Chu trình Hamilton](https://upload.wikimedia.org/wikipedia/commons/6/6c/Hamiltonian_path_3d.svg)
 
-## Naive Algorithm
+Một chu trình Hamilton có thể thông qua mọi đỉnh của một
+đa diện mười hai mặt được hiển thị bằng màu đỏ - giống như tất cả các hình đa diện đều,
+đa diện mười hai mặt là Hamilton.
 
-Generate all possible configurations of vertices and print a 
-configuration that satisfies the given constraints. There 
-will be `n!` (n factorial) configurations.
+## Thuật toán Naive
+
+Tạo ra tất cả các cấu hình có thể của các đỉnh và in ra một
+cấu hình thỏa mãn các ràng buộc đã cho. Sẽ có
+`n!` (n giai thừa) cấu hình.
 
 ```
 while there are untried configurations
 {
    generate the next configuration
    if ( there are edges between two consecutive vertices of this
-      configuration and there is an edge from the last vertex to 
+      configuration and there is an edge from the last vertex to
       the first ).
    {
       print this configuration;
@@ -32,17 +35,17 @@ while there are untried configurations
 }
 ```
 
-## Backtracking Algorithm
+## Thuật toán Backtracking
 
-Create an empty path array and add vertex `0` to it. Add other 
-vertices, starting from the vertex `1`. Before adding a vertex, 
-check for whether it is adjacent to the previously added vertex 
-and not already added. If we find such a vertex, we add the 
-vertex as part of the solution. If we do not find a vertex 
-then we return false.
+Tạo một mảng đường đi trống và thêm đỉnh `0` vào đó. Thêm các đỉnh
+khác, bắt đầu từ đỉnh `1`. Trước khi thêm một đỉnh,
+kiểm tra xem nó có kề với đỉnh đã thêm trước đó
+và chưa được thêm hay không. Nếu chúng ta tìm thấy một đỉnh như vậy, chúng ta thêm
+đỉnh đó làm một phần của giải pháp. Nếu chúng ta không tìm thấy một đỉnh
+thì chúng ta trả về false.
 
-## References
+## Tham khảo
 
-- [Hamiltonian path on Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path)
-- [Hamiltonian path on YouTube](https://www.youtube.com/watch?v=dQr4wZCiJJ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Hamiltonian cycle on GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-7-hamiltonian-cycle/)
+- [Đường đi Hamilton trên Wikipedia](https://vi.wikipedia.org/wiki/%C4%90%C6%B0%E1%BB%9Dng_%C4%91i_Hamilton)
+- [Đường đi Hamilton trên YouTube](https://www.youtube.com/watch?v=dQr4wZCiJJ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Chu trình Hamilton trên GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-7-hamiltonian-cycle/)
diff --git a/src/algorithms/graph/kruskal/README.en-EN.md b/src/algorithms/graph/kruskal/README.en-EN.md
new file mode 100644
index 0000000000..f7a7e801fe
--- /dev/null
+++ b/src/algorithms/graph/kruskal/README.en-EN.md
@@ -0,0 +1,52 @@
+# Kruskal's Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Kruskal's algorithm is a minimum-spanning-tree algorithm which
+finds an edge of the least possible weight that connects any two
+trees in the forest. It is a greedy algorithm in graph theory
+as it finds a minimum spanning tree for a connected weighted
+graph adding increasing cost arcs at each step. This means it
+finds a subset of the edges that forms a tree that includes every
+vertex, where the total weight of all the edges in the tree is
+minimized. If the graph is not connected, then it finds a
+minimum spanning forest (a minimum spanning tree for each
+connected component).
+
+![Kruskal Algorithm](https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif)
+
+![Kruskal Demo](https://upload.wikimedia.org/wikipedia/commons/b/bb/KruskalDemo.gif)
+
+A demo for Kruskal's algorithm based on Euclidean distance.
+
+## Minimum Spanning Tree
+
+A **minimum spanning tree** (MST) or minimum weight spanning tree
+is a subset of the edges of a connected, edge-weighted
+(un)directed graph that connects all the vertices together,
+without any cycles and with the minimum possible total edge
+weight. That is, it is a spanning tree whose sum of edge weights
+is as small as possible. More generally, any edge-weighted
+undirected graph (not necessarily connected) has a minimum
+spanning forest, which is a union of the minimum spanning
+trees for its connected components.
+
+![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)
+
+A planar graph and its minimum spanning tree. Each edge is
+labeled with its weight, which here is roughly proportional
+to its length.
+
+![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)
+
+This figure shows there may be more than one minimum spanning
+tree in a graph. In the figure, the two trees below the graph
+are two possibilities of minimum spanning tree of the given graph.
+
+## References
+
+- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
+- [Kruskal's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)
+- [Kruskal's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Kruskal's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/kruskal/README.ko-KR.md b/src/algorithms/graph/kruskal/README.ko-KR.md
deleted file mode 100644
index eefb6a6756..0000000000
--- a/src/algorithms/graph/kruskal/README.ko-KR.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# 크루스칼 알고리즘
-
-크루스칼 알고리즘은 두 트리를 연결하는 최소 간선 가중치를 찾는 최소 신장 트리 알고리즘입니다.
-각 단계에서 비용을 더하는 연결된 가중 그래프에 대한 최소 신장 트리를 찾기 때문에 그래프 이론에서의 그리디 알고리즘입니다. 즉, 트리의 모든 간선의 총 가중치가 최소화되는 모든 정점을 포함하는 트리를 형성하는 간선의 하위 집합을 찾습니다. 그래프가 연결되어 있지 않으면 최소 신장 포레스트(연결된 각 구성 요소의 최소 신장 트리)를 찾습니다.
-
-![Kruskal Algorithm](https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif)
-
-![Kruskal Demo](https://upload.wikimedia.org/wikipedia/commons/b/bb/KruskalDemo.gif)
-
-유클리드 거리를 기반으로 한 크루스칼 알고리즘의 데모입니다.
-
-## 최소 신장 트리
-
-**최소 신장 트리(MST)** 또는 최소 가중치 신장 트리는 연결된 간선 가중치 무 방향 그래프의 간선의 하위 집합으로, 사이클 없이 가능한 최소 총 간선 가중치로 모든 정점을 연결합니다. 즉, 간선 가중치의 합이 가능한 작은 신장 트리입니다. 보다 일반적으로, 간선-가중치 비방향 그래프(꼭 연결되지는 않음)에는 연결된 구성 요소에 대한 최소 신장 트리의 결합인 최소 신장 포레스트(minimum spanning forest)가 있습니다.
-
-![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)
-
-평면 그래프와 해당 최소 신장 트리입니다. 각 간선은 가중치로 레이블이 지정되며, 이 값은 길이에 거의 비례합니다.
-
-![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)
-
-이 그림은 그래프에 최소 신장 트리가 두 개 이상 있을 수 있음을 보여 줍니다. 그림에서 그래프 아래의 두 트리는 주어진 그래프에서 최소 신장 트리가 될 수 있는 두 가지 경우입니다.
-
-## 참조
-
-- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
-- [Kruskal's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)
-- [Kruskal's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Kruskal's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/kruskal/README.md b/src/algorithms/graph/kruskal/README.md
index 1a71390e2f..f7541fe926 100644
--- a/src/algorithms/graph/kruskal/README.md
+++ b/src/algorithms/graph/kruskal/README.md
@@ -1,52 +1,31 @@
-# Kruskal's Algorithm
-
-_Read this in other languages:_
-[_한국어_](README.ko-KR.md)
-
-Kruskal's algorithm is a minimum-spanning-tree algorithm which 
-finds an edge of the least possible weight that connects any two 
-trees in the forest. It is a greedy algorithm in graph theory 
-as it finds a minimum spanning tree for a connected weighted 
-graph adding increasing cost arcs at each step. This means it 
-finds a subset of the edges that forms a tree that includes every
-vertex, where the total weight of all the edges in the tree is 
-minimized. If the graph is not connected, then it finds a 
-minimum spanning forest (a minimum spanning tree for each 
-connected component).
+# Thuật toán Kruskal - Kruskal's Algorithm
+
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
+
+Thuật toán Kruskal là một thuật toán cây khung nhỏ nhất, tìm cạnh có trọng số nhỏ nhất có thể nối hai cây trong rừng. Đây là một thuật toán tham lam trong lý thuyết đồ thị khi nó tìm một cây khung nhỏ nhất cho một đồ thị có trọng số và liên thông, thêm các cung có chi phí tăng dần ở mỗi bước. Điều này có nghĩa là nó tìm một tập hợp các cạnh tạo thành một cây bao gồm mọi đỉnh, nơi tổng trọng số của tất cả các cạnh trong cây được tối thiểu hóa. Nếu đồ thị không liên thông, thì nó tìm một rừng khung nhỏ nhất (một cây khung nhỏ nhất cho mỗi thành phần liên thông).
 
 ![Kruskal Algorithm](https://upload.wikimedia.org/wikipedia/commons/5/5c/MST_kruskal_en.gif)
 
 ![Kruskal Demo](https://upload.wikimedia.org/wikipedia/commons/b/bb/KruskalDemo.gif)
 
-A demo for Kruskal's algorithm based on Euclidean distance.
+Một mô phỏng cho thuật toán Kruskal dựa trên khoảng cách Euclid.
 
-## Minimum Spanning Tree
+## Cây Khung Nhỏ Nhất - Minimum Spanning Tree
 
-A **minimum spanning tree** (MST) or minimum weight spanning tree 
-is a subset of the edges of a connected, edge-weighted 
-(un)directed graph that connects all the vertices together, 
-without any cycles and with the minimum possible total edge 
-weight. That is, it is a spanning tree whose sum of edge weights 
-is as small as possible. More generally, any edge-weighted 
-undirected graph (not necessarily connected) has a minimum 
-spanning forest, which is a union of the minimum spanning 
-trees for its connected components.
+Một **cây khung nhỏ nhất** (MST) hay cây khung có trọng số nhỏ nhất là một tập hợp các cạnh của một đồ thị liên thông, có trọng số cạnh, (không) có hướng nối tất cả các đỉnh lại với nhau, không có chu trình và có tổng trọng số cạnh nhỏ nhất có thể. Nói cách khác, đó là một cây khung mà tổng trọng số của các cạnh là nhỏ nhất có thể. Một cách tổng quát hơn, bất kỳ đồ thị có trọng số cạnh không có hướng (không nhất thiết phải liên thông) đều có một rừng khung nhỏ nhất, là sự kết hợp của các cây khung nhỏ nhất cho các thành phần liên thông của nó.
 
 ![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)
 
-A planar graph and its minimum spanning tree. Each edge is 
-labeled with its weight, which here is roughly proportional 
-to its length.
+Một đồ thị phẳng và cây khung nhỏ nhất của nó. Mỗi cạnh được gắn nhãn với trọng số của nó, ở đây tương đương với chiều dài của nó.
 
 ![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)
 
-This figure shows there may be more than one minimum spanning 
-tree in a graph. In the figure, the two trees below the graph 
-are two possibilities of minimum spanning tree of the given graph.
+Hình này cho thấy có thể có nhiều hơn một cây khung nhỏ nhất trong một đồ thị. Trong hình, hai cây dưới đồ thị là hai khả năng của cây khung nhỏ nhất của đồ thị đã cho.
 
-## References
+## Tài liệu tham khảo
 
-- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
-- [Kruskal's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)
-- [Kruskal's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Kruskal's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Cây Khung Nhỏ Nhất trên Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
+- [Thuật toán Kruskal trên Wikipedia](https://en.wikipedia.org/wiki/Kruskal%27s_algorithm)
+- [Thuật toán Kruskal trên YouTube bởi Tushar Roy](https://www.youtube.com/watch?v=fAuF0EuZVCk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Thuật toán Kruskal trên YouTube bởi Michael Sambol](https://www.youtube.com/watch?v=71UQH7Pr9kU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/prim/README.en-EN.md b/src/algorithms/graph/prim/README.en-EN.md
new file mode 100644
index 0000000000..0abc7c5aaf
--- /dev/null
+++ b/src/algorithms/graph/prim/README.en-EN.md
@@ -0,0 +1,50 @@
+# Prim's Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, **Prim's algorithm** is a greedy algorithm that
+finds a minimum spanning tree for a weighted undirected graph.
+
+The algorithm operates by building this tree one vertex at a
+time, from an arbitrary starting vertex, at each step adding
+the cheapest possible connection from the tree to another vertex.
+
+![Prim's Algorithm](https://upload.wikimedia.org/wikipedia/commons/f/f7/Prim%27s_algorithm.svg)
+
+Prim's algorithm starting at vertex `A`. In the third step, edges
+`BD` and `AB` both have weight `2`, so `BD` is chosen arbitrarily.
+After that step, `AB` is no longer a candidate for addition
+to the tree because it links two nodes that are already
+in the tree.
+
+## Minimum Spanning Tree
+
+A **minimum spanning tree** (MST) or minimum weight spanning tree
+is a subset of the edges of a connected, edge-weighted
+(un)directed graph that connects all the vertices together,
+without any cycles and with the minimum possible total edge
+weight. That is, it is a spanning tree whose sum of edge weights
+is as small as possible. More generally, any edge-weighted
+undirected graph (not necessarily connected) has a minimum
+spanning forest, which is a union of the minimum spanning
+trees for its connected components.
+
+![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)
+
+A planar graph and its minimum spanning tree. Each edge is
+labeled with its weight, which here is roughly proportional
+to its length.
+
+![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)
+
+This figure shows there may be more than one minimum spanning
+tree in a graph. In the figure, the two trees below the graph
+are two possibilities of minimum spanning tree of the given graph.
+
+## References
+
+- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
+- [Prim's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Prim%27s_algorithm)
+- [Prim's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=oP2-8ysT3QQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Prim's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=cplfcGZmX7I&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/prim/README.md b/src/algorithms/graph/prim/README.md
index 49061a278e..ae51136841 100644
--- a/src/algorithms/graph/prim/README.md
+++ b/src/algorithms/graph/prim/README.md
@@ -1,47 +1,31 @@
-# Prim's Algorithm
+# Thuật toán Prim - Prim's Algorithm
 
-In computer science, **Prim's algorithm** is a greedy algorithm that 
-finds a minimum spanning tree for a weighted undirected graph. 
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-The algorithm operates by building this tree one vertex at a 
-time, from an arbitrary starting vertex, at each step adding 
-the cheapest possible connection from the tree to another vertex.
+Trong khoa học máy tính, **Thuật toán Prim** là một thuật toán tham lam tìm cây khung nhỏ nhất cho một đồ thị vô hướng có trọng số.
+
+Thuật toán hoạt động bằng cách xây dựng cây này từng đỉnh một lần, bắt đầu từ một đỉnh bất kỳ, và tại mỗi bước thêm vào kết nối có chi phí thấp nhất có thể từ cây tới một đỉnh khác.
 
 ![Prim's Algorithm](https://upload.wikimedia.org/wikipedia/commons/f/f7/Prim%27s_algorithm.svg)
 
-Prim's algorithm starting at vertex `A`. In the third step, edges 
-`BD` and `AB` both have weight `2`, so `BD` is chosen arbitrarily. 
-After that step, `AB` is no longer a candidate for addition 
-to the tree because it links two nodes that are already 
-in the tree.
+Thuật toán Prim bắt đầu tại đỉnh `A`. Ở bước thứ ba, cạnh `BD` và `AB` đều có trọng số `2`, do đó `BD` được chọn một cách ngẫu nhiên. Sau bước đó, `AB` không còn là ứng viên để được thêm vào cây vì nó nối hai nút đã có trong cây.
 
-## Minimum Spanning Tree
+## Cây Khung Nhỏ Nhất - Minimum Spanning Tree
 
-A **minimum spanning tree** (MST) or minimum weight spanning tree 
-is a subset of the edges of a connected, edge-weighted 
-(un)directed graph that connects all the vertices together, 
-without any cycles and with the minimum possible total edge 
-weight. That is, it is a spanning tree whose sum of edge weights 
-is as small as possible. More generally, any edge-weighted 
-undirected graph (not necessarily connected) has a minimum 
-spanning forest, which is a union of the minimum spanning 
-trees for its connected components.
+Một **cây khung nhỏ nhất** (MST) hay cây khung có trọng số nhỏ nhất là một tập hợp các cạnh của một đồ thị liên thông, có trọng số cạnh, (không) có hướng nối tất cả các đỉnh lại với nhau, không có chu trình và có tổng trọng số cạnh nhỏ nhất có thể. Nói cách khác, đó là một cây khung mà tổng trọng số của các cạnh là nhỏ nhất có thể. Một cách tổng quát hơn, bất kỳ đồ thị có trọng số cạnh không có hướng (không nhất thiết phải liên thông) đều có một rừng khung nhỏ nhất, là sự kết hợp của các cây khung nhỏ nhất cho các thành phần liên thông của nó.
 
 ![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/d/d2/Minimum_spanning_tree.svg)
 
-A planar graph and its minimum spanning tree. Each edge is 
-labeled with its weight, which here is roughly proportional 
-to its length.
+Một đồ thị phẳng và cây khung nhỏ nhất của nó. Mỗi cạnh được gắn nhãn với trọng số của nó, ở đây tương đương với chiều dài của nó.
 
 ![Minimum Spanning Tree](https://upload.wikimedia.org/wikipedia/commons/c/c9/Multiple_minimum_spanning_trees.svg)
 
-This figure shows there may be more than one minimum spanning 
-tree in a graph. In the figure, the two trees below the graph 
-are two possibilities of minimum spanning tree of the given graph.
+Hình này cho thấy có thể có nhiều hơn một cây khung nhỏ nhất trong một đồ thị. Trong hình, hai cây dưới đồ thị là hai khả năng của cây khung nhỏ nhất của đồ thị đã cho.
 
-## References
+## Tài liệu tham khảo
 
-- [Minimum Spanning Tree on Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
-- [Prim's Algorithm on Wikipedia](https://en.wikipedia.org/wiki/Prim%27s_algorithm)
-- [Prim's Algorithm on YouTube by Tushar Roy](https://www.youtube.com/watch?v=oP2-8ysT3QQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Prim's Algorithm on YouTube by Michael Sambol](https://www.youtube.com/watch?v=cplfcGZmX7I&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Cây Khung Nhỏ Nhất trên Wikipedia](https://en.wikipedia.org/wiki/Minimum_spanning_tree)
+- [Thuật toán Prim trên Wikipedia](https://en.wikipedia.org/wiki/Prim%27s_algorithm)
+- [Thuật toán Prim trên YouTube bởi Tushar Roy](https://www.youtube.com/watch?v=oP2-8ysT3QQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Thuật toán Prim trên YouTube bởi Michael Sambol](https://www.youtube.com/watch?v=cplfcGZmX7I&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/strongly-connected-components/README.en-EN.md b/src/algorithms/graph/strongly-connected-components/README.en-EN.md
new file mode 100644
index 0000000000..40702b3284
--- /dev/null
+++ b/src/algorithms/graph/strongly-connected-components/README.en-EN.md
@@ -0,0 +1,19 @@
+# Strongly Connected Component
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A directed graph is called **strongly connected** if there is a path
+in each direction between each pair of vertices of the graph.
+In a directed graph G that may not itself be strongly connected,
+a pair of vertices `u` and `v` are said to be strongly connected
+to each other if there is a path in each direction between them.
+
+![Strongly Connected](https://upload.wikimedia.org/wikipedia/commons/5/5c/Scc.png)
+
+Graph with strongly connected components marked
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Strongly_connected_component)
+- [YouTube](https://www.youtube.com/watch?v=RpgcYiky7uw&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/strongly-connected-components/README.md b/src/algorithms/graph/strongly-connected-components/README.md
index 74f23ce051..701cb898b4 100644
--- a/src/algorithms/graph/strongly-connected-components/README.md
+++ b/src/algorithms/graph/strongly-connected-components/README.md
@@ -1,16 +1,15 @@
-# Strongly Connected Component
+# Thành phần liên thông mạnh - Strongly Connected Component
 
-A directed graph is called **strongly connected** if there is a path 
-in each direction between each pair of vertices of the graph. 
-In a directed graph G that may not itself be strongly connected, 
-a pair of vertices `u` and `v` are said to be strongly connected 
-to each other if there is a path in each direction between them.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
+
+Một đồ thị có hướng được gọi là **liên thông mạnh** nếu có đường đi theo mỗi hướng giữa mọi cặp đỉnh của đồ thị. Trong một đồ thị có hướng G có thể không liên thông mạnh, một cặp đỉnh `u` và `v` được coi là liên thông mạnh với nhau nếu có đường đi theo mỗi hướng giữa họ.
 
 ![Strongly Connected](https://upload.wikimedia.org/wikipedia/commons/5/5c/Scc.png)
 
-Graph with strongly connected components marked
+Đồ thị với các thành phần liên thông mạnh được đánh dấu
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Strongly_connected_component)
 - [YouTube](https://www.youtube.com/watch?v=RpgcYiky7uw&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/topological-sorting/README.en-EN.md b/src/algorithms/graph/topological-sorting/README.en-EN.md
new file mode 100644
index 0000000000..afbfbc4e82
--- /dev/null
+++ b/src/algorithms/graph/topological-sorting/README.en-EN.md
@@ -0,0 +1,58 @@
+# Topological Sorting
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In the field of computer science, a topological sort or
+topological ordering of a directed graph is a linear ordering
+of its vertices such that for every directed edge `uv` from
+vertex `u` to vertex `v`, `u` comes before `v` in the ordering.
+
+For instance, the vertices of the graph may represent tasks to
+be performed, and the edges may represent constraints that one
+task must be performed before another; in this application, a
+topological ordering is just a valid sequence for the tasks.
+
+A topological ordering is possible if and only if the graph has
+no directed cycles, that is, if it is a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph)
+(DAG). Any DAG has at least one topological ordering, and algorithms are
+known for constructing a topological ordering of any DAG in linear time.
+
+![Directed Acyclic Graph](https://upload.wikimedia.org/wikipedia/commons/c/c6/Topological_Ordering.svg)
+
+A topological ordering of a directed acyclic graph: every edge goes from
+earlier in the ordering (upper left) to later in the ordering (lower right).
+A directed graph is acyclic if and only if it has a topological ordering.
+
+## Example
+
+![Topologic Sorting](https://upload.wikimedia.org/wikipedia/commons/0/03/Directed_acyclic_graph_2.svg)
+
+The graph shown above has many valid topological sorts, including:
+
+- `5, 7, 3, 11, 8, 2, 9, 10` (visual left-to-right, top-to-bottom)
+- `3, 5, 7, 8, 11, 2, 9, 10` (smallest-numbered available vertex first)
+- `5, 7, 3, 8, 11, 10, 9, 2` (fewest edges first)
+- `7, 5, 11, 3, 10, 8, 9, 2` (largest-numbered available vertex first)
+- `5, 7, 11, 2, 3, 8, 9, 10` (attempting top-to-bottom, left-to-right)
+- `3, 7, 8, 5, 11, 10, 2, 9` (arbitrary)
+
+## Application
+
+The canonical application of topological sorting is in
+**scheduling a sequence of jobs** or tasks based on their dependencies. The jobs
+are represented by vertices, and there is an edge from `x` to `y` if
+job `x` must be completed before job `y` can be started (for
+example, when washing clothes, the washing machine must finish
+before we put the clothes in the dryer). Then, a topological sort
+gives an order in which to perform the jobs.
+
+Other application is **dependency resolution**. Each vertex is a package
+and each edge is a dependency of package `a` on package 'b'. Then topological
+sorting will provide a sequence of installing dependencies in a way that every
+next dependency has its dependent packages to be installed in prior.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Topological_sorting)
+- [Topological Sorting on YouTube by Tushar Roy](https://www.youtube.com/watch?v=ddTC4Zovtbc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/topological-sorting/README.md b/src/algorithms/graph/topological-sorting/README.md
index f4653a8b1e..f90bb34599 100644
--- a/src/algorithms/graph/topological-sorting/README.md
+++ b/src/algorithms/graph/topological-sorting/README.md
@@ -1,55 +1,38 @@
-# Topological Sorting
+# Sắp xếp Topo - Topological Sorting
 
-In the field of computer science, a topological sort or 
-topological ordering of a directed graph is a linear ordering 
-of its vertices such that for every directed edge `uv` from 
-vertex `u` to vertex `v`, `u` comes before `v` in the ordering.
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
 
-For instance, the vertices of the graph may represent tasks to 
-be performed, and the edges may represent constraints that one 
-task must be performed before another; in this application, a 
-topological ordering is just a valid sequence for the tasks.
+Trong lĩnh vực khoa học máy tính, sắp xếp topo hoặc sắp xếp topo của một đồ thị có hướng là một thứ tự tuyến tính của các đỉnh sao cho đối với mỗi cạnh có hướng `uv` từ đỉnh `u` đến đỉnh `v`, `u` đến trước `v` trong thứ tự.
 
-A topological ordering is possible if and only if the graph has
-no directed cycles, that is, if it is a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) 
-(DAG). Any DAG has at least one topological ordering, and algorithms are 
-known for constructing a topological ordering of any DAG in linear time.
+Ví dụ, các đỉnh của đồ thị có thể đại diện cho các nhiệm vụ cần thực hiện, và các cạnh có thể đại diện cho các ràng buộc rằng một nhiệm vụ phải được thực hiện trước nhiệm vụ khác; trong ứng dụng này, một thứ tự topo chỉ là một chuỗi hợp lệ cho các nhiệm vụ.
+
+Một thứ tự topo chỉ có thể có nếu đồ thị không có chu trình có hướng, tức là nếu nó là một [đồ thị không chu trình có hướng](https://en.wikipedia.org/wiki/Directed_acyclic_graph) (DAG). Mọi DAG đều có ít nhất một thứ tự topo, và có các thuật toán để xây dựng thứ tự topo của bất kỳ DAG nào trong thời gian tuyến tính.
 
 ![Directed Acyclic Graph](https://upload.wikimedia.org/wikipedia/commons/c/c6/Topological_Ordering.svg)
 
-A topological ordering of a directed acyclic graph: every edge goes from 
-earlier in the ordering (upper left) to later in the ordering (lower right). 
-A directed graph is acyclic if and only if it has a topological ordering.
+Một thứ tự topo của một đồ thị không chu trình có hướng: mỗi cạnh đi từ trước trong thứ tự (trên cùng bên trái) đến sau trong thứ tự (dưới cùng bên phải). Một đồ thị có hướng là không chu trình khi và chỉ khi nó có một thứ tự topo.
 
-## Example
+## Ví dụ
 
 ![Topologic Sorting](https://upload.wikimedia.org/wikipedia/commons/0/03/Directed_acyclic_graph_2.svg)
 
-The graph shown above has many valid topological sorts, including:
+Đồ thị được hiển thị ở trên có nhiều thứ tự topo hợp lệ, bao gồm:
 
-- `5, 7, 3, 11, 8, 2, 9, 10` (visual left-to-right, top-to-bottom)
-- `3, 5, 7, 8, 11, 2, 9, 10` (smallest-numbered available vertex first)
-- `5, 7, 3, 8, 11, 10, 9, 2` (fewest edges first)
-- `7, 5, 11, 3, 10, 8, 9, 2` (largest-numbered available vertex first)
-- `5, 7, 11, 2, 3, 8, 9, 10` (attempting top-to-bottom, left-to-right)
-- `3, 7, 8, 5, 11, 10, 2, 9` (arbitrary)
+- `5, 7, 3, 11, 8, 2, 9, 10` (trực quan từ trái sang phải, từ trên xuống dưới)
+- `3, 5, 7, 8, 11, 2, 9, 10` (đỉnh có số nhỏ nhất có sẵn đầu tiên)
+- `5, 7, 3, 8, 11, 10, 9, 2` (ít cạnh nhất đầu tiên)
+- `7, 5, 11, 3, 10, 8, 9, 2` (đỉnh có số lớn nhất có sẵn đầu tiên)
+- `5, 7, 11, 2, 3, 8, 9, 10` (cố gắng từ trên xuống dưới, từ trái sang phải)
+- `3, 7, 8, 5, 11, 10, 2, 9` (tùy ý)
 
-## Application
+## Ứng dụng
 
-The canonical application of topological sorting is in 
-**scheduling a sequence of jobs** or tasks based on their dependencies. The jobs 
-are represented by vertices, and there is an edge from `x` to `y` if 
-job `x` must be completed before job `y` can be started (for 
-example, when washing clothes, the washing machine must finish 
-before we put the clothes in the dryer). Then, a topological sort 
-gives an order in which to perform the jobs.
+Ứng dụng chuẩn của sắp xếp topo là trong **lập lịch một chuỗi công việc** hoặc nhiệm vụ dựa trên sự phụ thuộc của chúng. Các công việc được đại diện bởi các đỉnh, và có một cạnh từ `x` đến `y` nếu công việc `x` phải hoàn thành trước khi công việc `y` có thể bắt đầu (ví dụ, khi giặt quần áo, máy giặt phải hoàn thành trước khi chúng ta cho quần áo vào máy sấy). Sau đó, một thứ tự topo cung cấp một thứ tự để thực hiện các công việc.
 
-Other application is **dependency resolution**. Each vertex is a package
-and each edge is a dependency of package `a` on package 'b'. Then topological
-sorting will provide a sequence of installing dependencies in a way that every
-next dependency has its dependent packages to be installed in prior.
+Ứng dụng khác là **giải quyết phụ thuộc**. Mỗi đỉnh là một gói và mỗi cạnh là một sự phụ thuộc của gói `a` vào gói 'b'. Sau đó, sắp xếp topo sẽ cung cấp một chuỗi cài đặt các phụ thuộc một cách mà mỗi phụ thuộc tiếp theo đã có các gói phụ thuộc của nó được cài đặt trước.
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Topological_sorting)
-- [Topological Sorting on YouTube by Tushar Roy](https://www.youtube.com/watch?v=ddTC4Zovtbc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Sắp xếp Topo trên YouTube bởi Tushar Roy](https://www.youtube.com/watch?v=ddTC4Zovtbc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/graph/travelling-salesman/README.en-EN.md b/src/algorithms/graph/travelling-salesman/README.en-EN.md
new file mode 100644
index 0000000000..693b0fa320
--- /dev/null
+++ b/src/algorithms/graph/travelling-salesman/README.en-EN.md
@@ -0,0 +1,29 @@
+# Travelling Salesman Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The travelling salesman problem (TSP) asks the following question:
+"Given a list of cities and the distances between each pair of
+cities, what is the shortest possible route that visits each city
+and returns to the origin city?"
+
+![Travelling Salesman](https://upload.wikimedia.org/wikipedia/commons/1/11/GLPK_solution_of_a_travelling_salesman_problem.svg)
+
+Solution of a travelling salesman problem: the black line shows
+the shortest possible loop that connects every red dot.
+
+![Travelling Salesman Graph](https://upload.wikimedia.org/wikipedia/commons/3/30/Weighted_K4.svg)
+
+TSP can be modelled as an undirected weighted graph, such that
+cities are the graph's vertices, paths are the graph's edges,
+and a path's distance is the edge's weight. It is a minimization
+problem starting and finishing at a specified vertex after having
+visited each other vertex exactly once. Often, the model is a
+complete graph (i.e. each pair of vertices is connected by an
+edge). If no path exists between two cities, adding an arbitrarily
+long edge will complete the graph without affecting the optimal tour.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Travelling_salesman_problem)
diff --git a/src/algorithms/graph/travelling-salesman/README.md b/src/algorithms/graph/travelling-salesman/README.md
index 6690cd47ad..b7901e7fc7 100644
--- a/src/algorithms/graph/travelling-salesman/README.md
+++ b/src/algorithms/graph/travelling-salesman/README.md
@@ -1,26 +1,19 @@
-# Travelling Salesman Problem
+# Bài toán người bán hàng du lịch - Travelling Salesman Problem (TSP)
 
-The travelling salesman problem (TSP) asks the following question: 
-"Given a list of cities and the distances between each pair of 
-cities, what is the shortest possible route that visits each city 
-and returns to the origin city?"
+_Đọc tài liệu này bằng ngôn ngữ khác:_
+[_Tiếng Anh_](README.en-EN.md)
+
+Bài toán người bán hàng du lịch (TSP) đặt ra câu hỏi sau:
+"Cho một danh sách các thành phố và khoảng cách giữa từng cặp thành phố, đâu là tuyến đường ngắn nhất có thể đi qua mỗi thành phố và trở về thành phố xuất phát?"
 
 ![Travelling Salesman](https://upload.wikimedia.org/wikipedia/commons/1/11/GLPK_solution_of_a_travelling_salesman_problem.svg)
 
-Solution of a travelling salesman problem: the black line shows 
-the shortest possible loop that connects every red dot.
+Giải pháp cho bài toán người bán hàng du lịch: đường màu đen chỉ lộ trình ngắn nhất có thể nối mọi điểm đỏ.
 
 ![Travelling Salesman Graph](https://upload.wikimedia.org/wikipedia/commons/3/30/Weighted_K4.svg)
 
-TSP can be modelled as an undirected weighted graph, such that 
-cities are the graph's vertices, paths are the graph's edges, 
-and a path's distance is the edge's weight. It is a minimization 
-problem starting and finishing at a specified vertex after having 
-visited each other vertex exactly once. Often, the model is a 
-complete graph (i.e. each pair of vertices is connected by an 
-edge). If no path exists between two cities, adding an arbitrarily 
-long edge will complete the graph without affecting the optimal tour.
+TSP có thể được mô hình hóa như một đồ thị vô hướng có trọng số, trong đó các thành phố là các đỉnh của đồ thị, các lối đi là các cạnh của đồ thị, và khoảng cách của một lối đi là trọng số của cạnh đó. Đây là một bài toán tối ưu hóa bắt đầu và kết thúc tại một đỉnh xác định sau khi đã thăm mỗi đỉnh khác đúng một lần. Thường thì mô hình là một đồ thị hoàn chỉnh (tức là mỗi cặp đỉnh đều được nối với nhau bằng một cạnh). Nếu không có lối đi tồn tại giữa hai thành phố, việc thêm một cạnh tùy ý dài sẽ hoàn thành đồ thị mà không ảnh hưởng đến chuyến đi tối ưu.
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Travelling_salesman_problem)
diff --git a/src/algorithms/image-processing/seam-carving/README.en-EN.md b/src/algorithms/image-processing/seam-carving/README.en-EN.md
new file mode 100644
index 0000000000..e49222f739
--- /dev/null
+++ b/src/algorithms/image-processing/seam-carving/README.en-EN.md
@@ -0,0 +1,521 @@
+# Content-aware image resizing in JavaScript
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+![Content-aware image resizing in JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png)
+
+> There is an [interactive version of this post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) available where you can upload and resize your custom images.
+
+## TL;DR
+
+There are many great articles written about the _Seam Carving algorithm_ already, but I couldn't resist the temptation to explore this elegant, powerful, and _yet simple_ algorithm on my own, and to write about my personal experience with it. Another point that drew my attention (as a creator of [javascript-algorithms](https://github.com/trekhleb/javascript-algorithms) repo) was the fact that _Dynamic Programming (DP)_ approach might be smoothly applied to solve it. And, if you're like me and still on your "learning algorithms" journey, this algorithmic solution may enrich your personal DP arsenal.
+
+So, with this article I want to do three things:
+
+1. Provide you with an interactive **content-aware resizer** so that you could play around with resizing your own images
+2. Explain the idea behind the **Seam Carving algorithm**
+3. Explain the **dynamic programming approach** to implement the algorithm (we'll be using TypeScript for it)
+
+### Content-aware image resizing
+
+_Content-aware image resizing_ might be applied when it comes to changing the image proportions (i.e. reducing the width while keeping the height) and when losing some parts of the image is not desirable. Doing the straightforward image scaling in this case would distort the objects in it. To preserve the proportions of the objects while changing the image proportions we may use the [Seam Carving algorithm](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) that was introduced by _Shai Avidan_ and _Ariel Shamir_.
+
+The example below shows how the original image width was reduced by 50% using _content-aware resizing_ (left image) and _straightforward scaling_ (right image). In this particular case, the left image looks more natural since the proportions of the balloons were preserved.
+
+![Content-aware image resizing](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png)
+
+The Seam Carving algorithm's idea is to find the _seam_ (continuous sequence of pixels) with the lowest contribution to the image content and then _carve_ (remove) it. This process repeats over and over again until we get the required image width or height. In the example below you may see that the hot air balloon pixels contribute more to the content of the image than the sky pixels. Thus, the sky pixels are being removed first.
+
+![JS IMAGE CARVER DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-01.gif)
+
+Finding the seam with the lowest energy is a computationally expensive task (especially for large images). To make the seam search faster the _dynamic programming_ approach might be applied (we will go through the implementation details below).
+
+### Objects removal
+
+The importance of each pixel (so-called pixel's energy) is being calculated based on its color (`R`, `G`, `B`, `A`) difference between two neighbor pixels. Now, if we set the pixel energy to some really low level artificially (i.e. by drawing a mask on top of them), the Seam Carving algorithm would perform an **object removal** for us for free.
+
+![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
+
+### JS IMAGE CARVER demo
+
+I've created the [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) web-app (and also [open-sourced it on GitHub](https://github.com/trekhleb/js-image-carver)) that you may use to play around with resizing of your custom images.
+
+### More examples
+
+Here are some more examples of how the algorithm copes with more complex backgrounds.
+
+Mountains on the background are being shrunk smoothly without visible seams.
+
+![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png)
+
+The same goes for the ocean waves. The algorithm preserved the wave structure without distorting the surfers.
+
+![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png)
+
+We need to keep in mind that the Seam Carving algorithm is not a silver bullet, and it may fail to resize the images where _most of the pixels are edges_ (look important to the algorithm). In this case, it starts distorting even the important parts of the image. In the example below the content-aware image resizing looks pretty similar to a straightforward scaling since for the algorithm all the pixels look important, and it is hard for it to distinguish Van Gogh's face from the background.
+
+![Example when the algorithm does not work as expected](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png)
+
+## How Seam Carving algorithms works
+
+Imagine we have a `1000 x 500 px` picture, and we want to change its size to `500 x 500 px` to make it square (let's say the square ratio would better fit the Instagram feed). We might want to set up several **requirements to the resizing process** in this case:
+
+- _Preserve the important parts of the image_ (i.e. if there were 5 trees before the resizing we want to have 5 trees after resizing as well).
+- _Preserve the proportions_ of the important parts of the image (i.e. circle car wheels should not be squeezed to the ellipse wheels)
+
+To avoid changing the important parts of the image we may find the **continuous sequence of pixels (the seam)**, that goes from top to bottom and has _the lowest contribution to the content_ of the image (avoids important parts) and then remove it. The seam removal will shrink the image by 1 pixel. We will then repeat this step until the image will get the desired width.
+
+The question is how to define _the importance of the pixel_ and its contribution to the content (in the original paper the authors are using the term **energy of the pixel**). One of the ways to do it is to treat all the pixels that form the edges as important ones. In case if a pixel is a part of the edge its color would have a greater difference between the neighbors (left and right pixels) than the pixel that isn't a part of the edge.
+
+![Pixels color difference](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png)
+
+Assuming that the color of a pixel is represented by _4_ numbers (`R` - red, `G` - green, `B` - blue, `A` - alpha) we may use the following formula to calculate the color difference (the pixel energy):
+
+![Pixel energy formula](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png)
+
+Where:
+
+- `mEnergy` - _Energy_ (importance) of the _middle_ pixel (`[0..626]` if rounded)
+- `lR` - _Red_ channel value for the _left_ pixel (`[0..255]`)
+- `mR` - _Red_ channel value for the _middle_ pixel (`[0..255]`)
+- `rR` - _Red_ channel value for the _right_ pixel (`[0..255]`)
+- `lG` - _Green_ channel value for the _left_ pixel (`[0..255]`)
+- and so on...
+
+In the formula above we're omitting the alpha (transparency) channel, for now, assuming that there are no transparent pixels in the image. Later we will use the alpha channel for masking and for object removal.
+
+![Example of pixel energy calculation](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png)
+
+Now, since we know how to find the energy of one pixel, we can calculate, so-called, **energy map** which will contain the energies of each pixel of the image. On each resizing step the energy map should be re-calculated (at least partially, more about it below) and would have the same size as the image.
+
+For example, on the 1st resizing step we will have a `1000 x 500` image and a `1000 x 500` energy map. On the 2nd resizing step we will remove the seam from the image and re-calculate the energy map based on the new shrunk image. Thus, we will get a `999 x 500` image and a `999 x 500` energy map.
+
+The higher the energy of the pixel the more likely it is a part of an edge, and it is important for the image content and the less likely that we need to remove it.
+
+To visualize the energy map we may assign a brighter color to the pixels with the higher energy and darker colors to the pixels with the lower energy. Here is an artificial example of how the random part of the energy map might look like. You may see the bright line which represents the edge and which we want to preserve during the resizing.
+
+![Energy map sketch](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png)
+
+Here is a real example of the energy map for the demo image you saw above (with hot air balloons).
+
+![Energy map example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png)
+
+You may play around with your custom images and see how the energy map would look like in the [interactive version of the post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/).
+
+We may use the energy map to find the seams (one after another) with the lowest energy and by doing this to decide which pixels should be ultimately deleted.
+
+![Searching the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png)
+
+Finding the seam with the lowest energy is not a trivial task and requires exploring many possible pixel combinations before making the decision. We will apply the dynamic programming approach to speed it up.
+
+In the example below, you may see the energy map with the first lowest energy seam that was found for it.
+
+![Energy map example with seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png)
+
+In the examples above we were reducing the width of the image. A similar approach may be taken to reduce the image height. We need to "rotate" the approach though:
+
+- start using _top_ and _bottom_ pixel neighbors (instead of _left_ and _right_ ones) to calculate the pixel energy
+- when searching for a seam we need to move from _left_ to _right_ (instead of from _up_ to _bottom_)
+
+## Implementation in TypeScript
+
+> You may find the source code, and the functions mentioned below in the [js-image-carver](https://github.com/trekhleb/js-image-carver) repository.
+
+To implement the algorithm we will be using TypeScript. If you want a JavaScript version, you may ignore (remove) type definitions and their usages.
+
+For simplicity reasons let's implement the seam carving algorithm only for the image _width_ reduction.
+
+### Content-aware width resizing (the entry function)
+
+First, let's define some common types that we're going to use while implementing the algorithm.
+
+```typescript
+// Type that describes the image size (width and height).
+type ImageSize = { w: number; h: number };
+
+// The coordinate of the pixel.
+type Coordinate = { x: number; y: number };
+
+// The seam is a sequence of pixels (coordinates).
+type Seam = Coordinate[];
+
+// Energy map is a 2D array that has the same width and height
+// as the image the map is being calculated for.
+type EnergyMap = number[][];
+
+// Type that describes the image pixel's RGBA color.
+type Color =
+  | [
+      r: number, // Red
+      g: number, // Green
+      b: number, // Blue
+      a: number // Alpha (transparency)
+    ]
+  | Uint8ClampedArray;
+```
+
+On the high level the algorithm consists of the following steps:
+
+1. Calculate the **energy map** for the current version of the image.
+2. Find the **seam** with the lowest energy based on the energy map (this is where we will apply Dynamic Programming).
+3. **Delete the seam** with the lowest energy seam from the image.
+4. **Repeat** until the image width is reduced to the desired value.
+
+```typescript
+type ResizeImageWidthArgs = {
+  img: ImageData; // Image data we want to resize.
+  toWidth: number; // Final image width we want the image to shrink to.
+};
+
+type ResizeImageWidthResult = {
+  img: ImageData; // Resized image data.
+  size: ImageSize; // Resized image size (w x h).
+};
+
+// Performs the content-aware image width resizing using the seam carving method.
+export const resizeImageWidth = ({
+  img,
+  toWidth,
+}: ResizeImageWidthArgs): ResizeImageWidthResult => {
+  // For performance reasons we want to avoid changing the img data array size.
+  // Instead we'll just keep the record of the resized image width and height separately.
+  const size: ImageSize = { w: img.width, h: img.height };
+
+  // Calculating the number of pixels to remove.
+  const pxToRemove = img.width - toWidth;
+  if (pxToRemove < 0) {
+    throw new Error('Upsizing is not supported for now');
+  }
+
+  let energyMap: EnergyMap | null = null;
+  let seam: Seam | null = null;
+
+  // Removing the lowest energy seams one by one.
+  for (let i = 0; i < pxToRemove; i += 1) {
+    // 1. Calculate the energy map for the current version of the image.
+    energyMap = calculateEnergyMap(img, size);
+
+    // 2. Find the seam with the lowest energy based on the energy map.
+    seam = findLowEnergySeam(energyMap, size);
+
+    // 3. Delete the seam with the lowest energy seam from the image.
+    deleteSeam(img, seam, size);
+
+    // Reduce the image width, and continue iterations.
+    size.w -= 1;
+  }
+
+  // Returning the resized image and its final size.
+  // The img is actually a reference to the ImageData, so technically
+  // the caller of the function already has this pointer. But let's
+  // still return it for better code readability.
+  return { img, size };
+};
+```
+
+The image that needs to be resized is being passed to the function in [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. You may draw the image on the canvas and then extract the ImageData from the canvas like this:
+
+```javascript
+const ctx = canvas.getContext('2d');
+const imgData = ctx.getImageData(0, 0, imgWidth, imgHeight);
+```
+
+> The way of uploading and drawing images in JavaScript is out of scope for this article, but you may find the complete source code of how it may be done using React in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo.
+
+Let's break down each step ony be one and implement the `calculateEnergyMap()`, `findLowEnergySeam()` and `deleteSeam()` functions.
+
+### Calculating the pixel's energy
+
+Here we apply the color difference formula described above. For the left and right borders (when there are no left or right neighbors), we ignore the neighbors and don't take them into account during the energy calculation.
+
+```typescript
+// Calculates the energy of a pixel.
+const getPixelEnergy = (
+  left: Color | null,
+  middle: Color,
+  right: Color | null
+): number => {
+  // Middle pixel is the pixel we're calculating the energy for.
+  const [mR, mG, mB] = middle;
+
+  // Energy from the left pixel (if it exists).
+  let lEnergy = 0;
+  if (left) {
+    const [lR, lG, lB] = left;
+    lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;
+  }
+
+  // Energy from the right pixel (if it exists).
+  let rEnergy = 0;
+  if (right) {
+    const [rR, rG, rB] = right;
+    rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;
+  }
+
+  // Resulting pixel energy.
+  return Math.sqrt(lEnergy + rEnergy);
+};
+```
+
+### Calculating the energy map
+
+The image we're working with has the [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. It means that all the pixels (and their colors) are stored in a flat (_1D_) [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) array. For readability purposes let's introduce the couple of helper functions that will allow us to work with the Uint8ClampedArray array as with a _2D_ matrix instead.
+
+```typescript
+// Helper function that returns the color of the pixel.
+const getPixel = (img: ImageData, { x, y }: Coordinate): Color => {
+  // The ImageData data array is a flat 1D array.
+  // Thus we need to convert x and y coordinates to the linear index.
+  const i = y * img.width + x;
+  const cellsPerColor = 4; // RGBA
+  // For better efficiency, instead of creating a new sub-array we return
+  // a pointer to the part of the ImageData array.
+  return img.data.subarray(
+    i * cellsPerColor,
+    i * cellsPerColor + cellsPerColor
+  );
+};
+
+// Helper function that sets the color of the pixel.
+const setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => {
+  // The ImageData data array is a flat 1D array.
+  // Thus we need to convert x and y coordinates to the linear index.
+  const i = y * img.width + x;
+  const cellsPerColor = 4; // RGBA
+  img.data.set(color, i * cellsPerColor);
+};
+```
+
+To calculate the energy map we go through each image pixel and call the previously described `getPixelEnergy()` function against it.
+
+```typescript
+// Helper function that creates a matrix (2D array) of specific
+// size (w x h) and fills it with specified value.
+const matrix = <T>(w: number, h: number, filler: T): T[][] => {
+  return new Array(h).fill(null).map(() => {
+    return new Array(w).fill(filler);
+  });
+};
+
+// Calculates the energy of each pixel of the image.
+const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {
+  // Create an empty energy map where each pixel has infinitely high energy.
+  // We will update the energy of each pixel.
+  const energyMap: number[][] = matrix<number>(w, h, Infinity);
+  for (let y = 0; y < h; y += 1) {
+    for (let x = 0; x < w; x += 1) {
+      // Left pixel might not exist if we're on the very left edge of the image.
+      const left = x - 1 >= 0 ? getPixel(img, { x: x - 1, y }) : null;
+      // The color of the middle pixel that we're calculating the energy for.
+      const middle = getPixel(img, { x, y });
+      // Right pixel might not exist if we're on the very right edge of the image.
+      const right = x + 1 < w ? getPixel(img, { x: x + 1, y }) : null;
+      energyMap[y][x] = getPixelEnergy(left, middle, right);
+    }
+  }
+  return energyMap;
+};
+```
+
+> The energy map is going to be recalculated on every resize iteration. It means that it will be recalculated, let's say, 500 times if we need to shrink the image by 500 pixels which is not optimal. To speed up the energy map calculation on the 2nd, 3rd, and further steps, we may re-calculate the energy only for those pixels that are placed around the seam that is going to be removed. For simplicity reasons this optimization is omitted here, but you may find the example source-code in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo.
+
+### Finding the seam with the lowest energy (Dynamic Programming approach)
+
+> I've described some Dynamic Programming basics in [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) article before. There is a DP example based on the minimum edit distance problem. You might want to check it out to get some more context.
+
+The issue we need to solve now is to find the path (the seam) on the energy map that goes from top to bottom and has the minimum sum of pixel energies.
+
+#### The naive approach
+
+The naive approach would be to check all possible paths one after another.
+
+![The naive approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png)
+
+Going from top to bottom, for each pixel, we have 3 options (↙︎ go down-left, ↓ go down, ↘︎ go down-right). This gives us the time complexity of `O(w * 3^h)` or simply `O(3^h)`, where `w` and `h` are the width and the height of the image. This approach looks slow.
+
+#### The greedy approach
+
+We may also try to choose the next pixel as a pixel with the lowest energy, hoping that the resulting seam energy will be the smallest one.
+
+![The greedy approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png)
+
+This approach gives not the worst solution, but it cannot guarantee that we will find the best available solution. On the image above you may see how the greedy approach chose `5` instead of `10` at first and missed the chain of optimal pixels.
+
+The good part about this approach is that it is fast, and it has a time complexity of `O(w + h)`, where `w` and `h` are the width and the height of the image. In this case, the cost of the speed is the low quality of resizing. We need to find a minimum value in the first row (traversing `w` cells) and then we explore only 3 neighbor pixels for each row (traversing `h` rows).
+
+#### The dynamic programming approach
+
+You might have noticed that in the naive approach we summed up the same pixel energies over and over again while calculating the resulting seams' energy.
+
+![Repeated problems](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png)
+
+In the example above you see that for the first two seams we are re-using the energy of the shorter seam (which has the energy of `235`). Instead of doing just one operation `235 + 70` to calculate the energy of the 2nd seam we're doing four operations `(5 + 0 + 80 + 150) + 70`.
+
+> This fact that we're re-using the energy of the previous seam to calculate the current seam's energy might be applied recursively to all the shorter seams up to the very top 1st row seam. When we have such overlapping sub-problems, [it is a sign](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) that the general problem _might_ be optimized by dynamic programming approach.
+
+So, we may **save the energy of the current seam** at the particular pixel in an additional `seamsEnergies` table to make it re-usable for calculating the next seams faster (the `seamsEnergies` table will have the same size as the energy map and the image itself).
+
+Let's also keep in mind that for one particular pixel on the image (i.e. the bottom left one) we may have _several_ values of the previous seams energies.
+
+![What seam to choose](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png)
+
+Since we're looking for a seam with the lowest resulting energy it would make sense to pick the previous seam with the lowest resulting energy as well.
+
+![Seams energies example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png)
+
+In general, we have three possible previous seems to choose from:
+
+![Three options to choose from](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png)
+
+You may think about it this way:
+
+- The cell `[1][x]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[1][x]`
+- **The current cell** `[2][3]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[2][3]`. To calculate it we need to sum up the energy of the current pixel `[2][3]` (from the energy map) with the `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`
+
+If we fill the `seamsEnergies` table completely, then the minimum number in the lowest row would be the lowest possible seam energy.
+
+Let's try to fill several cells of this table to see how it works.
+
+![Seams energies map traversal](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png)
+
+After filling out the `seamsEnergies` table we may see that the lowest energy pixel has an energy of `50`. For convenience, during the `seamsEnergies` generation for each pixel, we may save not only the energy of the seam but also the coordinates of the previous lowest energy seam. This will give us the possibility to reconstruct the seam path from the bottom to the top easily.
+
+The time complexity of DP approach would be `O(w * h)`, where `w` and `h` are the width and the height of the image. We need to calculate energies for _every_ pixel of the image.
+
+Here is an example of how this logic might be implemented:
+
+```typescript
+// The metadata for the pixels in the seam.
+type SeamPixelMeta = {
+  energy: number; // The energy of the pixel.
+  coordinate: Coordinate; // The coordinate of the pixel.
+  previous: Coordinate | null; // The previous pixel in a seam.
+};
+
+// Finds the seam (the sequence of pixels from top to bottom) that has the
+// lowest resulting energy using the Dynamic Programming approach.
+const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
+  // The 2D array of the size of w and h, where each pixel contains the
+  // seam metadata (pixel energy, pixel coordinate and previous pixel from
+  // the lowest energy seam at this point).
+  const seamsEnergies: (SeamPixelMeta | null)[][] =
+    matrix<SeamPixelMeta | null>(w, h, null);
+
+  // Populate the first row of the map by just copying the energies
+  // from the energy map.
+  for (let x = 0; x < w; x += 1) {
+    const y = 0;
+    seamsEnergies[y][x] = {
+      energy: energyMap[y][x],
+      coordinate: { x, y },
+      previous: null,
+    };
+  }
+
+  // Populate the rest of the rows.
+  for (let y = 1; y < h; y += 1) {
+    for (let x = 0; x < w; x += 1) {
+      // Find the top adjacent cell with minimum energy.
+      // This cell would be the tail of a seam with lowest energy at this point.
+      // It doesn't mean that this seam (path) has lowest energy globally.
+      // Instead, it means that we found a path with the lowest energy that may lead
+      // us to the current pixel with the coordinates x and y.
+      let minPrevEnergy = Infinity;
+      let minPrevX: number = x;
+      for (let i = x - 1; i <= x + 1; i += 1) {
+        if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) {
+          minPrevEnergy = seamsEnergies[y - 1][i].energy;
+          minPrevX = i;
+        }
+      }
+
+      // Update the current cell.
+      seamsEnergies[y][x] = {
+        energy: minPrevEnergy + energyMap[y][x],
+        coordinate: { x, y },
+        previous: { x: minPrevX, y: y - 1 },
+      };
+    }
+  }
+
+  // Find where the minimum energy seam ends.
+  // We need to find the tail of the lowest energy seam to start
+  // traversing it from its tail to its head (from the bottom to the top).
+  let lastMinCoordinate: Coordinate | null = null;
+  let minSeamEnergy = Infinity;
+  for (let x = 0; x < w; x += 1) {
+    const y = h - 1;
+    if (seamsEnergies[y][x].energy < minSeamEnergy) {
+      minSeamEnergy = seamsEnergies[y][x].energy;
+      lastMinCoordinate = { x, y };
+    }
+  }
+
+  // Find the lowest energy energy seam.
+  // Once we know where the tail is we may traverse and assemble the lowest
+  // energy seam based on the "previous" value of the seam pixel metadata.
+  const seam: Seam = [];
+  if (!lastMinCoordinate) {
+    return seam;
+  }
+
+  const { x: lastMinX, y: lastMinY } = lastMinCoordinate;
+
+  // Adding new pixel to the seam path one by one until we reach the top.
+  let currentSeam = seamsEnergies[lastMinY][lastMinX];
+  while (currentSeam) {
+    seam.push(currentSeam.coordinate);
+    const prevMinCoordinates = currentSeam.previous;
+    if (!prevMinCoordinates) {
+      currentSeam = null;
+    } else {
+      const { x: prevMinX, y: prevMinY } = prevMinCoordinates;
+      currentSeam = seamsEnergies[prevMinY][prevMinX];
+    }
+  }
+
+  return seam;
+};
+```
+
+### Removing the seam with the lowest energy
+
+Once we found the lowest energy seam, we need to remove (to carve) the pixels that form it from the image. The removal is happening by shifting the pixels to the right of the seam by `1px` to the left. For performance reasons, we don't actually delete the last columns. Instead, the rendering component will just ignore the part of the image that lays beyond the resized image width.
+
+![Deleting the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png)
+
+```typescript
+// Deletes the seam from the image data.
+// We delete the pixel in each row and then shift the rest of the row pixels to the left.
+const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {
+  seam.forEach(({ x: seamX, y: seamY }: Coordinate) => {
+    for (let x = seamX; x < w - 1; x += 1) {
+      const nextPixel = getPixel(img, { x: x + 1, y: seamY });
+      setPixel(img, { x, y: seamY }, nextPixel);
+    }
+  });
+};
+```
+
+## Objects removal
+
+The Seam Carving algorithm tries to remove the seams which consist of low energy pixels first. We could leverage this fact and by assigning low energy to some pixels manually (i.e. by drawing on the image and masking out some areas of it) we could make the Seam Carving algorithm to do _objects removal_ for us for free.
+
+Currently, in `getPixelEnergy()` function we were using only the `R`, `G`, `B` color channels to calculate the pixel's energy. But there is also the `A` (alpha, transparency) parameter of the color that we didn't use yet. We may use the transparency channel to tell the algorithm that transparent pixels are the pixels we want to remove. You may check the [source-code of the energy function](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54) that takes transparency into account.
+
+Here is how the algorithm works for object removal.
+
+![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
+
+## Issues and what's next
+
+The [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) web app is far from being a production ready resizer of course. Its main purpose was to experiment with the Seam Carving algorithm interactively. So the plan for the future is to continue experimentation.
+
+The [original paper](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) describes how the Seam Carving algorithm might be used not only for the downscaling but also for the **upscaling of the images**. The upscaling, in turn, might be used to **upscale the image back to its original width after the objects' removal**.
+
+Another interesting area of experimentation might be to make the algorithm work in a **real-time**.
+
+> Those are the plans for the future, but for now, I hope that the example with image downsizing was interesting and useful for you. I also hope that you've got the idea of using dynamic programming to implement it.
+>
+> So, good luck with your own experiments!
diff --git a/src/algorithms/image-processing/seam-carving/README.md b/src/algorithms/image-processing/seam-carving/README.md
index 87004f7abe..18a9f11388 100644
--- a/src/algorithms/image-processing/seam-carving/README.md
+++ b/src/algorithms/image-processing/seam-carving/README.md
@@ -1,305 +1,320 @@
-# Content-aware image resizing in JavaScript
+# Thay Đổi Kích Thước Hình Ảnh Có Ý Thức Về Nội Dung Trong JavaScript
 
-![Content-aware image resizing in JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png)
+_Xem bằng các ngôn ngữ khác:_
+[_Tiếng Anh_](README.en.md)
 
-> There is an [interactive version of this post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) available where you can upload and resize your custom images.
+![Thay Đổi Kích Thước Hình Ảnh Có Ý Thức Về Nội Dung Trong JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png)
 
-## TL;DR
+> Có một [phiên bản tương tác của bài viết này](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) nơi bạn có thể tải lên và thay đổi kích thước hình ảnh tùy chỉnh của mình.
 
-There are many great articles written about the *Seam Carving algorithm* already, but I couldn't resist the temptation to explore this elegant, powerful, and *yet simple* algorithm on my own, and to write about my personal experience with it. Another point that drew my attention (as a creator of [javascript-algorithms](https://github.com/trekhleb/javascript-algorithms) repo) was the fact that *Dynamic Programming (DP)* approach might be smoothly applied to solve it. And, if you're like me and still on your "learning algorithms" journey, this algorithmic solution may enrich your personal DP arsenal.
+## Tóm Tắt
 
-So, with this article I want to do three things:
+Đã có nhiều bài viết tuyệt vời viết về _Thuật toán Carving Seam_, nhưng tôi không thể kiềm chế được sự hứng thú để khám phá thuật toán thanh lịch, mạnh mẽ và _vẫn đơn giản_ này một cách riêng của mình, và viết về kinh nghiệm cá nhân của tôi với nó. Một điểm khác thu hút sự chú ý của tôi (như một người tạo ra [javascript-algorithms](https://github.com/trekhleb/javascript-algorithms)) là sự thật rằng phương pháp _Lập trình Động (DP)_ có thể được áp dụng một cách mượt mà để giải quyết nó. Và, nếu bạn giống như tôi và vẫn đang trên hành trình "học thuật toán" của mình, giải pháp thuật toán này có thể làm phong phú thêm bộ công cụ DP cá nhân của bạn.
 
-1. Provide you with an interactive **content-aware resizer** so that you could play around with resizing your own images
-2. Explain the idea behind the **Seam Carving algorithm**
-3. Explain the **dynamic programming approach** to implement the algorithm (we'll be using TypeScript for it)
+Vì vậy, với bài viết này tôi muốn làm ba điều:
 
-### Content-aware image resizing
+1. Cung cấp cho bạn một **công cụ thay đổi kích thước có ý thức về nội dung** tương tác để bạn có thể chơi với việc thay đổi kích thước hình ảnh của riêng bạn
+2. Giải thích ý tưởng đằng sau **Thuật toán Carving Seam**
+3. Giải thích phương pháp **lập trình động** để thực hiện thuật toán (chúng tôi sẽ sử dụng TypeScript cho nó)
 
-*Content-aware image resizing* might be applied when it comes to changing the image proportions (i.e. reducing the width while keeping the height) and when losing some parts of the image is not desirable. Doing the straightforward image scaling in this case would distort the objects in it. To preserve the proportions of the objects while changing the image proportions we may use the [Seam Carving algorithm](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) that was introduced by *Shai Avidan* and *Ariel Shamir*.
+### Thay Đổi Kích Thước Hình Ảnh Có Ý Thức Về Nội Dung
 
-The example below shows how the original image width was reduced by 50% using *content-aware resizing* (left image) and *straightforward scaling* (right image). In this particular case, the left image looks more natural since the proportions of the balloons were preserved.
+_Thay đổi kích thước hình ảnh có ý thức về nội dung_ có thể được áp dụng khi cần thay đổi tỷ lệ hình ảnh (tức là giảm chiều rộng trong khi giữ chiều cao) và khi việc mất một số phần của hình ảnh không mong muốn. Thực hiện việc co giãn hình ảnh một cách trực tiếp trong trường hợp này sẽ làm méo mó các đối tượng trong đó. Để bảo tồn tỷ lệ của các đối tượng trong khi thay đổi tỷ lệ hình ảnh, chúng ta có thể sử dụng [Thuật toán Carving Seam](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) được giới thiệu bởi _Shai Avidan_ và _Ariel Shamir_.
 
-![Content-aware image resizing](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png)
+Ví dụ dưới đây cho thấy cách chiều rộng hình ảnh gốc đã giảm đi 50% bằng cách sử dụng _thay đổi kích thước có ý thức về nội dung_ (hình ảnh bên trái) và _co giãn trực tiếp_ (hình ảnh bên phải). Trong trường hợp cụ thể này, hình ảnh bên trái trông tự nhiên hơn vì tỷ lệ của các quả bóng bay đã được bảo tồn.
 
-The Seam Carving algorithm's idea is to find the *seam* (continuous sequence of pixels) with the lowest contribution to the image content and then *carve* (remove) it. This process repeats over and over again until we get the required image width or height. In the example below you may see that the hot air balloon pixels contribute more to the content of the image than the sky pixels. Thus, the sky pixels are being removed first.
+![Thay Đổi Kích Thước Hình Ảnh Có Ý Thức Về Nội Dung](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png)
+
+Ý tưởng của thuật toán Carving Seam là tìm ra _đường cắt_ (chuỗi liên tục các điểm ảnh) có đóng góp thấp nhất vào nội dung hình ảnh và sau đó _chạm_ (xóa) nó đi. Quá trình này lặp lại điều này cho đến khi chúng ta có được chiều rộng hoặc chiều cao hình ảnh yêu cầu. Trong ví dụ dưới đây, bạn có thể thấy rằng các điểm ảnh của quả bóng bay nóng hơn nhiều so với các điểm ảnh của bầu trời. Do đó, các điểm ảnh của bầu trời được loại bỏ trước.
 
 ![JS IMAGE CARVER DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-01.gif)
 
-Finding the seam with the lowest energy is a computationally expensive task (especially for large images). To make the seam search faster the *dynamic programming* approach might be applied (we will go through the implementation details below).
+Tìm ra đường cắt có năng lượng thấp nhất là một nhiệm vụ tốn công suất tính toán (đặc biệt là đối với các hình ảnh lớn). Để làm cho việc tìm kiếm đường cắt nhanh hơn, phương pháp _lập trình động_ có thể được áp dụng (chúng tôi sẽ đi qua chi tiết triển khai bên dưới).
 
-### Objects removal
+### Loại Bỏ Đối Tượng
 
-The importance of each pixel (so-called pixel's energy) is being calculated based on its color (`R`, `G`, `B`, `A`) difference between two neighbor pixels. Now, if we set the pixel energy to some really low level artificially (i.e. by drawing a mask on top of them), the Seam Carving algorithm would perform an **object removal** for us for free.
+Mức quan trọng của mỗi điểm ảnh (còn được gọi là năng lượng của điểm ảnh) được tính dựa trên sự khác biệt về màu sắc (`R`, `G`, `B`, `A`) giữa hai điểm ảnh kề nhau. Bây giờ, nếu chúng ta đặt năng lượng của điểm ảnh ở mức thấp thật sự (tức là bằng cách vẽ một mặt nạ lên đỉnh của chúng), thuật toán Carving Seam sẽ thực hiện việc **loại bỏ đối tượng** cho chúng ta một cách miễn phí.
 
 ![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
 
-### JS IMAGE CARVER demo
+### Demo JS IMAGE CARVER
+
+Tôi đã tạo ra ứng dụng web [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) (và cũng [được công bố mở trên GitHub](https://github.com/trekhleb/js-image-carver)) mà bạn có thể sử dụng để chơi với việc thay đổi kích thước của hình ảnh tùy chỉnh của bạn.
 
-I've created the [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) web-app (and also [open-sourced it on GitHub](https://github.com/trekhleb/js-image-carver)) that you may use to play around with resizing of your custom images.
+### Thêm ví dụ
 
-### More examples
+Dưới đây là một số ví dụ khác về cách thuật toán xử lý với các nền phức tạp hơn.
 
-Here are some more examples of how the algorithm copes with more complex backgrounds.
+Núi trên nền đẹp được thu nhỏ mà không có đường cắt rõ ràng.
 
-Mountains on the background are being shrunk smoothly without visible seams.
+![Demo thay đổi kích thước với nền phức tạp hơn](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png)
 
-![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png)
+Tương tự, với sóng biển. Thuật toán bảo tồn cấu trúc sóng mà không làm méo mó các vận động viên lướt sóng.
 
-The same goes for the ocean waves. The algorithm preserved the wave structure without distorting the surfers.
+![Demo thay đổi kích thước với nền phức tạp hơn](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png)
 
-![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png)
+Chúng ta cần nhớ rằng thuật toán Carving Seam không phải là một giải pháp toàn diện, và nó có thể không hoạt động cho việc thay đổi kích thước hình ảnh nơi _hầu hết các điểm ảnh là cạnh_ (trông quan trọng với thuật toán). Trong trường hợp này, nó bắt đầu làm méo mó cả các phần quan trọng của hình ảnh. Trong ví dụ dưới đây, việc thay đổi kích thước hình ảnh có ý thức về nội dung trông khá giống với một việc co giãn trực tiếp vì đối với thuật toán, tất cả các điểm ảnh đều trông quan trọng, và nó khó phân biệt được khuôn mặt của Van Gogh với nền.
 
-We need to keep in mind that the Seam Carving algorithm is not a silver bullet, and it may fail to resize the images where *most of the pixels are edges* (look important to the algorithm). In this case, it starts distorting even the important parts of the image. In the example below the content-aware image resizing looks pretty similar to a straightforward scaling since for the algorithm all the pixels look important, and it is hard for it to distinguish Van Gogh's face from the background.
+![Ví dụ khi thuật toán không hoạt động như mong đợi](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png)
 
-![Example when the algorithm does not work as expected](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png)
+## Cách Thức Hoạt Động của Thuật Toán Carving Seam
 
-## How Seam Carving algorithms works
+Hãy tưởng tượng chúng ta có một bức ảnh kích thước `1000 x 500 px`, và chúng ta muốn thay đổi kích thước của nó thành `500 x 500 px` để biến nó thành hình vuông (hãy nói tỷ lệ hình vuông sẽ phù hợp hơn với dòng thời gian Instagram). Trong trường hợp này, chúng ta có thể muốn đặt một số **yêu cầu cho quá trình thay đổi kích thước** như sau:
 
-Imagine we have a `1000 x 500 px` picture, and we want to change its size to `500 x 500 px` to make it square (let's say the square ratio would better fit the Instagram feed). We might want to set up several **requirements to the resizing process** in this case:
+- _Bảo tồn các phần quan trọng của hình ảnh_ (tức là nếu trước khi thay đổi kích thước có 5 cái cây thì chúng ta muốn có 5 cái cây sau khi thay đổi kích thước).
+- _Bảo tồn tỷ lệ_ của các phần quan trọng của hình ảnh (tức là bánh xe xe hơi hình tròn không nên bị ép vào hình bánh xe hình ellipse)
 
-- *Preserve the important parts of the image* (i.e. if there were 5 trees before the resizing we want to have 5 trees after resizing as well).
-- *Preserve the proportions* of the important parts of the image (i.e. circle car wheels should not be squeezed to the ellipse wheels)
+Để tránh thay đổi các phần quan trọng của hình ảnh, chúng ta có thể tìm ra **chuỗi liên tục các điểm ảnh (đường cắt)**, đi từ trên xuống và có _đóng góp thấp nhất vào nội dung_ của hình ảnh (tránh các phần quan trọng) và sau đó loại bỏ nó. Việc loại bỏ đường cắt sẽ làm giảm kích thước của hình ảnh đi 1 điểm ảnh. Chúng ta sau đó lặp lại bước này cho đến khi hình ảnh có được chiều rộng mong muốn.
 
-To avoid changing the important parts of the image we may find the **continuous sequence of pixels (the seam)**, that goes from top to bottom and has *the lowest contribution to the content* of the image (avoids important parts) and then remove it. The seam removal will shrink the image by 1 pixel. We will then repeat this step until the image will get the desired width.
+Câu hỏi là làm thế nào để xác định _sự quan trọng của điểm ảnh_ và đóng góp của nó vào nội dung (trong bài báo gốc, các tác giả sử dụng thuật ngữ **năng lượng của điểm ảnh**). Một trong những cách để làm điều này là coi tất cả các điểm ảnh tạo thành các cạnh là quan trọng. Trong trường hợp một điểm ảnh là một phần của cạnh, màu của nó sẽ có sự khác biệt lớn hơn giữa các điểm ảnh láng giềng (trái và phải) so với điểm ảnh không phải là một phần của cạnh.
 
-The question is how to define *the importance of the pixel* and its contribution to the content (in the original paper the authors are using the term **energy of the pixel**). One of the ways to do it is to treat all the pixels that form the edges as important ones. In case if a pixel is a part of the edge its color would have a greater difference between the neighbors (left and right pixels) than the pixel that isn't a part of the edge.
+![Sự khác biệt màu của các điểm ảnh](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png)
 
-![Pixels color difference](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png)
+Giả sử rằng màu của một điểm ảnh được biểu diễn bởi _4_ số (`R` - đỏ, `G` - xanh lá cây, `B` - xanh lam, `A` - alpha), chúng ta có thể sử dụng công thức sau để tính sự khác biệt màu (năng lượng của điểm ảnh):
 
-Assuming that the color of a pixel is represented by *4* numbers (`R` - red, `G` - green, `B` - blue, `A` - alpha) we may use the following formula to calculate the color difference (the pixel energy):
+![Công thức năng lượng của điểm ảnh](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png)
 
-![Pixel energy formula](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png)
+Trong đó:
 
-Where:
+- `mEnergy` - _Năng lượng_ (quan trọng) của điểm ảnh _giữa_ (`[0..626]` nếu làm tròn)
+- `lR` - Giá trị kênh _đỏ_ cho điểm ảnh _trái_ (`[0..255]`)
+- `mR` - Giá trị kênh _đỏ_ cho điểm ảnh _giữa_ (`[0..255]`)
+- `rR` - Giá trị kênh _đỏ_ cho điểm ảnh _phải_ (`[0..255]`)
+- `lG` - Giá trị kênh _xanh lá cây_ cho điểm ảnh _trái_ (`[0..255]`)
+- và cetera...
 
-- `mEnergy` - *Energy* (importance) of the *middle* pixel (`[0..626]` if rounded)
-- `lR` - *Red* channel value for the *left* pixel (`[0..255]`)
-- `mR` - *Red* channel value for the *middle* pixel (`[0..255]`)
-- `rR` - *Red* channel value for the *right* pixel (`[0..255]`)
-- `lG` - *Green* channel value for the *left* pixel (`[0..255]`)
-- and so on...
+Trong công thức trên, chúng ta không xem xét kênh alpha (độ trong suốt) tạm thời, giả định rằng không có điểm ảnh trong suốt trong hình ảnh. Sau này, chúng ta sẽ sử dụng kênh alpha để tạo mặt nạ và để loại bỏ đối tượng.
 
-In the formula above we're omitting the alpha (transparency) channel, for now, assuming that there are no transparent pixels in the image. Later we will use the alpha channel for masking and for object removal.
+![Ví dụ về cách tính năng lượng của điểm ảnh](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png)
 
-![Example of pixel energy calculation](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png)
+Bây giờ, khi chúng ta biết cách tìm ra năng lượng của một điểm ảnh, chúng ta có thể tính toán, cái gọi là, **bản đồ năng lượng** mà sẽ chứa các năng lượng của mỗi điểm ảnh của hình ảnh. Trên mỗi bước thay đổi kích thước, bản đồ năng lượng nên được tính toán lại (ít nhất là một phần, chi tiết hơn về điều này ở dưới) và sẽ có kích thước giống như hình ảnh.
 
-Now, since we know how to find the energy of one pixel, we can calculate, so-called, **energy map** which will contain the energies of each pixel of the image. On each resizing step the energy map should be re-calculated (at least partially, more about it below) and would have the same size as the image.
+Ví dụ, trên bước thay đổi kích thước đầu tiên, chúng ta sẽ có một hình ảnh `1000 x 500` và
 
-For example, on the 1st resizing step we will have a `1000 x 500` image and a `1000 x 500` energy map. On the 2nd resizing step we will remove the seam from the image and re-calculate the energy map based on the new shrunk image. Thus, we will get a `999 x 500` image and a `999 x 500` energy map.
+một bản đồ năng lượng `1000 x 500`. Trên bước thay đổi kích thước thứ hai, chúng ta sẽ loại bỏ đường cắt từ hình ảnh và tính toán lại bản đồ năng lượng dựa trên hình ảnh đã bị co lại mới. Do đó, chúng ta sẽ có một hình ảnh `999 x 500` và một bản đồ năng lượng `999 x 500`.
 
-The higher the energy of the pixel the more likely it is a part of an edge, and it is important for the image content and the less likely that we need to remove it.
+Năng lượng càng cao của điểm ảnh thì khả năng cao hơn là nó là một phần của một cạnh, và nó quan trọng cho nội dung của hình ảnh và khả năng ít có khả năng rằng chúng ta cần phải loại bỏ nó.
 
-To visualize the energy map we may assign a brighter color to the pixels with the higher energy and darker colors to the pixels with the lower energy. Here is an artificial example of how the random part of the energy map might look like. You may see the bright line which represents the edge and which we want to preserve during the resizing.
+Để minh họa bản đồ năng lượng, chúng ta có thể gán một màu sáng hơn cho các điểm ảnh có năng lượng cao hơn và màu tối cho các điểm ảnh có năng lượng thấp hơn. Dưới đây là một ví dụ giả mạo về cách bản đồ năng lượng có thể trông như thế nào. Bạn có thể thấy đường sáng đại diện cho cạnh và mà chúng ta muốn bảo tồn trong quá trình thay đổi kích thước.
 
-![Energy map sketch](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png)
+![Phác thảo bản đồ năng lượng](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png)
 
-Here is a real example of the energy map for the demo image you saw above (with hot air balloons).
+Dưới đây là một ví dụ thực về bản đồ năng lượng cho hình ảnh demo bạn đã thấy ở trên (với các quả bóng bay nóng).
 
-![Energy map example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png)
+![Ví dụ về bản đồ năng lượng](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png)
 
-You may play around with your custom images and see how the energy map would look like in the [interactive version of the post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/).
+Bạn có thể chơi với các hình ảnh tùy chỉnh của mình và xem cách bản đồ năng lượng sẽ trông như thế nào trong [phiên bản tương tác của bài viết](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/).
 
-We may use the energy map to find the seams (one after another) with the lowest energy and by doing this to decide which pixels should be ultimately deleted.
+Chúng ta có thể sử dụng bản đồ năng lượng để tìm ra các đường cắt (một sau một) có năng lượng thấp nhất và bằng cách này để quyết định những điểm ảnh nào cuối cùng nên bị xóa đi.
 
-![Searching the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png)
+![Tìm kiếm đường cắt](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png)
 
-Finding the seam with the lowest energy is not a trivial task and requires exploring many possible pixel combinations before making the decision. We will apply the dynamic programming approach to speed it up.
+Tìm kiếm đường cắt có năng lượng thấp nhất không phải là một nhiệm vụ dễ dàng và đòi hỏi phải khám phá nhiều kết hợp điểm ảnh có thể trước khi đưa ra quyết định. Chúng ta sẽ áp dụng phương pháp lập trình động để tăng tốc độ cho quá trình này.
 
-In the example below, you may see the energy map with the first lowest energy seam that was found for it.
+Trong ví dụ dưới đây, bạn có thể thấy bản đồ năng lượng với đường cắt năng lượng thấp nhất đầu tiên đã được tìm thấy cho nó.
 
-![Energy map example with seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png)
+![Ví dụ về bản đồ năng lượng với đường cắt](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png)
 
-In the examples above we were reducing the width of the image. A similar approach may be taken to reduce the image height. We need to "rotate" the approach though:
+Trong các ví dụ trên, chúng ta đã giảm chiều rộng của hình ảnh. Một phương pháp tương tự có thể được sử dụng để giảm chiều cao của hình ảnh. Tuy nhiên, chúng ta cần "xoay" phương pháp:
 
-- start using *top* and *bottom* pixel neighbors (instead of *left* and *right* ones) to calculate the pixel energy
-- when searching for a seam we need to move from *left* to *right* (instead of from *up* to *bottom*)
+- bắt đầu sử dụng điểm ảnh láng giềng _trên_ và _dưới_ (thay vì các điểm ảnh _trái_ và _phải_) để tính năng lượng của điểm ảnh
+- khi tìm kiếm đường cắt, chúng ta cần di chuyển từ _trái_ sang _phải_ (thay vì từ _trên_ xuống _dưới_)
 
-## Implementation in TypeScript
+## Cài đặt trong TypeScript
 
-> You may find the source code, and the functions mentioned below in the [js-image-carver](https://github.com/trekhleb/js-image-carver) repository.
+> Bạn có thể tìm mã nguồn và các hàm được đề cập dưới đây trong kho lưu trữ [js-image-carver](https://github.com/trekhleb/js-image-carver).
 
-To implement the algorithm we will be using TypeScript. If you want a JavaScript version, you may ignore (remove) type definitions and their usages.
+Để triển khai thuật toán, chúng tôi sẽ sử dụng TypeScript. Nếu bạn muốn một phiên bản JavaScript, bạn có thể bỏ qua (xóa) các định nghĩa loại và việc sử dụng chúng.
 
-For simplicity reasons let's implement the seam carving algorithm only for the image *width* reduction.
+Vì lý do đơn giản, hãy triển khai thuật toán chỉ cho việc giảm _chiều rộng_ của hình ảnh.
 
-### Content-aware width resizing (the entry function)
+### Thay đổi kích thước chiều rộng dựa trên nội dung (hàm nhập)
 
-First, let's define some common types that we're going to use while implementing the algorithm.
+Đầu tiên, hãy xác định một số loại thông thường mà chúng ta sẽ sử dụng trong quá trình triển khai thuật toán.
 
 ```typescript
-// Type that describes the image size (width and height).
-type ImageSize = { w: number, h: number };
+// Loại mô tả kích thước hình ảnh (chiều rộng và chiều cao).
+type ImageSize = { w: number; h: number };
 
-// The coordinate of the pixel.
-type Coordinate = { x: number, y: number };
+// Tọa độ của điểm ảnh.
+type Coordinate = { x: number; y: number };
 
-// The seam is a sequence of pixels (coordinates).
+// Đường cắt là một chuỗi liên tục của điểm ảnh (tọa độ).
 type Seam = Coordinate[];
 
-// Energy map is a 2D array that has the same width and height
-// as the image the map is being calculated for.
+// Bản đồ năng lượng là một mảng 2D có cùng chiều rộng và chiều cao
+// như hình ảnh mà bản đồ này đang được tính toán cho.
 type EnergyMap = number[][];
 
-// Type that describes the image pixel's RGBA color.
-type Color = [
-  r: number, // Red
-  g: number, // Green
-  b: number, // Blue
-  a: number, // Alpha (transparency)
-] | Uint8ClampedArray;
+// Loại mô tả màu RGBA của điểm ảnh.
+type Color =
+  | [
+      r: number, // Đỏ
+      g: number, // Xanh lá cây
+      b: number, // Xanh dương
+      a: number // Alpha (độ trong suốt)
+    ]
+  | Uint8ClampedArray;
 ```
 
-On the high level the algorithm consists of the following steps:
+Ở mức cao hơn, thuật toán bao gồm các bước sau:
 
-1. Calculate the **energy map** for the current version of the image.
-2. Find the **seam** with the lowest energy based on the energy map (this is where we will apply Dynamic Programming).
-3. **Delete the seam** with the lowest energy seam from the image.
-4. **Repeat** until the image width is reduced to the desired value.
+1. Tính toán **bản đồ năng lượng** cho phiên bản hiện tại của hình ảnh.
+2. Tìm **đường cắt** có năng lượng thấp nhất dựa trên bản đồ năng lượng (đây là nơi chúng tôi sẽ áp dụng Lập trình Động).
+3. **Xóa đường cắt** có đường cắt có năng lượng thấp nhất khỏi hình ảnh.
+4. **Lặp lại** cho đến khi chiều rộng của hình ảnh được giảm xuống giá trị mong muốn.
 
 ```typescript
 type ResizeImageWidthArgs = {
-  img: ImageData, // Image data we want to resize.
-  toWidth: number, // Final image width we want the image to shrink to.
+  img: ImageData; // Dữ liệu hình ảnh chúng ta muốn thay đổi kích thước.
+  toWidth: number; // Chiều rộng cuối cùng mà chúng ta muốn hình ảnh co lại.
 };
 
 type ResizeImageWidthResult = {
-  img: ImageData, // Resized image data.
-  size: ImageSize, // Resized image size (w x h).
+  img: ImageData; // Dữ liệu hình ảnh đã thay đổi kích thước.
+  size: ImageSize; // Kích thước hình ảnh đã thay đổi (w x h).
 };
 
-// Performs the content-aware image width resizing using the seam carving method.
-export const resizeImageWidth = (
-  { img, toWidth }: ResizeImageWidthArgs,
-): ResizeImageWidthResult => {
-  // For performance reasons we want to avoid changing the img data array size.
-  // Instead we'll just keep the record of the resized image width and height separately.
+// Thực hiện việc thay đổi kích thước chiều rộng hình ảnh dựa trên nội dung sử dụng phương pháp seam carving.
+export const resizeImageWidth = ({
+  img,
+  toWidth,
+}: ResizeImageWidthArgs): ResizeImageWidthResult => {
+  // Vì lý do hiệu suất, chúng ta muốn tránh việc thay đổi kích thước mảng dữ liệu hình ảnh.
+  // Thay vào đó, chúng ta chỉ giữ bản ghi về chiều rộng và chiều cao của hình ảnh đã thay đổi.
   const size: ImageSize = { w: img.width, h: img.height };
 
-  // Calculating the number of pixels to remove.
+  // Tính toán số điểm ảnh cần xóa.
   const pxToRemove = img.width - toWidth;
   if (pxToRemove < 0) {
-    throw new Error('Upsizing is not supported for now');
+    throw new Error('Không hỗ trợ phương pháp phóng to cho tới bây giờ');
   }
 
   let energyMap: EnergyMap | null = null;
   let seam: Seam | null = null;
 
-  // Removing the lowest energy seams one by one.
+  // Xóa các đường cắt có năng lượng thấp nhất một cách tuần tự.
   for (let i = 0; i < pxToRemove; i += 1) {
-    // 1. Calculate the energy map for the current version of the image.
+    // 1. Tính toán bản đồ năng lượng cho phiên bản hiện tại của hình ảnh.
     energyMap = calculateEnergyMap(img, size);
+    //
 
-    // 2. Find the seam with the lowest energy based on the energy map.
+2. Tìm đường cắt có năng lượng thấp nhất dựa trên bản đồ năng lượng.
     seam = findLowEnergySeam(energyMap, size);
 
-    // 3. Delete the seam with the lowest energy seam from the image.
+    // 3. Xóa đường cắt có đường cắt có năng lượng thấp nhất từ hình ảnh.
     deleteSeam(img, seam, size);
 
-    // Reduce the image width, and continue iterations.
+    // Giảm chiều rộng của hình ảnh và tiếp tục các lần lặp.
     size.w -= 1;
   }
 
-  // Returning the resized image and its final size.
-  // The img is actually a reference to the ImageData, so technically
-  // the caller of the function already has this pointer. But let's
-  // still return it for better code readability.
+  // Trả về hình ảnh đã thay đổi kích thước và kích thước cuối cùng của nó.
+  // Dữ liệu hình ảnh thực tế là một tham chiếu đến ImageData, vì vậy kỹ thuật
+  // người gọi của hàm đã có con trỏ này. Nhưng hãy vẫn trả về nó để đọc mã dễ hiểu hơn.
   return { img, size };
 };
 ```
 
-The image that needs to be resized is being passed to the function in [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. You may draw the image on the canvas and then extract the ImageData from the canvas like this:
+Hình ảnh cần được thay đổi kích thước được chuyển đến hàm dưới dạng [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Bạn có thể vẽ hình ảnh lên canvas và sau đó trích xuất ImageData từ canvas như sau:
 
 ```javascript
 const ctx = canvas.getContext('2d');
 const imgData = ctx.getImageData(0, 0, imgWidth, imgHeight);
 ```
 
-> The way of uploading and drawing images in JavaScript is out of scope for this article, but you may find the complete source code of how it may be done using React in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo.
+> Cách tải lên và vẽ hình ảnh trong JavaScript nằm ngoài phạm vi của bài viết này, nhưng bạn có thể tìm mã nguồn đầy đủ về cách thực hiện điều này bằng React trong kho lưu trữ [js-image-carver](https://github.com/trekhleb/js-image-carver).
 
-Let's break down each step ony be one and implement the `calculateEnergyMap()`, `findLowEnergySeam()` and `deleteSeam()` functions.
+Hãy phân rã từng bước một và triển khai các hàm `calculateEnergyMap()`, `findLowEnergySeam()` và `deleteSeam()`.
 
-### Calculating the pixel's energy
+### Tính năng lượng của điểm ảnh
 
-Here we apply the color difference formula described above. For the left and right borders (when there are no left or right neighbors), we ignore the neighbors and don't take them into account during the energy calculation.
+Ở đây, chúng ta áp dụng công thức khác biệt màu sắc đã mô tả ở trên. Đối với các biên trái và phải (khi không có hàng xóm bên trái hoặc bên phải), chúng ta bỏ qua hàng xóm và không tính chúng vào trong quá trình tính toán năng lượng.
 
 ```typescript
-// Calculates the energy of a pixel.
-const getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => {
-  // Middle pixel is the pixel we're calculating the energy for.
+// Tính toán năng lượng của một điểm ảnh.
+const getPixelEnergy = (
+  left: Color | null,
+  middle: Color,
+  right: Color | null
+): number => {
+  // Điểm ảnh ở giữa là điểm ảnh mà chúng tôi đang tính toán năng lượng cho.
   const [mR, mG, mB] = middle;
 
-  // Energy from the left pixel (if it exists).
+  // Năng lượng từ điểm ảnh bên trái (nếu tồn tại).
   let lEnergy = 0;
   if (left) {
     const [lR, lG, lB] = left;
     lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;
   }
 
-  // Energy from the right pixel (if it exists).
+  // Năng lượng từ điểm ảnh bên phải (nếu tồn tại).
   let rEnergy = 0;
   if (right) {
     const [rR, rG, rB] = right;
     rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;
   }
 
-  // Resulting pixel energy.
+  // Năng lượng của điểm ảnh kết quả.
   return Math.sqrt(lEnergy + rEnergy);
 };
 ```
 
-### Calculating the energy map
+### Tính toán bản đồ năng lượng
 
-The image we're working with has the [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. It means that all the pixels (and their colors) are stored in a flat (*1D*) [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) array. For readability purposes let's introduce the couple of helper functions that will allow us to work with the Uint8ClampedArray array as with a *2D* matrix instead.
+Hình ảnh mà chúng ta đang làm việc có định dạng [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Điều này có nghĩa là tất cả các điểm ảnh (và màu sắc của chúng) được lưu trữ trong một mảng _1D_ [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray). Vì mục đích đọc mã dễ hiểu hơn, hãy giới thiệu một cặp hàm trợ giúp để cho phép chúng ta làm việc với mảng Uint8ClampedArray như một ma trận _2D_ thay vì như một mảng _1D_.
 
 ```typescript
-// Helper function that returns the color of the pixel.
+// Hàm trợ giúp trả về màu sắc của điểm ảnh.
 const getPixel = (img: ImageData, { x, y }: Coordinate): Color => {
-  // The ImageData data array is a flat 1D array.
-  // Thus we need to convert x and y coordinates to the linear index.
+  // Mảng dữ liệu ImageData là một mảng 1D phẳng.
+  // Do đó, chúng ta cần chuyển đổi các tọa độ x và y thành chỉ số tuyến tính.
   const i = y * img.width + x;
   const cellsPerColor = 4; // RGBA
-  // For better efficiency, instead of creating a new sub-array we return
-  // a pointer to the part of the ImageData array.
-  return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor);
+  // Để hiệu quả hơn, thay vì tạo một mảng con mới, chúng tôi trả về
+  // một con trỏ đến phần của mảng ImageData.
+  return img.data.subarray(
+    i * cellsPerColor,
+    i * cellsPerColor + cellsPerColor
+  );
 };
 
-// Helper function that sets the color of the pixel.
+// Hàm trợ giúp thiết lập màu sắc của điểm ảnh.
 const setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => {
-  // The ImageData data array is a flat 1D array.
-  // Thus we need to convert x and y coordinates to the linear index.
+  // Mảng dữ liệu ImageData là một mảng 1D phẳng.
+  // Do đó, chúng ta cần chuyển đổi các tọa độ x và y thành chỉ số tuyến tính.
   const i = y * img.width + x;
   const cellsPerColor = 4; // RGBA
   img.data.set(color, i * cellsPerColor);
 };
 ```
 
-To calculate the energy map we go through each image pixel and call the previously described `getPixelEnergy()` function against it.
+Để tính toán bản đồ năng lượng, chúng ta duyệt qua từng điểm ảnh của hình ảnh và gọi hàm `getPixelEnergy()` đã mô tả trước đó.
 
 ```typescript
-// Helper function that creates a matrix (2D array) of specific
-// size (w x h) and fills it with specified value.
+// Hàm trợ giúp tạo ma trận (mảng 2D) có kích thước cụ thể
+// (w x h) và điền nó bằng giá trị đã cho.
 const matrix = <T>(w: number, h: number, filler: T): T[][] => {
-  return new Array(h)
-    .fill(null)
-    .map(() => {
-      return new Array(w).fill(filler);
-    });
+  return new Array(h).fill(null).map(() => {
+    return new Array(w).fill(filler);
+  });
 };
 
-// Calculates the energy of each pixel of the image.
+// Tính toán năng lượng của mỗi điểm ảnh của hình ảnh.
 const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {
-  // Create an empty energy map where each pixel has infinitely high energy.
-  // We will update the energy of each pixel.
+  // Tạo một bản đồ năng lượng trống nơi mỗi điểm ảnh có năng lượng vô cùng cao.
+  // Chúng tôi sẽ cập nhật năng lượng của mỗi điểm ảnh.
   const energyMap: number[][] = matrix<number>(w, h, Infinity);
   for (let y = 0; y < h; y += 1) {
     for (let x = 0; x < w; x += 1) {
-      // Left pixel might not exist if we're on the very left edge of the image.
-      const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null;
-      // The color of the middle pixel that we're calculating the energy for.
+      // Điểm ảnh bên trái có thể không tồn tại nếu chúng tôi đang ở biên trái cực của hình ảnh.
+      const left = x - 1 >= 0 ? getPixel(img, { x: x - 1, y }) : null;
+      // Màu sắc của điểm ảnh ở giữa mà chúng tôi đang tính toán năng lượng cho.
       const middle = getPixel(img, { x, y });
-      // Right pixel might not exist if we're on the very right edge of the image.
-      const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null;
+      // Điểm ảnh bên phải có thể không tồn tại nếu chúng tôi đang ở biên phải cực
+
+ của hình ảnh.
+      const right = x + 1 < w ? getPixel(img, { x: x + 1, y }) : null;
       energyMap[y][x] = getPixelEnergy(left, middle, right);
     }
   }
@@ -307,91 +322,96 @@ const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {
 };
 ```
 
-> The energy map is going to be recalculated on every resize iteration. It means that it will be recalculated, let's say, 500 times if we need to shrink the image by 500 pixels which is not optimal. To speed up the energy map calculation on the 2nd, 3rd, and further steps, we may re-calculate the energy only for those pixels that are placed around the seam that is going to be removed. For simplicity reasons this optimization is omitted here, but you may find the example source-code in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo.
+> Bản đồ năng lượng sẽ được tính toán lại sau mỗi lần thay đổi kích thước. Điều này có nghĩa là nó sẽ được tính toán lại, chẳng hạn, 500 lần nếu chúng ta cần thu nhỏ hình ảnh đi 500 điểm ảnh, điều này không hiệu quả. Để tăng tốc độ tính toán của bản đồ năng lượng ở các bước 2, 3 và các bước tiếp theo, chúng ta có thể tính toán lại năng lượng chỉ cho những điểm ảnh được đặt xung quanh đường cắt sẽ được loại bỏ. Vì lý do đơn giản, tối ưu hóa này đã bị bỏ qua ở đây, nhưng bạn có thể tìm mã nguồn ví dụ trong kho lưu trữ [js-image-carver](https://github.com/trekhleb/js-image-carver).
 
-### Finding the seam with the lowest energy (Dynamic Programming approach)
+### Tìm đường cắt có năng lượng thấp nhất (phương pháp lập trình động)
 
-> I've described some Dynamic Programming basics in [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) article before. There is a DP example based on the minimum edit distance problem. You might want to check it out to get some more context.
+> Tôi đã mô tả một số kiến thức cơ bản về lập trình động trong bài viết [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/). Có một ví dụ về lập trình động dựa trên vấn đề khoảng cách chỉnh sửa tối thiểu. Bạn có thể muốn kiểm tra để hiểu rõ hơn về ngữ cảnh.
 
-The issue we need to solve now is to find the path (the seam) on the energy map that goes from top to bottom and has the minimum sum of pixel energies.
+Vấn đề chúng ta cần giải quyết bây giờ là tìm đường (đường cắt) trên bản đồ năng lượng đi từ trên xuống dưới và có tổng năng lượng pixel nhỏ nhất.
 
-#### The naive approach
+#### Phương pháp ngây thơ
 
-The naive approach would be to check all possible paths one after another.
+Phương pháp ngây thơ sẽ là kiểm tra tất cả các đường đi có thể một sau một.
 
-![The naive approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png)
+![Phương pháp ngây thơ](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png)
 
-Going from top to bottom, for each pixel, we have 3 options (↙︎ go down-left, ↓ go down, ↘︎ go down-right). This gives us the time complexity of `O(w * 3^h)` or simply `O(3^h)`, where `w` and `h` are the width and the height of the image. This approach looks slow.
+Đi từ trên xuống dưới, cho mỗi điểm ảnh, chúng ta có 3 lựa chọn (↙︎ đi xuống bên trái, ↓ đi xuống, ↘︎ đi xuống bên phải). Điều này cho chúng ta độ phức tạp thời gian là `O(w * 3^h)` hoặc đơn giản là `O(3^h)`, trong đó `w` và `h` lần lượt là chiều rộng và chiều cao của hình ảnh. Phương pháp này trông chậm.
 
-#### The greedy approach
+#### Phương pháp tham lam
 
-We may also try to choose the next pixel as a pixel with the lowest energy, hoping that the resulting seam energy will be the smallest one.
+Chúng ta cũng có thể thử chọn điểm ảnh tiếp theo là điểm ảnh có năng lượng thấp nhất, hy vọng rằng năng lượng của đường cắt kết quả sẽ là nhỏ nhất.
 
-![The greedy approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png)
+![Phương pháp tham lam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png)
 
-This approach gives not the worst solution, but it cannot guarantee that we will find the best available solution. On the image above you may see how the greedy approach chose `5` instead of `10` at first and missed the chain of optimal pixels.
+Phương pháp này không cho kết quả tồi nhất, nhưng không thể đảm bảo rằng chúng ta sẽ tìm được giải pháp tốt nhất có sẵn. Trên hình ảnh trên, bạn có thể thấy cách phương pháp tham lam đã chọn `5` thay vì `10` ban đầu và bỏ lỡ chuỗi điểm ảnh tối ưu.
 
-The good part about this approach is that it is fast, and it has a time complexity of `O(w + h)`, where `w` and `h` are the width and the height of the image. In this case, the cost of the speed is the low quality of resizing. We need to find a minimum value in the first row (traversing `w` cells) and then we explore only 3 neighbor pixels for each row (traversing `h` rows).
+Phần tốt của phương pháp này là nó nhanh chóng, và nó có độ phức tạp thời gian là `O(w + h)`, trong đó `w` và `h` lần lượt là chiều rộng và chiều cao của hình ảnh. Trong trường hợp này, chi phí của tốc độ là chất lượng thấp của việc thay đổi kích thước. Chúng ta cần tìm một giá trị nhỏ nhất trong hàng đầu tiên (duyệt `w` ô) và sau đó chúng ta khám phá chỉ 3 ô hàng xóm cho mỗi hàng (duyệt `h` hàng).
 
-#### The dynamic programming approach
+#### Phương pháp lập trình động
 
-You might have noticed that in the naive approach we summed up the same pixel energies over and over again while calculating the resulting seams' energy.
+Bạn có thể đã nhận ra rằng trong phương pháp ngây thơ chúng ta đã tính tổng năng lượng pixel giống nhau lần lượt khi tính toán năng lượng của các đường cắt kết quả.
 
-![Repeated problems](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png)
+![Các vấn đề lặp lại](https://raw.githubusercontent.com/trekhleb/trekhleb
 
-In the example above you see that for the first two seams we are re-using the energy of the shorter seam (which has the energy of `235`). Instead of doing just one operation `235 + 70` to calculate the energy of the 2nd seam we're doing four operations `(5 + 0 + 80 + 150) + 70`.
+.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png)
 
-> This fact that we're re-using the energy of the previous seam to calculate the current seam's energy might be applied recursively to all the shorter seams up to the very top 1st row seam. When we have such overlapping sub-problems, [it is a sign](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) that the general problem *might* be optimized by dynamic programming approach.
+Trong ví dụ trên, bạn thấy rằng cho hai đường cắt đầu tiên, chúng ta đang sử dụng lại năng lượng của đường cắt ngắn hơn (có năng lượng là `235`). Thay vì thực hiện một thao tác `235 + 70` để tính toán năng lượng của đường cắt thứ hai, chúng ta đang thực hiện bốn thao tác `(5 + 0 + 80 + 150) + 70`.
 
-So, we may **save the energy of the current seam** at the particular pixel in an additional `seamsEnergies` table to make it re-usable for calculating the next seams faster (the `seamsEnergies` table will have the same size as the energy map and the image itself).
+> Sự thật rằng chúng ta đang sử dụng lại năng lượng của đường cắt trước để tính toán năng lượng của đường cắt hiện tại có thể được áp dụng đệ quy cho tất cả các đường cắt ngắn hơn lên tới đường cắt đầu tiên ở hàng 1. Khi chúng ta có các bài toán con trùng lặp như vậy, [đó là một dấu hiệu](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) cho thấy vấn đề chung _có thể_ được tối ưu hóa bằng cách tiế approach này.
 
-Let's also keep in mind that for one particular pixel on the image (i.e. the bottom left one) we may have *several* values of the previous seams energies.
+Vì vậy, chúng ta có thể **lưu năng lượng của đường cắt hiện tại** tại pixel cụ thể trong một bảng bổ sung `seamsEnergies` để làm cho nó có thể sử dụng lại cho việc tính toán các đường cắt tiếp theo nhanh hơn (bảng `seamsEnergies` sẽ có kích thước giống như bản đồ năng lượng và hình ảnh chính nó).
 
-![What seam to choose](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png)
+Hãy cũng nhớ rằng cho một pixel cụ thể trên hình ảnh (ví dụ: ở góc dưới bên trái) chúng ta có thể có _nhiều_ giá trị của năng lượng đường cắt trước đó.
 
-Since we're looking for a seam with the lowest resulting energy it would make sense to pick the previous seam with the lowest resulting energy as well.
+![Chọn đường cắt nào](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png)
 
-![Seams energies example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png)
+Vì chúng ta đang tìm kiếm một đường cắt có năng lượng kết quả thấp nhất nên sẽ hợp lý khi chọn đường cắt trước đó có năng lượng kết quả thấp nhất.
 
-In general, we have three possible previous seems to choose from:
+![Ví dụ về năng lượng đường cắt](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png)
 
-![Three options to choose from](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png)
+Nói chung, chúng ta có ba đường cắt trước đó có thể lựa chọn:
 
-You may think about it this way:
+![Ba lựa chọn để chọn](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png)
 
-- The cell `[1][x]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[1][x]`
-- **The current cell** `[2][3]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[2][3]`. To calculate it we need to sum up the energy of the current pixel `[2][3]` (from the energy map) with the `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`
+Bạn có thể nghĩ về nó như sau:
 
-If we fill the `seamsEnergies` table completely, then the minimum number in the lowest row would be the lowest possible seam energy.
+- Ô `[1][x]`: chứa năng lượng thấp nhất có thể của đường cắt bắt đầu từ đâu đó trên hàng `[0][?]` và kết thúc tại ô `[1][x]`
+- **Ô hiện tại** `[2][3]`: chứa năng lượng thấp nhất có thể của đường cắt bắt đầu từ đâu đó trên hàng `[0][?]` và kết thúc tại ô `[2][3]`. Để tính toán nó, chúng ta cần cộng năng lượng của pixel hiện tại `[2][3]` (từ bản đồ năng lượng) với `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`
 
-Let's try to fill several cells of this table to see how it works.
+Nếu chúng ta điền đầy đủ bảng `seamsEnergies`, thì số nhỏ nhất ở hàng dưới cùng sẽ là năng lượng đường cắt nhỏ nhất có thể.
 
-![Seams energies map traversal](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png)
+Hãy thử điền vài ô của bảng này để xem nó hoạt động như thế nào.
 
-After filling out the `seamsEnergies` table we may see that the lowest energy pixel has an energy of `50`. For convenience, during the `seamsEnergies` generation for each pixel, we may save not only the energy of the seam but also the coordinates of the previous lowest energy seam. This will give us the possibility to reconstruct the seam path from the bottom to the top easily.
+![Điều hướng bản đồ năng lượng đường cắt](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png)
 
-The time complexity of DP approach would be `O(w * h)`, where `w` and `h` are the width and the height of the image. We need to calculate energies for *every* pixel of the image.
+Sau khi điền bảng `seamsEnergies`, chúng ta có thể thấy rằng pixel năng lượng thấp nhất có năng lượng là `50`. Để thuận tiện trong quá trình tạo bảng `seamsEnergies` cho mỗi pixel, chúng ta có thể lưu không chỉ năng lượng của đường cắt mà còn là tọa độ của đường cắt trước đó. Điều này sẽ cho chúng ta khả năng tái tạo đường cắt từ dưới lên trên một cách dễ dàng.
 
-Here is an example of how this logic might be implemented:
+Độ phức tạp thời gian của phương pháp lập trình động sẽ là `O(w * h)`, trong đó `w` và `h` lần lượt là chiều rộng và chiều cao của hình ảnh. Chúng ta cần tính năng lượng cho _mỗi_ pixel của hình ảnh.
+
+Dưới đây là một ví dụ về cách triển khai logic này:
 
 ```typescript
-// The metadata for the pixels in the seam.
+// Thông tin về các pixel
+
+ trong đường cắt.
 type SeamPixelMeta = {
-  energy: number, // The energy of the pixel.
-  coordinate: Coordinate, // The coordinate of the pixel.
-  previous: Coordinate | null, // The previous pixel in a seam.
+  energy: number; // Năng lượng của pixel.
+  coordinate: Coordinate; // Tọa độ của pixel.
+  previous: Coordinate | null; // Pixel trước đó trong một đường cắt.
 };
 
-// Finds the seam (the sequence of pixels from top to bottom) that has the
-// lowest resulting energy using the Dynamic Programming approach.
+// Tìm đường cắt (dãy các pixel từ trên xuống dưới) có
+// năng lượng kết quả thấp nhất sử dụng phương pháp lập trình động.
 const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
-  // The 2D array of the size of w and h, where each pixel contains the
-  // seam metadata (pixel energy, pixel coordinate and previous pixel from
-  // the lowest energy seam at this point).
-  const seamsEnergies: (SeamPixelMeta | null)[][] = matrix<SeamPixelMeta | null>(w, h, null);
-
-  // Populate the first row of the map by just copying the energies
-  // from the energy map.
+  // Mảng 2D có kích thước w và h, mỗi pixel chứa
+  // thông tin metadata của đường cắt (năng lượng pixel, tọa độ pixel và pixel trước
+  // đó từ đường cắt năng lượng thấp nhất ở điểm này).
+  const seamsEnergies: (SeamPixelMeta | null)[][] =
+    matrix<SeamPixelMeta | null>(w, h, null);
+
+  // Điền vào hàng đầu tiên của bảng bằng cách sao chép năng lượng
+  // từ bản đồ năng lượng.
   for (let x = 0; x < w; x += 1) {
     const y = 0;
     seamsEnergies[y][x] = {
@@ -401,24 +421,24 @@ const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
     };
   }
 
-  // Populate the rest of the rows.
+  // Điền vào phần còn lại của các hàng.
   for (let y = 1; y < h; y += 1) {
     for (let x = 0; x < w; x += 1) {
-      // Find the top adjacent cell with minimum energy.
-      // This cell would be the tail of a seam with lowest energy at this point.
-      // It doesn't mean that this seam (path) has lowest energy globally.
-      // Instead, it means that we found a path with the lowest energy that may lead
-      // us to the current pixel with the coordinates x and y.
+      // Tìm ô kề trên với năng lượng thấp nhất.
+      // Ô này sẽ là đuôi của một đường cắt với năng lượng thấp nhất tại điểm này.
+      // Điều này không có nghĩa là đường cắt (đường dẫn) này có năng lượng thấp nhất
+      // toàn cầu. Thay vào đó, điều này có nghĩa là chúng ta đã tìm thấy một đường dẫn với
+      // năng lượng thấp nhất có thể dẫn chúng ta đến pixel hiện tại với tọa độ x và y.
       let minPrevEnergy = Infinity;
       let minPrevX: number = x;
-      for (let i = (x - 1); i <= (x + 1); i += 1) {
+      for (let i = x - 1; i <= x + 1; i += 1) {
         if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) {
           minPrevEnergy = seamsEnergies[y - 1][i].energy;
           minPrevX = i;
         }
       }
 
-      // Update the current cell.
+      // Cập nhật ô hiện tại.
       seamsEnergies[y][x] = {
         energy: minPrevEnergy + energyMap[y][x],
         coordinate: { x, y },
@@ -427,9 +447,9 @@ const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
     }
   }
 
-  // Find where the minimum energy seam ends.
-  // We need to find the tail of the lowest energy seam to start
-  // traversing it from its tail to its head (from the bottom to the top).
+  // Tìm nơi đường cắt năng lượng thấp nhất kết thúc.
+  // Chúng ta cần tìm đuôi của đường cắt năng lượng thấp nhất để bắt đầu
+  // điều hướng nó từ đuôi đến đầu (từ dưới lên trên).
   let lastMinCoordinate: Coordinate | null = null;
   let minSeamEnergy = Infinity;
   for (let x = 0; x < w; x += 1) {
@@ -440,9 +460,9 @@ const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
     }
   }
 
-  // Find the lowest energy energy seam.
-  // Once we know where the tail is we may traverse and assemble the lowest
-  // energy seam based on the "previous" value of the seam pixel metadata.
+  // Tìm đường cắt năng lượng thấp nhất.
+  // Khi chúng ta biết nơi đuôi đặt, chúng ta có thể điều hướng và lắp ráp
+  // đường cắt năng lượng thấp nhất dựa trên giá trị "trước" của metadata pixel đường cắt.
   const seam: Seam = [];
   if (!lastMinCoordinate) {
     return seam;
@@ -450,7 +470,7 @@ const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
 
   const { x: lastMinX, y: lastMinY } = lastMinCoordinate;
 
-  // Adding new pixel to the seam path one by one until we reach the top.
+  // Thêm pixel mới vào đường cắt một cách tuần tự cho đến khi chúng ta đến đầu.
   let currentSeam = seamsEnergies[lastMinY][lastMinX];
   while (currentSeam) {
     seam.push(currentSeam.coordinate);
@@ -467,18 +487,18 @@ const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
 };
 ```
 
-### Removing the seam with the lowest energy
+### Xóa đường cắt có năng lượng thấp nhất
 
-Once we found the lowest energy seam, we need to remove (to carve) the pixels that form it from the image. The removal is happening by shifting the pixels to the right of the seam by `1px` to the left. For performance reasons, we don't actually delete the last columns. Instead, the rendering component will just ignore the part of the image that lays beyond the resized image width.
+Sau khi chúng ta đã tìm ra đường cắt có năng lượng thấp nhất, chúng ta cần xóa (điêu chỉnh) các pixel tạo thành nó khỏi hình ảnh. Việc xóa diễn ra bằng cách dịch chuyển các pixel sang phải của đường cắt sang trái `1px`. Vì lý do hiệu suất, chúng ta không thực sự xóa các cột cuối cùng. Thay vào đó, thành phần hiển thị sẽ chỉ bỏ qua phần của hình ảnh nằm ngoài chiều rộng của hình ảnh đã được thay đổi kích thước.
 
-![Deleting the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png)
+![Xóa đường cắt](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png)
 
 ```typescript
-// Deletes the seam from the image data.
-// We delete the pixel in each row and then shift the rest of the row pixels to the left.
+// Xóa đường cắt khỏi dữ liệu hình ảnh.
+// Chúng ta xóa pixel trong mỗi hàng và sau đó dịch chuyển các pixel còn lại của hàng sang trái.
 const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {
   seam.forEach(({ x: seamX, y: seamY }: Coordinate) => {
-    for (let x = seamX; x < (w - 1); x += 1) {
+    for (let x = seamX; x < w - 1; x += 1) {
       const nextPixel = getPixel(img, { x: x + 1, y: seamY });
       setPixel(img, { x, y: seamY }, nextPixel);
     }
@@ -486,24 +506,24 @@ const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {
 };
 ```
 
-## Objects removal
+## Xóa đối tượng
 
-The Seam Carving algorithm tries to remove the seams which consist of low energy pixels first. We could leverage this fact and by assigning low energy to some pixels manually (i.e. by drawing on the image and masking out some areas of it) we could make the Seam Carving algorithm to do *objects removal* for us for free.
+Thuật toán Seam Carving cố gắng xóa các đường cắt được tạo thành từ các pixel có năng lượng thấp trước tiên. Chúng ta có thể tận dụng sự thật này và bằng cách gán năng lượng thấp cho một số pixel một cách thủ công (tức là bằng cách vẽ trên hình ảnh và che khuất một số khu vực của nó), chúng ta có thể làm cho thuật toán Seam Carving thực hiện _xóa đối tượng_ cho chúng ta miễn phí.
 
-Currently, in `getPixelEnergy()` function we were using only the `R`, `G`, `B` color channels to calculate the pixel's energy. But there is also the `A` (alpha, transparency) parameter of the color that we didn't use yet. We may use the transparency channel to tell the algorithm that transparent pixels are the pixels we want to remove. You may check the [source-code of the energy function](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54) that takes transparency into account.
+Hiện tại, trong hàm `getPixelEnergy()`, chúng ta chỉ sử dụng các kênh màu `R`, `G`, `B` để tính toán năng lượng của pixel. Nhưng cũng có tham số `A` (alpha, độ trong suốt) của màu mà chúng ta chưa sử dụng. Chúng ta có thể sử dụng kênh độ trong suốt để thông báo cho thuật toán rằng các pixel trong suốt là các pixel chúng ta muốn xóa. Bạn có thể kiểm tra [mã nguồn của hàm năng lượng](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54) mà tính đến độ trong suốt.
 
-Here is how the algorithm works for object removal.
+Dưới đây là cách thuật toán hoạt động cho việc xóa đối tượng.
 
 ![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
 
-## Issues and what's next
+## Vấn đề và những gì tiếp theo
 
-The [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) web app is far from being a production ready resizer of course. Its main purpose was to experiment with the Seam Carving algorithm interactively. So the plan for the future is to continue experimentation.
+Ứng dụng web [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) chắc chắn chưa thể trở thành một công cụ thay đổi kích thước sẵn sàng cho sản xuất. Mục đích chính của nó là thử nghiệm với thuật toán Seam Carving theo cách tương tác. Vì vậy, kế hoạch cho tương lai là tiếp tục thử nghiệm.
 
-The [original paper](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) describes how the Seam Carving algorithm might be used not only for the downscaling but also for the **upscaling of the images**. The upscaling, in turn, might be used to **upscale the image back to its original width after the objects' removal**.
+[Bài báo gốc](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) mô tả cách thuật toán Seam Carving có thể được sử dụng không chỉ để co giảm kích thước mà còn để **mở rộng kích thước của hình ảnh**. Việc mở rộng, lần lượt, có thể được sử dụng để **mở rộng lại hình ảnh về chiều rộng ban đầu sau khi loại bỏ các đối tượng**.
 
-Another interesting area of experimentation might be to make the algorithm work in a **real-time**.
+Một lĩnh vực thử nghiệm thú vị khác có thể là làm cho thuật toán hoạt động **trực tiếp**.
 
-> Those are the plans for the future, but for now, I hope that the example with image downsizing was interesting and useful for you. I also hope that you've got the idea of using dynamic programming to implement it.
+> Đó là các kế hoạch cho tương lai, nhưng hiện tại, tôi hy vọng rằng ví dụ về việc giảm kích thước hình ảnh đã làm bạn thấy thú vị và hữu ích. Tôi cũng hy vọng rằng bạn đã hiểu được cách sử dụng lập trình động để triển khai nó.
 >
-> So, good luck with your own experiments!
+> Vì vậy, chúc bạn may mắn với các thử nghiệm của riêng bạn!
diff --git a/src/algorithms/image-processing/seam-carving/README.ru-RU.md b/src/algorithms/image-processing/seam-carving/README.ru-RU.md
deleted file mode 100644
index 444ce6df61..0000000000
--- a/src/algorithms/image-processing/seam-carving/README.ru-RU.md
+++ /dev/null
@@ -1,509 +0,0 @@
-# Изменение размеров изображения с учетом его содержимого в JavaScript
-
-![Content-aware image resizing in JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png)
-
-> Доступна [английская интерактивная версия этой статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) в которой вы можете загрузить свои собственные изображения и посмотреть, как алгоритм "справляется" с ними.
-
-## TL;DR
-
-Написано много замечательных статей об алгоритме *Seam Carving* ("Вырезание швов"), но я не смог устоять перед соблазном самостоятельно исследовать этот элегантный, мощный и в то же время простой алгоритм и написать о своем личном опыте работы с ним. Мое внимание также привлек тот факт, что для его имплементации мы можем применить *динамическое программирование (DP)*. И, если вы, как и я, все еще находитесь на пути изучения алгоритмов, то это решение может обогатить ваш личный арсенал DP.
-
-Итак, в этой статье я хочу сделать три вещи:
-
-1. Предоставить вам возможность "поиграться" с алгоритмом самостоятельно при помощи **интерактивного ресайзера**.
-2. Объяснить **идею алгоритма Seam Carving**.
-3. Объяснить как можно **применить динамическое программирование** для имплементации алгоритма (мы будем писать на TypeScript).
-
-### Изменение размеров изображений с учетом их содержимого
-
-*Изменение размера изображения с учетом содержимого* (content-aware image resizing) может быть применено, когда дело доходит до изменения пропорций изображения (например, уменьшения ширины при сохранении высоты), а также когда потеря некоторых частей изображения нежелательна. Простое масштабирование изображения в этом случае исказит находящиеся в нем объекты. Для сохранения пропорций объектов при изменении пропорций изображения можно использовать [алгоритм Seam Carving](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf), который был описан *Shai Avidan* и *Ariel Shamir*.
-
-В приведенном ниже примере показано, как ширина исходного изображения была уменьшена на 50% *с учетом содержимого изображения* (слева) и *без учета содержимого изображения* (справа, простой скейлинг). В данном случае левое изображение выглядит более естественным, так как пропорции воздушных шаров в нем были сохранены.
-
-![Content-aware image resizing](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png)
-
-Идея алгоритма Seam Carving заключается в том, чтобы найти *шов* (seam, непрерывную последовательность пикселей) с наименьшим влиянием на содержание изображения, а затем его *вырезать* (carve). Этот процесс повторяется снова и снова, пока мы не получим требуемую ширину или высоту изображения. В примере ниже интуитивно видно, что пиксели воздушных шаров вносят больший "вклад" в содержание и смысл изображения, чем пиксели неба. Таким образом, сначала удаляются пиксели неба.
-
-![JS IMAGE CARVER DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-01.gif)
-
-Поиск шва с наименьшей энергией (с наименьшим вкладом в содержимое изображения) является вычислительно дорогостоящей операцией (особенно для больших изображений). Для ускорения поиска шва может быть применено *динамическое программирование* (мы рассмотрим детали реализации ниже).
-
-### Удаление объектов
-
-Важность каждого пикселя (так называемая энергия пикселя) вычисляется исходя из его цветовой разницы (`R`, `G`, `B`, `A`) между двумя соседними пикселями. Если же мы вручную зададим некоторым пикселям низкий уровень энергии (например нарисовав маску поверх них), то алгоритм Seam Carving выполнит для нас **удаление помеченного объекта**, как говорится, "забесплатно".
-
-![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
-
-### Интерактивный ресзайзер
-
-Для этой статьи я создал приложение [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) (доступен также и [исходный код на GitHub](https://github.com/trekhleb/js-image-carver)), которым вы можете воспользоваться для ресайза своих изображений и увидеть в реальном времени, как работает алгоритм.
-
-### Другие примеры ресайза
-
-Вот еще несколько примеров того, как алгоритм справляется с более сложным фоном.
-
-Горы на заднем плане плавно сжимаются, без видимых швов.
-
-![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png)
-
-То же самое и с океанскими волнами. Алгоритм сохранил волновую структуру, не искажая серферов.
-
-![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png)
-
-Нужно помнить, что алгоритм Seam Carving не является "волшебной таблеткой", и может не сохранить пропорции важных частей изображения в том случае, когда *большая часть пикселей выглядят как края, ребра или границы* (почти все пиксели выглядят одинаково важными с точки зрения алгоритма). В приведенном ниже примере изменение размера изображения с учетом содержимого похоже на простое масштабирование, т.к. для алгоритма все пиксели выглядят важными, и ему трудно отличить лицо Ван Гога от фона.
-
-![Example when the algorithm does not work as expected](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png)
-
-## Как работает алгоритм Seam Carving
-
-Представим, что у нас есть картинка размером `1000 x 500 px`, и мы хотим уменьшить ее до `500 x 500 px` (допустим, квадратное изображение больше подходит для Instagram). В этом случае мы, возможно, захотим задать несколько **требований к процессу изменения размера**:
-
-- *Важные части изображения должны быть сохранены* (если до ресайза на фото было 5 деревьев, то и после ресайза мы хотим увидеть все те же 5 деревьев).
-- *Пропорции важных частей изображения должны быть сохранены* (круглые колеса автомобиля не должны стать овальными после ресайза).
-
-Чтобы избежать изменения важных частей изображения можно найти **непрерывную последовательность пикселей (шов)**, которая будет идти от верхней границы к нижней и иметь *наименьший вклад в содержимое* изображения (шов, который не проходит через важные части изображения), а затем удалить его. Удаление шва сожмет изображение на один пиксель. Далее надо повторять этот шаг до тех пор, пока изображение не станет нужной ширины.
-
-Вопрос в том, как определить *важность пикселя* и его вклад в содержание изображения (в оригинальной статье авторы используют термин **энергия пикселя**). Один из способов это сделать — рассматривать все пиксели, образующие края (границы, ребра), как важные. В случае, если пиксель является частью ребра, его цвет будет отличаться от соседей (левого и правого пикселей).
-
-![Pixels color difference](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png)
-
-Предполагая, что цвет пикселя представлен *4-мя* числами (`R` - красный, `G` - зеленый, `B` - синий, `A` - альфа, прозрачность), мы можем использовать следующую формулу для вычисления разницы в цвете (энергии пикселя):
-
-![Pixel energy formula](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png)
-
-Где:
-
-- `mEnergy` - *Энергия* (важность) *среднего* пикселя (`[0..626]` если округлить)
-- `lR` - *Красный* цветовой канал *левого* пикселя (`[0..255]`)
-- `mR` - *Красный* цветовой канал *среднего* пикселя (`[0..255]`)
-- `rR` - *Красный* цветовой канал *правого* пикселя (`[0..255]`)
-- `lG` - *Зеленый* цветовой канал *левого* пикселя (`[0..255]`)
-- и так далее...
-
-В приведенной выше формуле мы пока не используем альфа-канал (прозрачность), предполагая, что изображение не содержит прозрачные пиксели. Позже мы будем использовать альфа-канал для маскировки и удаления объектов.
-
-![Example of pixel energy calculation](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png)
-
-Поскольку мы знаем, как найти энергию одного пикселя, мы можем вычислить так называемую **энергетическую карту**, которая будет содержать энергии каждого пикселя изображения. На каждом шаге изменения размера изображения карту энергий необходимо пересчитывать (по крайней мере частично, подробнее об этом ниже), и она будет иметь тот же размер, что и изображение.
-
-Например, на 1-м шаге у нас будет изображение размером `1000 x 500` и энергетическая карта размером `1000 x 500`. На 2-м шаге изменения размера мы удалим шов с изображения и пересчитаем карту энергий на основе нового уменьшенного изображения. Таким образом, мы получим изображение размером `999 x 500` и карту энергий размером `999 x 500`.
-
-Чем выше энергия пикселя, тем больше вероятность того, что он является частью ребра, важен для содержимого изображения и тем меньше вероятность того, что нам потребуется его удалить.
-
-Для визуализации карты энергий мы можем присвоить более яркий цвет пикселям с большей энергией и более темные цвета пикселям с меньшей энергией. Вот как может выглядеть часть карты энергий. Вы можете увидеть светлую линию, которая представляет край и которую мы хотим сохранить при изменении размера.
-
-![Energy map sketch](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png)
-
-Вот реальный пример энергетической карты для изображения, которое вы видели выше (с воздушными шарами).
-
-![Energy map example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png)
-
-Вы можете загрузить свое изображение и посмотреть, как будет выглядеть энергетическая карта в [интерактивной версии статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/).
-
-Мы можем использовать энергетическую карту, чтобы найти швы (один за другим) с наименьшей энергией и тем самым решить, какие пиксели в конечном итоге должны быть удалены.
-
-![Searching the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png)
-
-Поиск шва с наименьшими затратами энергии не является тривиальной задачей и требует перебора множества возможных комбинаций пикселей. Мы применим динамическое программирование для оптимизации поиска шва.
-
-В примере ниже вы можете увидеть карту энергий с первым найденным для нее швом с наименьшей энергией.
-
-![Energy map example with seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png)
-
-В приведенных выше примерах мы уменьшали ширину изображения. Аналогичный подход может быть использован для уменьшения высоты изображения. Для этого нам нужно:
-
-- начать использовать соседей *сверху* и *снизу*, а не *слева* и *справа*, для вычисления энергии пикселя
-- при поиске шва нам нужно двигаться *слева* *направо*, а не *сверху* *вниз*.
-
-## Реализация алгоритма на TypeScript
-
-> Исходный код и функции, упомянутые ниже, можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).
-
-Для реализации алгоритма мы будем использовать TypeScript. Если вам нужна версия на JavaScript, вы можете игнорировать (удалить) определения типов и их использование.
-
-Для простоты примеров мы напишем код только для уменьшения *ширины* изображения.
-
-### Уменьшение ширины с учетом содержимого изображения (исходная функция)
-
-Для начала определим некоторые общие типы, которые мы будем использовать при реализации алгоритма.
-
-```typescript
-// Type that describes the image size (width and height).
-type ImageSize = { w: number, h: number };
-
-// The coordinate of the pixel.
-type Coordinate = { x: number, y: number };
-
-// The seam is a sequence of pixels (coordinates).
-type Seam = Coordinate[];
-
-// Energy map is a 2D array that has the same width and height
-// as the image the map is being calculated for.
-type EnergyMap = number[][];
-
-// Type that describes the image pixel's RGBA color.
-type Color = [
-  r: number, // Red
-  g: number, // Green
-  b: number, // Blue
-  a: number, // Alpha (transparency)
-] | Uint8ClampedArray;
-```
-
-Для имплементации алгоритма нам необходимо выполнить следующие шаги:
-
-1. Рассчитать **карту энергии** для текущей версии изображения.
-2. Найти **шов** с наименьшей энергией на основе карты энергий (здесь мы применим динамическое программирование).
-3. **Удалить шов** с наименьшей энергией из изображения.
-4. **Повторять** до тех пор, пока ширина изображения не будет уменьшена до нужного значения.
-
-```typescript
-type ResizeImageWidthArgs = {
-  img: ImageData, // Image data we want to resize.
-  toWidth: number, // Final image width we want the image to shrink to.
-};
-
-type ResizeImageWidthResult = {
-  img: ImageData, // Resized image data.
-  size: ImageSize, // Resized image size (w x h).
-};
-
-// Performs the content-aware image width resizing using the seam carving method.
-export const resizeImageWidth = (
-  { img, toWidth }: ResizeImageWidthArgs,
-): ResizeImageWidthResult => {
-  // For performance reasons we want to avoid changing the img data array size.
-  // Instead we'll just keep the record of the resized image width and height separately.
-  const size: ImageSize = { w: img.width, h: img.height };
-
-  // Calculating the number of pixels to remove.
-  const pxToRemove = img.width - toWidth;
-  if (pxToRemove < 0) {
-    throw new Error('Upsizing is not supported for now');
-  }
-
-  let energyMap: EnergyMap | null = null;
-  let seam: Seam | null = null;
-
-  // Removing the lowest energy seams one by one.
-  for (let i = 0; i < pxToRemove; i += 1) {
-    // 1. Calculate the energy map for the current version of the image.
-    energyMap = calculateEnergyMap(img, size);
-
-    // 2. Find the seam with the lowest energy based on the energy map.
-    seam = findLowEnergySeam(energyMap, size);
-
-    // 3. Delete the seam with the lowest energy seam from the image.
-    deleteSeam(img, seam, size);
-
-    // Reduce the image width, and continue iterations.
-    size.w -= 1;
-  }
-
-  // Returning the resized image and its final size.
-  // The img is actually a reference to the ImageData, so technically
-  // the caller of the function already has this pointer. But let's
-  // still return it for better code readability.
-  return { img, size };
-};
-```
-
-Изображение, которому необходимо изменить размер, передается в функцию в формате [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Вы можете отобразить изображение на canvas-е, а затем извлечь ImageData из того же canvas-а следующим образом:
-
-```javascript
-const ctx = canvas.getContext('2d');
-const imgData = ctx.getImageData(0, 0, imgWidth, imgHeight);
-```
-
-> Загрузка и отрисовка изображений в JavaScript выходит за рамки данной статьи, но вы можете найти полный исходный код того, как это можно сделать с помощью React в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).
-
-Теперь, пошагово реализуем функции `calculateEnergyMap()`, `findLowEnergySeam()` и `deleteSeam()`.
-
-### Расчет энергии пикселя
-
-Для расчета воспользуемся формулой разницы цветов, описанной выше. Для левой и правой краев изображения (когда нет левого или правого соседей) мы игнорируем соседей и не учитываем их при расчете энергии.
-
-```typescript
-// Calculates the energy of a pixel.
-const getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => {
-  // Middle pixel is the pixel we're calculating the energy for.
-  const [mR, mG, mB] = middle;
-
-  // Energy from the left pixel (if it exists).
-  let lEnergy = 0;
-  if (left) {
-    const [lR, lG, lB] = left;
-    lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2;
-  }
-
-  // Energy from the right pixel (if it exists).
-  let rEnergy = 0;
-  if (right) {
-    const [rR, rG, rB] = right;
-    rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2;
-  }
-
-  // Resulting pixel energy.
-  return Math.sqrt(lEnergy + rEnergy);
-};
-```
-
-### Расчет энергетической карты
-
-Изображение, с которым мы работаем, имеет формат [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Это означает, что все пиксели (и их цвета) хранятся в одномерном массиве [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray). Для удобства чтения введем пару вспомогательных функций, которые позволят работать с массивом Uint8ClampedArray как с *2D* матрицей.
-
-```typescript
-// Helper function that returns the color of the pixel.
-const getPixel = (img: ImageData, { x, y }: Coordinate): Color => {
-  // The ImageData data array is a flat 1D array.
-  // Thus we need to convert x and y coordinates to the linear index.
-  const i = y * img.width + x;
-  const cellsPerColor = 4; // RGBA
-  // For better efficiency, instead of creating a new sub-array we return
-  // a pointer to the part of the ImageData array.
-  return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor);
-};
-
-// Helper function that sets the color of the pixel.
-const setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => {
-  // The ImageData data array is a flat 1D array.
-  // Thus we need to convert x and y coordinates to the linear index.
-  const i = y * img.width + x;
-  const cellsPerColor = 4; // RGBA
-  img.data.set(color, i * cellsPerColor);
-};
-```
-
-Для вычисления карты энергии мы проходим через каждый пиксель изображения и вызываем для него описанную ранее функцию `getPixelEnergy()`.
-
-```typescript
-// Helper function that creates a matrix (2D array) of specific
-// size (w x h) and fills it with specified value.
-const matrix = <T>(w: number, h: number, filler: T): T[][] => {
-  return new Array(h)
-    .fill(null)
-    .map(() => {
-      return new Array(w).fill(filler);
-    });
-};
-
-// Calculates the energy of each pixel of the image.
-const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => {
-  // Create an empty energy map where each pixel has infinitely high energy.
-  // We will update the energy of each pixel.
-  const energyMap: number[][] = matrix<number>(w, h, Infinity);
-  for (let y = 0; y < h; y += 1) {
-    for (let x = 0; x < w; x += 1) {
-      // Left pixel might not exist if we're on the very left edge of the image.
-      const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null;
-      // The color of the middle pixel that we're calculating the energy for.
-      const middle = getPixel(img, { x, y });
-      // Right pixel might not exist if we're on the very right edge of the image.
-      const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null;
-      energyMap[y][x] = getPixelEnergy(left, middle, right);
-    }
-  }
-  return energyMap;
-};
-```
-
-> Карта энергии будет пересчитываться при каждой итерации изменения размера. Это значит, что она будет пересчитываться, скажем, 500 раз, если нам нужно будет уменьшить изображение на 500 пикселей, что выглядит неоптимально. Чтобы ускорить вычисление карты энергии на 2-м, 3-м и последующих этапах, мы можем пересчитать энергию только для тех пикселей, которые расположены вокруг шва, который будет удален. Для простоты эта оптимизация здесь пропущена, но пример с исходным кодом можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver).
-
-### Нахождение шва с минимальной энергией (применяем динамическое программирование)
-
-> В статье [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) я описывал некоторые аспекты динамического программирования на примере нахождения "расстояния Левенштейна" (преобразование одной строки в другую). Возможно она будет полезна для ознакомления.
-
-Проблема, которую нам необходимо решить заключается в нахождении пути (шва) на энергетической карте, который идет от верхней границы изображения к нижней и имеет минимальную энергию (сумма энергий пикселей, составляющих шов должна быть минимальной).
-
-#### "Наивный" подход (naive)
-
-Прямолинейный ("наивный") подход — перебрать все возможные пути один за другим.
-
-![The naive approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png)
-
-Двигаясь сверху вниз, для каждого пикселя у нас есть 3 варианта (↙︎ идти вниз-влево, ↓ вниз, ↘︎ идти вниз-вправо). Это дает нам временную сложность `O (w * 3 ^ h)` или просто `O (3 ^ h)`, где `w` и` h` - ширина и высота изображения. Такой подход выглядит неоптимальным.
-
-#### "Жадный" подход (greedy)
-
-Жадный подход — выбирать следующий пиксель как пиксель с наименьшей энергией, надеясь, что результирующая энергия шва будет наименьшей.
-
-![The greedy approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png)
-
-Жадный подход приведет нас к не самому худшему решению, но он не сможет гарантировать, что мы найдем наилучшее доступное решение. На картинке выше видно, как мы выбрали `5` вместо `10` и пропустили цепочку оптимальных пикселей.
-
-Плюс этого подхода в том, что он быстрый и имеет временную сложность `O(w + h)`, где `w` и `h` - это ширина и высота изображения. В этом случае плата за скорость — низкое качество ресайза (много искажений). Временная сложность обусловлена тем, что нужно найти минимальное значение в первом ряду (обход `w` ячеек), а затем исследовать только 3 соседних пикселя для каждого ряда (обход `h` рядов).
-
-#### Используем динамическое программирование
-
-Вы, наверное, заметили, что в наивном подходе мы снова и снова суммировали одни и те же энергии пикселей, вычисляя энергию образовавшихся швов.
-
-![Repeated problems](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png)
-
-В примере выше видно, что для первых двух швов мы повторно используем энергию более короткого шва (который имеет энергию `235`). Вместо одной операции `235 + 70` для вычисления энергии 2-го шва мы делаем четыре операции `(5 + 0 + 80 + 150) + 70`.
-
-> Тот факт, что мы повторно используем энергию предыдущего шва для вычисления энергии текущего шва, может быть применен рекурсивно ко всем более коротким швам до самого верхнего 1-го ряда. Когда у нас есть такие перекрывающиеся под-проблемы, [это признак](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/), что общая задача *может* быть оптимизирована с использованием динамического программирования.
-
-Таким образом, мы можем **сохранить энергию текущего шва** для конкретного пикселя в дополнительной таблице `samsEnergies`, чтобы повторно использовать ее при расчете энергии следующих швов (таблица `samsEnergies` будет иметь тот же размер, что и энергетическая карта и само изображение).
-
-Обратите также внимание, что для большинства пикселей в изображении (например, для левого нижнего) мы можем иметь *несколько* значений энергий предыдущих швов.
-
-![What seam to choose](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png)
-
-Так как мы ищем шов с наименьшей результирующей энергией, имеет смысл выбирать и предыдущий шов с наименьшей результирующей энергией.
-
-![Seams energies example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png)
-
-Как правило, у нас есть три возможных предыдущих шва, которые текущий пиксель продолжает:
-
-![Three options to choose from](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png)
-
-Можем посмотреть на это с такой стороны:
-
-- Ячейка `[1][x]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[1][x]`.
-- **Текущая ячейка** `[2][3]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[2][3]`. Для вычисления нужно суммировать энергию текущего пикселя `[2][3]` (из энергетической карты) с `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`.
-
-Если мы заполним таблицу `ShesamsEnergies` полностью, то минимальное число в нижнем ряду будет наименьшей возможной энергией шва.
-
-Попробуем заполнить несколько ячеек этой таблицы, чтобы посмотреть, как это работает.
-
-![Seams energies map traversal](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png)
-
-После заполнения таблицы `ShesamsEnergies` видно, что в нижнем ряду пиксель с самой низкой энергией имеет значение `50`. Для удобства во время генерации `samsEnergies` для каждого пикселя мы можем сохранить не только энергию шва, но и координаты предыдущего шва с наименьшей энергией. Это даст нам возможность легко восстанавливать траекторию шва снизу вверх.
-
-Временная сложность DP подхода составит `O(w * h)`, где `w` и `h` - это ширина и высота изображения. Обусловлена она тем, что нужно вычислить энергии для *всех* пикселей изображения.
-
-Вот пример того, как эта логика может быть реализована:
-
-```typescript
-// The metadata for the pixels in the seam.
-type SeamPixelMeta = {
-  energy: number, // The energy of the pixel.
-  coordinate: Coordinate, // The coordinate of the pixel.
-  previous: Coordinate | null, // The previous pixel in a seam.
-};
-
-// Finds the seam (the sequence of pixels from top to bottom) that has the
-// lowest resulting energy using the Dynamic Programming approach.
-const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => {
-  // The 2D array of the size of w and h, where each pixel contains the
-  // seam metadata (pixel energy, pixel coordinate and previous pixel from
-  // the lowest energy seam at this point).
-  const seamsEnergies: (SeamPixelMeta | null)[][] = matrix<SeamPixelMeta | null>(w, h, null);
-
-  // Populate the first row of the map by just copying the energies
-  // from the energy map.
-  for (let x = 0; x < w; x += 1) {
-    const y = 0;
-    seamsEnergies[y][x] = {
-      energy: energyMap[y][x],
-      coordinate: { x, y },
-      previous: null,
-    };
-  }
-
-  // Populate the rest of the rows.
-  for (let y = 1; y < h; y += 1) {
-    for (let x = 0; x < w; x += 1) {
-      // Find the top adjacent cell with minimum energy.
-      // This cell would be the tail of a seam with lowest energy at this point.
-      // It doesn't mean that this seam (path) has lowest energy globally.
-      // Instead, it means that we found a path with the lowest energy that may lead
-      // us to the current pixel with the coordinates x and y.
-      let minPrevEnergy = Infinity;
-      let minPrevX: number = x;
-      for (let i = (x - 1); i <= (x + 1); i += 1) {
-        if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) {
-          minPrevEnergy = seamsEnergies[y - 1][i].energy;
-          minPrevX = i;
-        }
-      }
-
-      // Update the current cell.
-      seamsEnergies[y][x] = {
-        energy: minPrevEnergy + energyMap[y][x],
-        coordinate: { x, y },
-        previous: { x: minPrevX, y: y - 1 },
-      };
-    }
-  }
-
-  // Find where the minimum energy seam ends.
-  // We need to find the tail of the lowest energy seam to start
-  // traversing it from its tail to its head (from the bottom to the top).
-  let lastMinCoordinate: Coordinate | null = null;
-  let minSeamEnergy = Infinity;
-  for (let x = 0; x < w; x += 1) {
-    const y = h - 1;
-    if (seamsEnergies[y][x].energy < minSeamEnergy) {
-      minSeamEnergy = seamsEnergies[y][x].energy;
-      lastMinCoordinate = { x, y };
-    }
-  }
-
-  // Find the lowest energy energy seam.
-  // Once we know where the tail is we may traverse and assemble the lowest
-  // energy seam based on the "previous" value of the seam pixel metadata.
-  const seam: Seam = [];
-  if (!lastMinCoordinate) {
-    return seam;
-  }
-
-  const { x: lastMinX, y: lastMinY } = lastMinCoordinate;
-
-  // Adding new pixel to the seam path one by one until we reach the top.
-  let currentSeam = seamsEnergies[lastMinY][lastMinX];
-  while (currentSeam) {
-    seam.push(currentSeam.coordinate);
-    const prevMinCoordinates = currentSeam.previous;
-    if (!prevMinCoordinates) {
-      currentSeam = null;
-    } else {
-      const { x: prevMinX, y: prevMinY } = prevMinCoordinates;
-      currentSeam = seamsEnergies[prevMinY][prevMinX];
-    }
-  }
-
-  return seam;
-};
-```
-
-### Удаление шва с минимальной энергией
-
-Как только мы нашли шов с наименьшей суммарной энергией, нам нужно удалить (вырезать) пиксели, которые образуют его из изображения. Удаление происходит путем смещения пикселей справа от шва на `1px` влево. Из соображений производительности мы не будем удалять крайний столбик пикселей. Вместо этого, компонент, отвечающий за отрисовку уменьшенного изображения просто проигнорирует ту часть изображения, которая лежит за пределами обрезанной ширины.
-
-![Deleting the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png)
-
-```typescript
-// Deletes the seam from the image data.
-// We delete the pixel in each row and then shift the rest of the row pixels to the left.
-const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => {
-  seam.forEach(({ x: seamX, y: seamY }: Coordinate) => {
-    for (let x = seamX; x < (w - 1); x += 1) {
-      const nextPixel = getPixel(img, { x: x + 1, y: seamY });
-      setPixel(img, { x, y: seamY }, nextPixel);
-    }
-  });
-};
-```
-
-## Удаление объектов с изображения
-
-Seam Carving алгоритм пытается сначала удалить швы, состоящие из низкоэнергетических пикселей. Мы могли бы использовать этот факт и, присвоив низкую энергию некоторым пикселям вручную (например, нарисовав на изображении маску), мы могли бы заставить алгоритм удалить отмеченные пиксели (*объекты*).
-
-В настоящее время в функции `getPixelEnergy()` мы используем только каналы цветов `R`, `G`, `B` для вычисления энергии пикселей. Но есть еще и параметр `A` (альфа, прозрачность), который мы не использовали. Мы можем использовать канал прозрачности, чтобы "сказать" алгоритму, что прозрачные пиксели — это те пиксели, которые мы хотим удалить. Вы можете ознакомиться с [исходным кодом функции getPixelEnergy()](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54), которая учитывает прозрачность.
-
-Вот как при этом будет выглядеть удаление объектов:
-
-![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif)
-
-## Проблемы алгоритма и дальнейшие планы
-
-Приложение [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) далеко от идеала и не является приложением production-ready качества. Основной его целью была возможность интерактивного экспериментирования с алгоритмом. Поэтому в дальнейших планах — использовать его именно для экспериментов.
-
-В [оригинальной статье](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) описывается, как алгоритм может быть использован не только для уменьшения, но и для **увеличения изображения**. Увеличение (расширение) изображения, в свою очередь, может быть использовано для **автоматического расширения изображения до его исходной ширины после удаления объектов**.
-
-Еще одной интересной областью экспериментов может быть попытка ускорить алгоритм, чтобы он работал в режиме **реального времени**.
-
-> Таковы планы на будущее, но пока, надеюсь, пример с уменьшением изображения был интересен и полезен для вас. Также надеюсь, что вам было интересно увидеть применение динамического программирования в задачах, приближенных к реальности.
->
-> Удачи с вашими собственными экспериментами!
diff --git a/src/algorithms/linked-list/reverse-traversal/README.en-EN.md b/src/algorithms/linked-list/reverse-traversal/README.en-EN.md
new file mode 100644
index 0000000000..f6a0da0c50
--- /dev/null
+++ b/src/algorithms/linked-list/reverse-traversal/README.en-EN.md
@@ -0,0 +1,22 @@
+# Reversed Linked List Traversal
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The task is to traverse the given linked list in reversed order.
+
+For example for the following linked list:
+
+![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
+
+The order of traversal should be:
+
+```text
+37 → 99 → 12
+```
+
+The time complexity is `O(n)` because we visit every node only once.
+
+## Reference
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
diff --git a/src/algorithms/linked-list/reverse-traversal/README.md b/src/algorithms/linked-list/reverse-traversal/README.md
index 7e3f3cd6bb..df83582087 100644
--- a/src/algorithms/linked-list/reverse-traversal/README.md
+++ b/src/algorithms/linked-list/reverse-traversal/README.md
@@ -1,23 +1,22 @@
-# Reversed Linked List Traversal
+# Duyệt danh sách liên kết theo thứ tự ngược lại
 
-_Read this in other languages:_
-[_中文_](README.zh-CN.md),
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The task is to traverse the given linked list in reversed order.
+Nhiệm vụ là duyệt danh sách liên kết đã cho theo thứ tự ngược lại.
 
-For example for the following linked list: 
+Ví dụ cho danh sách liên kết sau:
 
 ![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
 
-The order of traversal should be:
+Thứ tự duyệt sẽ là:
 
 ```text
 37 → 99 → 12
 ```
 
-The time complexity is `O(n)` because we visit every node only once.
+Độ phức tạp về thời gian là `O(n)` vì chúng ta chỉ duyệt qua mỗi nút một lần.
 
-## Reference
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
diff --git a/src/algorithms/linked-list/reverse-traversal/README.pt-BR.md b/src/algorithms/linked-list/reverse-traversal/README.pt-BR.md
deleted file mode 100644
index b2761ad720..0000000000
--- a/src/algorithms/linked-list/reverse-traversal/README.pt-BR.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Travessia de Lista Encadeada Reversa
-
-_Leia isso em outros idiomas:_
-[_中文_](README.zh-CN.md),
-[_English_](README.md)
-
-A tarefa é percorrer a lista encadeada fornecida em ordem inversa.
-
-Por exemplo, para a seguinte lista vinculada:
-
-![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
-
-A ordem de travessia deve ser:
-
-```texto
-37 → 99 → 12
-```
-
-A complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez.
-
-## Referência
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
diff --git a/src/algorithms/linked-list/reverse-traversal/README.zh-CN.md b/src/algorithms/linked-list/reverse-traversal/README.zh-CN.md
deleted file mode 100644
index cf0217a5b1..0000000000
--- a/src/algorithms/linked-list/reverse-traversal/README.zh-CN.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# 链表倒序遍历
-
-我们的任务是倒序遍历给定的链表
-
-比如下面的链表
-
-![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
-
-遍历的顺序应该是
-
-```text
-37 → 99 → 12
-```
-
-因为我们每个节点只访问一次，时间复杂度应该是`O(n)`
-
-## 参考
-
-- [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8)
diff --git a/src/algorithms/linked-list/traversal/README.en-EN.md b/src/algorithms/linked-list/traversal/README.en-EN.md
new file mode 100644
index 0000000000..3a7d639c8c
--- /dev/null
+++ b/src/algorithms/linked-list/traversal/README.en-EN.md
@@ -0,0 +1,22 @@
+# Linked List Traversal
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The task is to traverse the given linked list in straight order.
+
+For example for the following linked list:
+
+![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
+
+The order of traversal should be:
+
+```text
+12 → 99 → 37
+```
+
+The time complexity is `O(n)` because we visit every node only once.
+
+## Reference
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
diff --git a/src/algorithms/linked-list/traversal/README.md b/src/algorithms/linked-list/traversal/README.md
index 09b177494c..cbb1da9129 100644
--- a/src/algorithms/linked-list/traversal/README.md
+++ b/src/algorithms/linked-list/traversal/README.md
@@ -1,9 +1,7 @@
 # Linked List Traversal
 
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md),
-[_中文_](README.zh-CN.md),
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
 The task is to traverse the given linked list in straight order.
 
diff --git a/src/algorithms/linked-list/traversal/README.pt-BR.md b/src/algorithms/linked-list/traversal/README.pt-BR.md
deleted file mode 100644
index 0fae9ed01a..0000000000
--- a/src/algorithms/linked-list/traversal/README.pt-BR.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Travessia de Lista Encadeada
-
-_Leia isso em outros idiomas:_
-[_Русский_](README.ru-RU.md),
-[_中文_](README.zh-CN.md),
-[_English_](README.md)
-
-A tarefa é percorrer a lista encadeada fornecida em ordem direta.
-
-Por exemplo, para a seguinte lista vinculada:
-
-![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
-
-A ordem de travessia deve ser:
-
-```texto
-12 → 99 → 37
-```
-
-A complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez.
-
-## Referência
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
diff --git a/src/algorithms/linked-list/traversal/README.ru-RU.md b/src/algorithms/linked-list/traversal/README.ru-RU.md
deleted file mode 100644
index fa3cfb2fb1..0000000000
--- a/src/algorithms/linked-list/traversal/README.ru-RU.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Обход связного списка
-
-Задача состоит в том, чтобы обойти связный список в прямом порядке.
-
-Например, для следующего связного списка:
-
-![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
-
-Порядок обхода будет такой:
-
-```text
-12 → 99 → 37
-```
-
-Временная сложность - `O(n)`, потому что мы посещаем каждый узел только один раз.
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA)
diff --git a/src/algorithms/linked-list/traversal/README.zh-CN.md b/src/algorithms/linked-list/traversal/README.zh-CN.md
deleted file mode 100644
index 19a01502b5..0000000000
--- a/src/algorithms/linked-list/traversal/README.zh-CN.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# 链表遍历
-
-我们的任务是顺序遍历给定的链表
-
-比如下面的链表
-
-![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
-
-遍历的顺序应该是
-
-```text
-12 → 99 → 37
-```
-
-因为我们每个节点只访问一次，时间复杂度应该是`O(n)`
-
-## 参考
-
-- [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8)
\ No newline at end of file
diff --git a/src/algorithms/math/binary-floating-point/README.en-EN.md b/src/algorithms/math/binary-floating-point/README.en-EN.md
new file mode 100644
index 0000000000..7585536a5a
--- /dev/null
+++ b/src/algorithms/math/binary-floating-point/README.en-EN.md
@@ -0,0 +1,106 @@
+# Binary representation of floating-point numbers
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Have you ever wondered how computers store the floating-point numbers like `3.1416` (𝝿) or `9.109 × 10⁻³¹` (the mass of the electron in kg) in the memory which is limited by a finite number of ones and zeroes (aka bits)?
+
+It seems pretty straightforward for integers (i.e. `17`). Let's say we have 16 bits (2 bytes) to store the number. In 16 bits we may store the integers in a range of `[0, 65535]`:
+
+```text
+(0000000000000000)₂ = (0)₁₀
+
+(0000000000010001)₂ =
+    (1 × 2⁴) +
+    (0 × 2³) +
+    (0 × 2²) +
+    (0 × 2¹) +
+    (1 × 2⁰) = (17)₁₀
+
+(1111111111111111)₂ =
+    (1 × 2¹⁵) +
+    (1 × 2¹⁴) +
+    (1 × 2¹³) +
+    (1 × 2¹²) +
+    (1 × 2¹¹) +
+    (1 × 2¹⁰) +
+    (1 × 2⁹) +
+    (1 × 2⁸) +
+    (1 × 2⁷) +
+    (1 × 2⁶) +
+    (1 × 2⁵) +
+    (1 × 2⁴) +
+    (1 × 2³) +
+    (1 × 2²) +
+    (1 × 2¹) +
+    (1 × 2⁰) = (65535)₁₀
+```
+
+If we need a signed integer we may use [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) and shift the range of `[0, 65535]` towards the negative numbers. In this case, our 16 bits would represent the numbers in a range of `[-32768, +32767]`.
+
+As you might have noticed, this approach won't allow you to represent the numbers like `-27.15625` (numbers after the decimal point are just being ignored).
+
+We're not the first ones who have noticed this issue though. Around ≈36 years ago some smart folks overcame this limitation by introducing the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard for floating-point arithmetic.
+
+The IEEE 754 standard describes the way (the framework) of using those 16 bits (or 32, or 64 bits) to store the numbers of wider range, including the small floating numbers (smaller than 1 and closer to 0).
+
+To get the idea behind the standard we might recall the [scientific notation](https://en.wikipedia.org/wiki/Scientific_notation) - a way of expressing numbers that are too large or too small (usually would result in a long string of digits) to be conveniently written in decimal form.
+
+![Scientific number notation](images/03-scientific-notation.png)
+
+As you may see from the image, the number representation might be split into three parts:
+
+- **sign**
+- **fraction (aka significand)** - the valuable digits (the meaning, the payload) of the number
+- **exponent** - controls how far and in which direction to move the decimal point in the fraction
+
+The **base** part we may omit by just agreeing on what it will be equal to. In our case, we'll be using `2` as a base.
+
+Instead of using all 16 bits (or 32 bits, or 64 bits) to store the fraction of the number, we may share the bits and store a sign, exponent, and fraction at the same time. Depending on the number of bits that we're going to use to store the number we end up with the following splits:
+
+| Floating-point format                                                                    | Total bits | Sign bits | Exponent bits | Fraction bits | Base |
+| :--------------------------------------------------------------------------------------- | :--------: | :-------: | :-----------: | :-----------: | :--: |
+| [Half-precision](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)     |     16     |     1     |       5       |      10       |  2   |
+| [Single-precision](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) |     32     |     1     |       8       |      23       |  2   |
+| [Double-precision](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) |     64     |     1     |      11       |      52       |  2   |
+
+With this approach, the number of bits for the fraction has been reduced (i.e. for the 16-bits number it was reduced from 16 bits to 10 bits). It means that the fraction might take a narrower range of values now (losing some precision). However, since we also have an exponent part, it will actually increase the ultimate number range and also allow us to describe the numbers between 0 and 1 (if the exponent is negative).
+
+> For example, a signed 32-bit integer variable has a maximum value of 2³¹ − 1 = 2,147,483,647, whereas an IEEE 754 32-bit base-2 floating-point variable has a maximum value of ≈ 3.4028235 × 10³⁸.
+
+To make it possible to have a negative exponent, the IEEE 754 standard uses the [biased exponent](https://en.wikipedia.org/wiki/Exponent_bias). The idea is simple - subtract the bias from the exponent value to make it negative. For example, if the exponent has 5 bits, it might take the values from the range of `[0, 31]` (all values are positive here). But if we subtract the value of `15` from it, the range will be `[-15, 16]`. The number `15` is called bias, and it is being calculated by the following formula:
+
+```
+exponent_bias = 2 ^ (k−1) − 1
+
+k - number of exponent bits
+```
+
+I've tried to describe the logic behind the converting of floating-point numbers from a binary format back to the decimal format on the image below. Hopefully, it will give you a better understanding of how the IEEE 754 standard works. The 16-bits number is being used here for simplicity, but the same approach works for 32-bits and 64-bits numbers as well.
+
+![Half-precision floating point number format explained in one picture](images/02-half-precision-floating-point-number-explained.png)
+
+> Checkout the [interactive version of this diagram](https://trekhleb.dev/blog/2021/binary-floating-point/) to play around with setting bits on and off, and seeing how it would influence the final result
+
+Here is the number ranges that different floating-point formats support:
+
+| Floating-point format | Exp min | Exp max | Range             | Min positive |
+| :-------------------- | :------ | :------ | :---------------- | :----------- |
+| Half-precision        | −14     | +15     | ±65,504           | 6.10 × 10⁻⁵  |
+| Single-precision      | −126    | +127    | ±3.4028235 × 10³⁸ | 1.18 × 10⁻³⁸ |
+
+Be aware that this is by no means a complete and sufficient overview of the IEEE 754 standard. It is rather a simplified and basic overview. Several corner cases were omitted in the examples above for simplicity of presentation (i.e. `-0`, `-∞`, `+∞` and `NaN` (not a number) values)
+
+## Code examples
+
+- See the [bitsToFloat.js](bitsToFloat.js) for the example of how to convert array of bits to the floating point number (the example is a bit artificial but still it gives the overview of how the conversion is going on)
+- See the [floatAsBinaryString.js](floatAsBinaryString.js) for the example of how to see the actual binary representation of the floating-point number in JavaScript
+
+## References
+
+You might also want to check out the following resources to get a deeper understanding of the binary representation of floating-point numbers:
+
+- [Interactive version of this article](https://trekhleb.dev/blog/2021/binary-floating-point/) (allows setting the bits manually and seeing the resulting floating number)
+- [Here is what you need to know about JavaScript’s Number type](https://indepth.dev/posts/1139/here-is-what-you-need-to-know-about-javascripts-number-type)
+- [Float Exposed](https://float.exposed/)
+- [IEEE754 Visualization](https://bartaz.github.io/ieee754-visualization/)
diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md
index d1ae72731e..97a866c28f 100644
--- a/src/algorithms/math/binary-floating-point/README.md
+++ b/src/algorithms/math/binary-floating-point/README.md
@@ -1,8 +1,11 @@
-# Binary representation of floating-point numbers
+# Biểu diễn nhị phân của số dấu chấm động
 
-Have you ever wondered how computers store the floating-point numbers like `3.1416` (𝝿) or `9.109 × 10⁻³¹` (the mass of the electron in kg) in the memory which is limited by a finite number of ones and zeroes (aka bits)?
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-It seems pretty straightforward for integers (i.e. `17`). Let's say we have 16 bits (2 bytes) to store the number. In 16 bits we may store the integers in a range of `[0, 65535]`:
+Bạn có bao giờ tự hỏi là máy tính lưu trữ các số dấu chấm động như `3.1416` (𝝿) hoặc `9.109 × 10⁻³¹` (khối lượng của electron tính bằng kg) trong bộ nhớ có hạn bởi một số hữu hạn các số một và số không (còn gọi là bit) không?
+
+Có vẻ khá đơn giản đối với số nguyên (ví dụ: `17`). Hãy nói chúng ta có 16 bit (2 byte) để lưu trữ số. Trong 16 bit, chúng ta có thể lưu trữ số nguyên trong một phạm vi `[0, 65535]`:
 
 ```text
 (0000000000000000)₂ = (0)₁₀
@@ -33,71 +36,74 @@ It seems pretty straightforward for integers (i.e. `17`). Let's say we have 16 b
     (1 × 2⁰) = (65535)₁₀
 ```
 
-If we need a signed integer we may use [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) and shift the range of `[0, 65535]` towards the negative numbers. In this case, our 16 bits would represent the numbers in a range of `[-32768, +32767]`.
+Nếu chúng ta cần một số nguyên có dấu, chúng ta có thể sử dụng [bù hai](https://en.wikipedia.org/wiki/Two%27s_complement) và dịch phạm vi từ `[0, 65535]` sang các số âm. Trong trường hợp này, 16 bit của chúng ta sẽ biểu diễn các số trong phạm vi `[-32768, +32767]`.
+
+Như bạn có thể đã nhận thấy, phương pháp này sẽ không cho phép bạn biểu diễn các số như `-27.15625` (các số sau dấu thập phân đơn giản chỉ bị bỏ qua).
 
-As you might have noticed, this approach won't allow you to represent the numbers like `-27.15625` (numbers after the decimal point are just being ignored).
+Tuy nhiên, chúng ta không phải là những người đầu tiên nhận thấy vấn đề này. Khoảng ≈36 năm trước, một số người thông minh đã vượt qua hạn chế này bằng cách giới thiệu tiêu chuẩn [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) cho phép tính toán số dấu chấm động.
 
-We're not the first ones who have noticed this issue though. Around ≈36 years ago some smart folks overcame this limitation by introducing the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard for floating-point arithmetic.
+Tiêu chuẩn IEEE 754 mô tả cách (khung) sử dụng các 16 bit đó (hoặc 32, hoặc 64 bit) để lưu trữ các số có phạm vi rộng hơn, bao gồm cả các số dấu chấm động nhỏ (nhỏ hơn 1 và gần với 0).
 
-The IEEE 754 standard describes the way (the framework) of using those 16 bits (or 32, or 64 bits) to store the numbers of wider range, including the small floating numbers (smaller than 1 and closer to 0).
+Để hiểu ý tưởng sau tiêu chuẩn, chúng ta có thể nhớ lại [cách biểu diễn khoa học](https://en.wikipedia.org/wiki/Scientific_notation) - cách biểu diễn các số quá lớn hoặc quá nhỏ (thường sẽ cho ra một chuỗi số dài) để viết dễ dàng hơn trong dạng thập phân.
 
-To get the idea behind the standard we might recall the [scientific notation](https://en.wikipedia.org/wiki/Scientific_notation) - a way of expressing numbers that are too large or too small (usually would result in a long string of digits) to be conveniently written in decimal form.
+![Biểu diễn số học](images/03-scientific-notation.png)
 
-![Scientific number notation](images/03-scientific-notation.png)
+Như bạn có thể thấy từ hình ảnh, biểu diễn số có thể được chia thành ba phần:
 
-As you may see from the image, the number representation might be split into three parts:
+- **dấu**
+- \*\*phân số (còn gọi là phần quan trọng)\*\* - các chữ số có giá trị (ý nghĩa, dữ liệu) của số
 
-- **sign**
-- **fraction (aka significand)** - the valuable digits (the meaning, the payload) of the number
-- **exponent** - controls how far and in which direction to move the decimal point in the fraction
+- **số mũ** - điều khiển việc di chuyển dấu thập phân ở phân số ra xa và theo hướng nào
 
-The **base** part we may omit by just agreeing on what it will be equal to. In our case, we'll be using `2` as a base.
+Phần **cơ số** chúng ta có thể bỏ qua bằng cách đồng ý về giá trị của nó. Trong trường hợp của chúng tôi, chúng tôi sẽ sử dụng `2` làm cơ số.
 
-Instead of using all 16 bits (or 32 bits, or 64 bits) to store the fraction of the number, we may share the bits and store a sign, exponent, and fraction at the same time. Depending on the number of bits that we're going to use to store the number we end up with the following splits:
+Thay vì sử dụng tất cả 16 bit (hoặc 32 bit, hoặc 64 bit) để lưu trữ phần phân số của số, chúng ta có thể chia sẻ các bit và lưu trữ dấu, số mũ và phân số cùng một lúc. Tùy thuộc vào số bit mà chúng ta sẽ sử dụng để lưu trữ số, chúng ta sẽ có các phân chia như sau:
 
-| Floating-point format | Total bits | Sign bits | Exponent bits | Fraction bits | Base |
-| :-------------------- | :--------: | :-------: | :-----------: | :--------------: | :--: |
-| [Half-precision](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)        | 16         | 1         | 5             | 10               | 2    |
-| [Single-precision](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)      | 32         | 1         | 8             | 23               | 2    |
-| [Double-precision](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)      | 64         | 1         | 11            | 52               | 2    |
+| Định dạng số dấu chấm động                                                               | Tổng số bit | Số bit dấu | Số bit số mũ | Số bit phân số | Cơ số |
+| :--------------------------------------------------------------------------------------- | :---------: | :--------: | :----------: | :------------: | :---: |
+| [Nửa độ chính xác](https://en.wikipedia.org/wiki/Half-precision_floating-point_format)   |     16      |     1      |      5       |       10       |   2   |
+| [Đơn độ chính xác](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) |     32      |     1      |      8       |       23       |   2   |
+| [Đôi độ chính xác](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) |     64      |     1      |      11      |       52       |   2   |
 
-With this approach, the number of bits for the fraction has been reduced (i.e. for the 16-bits number it was reduced from 16 bits to 10 bits). It means that the fraction might take a narrower range of values now (losing some precision). However, since we also have an exponent part, it will actually increase the ultimate number range and also allow us to describe the numbers between 0 and 1 (if the exponent is negative).
+Với cách tiếp cận này, số lượng bit cho phần phân số đã được giảm (ví dụ: đối với số 16 bit, nó đã được giảm từ 16 bit xuống còn 10 bit). Điều này có nghĩa là phần phân số có thể có một phạm vi giá trị hẹp hơn bây giờ (mất một số độ chính xác). Tuy nhiên, vì chúng ta cũng có một phần số mũ, điều này thực sự sẽ tăng phạm vi số cuối cùng và cũng cho phép chúng ta mô tả các số giữa 0 và 1 (nếu số mũ là âm).
 
-> For example, a signed 32-bit integer variable has a maximum value of 2³¹ − 1 = 2,147,483,647, whereas an IEEE 754 32-bit base-2 floating-point variable has a maximum value of ≈ 3.4028235 × 10³⁸.
+> Ví dụ, một biến số nguyên có dấu 32 bit có giá trị tối đa là 2³¹ − 1 = 2,147,483,647, trong khi một biến số dấu chấm động 32 bit theo chuẩn IEEE 754 có giá trị tối đa là ≈ 3.4028235 × 10³⁸.
 
-To make it possible to have a negative exponent, the IEEE 754 standard uses the [biased exponent](https://en.wikipedia.org/wiki/Exponent_bias). The idea is simple - subtract the bias from the exponent value to make it negative. For example, if the exponent has 5 bits, it might take the values from the range of `[0, 31]` (all values are positive here). But if we subtract the value of `15` from it, the range will be `[-15, 16]`. The number `15` is called bias, and it is being calculated by the following formula:
+Để có thể có số mũ âm, tiêu chuẩn IEEE 754 sử dụng [số mũ lệch](https://en.wikipedia.org/wiki/Exponent_bias). Ý tưởng đơn giản - trừ bias từ giá trị số mũ để làm cho nó trở thành số mũ âm. Ví dụ, nếu số mũ có 5 bit, nó có thể lấy các giá trị từ phạm vi `[0, 31]` (tất cả các giá trị ở đây đều là dương). Nhưng nếu chúng ta trừ giá trị `15` từ đó, phạm vi sẽ là `[-15, 16]`. Số `15` được gọi là bias, và nó được tính bằng công thức sau:
 
 ```
-exponent_bias = 2 ^ (k−1) − 1
+số mũ lệch = 2 ^ (k−1) − 1
 
-k - number of exponent bits
+k - số bit số mũ
 ```
 
-I've tried to describe the logic behind the converting of floating-point numbers from a binary format back to the decimal format on the image below. Hopefully, it will give you a better understanding of how the IEEE 754 standard works. The 16-bits number is being used here for simplicity, but the same approach works for 32-bits and 64-bits numbers as well.
+Tôi đã cố gắng mô tả logic sau việc chuyển đổi số dấu chấm động từ dạng nhị phân trở lại dạng thập phân trên hình ảnh dưới đây. Hy vọng, điều này sẽ giúp bạn hiểu rõ hơn về cách tiêu chuẩn IEEE 754 hoạt động. Số 16 bit được sử dụng ở đây để đơn giản hóa, nhưng cách tiếp cận tương tự cũng hoạt động cho các số 32 bit và 64 bit.
+
+![Định dạng số dấu chấm động nửa độ chính xác được giải thích trong một hình ảnh](images/02-half-precision-floating-point-number-explained.png)
 
-![Half-precision floating point number format explained in one picture](images/02-half-precision-floating-point-number-explained.png)
+> Kiểm tra [phiên bản tương tác của biểu đồ này](https://trekhleb.dev/blog/2021/binary-floating-point/) để chơi với việc thiết lập bit bật và tắt, và xem làm thế nào nó sẽ ảnh hưởng đến kết quả cuối cùng
 
-> Checkout the [interactive version of this diagram](https://trekhleb.dev/blog/2021/binary-floating-point/) to play around with setting bits on and off, and seeing how it would influence the final result
+Dưới đây là phạm vi số mà các định dạng số dấu chấm động khác nhau hỗ trợ:
 
-Here is the number ranges that different floating-point formats support:
+| Định dạng số dấu chấm động | Số mũ tối thiểu | Số mũ tối đa | Phạm vi | Số dương nhỏ nhất |
+| :------------------------- | :-------------- | :----------- | :------ | :---------------- |
+| Nửa độ chính xác           | −14             | +15          | ±65,504 | 6.10 ×            |
 
-| Floating-point format | Exp min | Exp max | Range            | Min positive |
-| :-------------------- | :------ | :------ | :--------------- | :----------- |
-| Half-precision        | −14     | +15     | ±65,504          | 6.10 × 10⁻⁵  |
-| Single-precision      | −126    | +127    | ±3.4028235 × 10³⁸| 1.18 × 10⁻³⁸ |
+10⁻⁵ |
+| Đơn độ chính xác | −126 | +127 | ±3.4028235 × 10³⁸ | 1.18 × 10⁻³⁸ |
 
-Be aware that this is by no means a complete and sufficient overview of the IEEE 754 standard. It is rather a simplified and basic overview. Several corner cases were omitted in the examples above for simplicity of presentation (i.e. `-0`, `-∞`, `+∞` and `NaN` (not a number) values)
+Hãy nhớ rằng đây hoàn toàn không phải là một cái nhìn toàn diện và đầy đủ về tiêu chuẩn IEEE 754. Đây thực sự là một cái nhìn tổng quan và đơn giản. Một số trường hợp cụ thể đã bị bỏ qua trong các ví dụ trên để đơn giản hóa trong quá trình trình bày (ví dụ: `-0`, `-∞`, `+∞` và giá trị `NaN` (không phải là một số))
 
-## Code examples
+## Ví dụ mã
 
-- See the [bitsToFloat.js](bitsToFloat.js) for the example of how to convert array of bits to the floating point number (the example is a bit artificial but still it gives the overview of how the conversion is going on)
-- See the [floatAsBinaryString.js](floatAsBinaryString.js) for the example of how to see the actual binary representation of the floating-point number in JavaScript
+- Xem tệp [bitsToFloat.js](bitsToFloat.js) để xem ví dụ về cách chuyển đổi mảng bit thành số dấu chấm động (ví dụ này hơi nhân tạo nhưng vẫn cho cái nhìn tổng quan về cách chuyển đổi đang diễn ra)
+- Xem tệp [floatAsBinaryString.js](floatAsBinaryString.js) để xem ví dụ về cách xem biểu diễn nhị phân thực sự của số dấu chấm động trong JavaScript
 
-## References
+## Tham khảo
 
-You might also want to check out the following resources to get a deeper understanding of the binary representation of floating-point numbers:
+Bạn cũng có thể muốn kiểm tra các tài nguyên sau để hiểu sâu hơn về biểu diễn nhị phân của số dấu chấm động:
 
-- [Interactive version of this article](https://trekhleb.dev/blog/2021/binary-floating-point/) (allows setting the bits manually and seeing the resulting floating number)
-- [Here is what you need to know about JavaScript’s Number type](https://indepth.dev/posts/1139/here-is-what-you-need-to-know-about-javascripts-number-type)
+- [Phiên bản tương tác của bài viết này](https://trekhleb.dev/blog/2021/binary-floating-point/) (cho phép thiết lập các bit bật và tắt thủ công và xem số dấu chấm động kết quả)
+- [Đây là những gì bạn cần biết về kiểu số JavaScript](https://indepth.dev/posts/1139/here-is-what-you-need-to-know-about-javascripts-number-type)
 - [Float Exposed](https://float.exposed/)
-- [IEEE754 Visualization](https://bartaz.github.io/ieee754-visualization/)
+- [Trực quan hóa IEEE754](https://bartaz.github.io/ieee754-visualization/)
diff --git a/src/algorithms/math/bits/README.en-EN.md b/src/algorithms/math/bits/README.en-EN.md
new file mode 100644
index 0000000000..361d2824a9
--- /dev/null
+++ b/src/algorithms/math/bits/README.en-EN.md
@@ -0,0 +1,273 @@
+# Bit Manipulation
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+#### Get Bit
+
+This method shifts the relevant bit to the zeroth position.
+Then we perform `AND` operation with one which has bit
+pattern like `0001`. This clears all bits from the original
+number except the relevant one. If the relevant bit is one,
+the result is `1`, otherwise the result is `0`.
+
+> See [getBit.js](getBit.js) for further details.
+
+#### Set Bit
+
+This method shifts `1` over by `bitPosition` bits, creating a
+value that looks like `00100`. Then we perform `OR` operation
+that sets specific bit into `1` but it does not affect on
+other bits of the number.
+
+> See [setBit.js](setBit.js) for further details.
+
+#### Clear Bit
+
+This method shifts `1` over by `bitPosition` bits, creating a
+value that looks like `00100`. Than it inverts this mask to get
+the number that looks like `11011`. Then `AND` operation is
+being applied to both the number and the mask. That operation
+unsets the bit.
+
+> See [clearBit.js](clearBit.js) for further details.
+
+#### Update Bit
+
+This method is a combination of "Clear Bit" and "Set Bit" methods.
+
+> See [updateBit.js](updateBit.js) for further details.
+
+#### isEven
+
+This method determines if the number provided is even.
+It is based on the fact that odd numbers have their last
+right bit to be set to 1.
+
+```text
+Number: 5 = 0b0101
+isEven: false
+
+Number: 4 = 0b0100
+isEven: true
+```
+
+> See [isEven.js](isEven.js) for further details.
+
+#### isPositive
+
+This method determines if the number is positive. It is based on the fact that all positive
+numbers have their leftmost bit to be set to `0`. However, if the number provided is zero
+or negative zero, it should still return `false`.
+
+```text
+Number: 1 = 0b0001
+isPositive: true
+
+Number: -1 = -0b0001
+isPositive: false
+```
+
+> See [isPositive.js](isPositive.js) for further details.
+
+#### Multiply By Two
+
+This method shifts original number by one bit to the left.
+Thus all binary number components (powers of two) are being
+multiplying by two and thus the number itself is being
+multiplied by two.
+
+```
+Before the shift
+Number: 0b0101 = 5
+Powers of two: 0 + 2^2 + 0 + 2^0
+
+After the shift
+Number: 0b1010 = 10
+Powers of two: 2^3 + 0 + 2^1 + 0
+```
+
+> See [multiplyByTwo.js](multiplyByTwo.js) for further details.
+
+#### Divide By Two
+
+This method shifts original number by one bit to the right.
+Thus all binary number components (powers of two) are being
+divided by two and thus the number itself is being
+divided by two without remainder.
+
+```
+Before the shift
+Number: 0b0101 = 5
+Powers of two: 0 + 2^2 + 0 + 2^0
+
+After the shift
+Number: 0b0010 = 2
+Powers of two: 0 + 0 + 2^1 + 0
+```
+
+> See [divideByTwo.js](divideByTwo.js) for further details.
+
+#### Switch Sign
+
+This method make positive numbers to be negative and backwards.
+To do so it uses "Twos Complement" approach which does it by
+inverting all of the bits of the number and adding 1 to it.
+
+```
+1101 -3
+1110 -2
+1111 -1
+0000  0
+0001  1
+0010  2
+0011  3
+```
+
+> See [switchSign.js](switchSign.js) for further details.
+
+#### Multiply Two Signed Numbers
+
+This method multiplies two signed integer numbers using bitwise operators.
+This method is based on the following facts:
+
+```text
+a * b can be written in the below formats:
+  0                     if a is zero or b is zero or both a and b are zeroes
+  2a * (b/2)            if b is even
+  2a * (b - 1)/2 + a    if b is odd and positive
+  2a * (b + 1)/2 - a    if b is odd and negative
+```
+
+The advantage of this approach is that in each recursive step one of the operands
+reduces to half its original value. Hence, the run time complexity is `O(log(b))` where `b` is
+the operand that reduces to half on each recursive step.
+
+> See [multiply.js](multiply.js) for further details.
+
+#### Multiply Two Unsigned Numbers
+
+This method multiplies two integer numbers using bitwise operators.
+This method is based on that "Every number can be denoted as the sum of powers of 2".
+
+The main idea of bitwise multiplication is that every number may be split
+to the sum of powers of two:
+
+I.e.
+
+```text
+19 = 2^4 + 2^1 + 2^0
+```
+
+Then multiplying number `x` by `19` is equivalent of:
+
+```text
+x * 19 = x * 2^4 + x * 2^1 + x * 2^0
+```
+
+Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
+by `4` bits (`x << 4`).
+
+> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.
+
+#### Count Set Bits
+
+This method counts the number of set bits in a number using bitwise operators.
+The main idea is that we shift the number right by one bit at a time and check
+the result of `&` operation that is `1` if bit is set and `0` otherwise.
+
+```text
+Number: 5 = 0b0101
+Count of set bits = 2
+```
+
+> See [countSetBits.js](countSetBits.js) for further details.
+
+#### Count Bits to Flip One Number to Another
+
+This methods outputs the number of bits required to convert one number to another.
+This makes use of property that when numbers are `XOR`-ed the result will be number
+of different bits.
+
+```
+5 = 0b0101
+1 = 0b0001
+Count of Bits to be Flipped: 1
+```
+
+> See [bitsDiff.js](bitsDiff.js) for further details.
+
+#### Count Bits of a Number
+
+To calculate the number of valuable bits we need to shift `1` one bit left each
+time and see if shifted number is bigger than the input number.
+
+```
+5 = 0b0101
+Count of valuable bits is: 3
+When we shift 1 four times it will become bigger than 5.
+```
+
+> See [bitLength.js](bitLength.js) for further details.
+
+#### Is Power of Two
+
+This method checks if a number provided is power of two. It uses the following
+property. Let's say that `powerNumber` is a number that has been formed as a power
+of two (i.e. 2, 4, 8, 16 etc.). Then if we'll do `&` operation between `powerNumber`
+and `powerNumber - 1` it will return `0` (in case if number is power of two).
+
+```
+Number: 4 = 0b0100
+Number: 3 = (4 - 1) = 0b0011
+4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two.
+
+Number: 10 = 0b01010
+Number: 9 = (10 - 1) = 0b01001
+10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two.
+```
+
+> See [isPowerOfTwo.js](isPowerOfTwo.js) for further details.
+
+#### Full Adder
+
+This method adds up two integer numbers using bitwise operators.
+
+It implements [full adder](<https://en.wikipedia.org/wiki/Adder_(electronics)>)
+electronics circuit logic to sum two 32-bit integers in two's complement format.
+It's using the boolean logic to cover all possible cases of adding two input bits:
+with and without a "carry bit" from adding the previous less-significant stage.
+
+Legend:
+
+- `A`: Number `A`
+- `B`: Number `B`
+- `ai`: ith bit of number `A`
+- `bi`: ith bit of number `B`
+- `carryIn`: a bit carried in from the previous less-significant stage
+- `carryOut`: a bit to carry to the next most-significant stage
+- `bitSum`: The sum of `ai`, `bi`, and `carryIn`
+- `resultBin`: The full result of adding current stage with all less-significant stages (in binary)
+- `resultDec`: The full result of adding current stage with all less-significant stages (in decimal)
+
+```
+A = 3: 011
+B = 6: 110
+┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐
+│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │
+├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤
+│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │
+│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │
+│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │
+│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │
+└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘
+```
+
+> See [fullAdder.js](fullAdder.js) for further details.
+> See [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).
+
+## References
+
+- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)
diff --git a/src/algorithms/math/bits/README.fr-FR.md b/src/algorithms/math/bits/README.fr-FR.md
deleted file mode 100644
index 64ccd2dde1..0000000000
--- a/src/algorithms/math/bits/README.fr-FR.md
+++ /dev/null
@@ -1,295 +0,0 @@
-# Manipulation de bits
-
-_Read this in other languages:_
-[english](README.md).
-
-#### Vérifier un bit (_get_)
-
-Cette méthode décale le bit correspondant (_bit shifting_) à la position zéro.
-Ensuite, nous exécutons l'opération `AND` avec un masque comme `0001`.
-Cela efface tous les bits du nombre original sauf le correspondant.
-Si le bit pertinent est `1`, le résultat est `1`, sinon le résultat est `0`.
-
-> Voir [getBit.js](getBit.js) pour plus de détails.
-
-#### Mettre un bit à 1(_set_)
-
-Cette méthode met un bit à `1` en fonction d'un rang (`bitPosition`),
-créant ainsi une valeur qui ressemble à `00100`.
-Ensuite, nous effectuons l'opération `OU` qui met un bit spécifique
-en `1` sans affecter les autres bits du nombre.
-
-> Voir [setBit.js](setBit.js) pour plus de détails.
-
-#### Mettre un bit à 0 (_clear_)
-
-Cette méthode met un bit à `1` en fonction d'un rang (`bitPosition`),
-créant ainsi une valeur qui ressemble à `00100`.
-Puis on inverse ce masque de bits pour obtenir un nombre ressemblant à `11011`.
-Enfin, l'opération `AND` est appliquée au nombre et au masque.
-Cette opération annule le bit.
-
-> Voir [clearBit.js](clearBit.js) pour plus de détails.
-
-#### Mettre à jour un Bit (_update_)
-
-Cette méthode est une combinaison de l'"annulation de bit"
-et du "forçage de bit".
-
-> Voir [updateBit.js](updateBit.js) pour plus de détails.
-
-#### Vérifier si un nombre est pair (_isEven_)
-
-Cette méthode détermine si un nombre donné est pair.
-Elle s'appuie sur le fait que les nombres impairs ont leur dernier
-bit droit à `1`.
-
-```text
-Nombre: 5 = 0b0101
-isEven: false
-
-Nombre: 4 = 0b0100
-isEven: true
-```
-
-> Voir [isEven.js](isEven.js) pour plus de détails.
-
-#### Vérifier si un nombre est positif (_isPositive_)
-
-Cette méthode détermine un le nombre donné est positif.
-Elle s'appuie sur le fait que tous les nombres positifs
-ont leur bit le plus à gauche à `0`.
-Cependant, si le nombre fourni est zéro
-ou zéro négatif, il doit toujours renvoyer `false`.
-
-```text
-Nombre: 1 = 0b0001
-isPositive: true
-
-Nombre: -1 = -0b0001
-isPositive: false
-```
-
-> Voir [isPositive.js](isPositive.js) pour plus de détails.
-
-#### Multiplier par deux
-
-Cette méthode décale un nombre donné d'un bit vers la gauche.
-Ainsi, toutes les composantes du nombre binaire (en puissances de deux) sont
-multipliées par deux et donc le nombre lui-même est
-multiplié par deux.
-
-```
-Avant le décalage
-Nombre: 0b0101 = 5
-Puissances de deux: 0 + 2^2 + 0 + 2^0
-
-Après le décalage
-Nombre: 0b1010 = 10
-Puissances de deux: 2^3 + 0 + 2^1 + 0
-```
-
-> Voir [multiplyByTwo.js](multiplyByTwo.js) pour plus de détails.
-
-#### Diviser par deux
-
-Cette méthode décale un nombre donné d'un bit vers la droite.
-Ainsi, toutes les composantes du nombre binaire (en puissances de deux) sont
-divisées par deux et donc le nombre lui-même est
-divisé par deux, sans reste.
-
-```
-Avant le décalage
-Nombre: 0b0101 = 5
-Puissances de deux: 0 + 2^2 + 0 + 2^0
-
-Après le décalage
-Nombre: 0b0010 = 2
-Puissances de deux: 0 + 0 + 2^1 + 0
-```
-
-> Voir [divideByTwo.js](divideByTwo.js) pour plus de détails.
-
-#### Inverser le signe (_Switch Sign_)
-
-Cette méthode rend positifs les nombres négatifs, et vice-versa.
-Pour ce faire, elle s'appuie sur l'approche "Complément à deux",
-qui inverse tous les bits du nombre et y ajoute 1.
-
-```
-1101 -3
-1110 -2
-1111 -1
-0000  0
-0001  1
-0010  2
-0011  3
-```
-
-> Voir [switchSign.js](switchSign.js) pour plus de détails.
-
-#### Multiplier deux nombres signés
-
-Cette méthode multiplie deux nombres entiers signés
-à l'aide d'opérateurs bit à bit.
-Cette méthode est basée sur les faits suivants:
-
-```text
-a * b peut être écrit sous les formes suivantes:
-  0                     si a est zero ou b est zero ou les deux sont zero
-  2a * (b/2)            si b est pair
-  2a * (b - 1)/2 + a    si b est impair et positif
-  2a * (b + 1)/2 - a    si b est impair et negatif
-```
-
-L'avantage de cette approche est qu'à chaque étape de la récursion
-l'un des opérandes est réduit à la moitié de sa valeur d'origine.
-Par conséquent, la complexité d'exécution est `O(log(b))`
-où `b` est l'opérande qui se réduit de moitié à chaque récursion.
-
-> Voir [multiply.js](multiply.js) pour plus de détails.
-
-#### Multiplier deux nombres positifs
-
-Cette méthode multiplie deux nombres entiers à l'aide d'opérateurs bit à bit.
-Cette méthode s'appuie sur le fait que "Chaque nombre peut être lu
-comme une somme de puissances de 2".
-
-L'idée principale de la multiplication bit à bit
-est que chaque nombre peut être divisé en somme des puissances de deux:
-
-Ainsi
-
-```text
-19 = 2^4 + 2^1 + 2^0
-```
-
-Donc multiplier `x` par `19` est equivalent à :
-
-```text
-x * 19 = x * 2^4 + x * 2^1 + x * 2^0
-```
-
-Nous devons maintenant nous rappeler que `x * 2 ^ 4` équivaut
-à déplacer`x` vers la gauche par `4` bits (`x << 4`).
-
-> Voir [multiplyUnsigned.js](multiplyUnsigned.js) pour plus de détails.
-
-#### Compter les bits à 1
-
-This method counts the number of set bits in a number using bitwise operators.
-The main idea is that we shift the number right by one bit at a time and check
-the result of `&` operation that is `1` if bit is set and `0` otherwise.
-
-Cette méthode décompte les bits à `1` d'un nombre
-à l'aide d'opérateurs bit à bit.
-L'idée principale est de décaler le nombre vers la droite, un bit à la fois,
-et de vérifier le résultat de l'opération `&` :
-`1` si le bit est défini et `0` dans le cas contraire.
-
-```text
-Nombre: 5 = 0b0101
-Décompte des bits à 1 = 2
-```
-
-> Voir [countSetBits.js](countSetBits.js) pour plus de détails.
-
-#### Compter les bits nécessaire pour remplacer un nombre
-
-This methods outputs the number of bits required to convert one number to another.
-This makes use of property that when numbers are `XOR`-ed the result will be number
-of different bits.
-
-Cette méthode retourne le nombre de bits requis
-pour convertir un nombre en un autre.
-Elle repose sur la propriété suivante:
-lorsque les nombres sont évalués via `XOR`, le résultat est le nombre
-de bits différents entre les deux.
-
-```
-5 = 0b0101
-1 = 0b0001
-Nombre de bits pour le remplacement: 1
-```
-
-> Voir [bitsDiff.js](bitsDiff.js) pour plus de détails.
-
-#### Calculer les bits significatifs d'un nombre
-
-Pour connaître les bits significatifs d'un nombre,
-on peut décaler `1` d'un bit à gauche plusieurs fois d'affilée
-jusqu'à ce que ce nombre soit plus grand que le nombre à comparer.
-
-```
-5 = 0b0101
-Décompte des bits significatifs: 3
-On décale 1 quatre fois pour dépasser 5.
-```
-
-> Voir [bitLength.js](bitLength.js) pour plus de détails.
-
-#### Vérifier si un nombre est une puissance de 2
-
-Cette méthode vérifie si un nombre donné est une puissance de deux.
-Elle s'appuie sur la propriété suivante.
-Disons que `powerNumber` est une puissance de deux (c'est-à-dire 2, 4, 8, 16 etc.).
-Si nous faisons l'opération `&` entre `powerNumber` et `powerNumber - 1`,
-elle retournera`0` (dans le cas où le nombre est une puissance de deux).
-
-```
-Nombre: 4 = 0b0100
-Nombre: 3 = (4 - 1) = 0b0011
-4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Égal à zéro, car c'est une puissance de 2.
-
-Nombre: 10 = 0b01010
-Nombre: 9 = (10 - 1) = 0b01001
-10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Différent de 0, donc n'est pas une puissance de 2.
-```
-
-> Voir [isPowerOfTwo.js](isPowerOfTwo.js) pour plus de détails.
-
-#### Additionneur complet
-
-Cette méthode ajoute deux nombres entiers à l'aide d'opérateurs bit à bit.
-
-Elle implémente un [additionneur](https://fr.wikipedia.org/wiki/Additionneur)
-simulant un circuit électronique logique,
-pour additionner deux entiers de 32 bits,
-sous la forme « complément à deux ».
-Elle utilise la logique booléenne pour couvrir tous les cas possibles
-d'ajout de deux bits donnés:
-avec et sans retenue de l'ajout de l'étape précédente la moins significative.
-
-Légende:
-
-- `A`: Nombre `A`
-- `B`: Nombre `B`
-- `ai`: ième bit du nombre `A`
-- `bi`: ième bit du nombre `B`
-- `carryIn`: un bit retenu de la précédente étape la moins significative
-- `carryOut`: un bit retenu pour la prochaine étape la plus significative
-- `bitSum`: La somme de `ai`, `bi`, et `carryIn`
-- `resultBin`: Le résultat complet de l'ajout de l'étape actuelle avec toutes les étapes moins significatives (en binaire)
-- `resultDec`: Le résultat complet de l'ajout de l'étape actuelle avec toutes les étapes moins significatives (en decimal)
-
-```
-A = 3: 011
-B = 6: 110
-┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐
-│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │
-├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤
-│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │
-│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │
-│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │
-│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │
-└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘
-```
-
-> Voir [fullAdder.js](fullAdder.js) pour plus de détails.  
-> Voir [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).
-
-## Références
-
-- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)
diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md
index 1218094287..358b50c75d 100644
--- a/src/algorithms/math/bits/README.md
+++ b/src/algorithms/math/bits/README.md
@@ -1,119 +1,116 @@
 # Bit Manipulation
 
-_Read this in other languages:_
-[français](README.fr-FR.md),
-[简体中文](README.zh-CN.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-#### Get Bit
+#### Lấy Bit
 
-This method shifts the relevant bit to the zeroth position.
-Then we perform `AND` operation with one which has bit
-pattern like `0001`. This clears all bits from the original
-number except the relevant one. If the relevant bit is one,
-the result is `1`, otherwise the result is `0`.
+Phương thức này dịch chuyển bit liên quan đến vị trí số 0.
+Sau đó, chúng ta thực hiện phép `AND` với số một có dạng bit
+như `0001`. Điều này xóa tất cả các bit từ số gốc
+ngoại trừ bit liên quan. Nếu bit liên quan là một,
+kết quả là `1`, nếu không, kết quả là `0`.
 
-> See [getBit.js](getBit.js) for further details.
+> Xem [getBit.js](getBit.js) để biết thêm chi tiết.
 
-#### Set Bit
+#### Đặt Bit
 
-This method shifts `1` over by `bitPosition` bits, creating a
-value that looks like `00100`. Then we perform `OR` operation
-that sets specific bit into `1` but it does not affect on
-other bits of the number.
+Phương thức này dịch `1` qua `bitPosition` bit, tạo ra một
+giá trị có dạng `00100`. Sau đó, chúng ta thực hiện phép `OR`
+đặt bit cụ thể thành `1` nhưng không ảnh hưởng đến
+các bit khác của số.
 
-> See [setBit.js](setBit.js) for further details.
+> Xem [setBit.js](setBit.js) để biết thêm chi tiết.
 
-#### Clear Bit
+#### Xóa Bit
 
-This method shifts `1` over by `bitPosition` bits, creating a
-value that looks like `00100`. Than it inverts this mask to get
-the number that looks like `11011`. Then `AND` operation is
-being applied to both the number and the mask. That operation
-unsets the bit.
+Phương thức này dịch `1` qua `bitPosition` bit, tạo ra một
+giá trị có dạng `00100`. Sau đó, nó đảo ngược mặt nạ này để có được
+số giống như `11011`. Sau đó, phép `AND` được áp dụng
+với cả số và mặt nạ. Phép toán này loại bỏ bit đó.
 
-> See [clearBit.js](clearBit.js) for further details.
+> Xem [clearBit.js](clearBit.js) để biết thêm chi tiết.
 
-#### Update Bit
+#### Cập Nhật Bit
 
-This method is a combination of "Clear Bit" and "Set Bit" methods.
+Phương thức này là sự kết hợp của các phương thức "Xóa Bit" và "Đặt Bit".
 
-> See [updateBit.js](updateBit.js) for further details.
+> Xem [updateBit.js](updateBit.js) để biết thêm chi tiết.
 
 #### isEven
 
-This method determines if the number provided is even.
-It is based on the fact that odd numbers have their last
-right bit to be set to 1.
+Phương thức này xác định xem số được cung cấp có là số chẵn không.
+Nó dựa trên sự thật rằng số lẻ có bit cuối cùng ở phải cùng được thiết lập thành 1.
 
 ```text
-Number: 5 = 0b0101
+Số: 5 = 0b0101
 isEven: false
 
-Number: 4 = 0b0100
+Số: 4 = 0b0100
 isEven: true
 ```
 
-> See [isEven.js](isEven.js) for further details.
+> Xem [isEven.js](isEven.js) để biết thêm chi tiết.
 
 #### isPositive
 
-This method determines if the number is positive. It is based on the fact that all positive
-numbers have their leftmost bit to be set to `0`. However, if the number provided is zero
-or negative zero, it should still return `false`.
+Phương thức này xác định xem số có là số dương không. Nó dựa trên sự thật rằng tất cả
+các số dương có bit đầu tiên bên trái được thiết lập thành `0`. Tuy nhiên, nếu số được cung cấp là không
+hoặc số không âm, nó vẫn nên trả về `false`.
 
 ```text
-Number: 1 = 0b0001
+Số: 1 = 0b0001
 isPositive: true
 
-Number: -1 = -0b0001
+Số: -1 = -0b0001
 isPositive: false
 ```
 
-> See [isPositive.js](isPositive.js) for further details.
+> Xem [isPositive.js](isPositive.js) để biết thêm chi tiết.
 
-#### Multiply By Two
+#### Nhân Lên Hai
 
-This method shifts original number by one bit to the left.
-Thus all binary number components (powers of two) are being
-multiplying by two and thus the number itself is being
-multiplied by two.
+Phương thức này dịch số gốc một bit sang trái.
+Do đó, tất cả các thành phần số nhị phân (lũy thừa của hai) đều
+được nhân lên hai và do đó chính số đó được
+nhân lên hai.
 
 ```
-Before the shift
-Number: 0b0101 = 5
-Powers of two: 0 + 2^2 + 0 + 2^0
+Trước khi dịch
+Số: 0b0101 = 5
+Lũy thừa của hai: 0 + 2^2 + 0 + 2^0
 
-After the shift
-Number: 0b1010 = 10
-Powers of two: 2^3 + 0 + 2^1 + 0
+Sau khi dịch
+Số: 0b1010 = 10
+Lũy thừa của hai: 2^3 + 0 + 2^1 + 0
 ```
 
-> See [multiplyByTwo.js](multiplyByTwo.js) for further details.
+> Xem [multiplyByTwo.js](multiplyByTwo.js) để biết thêm chi tiết.
 
-#### Divide By Two
+#### Chia Cho Hai
 
-This method shifts original number by one bit to the right.
-Thus all binary number components (powers of two) are being
-divided by two and thus the number itself is being
-divided by two without remainder.
+Phương thức này dịch số gốc một bit sang phải.
+Do đó, tất cả các thành phần số nhị phân (lũy thừa của hai) đều
+bị chia cho hai và do đó chính số đó được
+chia cho hai mà không có dư.
 
 ```
-Before the shift
-Number: 0b0101 = 5
-Powers of two: 0 + 2^2 + 0 + 2^0
+Trước khi dịch
+Số: 0b0101 = 5
+Lũy thừa của hai: 0 + 2^2 + 0 + 2^0
 
-After the shift
-Number: 0b0010 = 2
-Powers of two: 0 + 0 + 2^1 + 0
+Sau khi dịch
+Số: 0b0010 = 2
+Lũy thừa của hai: 0 + 0 + 2^1 + 0
 ```
 
-> See [divideByTwo.js](divideByTwo.js) for further details.
+> Xem [divideByTwo.js](divideByTwo.js) để biết thêm chi tiết.
 
-#### Switch Sign
+#### Đảo Dấu
 
-This method make positive numbers to be negative and backwards.
-To do so it uses "Twos Complement" approach which does it by
-inverting all of the bits of the number and adding 1 to it.
+Phương thức này biến số dương thành số âm và ngược lại.
+Để làm điều này, nó sử dụng phương pháp "Bù Hai" mà làm điều đó bằng cách
+đảo ngược tất cả các bit của số và thêm 1 vào nó.
 
 ```
 1101 -3
@@ -125,131 +122,136 @@ inverting all of the bits of the number and adding 1 to it.
 0011  3
 ```
 
-> See [switchSign.js](switchSign.js) for further details.
+> Xem [switchSign.js](switchSign.js) để biết thêm chi tiết.
 
-#### Multiply Two Signed Numbers
+#### Nhân Hai Số Có Dấu
 
-This method multiplies two signed integer numbers using bitwise operators.
-This method is based on the following facts:
+Phương thức này nhân hai số nguyên có dấu bằng các toán tử bitwise.
+Phương thức này dựa trên các sự thật sau:
 
-```text
-a * b can be written in the below formats:
-  0                     if a is zero or b is zero or both a and b are zeroes
-  2a * (b/2)            if b is even
-  2a * (b - 1)/2 + a    if b is odd and positive
-  2a * (b + 1)/2 - a    if b is odd and negative
-```
+````text
+a * b có thể được viết ở các định dạng sau:
+  0                     nếu a là số không hoặc b là số không hoặc cả hai a và b đều là số không
+  2a * (b/2)            nếu b là số chẵn
+  2a * (b - 1)/2 + a    nếu b là số lẻ và dương
+  2a * (b + 1)/2 - a    nếu b là số lẻ và âm
+``
+
+`
 
-The advantage of this approach is that in each recursive step one of the operands
-reduces to half its original value. Hence, the run time complexity is `O(log(b))` where `b` is
-the operand that reduces to half on each recursive step.
+Ưu điểm của phương pháp này là trong mỗi bước đệ quy một trong các toán hạng
+giảm xuống còn một nửa giá trị ban đầu của nó. Do đó, độ phức tạp thời gian chạy là `O(log(b))` với `b` là
+toán hạng giảm xuống một nửa trong mỗi bước đệ quy.
 
-> See [multiply.js](multiply.js) for further details.
+> Xem [multiply.js](multiply.js) để biết thêm chi tiết.
 
-#### Multiply Two Unsigned Numbers
+#### Nhân Hai Số Không Dấu
 
-This method multiplies two integer numbers using bitwise operators.
-This method is based on that "Every number can be denoted as the sum of powers of 2".
+Phương thức này nhân hai số nguyên bằng các toán tử bitwise.
+Phương pháp này dựa trên việc "Mọi số có thể được biểu diễn dưới dạng tổng của lũy thừa của 2".
 
-The main idea of bitwise multiplication is that every number may be split
-to the sum of powers of two:
+Ý tưởng chính của việc nhân theo cách bitwise là mọi số có thể được chia ra
+thành tổng của lũy thừa của hai:
 
-I.e.
+Ví dụ
 
 ```text
 19 = 2^4 + 2^1 + 2^0
-```
+````
 
-Then multiplying number `x` by `19` is equivalent of:
+Sau đó, việc nhân số `x` với `19` tương đương với:
 
 ```text
 x * 19 = x * 2^4 + x * 2^1 + x * 2^0
 ```
 
-Now we need to remember that `x * 2^4` is equivalent of shifting `x` left
-by `4` bits (`x << 4`).
+Bây giờ chúng ta cần nhớ rằng `x * 2^4` tương đương với dịch `x` sang trái
+bởi `4` bit (`x << 4`).
 
-> See [multiplyUnsigned.js](multiplyUnsigned.js) for further details.
+> Xem [multiplyUnsigned.js](multiplyUnsigned.js) để biết thêm chi tiết.
 
-#### Count Set Bits
+#### Đếm Các Bit Được Đặt
 
-This method counts the number of set bits in a number using bitwise operators.
-The main idea is that we shift the number right by one bit at a time and check
-the result of `&` operation that is `1` if bit is set and `0` otherwise.
+Phương thức này đếm số lượng bit được đặt trong một số bằng cách sử dụng toán tử bitwise.
+Ý tưởng chính là chúng ta dịch số sang phải một bit mỗi lần và kiểm tra
+kết quả của phép `&` có phải là `1` nếu bit được đặt và `0` nếu không.
 
 ```text
-Number: 5 = 0b0101
-Count of set bits = 2
+Số: 5 = 0b0101
+Số bit được đặt = 2
 ```
 
-> See [countSetBits.js](countSetBits.js) for further details.
+> Xem [countSetBits.js](countSetBits.js) để biết thêm chi tiết.
 
-#### Count Bits to Flip One Number to Another
+#### Đếm Số Bit Cần Đảo Để Chuyển Một Số Thành Số Khác
 
-This methods outputs the number of bits required to convert one number to another.
-This makes use of property that when numbers are `XOR`-ed the result will be number
-of different bits.
+Phương thức này xuất số bit cần thiết để chuyển đổi một số thành số khác.
+Điều này sử dụng thuộc tính khi các số được `XOR` thì kết quả sẽ là số
+các bit khác nhau.
 
 ```
 5 = 0b0101
 1 = 0b0001
-Count of Bits to be Flipped: 1
+Số bit cần đảo: 1
 ```
 
-> See [bitsDiff.js](bitsDiff.js) for further details.
+> Xem [bitsDiff.js](bitsDiff.js) để biết thêm chi tiết.
 
-#### Count Bits of a Number
+#### Đếm Các Bit Của Một Số
 
-To calculate the number of valuable bits we need to shift `1` one bit left each
-time and see if shifted number is bigger than the input number.
+Để tính toán số bit có ý nghĩa, chúng ta cần dịch `1` sang trái một bit mỗi lần
+và kiểm tra xem số dịch có lớn hơn số đầu vào không.
 
 ```
 5 = 0b0101
-Count of valuable bits is: 3
-When we shift 1 four times it will become bigger than 5.
+Số bit có ý nghĩa là: 3
+Khi chúng ta dịch 1 bốn lần, nó sẽ trở nên lớn hơn 5.
 ```
 
-> See [bitLength.js](bitLength.js) for further details.
+> Xem [bitLength.js](bitLength.js) để biết thêm chi tiết.
 
-#### Is Power of Two
+#### Là Số Lũy Thừa Của Hai
 
-This method checks if a number provided is power of two. It uses the following
-property. Let's say that `powerNumber` is a number that has been formed as a power
-of two (i.e. 2, 4, 8, 16 etc.). Then if we'll do `&` operation between `powerNumber`
-and `powerNumber - 1` it will return `0` (in case if number is power of two).
+Phương thức này kiểm tra xem một số có phải là lũy thừa của hai không. Nó sử dụng thuộc tính sau
+là nếu `powerNumber` là một số đã được hình thành như một lũy thừa
+của hai (tức là 2, 4, 8, 16 v.v.). Sau đó nếu chúng ta thực hiện phép `&` giữa `powerNumber`
+và `powerNumber - 1` nó sẽ trả về `0` (trong trường hợp số là lũy thừa của hai).
 
 ```
-Number: 4 = 0b0100
-Number: 3 = (4 - 1) = 0b0011
-4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two.
+Số: 4 = 0b0100
+Số: 3 = (4 - 1) = 0b0011
+4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Bằng không, là lũy thừa của hai.
 
-Number: 10 = 0b01010
-Number: 9 = (10 - 1) = 0b01001
-10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two.
+Số: 10 = 0b01010
+Số: 9 = (10 - 1) = 0b01001
+10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Không bằng không, không phải là lũy thừa của hai.
 ```
 
-> See [isPowerOfTwo.js](isPowerOfTwo.js) for further details.
+> Xem [isPowerOfTwo.js](isPowerOfTwo.js) để biết thêm chi tiết.
+
+#### Bộ Cộng Đầy Đủ
+
+Phương thức này cộng hai số nguyên bằng cách sử dụng toán tử bitwise.
 
-#### Full Adder
+Nó thực hiện mạch điện tử [full adder](<https://en.wikipedia.org/wiki/Adder_(electronics)>)
+để cộng hai số nguyên 32 bit trong định dạng bù hai.
+Nó sử dụng logic boolean để bao phủ tất cả các trường hợp có thể của việc cộng hai bit đầu vào:
+có và không có một "carry bit" từ việc cộng giai đoạn trước đó ít quan trọng hơn.
 
-This method adds up two integer numbers using bitwise operators.
+Chú thích:
 
-It implements [full adder](<https://en.wikipedia.org/wiki/Adder_(electronics)>)
-electronics circuit logic to sum two 32-bit integers in two's complement format.
-It's using the boolean logic to cover all possible cases of adding two input bits:
-with and without a "carry bit" from adding the previous less-significant stage.
+- `A`: Số `A`
+- `B`: Số `B`
+- `ai`: bit thứ i của số `A`
+- `bi`: bit thứ i của số `B`
+- `carryIn`: một bit được mang từ giai đoạn ít quan trọng hơn trước đó
+- `carryOut`: một bit được mang đến
 
-Legend:
+giai đoạn quan trọng hơn tiếp theo
 
-- `A`: Number `A`
-- `B`: Number `B`
-- `ai`: ith bit of number `A`
-- `bi`: ith bit of number `B`
-- `carryIn`: a bit carried in from the previous less-significant stage
-- `carryOut`: a bit to carry to the next most-significant stage
-- `bitSum`: The sum of `ai`, `bi`, and `carryIn`
-- `resultBin`: The full result of adding current stage with all less-significant stages (in binary)
-- `resultDec`: The full result of adding current stage with all less-significant stages (in decimal)
+- `bitSum`: Tổng của `ai`, `bi`, và `carryIn`
+- `resultBin`: Kết quả đầy đủ của việc cộng giai đoạn hiện tại với tất cả các giai đoạn ít quan trọng hơn (ở dạng nhị phân)
+- `resultDec`: Kết quả đầy đủ của việc cộng giai đoạn hiện tại với tất cả các giai đoạn ít quan trọng hơn (ở dạng thập phân)
 
 ```
 A = 3: 011
@@ -264,11 +266,11 @@ B = 6: 110
 └──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘
 ```
 
-> See [fullAdder.js](fullAdder.js) for further details.
-> See [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).
+> Xem [fullAdder.js](fullAdder.js) để biết thêm chi tiết.
+> Xem [Full Adder trên YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).
 
-## References
+## Tài Liệu Tham Khảo
 
-- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)
+- [Bit Manipulation trên YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Số Âm trong nhị phân trên YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Những Mẹo Bit trên stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)
diff --git a/src/algorithms/math/bits/README.zh-CN.md b/src/algorithms/math/bits/README.zh-CN.md
deleted file mode 100644
index 9ec75069c6..0000000000
--- a/src/algorithms/math/bits/README.zh-CN.md
+++ /dev/null
@@ -1,236 +0,0 @@
-# 位运算
-
-_Read this in other languages:_
-[français](README.fr-FR.md),
-[english](README.md)
-
-#### Get Bit
-
-该方法向右移动目标位到最右边，即位数组的第0个位置上。然后在该数上与形如 `0001`的二进制形式的数进行`AND`操作。这会清理掉除了目标位的所有其它位的数据。如果目标位是1，那么结果就是`1`，反之，结果是`0`;
-
-> 查看[getBit.js](getBit.js)了解更多细节。
-
-#### Set Bit
-
-该方法把`1`向左移动了`bitPosition`位，生成了一个二进制形如`00100`的值。然后我们拿该值与目标数字进行`OR`操作，就能把目标位设置位`1`而不影响其它位。
-
-> 查看[setBit.js](setBit.js)了解更多细节。
-
-#### Clear Bit
-
-该方法把`1`向左移动了`bitPosition`位，生成了一个二进制形如`00100`的值。然后反转每一位的数字，得到一个二进制形如`11011`的值。接着与目标值进行`AND`操作，就能清除掉目标位的值。
-
-> 查看[clearBit.js](clearBit.js)了解更多细节。
-
-#### Update Bit
-
-该方法组合了“Clear Bit”和“Set Bit”
-
-> 查看[updateBit.js](updateBit.js)了解更多细节。
-
-#### isEven
-
-该方法检测传入的number是否是偶数。它的实现基于奇数的最右边的位永远是`1`这个事实。
-
-```text
-Number: 5 = 0b0101
-isEven: false
-
-Number: 4 = 0b0100
-isEven: true
-```
-
-> 查看[isEven.js](isEven.js)了解更多细节。
-
-#### isPositive
-
-该方法检测传入的number是否是正数。它的实现基于正数最左边的位永远是`0`这个事实。然而如果传入的number是0或者-0，它也应该返回false。
-
-```text
-Number: 1 = 0b0001
-isPositive: true
-
-Number: -1 = -0b0001
-isPositive: false
-```
-
-> 查看[isPositive.js](isPositive.js)了解更多细节。
-
-#### Multiply By Two
-
-该方法将原始数字向左移动一位。因此所有位都将乘以2，因此数字本身也将乘以2。
-
-```
-Before the shift
-Number: 0b0101 = 5
-Powers of two: 0 + 2^2 + 0 + 2^0
-
-After the shift
-Number: 0b1010 = 10
-Powers of two: 2^3 + 0 + 2^1 + 0
-```
-
-> 查看[multiplyByTwo.js](multiplyByTwo.js)了解更多细节。
-
-#### Divide By Two
-
-该方法将原始数字向右移动一位。因此所有位都将除以2，因此数字本身也将除以2,且不会产生余数。
-
-```
-Before the shift
-Number: 0b0101 = 5
-Powers of two: 0 + 2^2 + 0 + 2^0
-
-After the shift
-Number: 0b0010 = 2
-Powers of two: 0 + 0 + 2^1 + 0
-```
-
-> 查看[divideByTwo.js](divideByTwo.js)了解更多细节。
-
-#### Switch Sign
-
-该方法将正数变成负数，反之亦然。为了做到这一点，它使用了“二进制补码”的方法，即取反所有位然后加1.
-
-```
-1101 -3
-1110 -2
-1111 -1
-0000  0
-0001  1
-0010  2
-0011  3
-```
-
-> 查看[switchSign.js](switchSign.js)了解更多细节。
-
-#### Multiply Two Signed Numbers
-
-该方法使用位运算符计算两个有符号数的乘积。实现基于以下事实：
-
-```text
-a * b 可以被改写成如下形式:
-  0                     a为0，b为0，或者a，b都为0
-  2a * (b/2)            b是偶数
-  2a * (b - 1)/2 + a    b是奇数，正数
-  2a * (b + 1)/2 - a    b是奇数，负数
-```
-
-这样转换的优势在于，递归的每一步，递归的操作数的值都减少了一半。因此，运行时的时间复杂度为`O(log(b))`,其中b是在每个递归步骤上减少为一半的操作数。
-
-
-> 查看[multiply.js](multiply.js)了解更多细节。
-
-#### Multiply Two Unsigned Numbers
-
-该方法使用位运算符计算两个无符号数的乘积。实现基于“每个数字都可以表示为一系列2的幂的和”。
-
-逐位乘法的主要思想是，每个数字都可以拆分为两个乘方的和：
-
-比如：
-
-```text
-19 = 2^4 + 2^1 + 2^0
-```
-
-然后`19`乘`x`就等价于：
-
-```text
-x * 19 = x * 2^4 + x * 2^1 + x * 2^0
-```
-
-接着我们应该意识到`x*2^4`是等价于`x`向左移动`4`位（`x << 4`）的;
-
-> 查看[multiplyUnsigned.js](multiplyUnsigned.js)了解更多细节。
-
-#### Count Set Bits
-
-该方法使用位运算符对一个数字里设置为`1`的位进行记数。主要方法是，把数字每次向右移动1位，然后使用`&`操作符取出最右边一位的值，`1`则记数加1，`0`则不计。
-
-```text
-Number: 5 = 0b0101
-Count of set bits = 2
-```
-
-> 查看[countSetBits.js](countSetBits.js)了解更多细节。
-
-#### Count Bits to Flip One Number to Another
-
-
-该方法输出把一个数字转换为另一个数字所需要转换的位数。这利用了以下特性：当数字进行`XOR`异或运算时，结果将是不同位数的数量(即异或的结果中所有被设置为1的位的数量)。
-
-```
-5 = 0b0101
-1 = 0b0001
-Count of Bits to be Flipped: 1
-```
-
-> 查看[bitsDiff.js](bitsDiff.js)了解更多细节。
-
-#### Count Bits of a Number
-
-为了计算数字的有效位数，我们需要把`1`每次向左移动一位，然后检查产生的值是否大于输入的数字。
-
-```
-5 = 0b0101
-有效位数: 3
-当我们把1向左移动4位的时候，会大于5.
-```
-
-> 查看[bitLength.js](bitLength.js)了解更多细节。
-
-#### Is Power of Two
-
-该方法检测数字是否可以表示为2的幂。它使用了以下特性，我们定义`powerNumber`是可以写成2的幂的形式的数(2,4,8,16 etc.)。然后我们会把`powerNumber`和`powerNumber - 1`进行`&`操作，它会返回`0`(如果该数字可以表示为2的幂)。
-
-```
-Number: 4 = 0b0100
-Number: 3 = (4 - 1) = 0b0011
-4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two.
-
-Number: 10 = 0b01010
-Number: 9 = (10 - 1) = 0b01001
-10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two.
-```
-
-> 查看[isPowerOfTwo.js](isPowerOfTwo.js)了解更多细节。
-
-#### Full Adder
-
-该方法使用位运算符计算两个数的和。
-
-它实现了[完整的加法器](<https://en.wikipedia.org/wiki/Adder_(electronics)>)电子电路逻辑，以补码的形式计算两个32位数字的和。它使用布尔逻辑来覆盖了两个位相加的所有情况：从前一位相加的时候，产没产生进位“carry bit”。
-
-Legend:
-
-- `A`: 数字 `A`
-- `B`: 数字 `B`
-- `ai`: 数字`A`以二进制表示时的位下标
-- `bi`: 数字`B`以二进制表示时的位下标
-- `carryIn`: 本次计算产生的进位
-- `carryOut`: 带入此次计算的进位
-- `bitSum`: `ai`, `bi`, 和 `carryIn` 的和
-- `resultBin`: 当前计算的结果（二进制形式）
-- `resultDec`: 当前计算的结果（十进制形式）
-
-```
-A = 3: 011
-B = 6: 110
-┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐
-│  bit │ ai │ bi │ carryIn │ carryOut │  bitSum │ resultBin │ resultDec │
-├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤
-│   0  │ 1  │ 0  │    0    │    0     │     1   │       1   │     1     │
-│   1  │ 1  │ 1  │    0    │    1     │     0   │      01   │     1     │
-│   2  │ 0  │ 1  │    1    │    1     │     0   │     001   │     1     │
-│   3  │ 0  │ 0  │    1    │    0     │     1   │    1001   │     9     │
-└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘
-```
-
-> 查看[fullAdder.js](fullAdder.js)了解更多细节。  
-> 查看[Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8).
-
-## References
-
-- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html)
diff --git a/src/algorithms/math/complex-number/README.en-EN.md b/src/algorithms/math/complex-number/README.en-EN.md
new file mode 100644
index 0000000000..8f42201c82
--- /dev/null
+++ b/src/algorithms/math/complex-number/README.en-EN.md
@@ -0,0 +1,228 @@
+# Complex Number
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **complex number** is a number that can be expressed in the
+form `a + b * i`, where `a` and `b` are real numbers, and `i` is a solution of
+the equation `x^2 = −1`. Because no _real number_ satisfies this
+equation, `i` is called an _imaginary number_. For the complex
+number `a + b * i`, `a` is called the _real part_, and `b` is called
+the _imaginary part_.
+
+![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)
+
+A Complex Number is a combination of a Real Number and an Imaginary Number:
+
+![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)
+
+Geometrically, complex numbers extend the concept of the one-dimensional number
+line to the _two-dimensional complex plane_ by using the horizontal axis for the
+real part and the vertical axis for the imaginary part. The complex
+number `a + b * i` can be identified with the point `(a, b)` in the complex plane.
+
+A complex number whose real part is zero is said to be _purely imaginary_; the
+points for these numbers lie on the vertical axis of the complex plane. A complex
+number whose imaginary part is zero can be viewed as a _real number_; its point
+lies on the horizontal axis of the complex plane.
+
+| Complex Number | Real Part | Imaginary Part |                  |
+| :------------- | :-------: | :------------: | ---------------- |
+| 3 + 2i         |     3     |       2        |                  |
+| 5              |     5     |     **0**      | Purely Real      |
+| −6i            |   **0**   |       -6       | Purely Imaginary |
+
+A complex number can be visually represented as a pair of numbers `(a, b)` forming
+a vector on a diagram called an _Argand diagram_, representing the _complex plane_.
+`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.
+
+![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)
+
+> Complex does not mean complicated. It means the two types of numbers, real and
+> imaginary, together form a complex, just like a building complex (buildings
+> joined together).
+
+## Polar Form
+
+An alternative way of defining a point `P` in the complex plane, other than using
+the x- and y-coordinates, is to use the distance of the point from `O`, the point
+whose coordinates are `(0, 0)` (the origin), together with the angle subtended
+between the positive real axis and the line segment `OP` in a counterclockwise
+direction. This idea leads to the polar form of complex numbers.
+
+![Polar Form](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)
+
+The _absolute value_ (or modulus or magnitude) of a complex number `z = x + yi` is:
+
+![Radius](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)
+
+The argument of `z` (in many applications referred to as the "phase") is the angle
+of the radius `OP` with the positive real axis, and is written as `arg(z)`. As
+with the modulus, the argument can be found from the rectangular form `x+yi`:
+
+![Phase](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)
+
+Together, `r` and `φ` give another way of representing complex numbers, the
+polar form, as the combination of modulus and argument fully specify the
+position of a point on the plane. Recovering the original rectangular
+co-ordinates from the polar form is done by the formula called trigonometric
+form:
+
+![Polar Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)
+
+Using Euler's formula this can be written as:
+
+![Euler's Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)
+
+## Basic Operations
+
+### Adding
+
+To add two complex numbers we add each part separately:
+
+```text
+(a + b * i) + (c + d * i) = (a + c) + (b + d) * i
+```
+
+**Example**
+
+```text
+(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i
+```
+
+On complex plane the adding operation will look like the following:
+
+![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)
+
+### Subtracting
+
+To subtract two complex numbers we subtract each part separately:
+
+```text
+(a + b * i) - (c + d * i) = (a - c) + (b - d) * i
+```
+
+**Example**
+
+```text
+(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i
+```
+
+### Multiplying
+
+To multiply complex numbers each part of the first complex number gets multiplied
+by each part of the second complex number:
+
+Just use "FOIL", which stands for "**F**irsts, **O**uters, **I**nners, **L**asts" (
+see [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) for
+more details):
+
+![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)
+
+- Firsts: `a × c`
+- Outers: `a × di`
+- Inners: `bi × c`
+- Lasts: `bi × di`
+
+In general it looks like this:
+
+```text
+(a + bi)(c + di) = ac + adi + bci + bdi^2
+```
+
+But there is also a quicker way!
+
+Use this rule:
+
+```text
+(a + bi)(c + di) = (ac − bd) + (ad + bc)i
+```
+
+**Example**
+
+```text
+(3 + 2i)(1 + 7i)
+= 3×1 + 3×7i + 2i×1+ 2i×7i
+= 3 + 21i + 2i + 14i^2
+= 3 + 21i + 2i − 14   (because i^2 = −1)
+= −11 + 23i
+```
+
+```text
+(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i
+```
+
+### Conjugates
+
+We will need to know about conjugates in a minute!
+
+A conjugate is where we change the sign in the middle like this:
+
+![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)
+
+A conjugate is often written with a bar over it:
+
+```text
+______
+5 − 3i   =   5 + 3i
+```
+
+On the complex plane the conjugate number will be mirrored against real axes.
+
+![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)
+
+### Dividing
+
+The conjugate is used to help complex division.
+
+The trick is to _multiply both top and bottom by the conjugate of the bottom_.
+
+**Example**
+
+```text
+2 + 3i
+------
+4 − 5i
+```
+
+Multiply top and bottom by the conjugate of `4 − 5i`:
+
+```text
+  (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2
+= ------------------- = ----------------------
+  (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2
+```
+
+Now remember that `i^2 = −1`, so:
+
+```text
+  8 + 10i + 12i − 15    −7 + 22i   −7   22
+= ------------------- = -------- = -- + -- * i
+  16 + 20i − 20i + 25      41      41   41
+
+```
+
+There is a faster way though.
+
+In the previous example, what happened on the bottom was interesting:
+
+```text
+(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i
+```
+
+The middle terms `(20i − 20i)` cancel out! Also `i^2 = −1` so we end up with this:
+
+```text
+(4 − 5i)(4 + 5i) = 4^2 + 5^2
+```
+
+Which is really quite a simple result. The general rule is:
+
+```text
+(a + bi)(a − bi) = a^2 + b^2
+```
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Complex_number)
+- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)
diff --git a/src/algorithms/math/complex-number/README.fr-FR.md b/src/algorithms/math/complex-number/README.fr-FR.md
deleted file mode 100644
index 0e42a484d4..0000000000
--- a/src/algorithms/math/complex-number/README.fr-FR.md
+++ /dev/null
@@ -1,237 +0,0 @@
-# Nombre complexe
-
-_Read this in other languages:_
-[english](README.md).
-
-Un **nombre complexe** est un nombre qui peut s'écrire sous la forme
-`a + b * i`, tels que `a` et `b` sont des nombres réels,
-et `i` est la solution de l'équation `x^2 = −1`.
-Du fait qu'aucun _nombre réel_ ne statisfait l'équation,
-`i` est appellé _nombre imaginaire_. Étant donné le nombre complexe `a + b * i`,
-`a` est appellé _partie réelle_, et `b`, _partie imaginaire_.
-
-![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)
-
-Un nombre complexe est donc la combinaison
-d'un nombre réel et d'un nombre imaginaire :
-
-![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)
-
-En géométrie, les nombres complexes étendent le concept
-de ligne de nombres sur une dimension à un _plan complexe à deux dimensions_
-en utilisant l'axe horizontal pour lepartie réelle
-et l'axe vertical pour la partie imaginaire. Le nombre complexe `a + b * i`
-peut être identifié avec le point `(a, b)` dans le plan complexe.
-
-Un nombre complexe dont la partie réelle est zéro est dit _imaginaire pur_;
-les points pour ces nombres se trouvent sur l'axe vertical du plan complexe.
-Un nombre complexe dont la partie imaginaire est zéro
-peut être considéré comme un _nombre réel_; son point
-se trouve sur l'axe horizontal du plan complexe.
-
-| Nombre complexe | Partie réelle | partie imaginaire |                  |
-| :-------------- | :-----------: | :---------------: | ---------------- |
-| 3 + 2i          |       3       |         2         |                  |
-| 5               |       5       |       **0**       | Purely Real      |
-| −6i             |     **0**     |        -6         | Purely Imaginary |
-
-A complex number can be visually represented as a pair of numbers `(a, b)` forming
-a vector on a diagram called an _Argand diagram_, representing the _complex plane_.
-`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.
-
-Un nombre complexe peut être représenté visuellement comme une paire de nombres
-`(a, b)` formant un vecteur sur un diagramme appelé _diagramme d'Argand_,
-représentant le _plan complexe_.
-_Re_ est l'axe réel, _Im_ est l'axe imaginaire et `i` satisfait `i^2 = −1`.
-
-![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)
-
-> Complexe ne veut pas dire compliqué. Cela signifie simplement que
-> les deux types de nombres, réels et imaginaires, forment ensemble un complexe
-> comme on le dirait d'un complexe de bâtiments (bâtiments réunis).
-
-## Forme polaire
-
-Une manière de définir un point `P` dans le plan complexe, autre que d'utiliser
-les coordonnées x et y, consiste à utiliser la distance entre le point `O`, le point
-dont les coordonnées sont `(0, 0)` (l'origine), et l'angle sous-tendu
-entre l'axe réel positif et le segment de droite `OP` dans le sens antihoraire.
-Cette idée conduit à la forme polaire des nombres complexes.
-
-![Polar Form](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)
-
-The _valeur absolue_ (ou module) d'un nombre complexe `z = x + yi` est:
-
-![Radius](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)
-
-L'argument de `z` (parfois appelé « phase » ou « amplitude ») est l'angle
-du rayon `OP` avec l'axe des réels positifs, et s'écrit `arg(z)`. Comme
-avec le module, l'argument peut être trouvé à partir de la forme rectangulaire `x + yi`:
-
-![Phase](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)
-
-Ensemble, `r` et`φ` donnent une autre façon de représenter les nombres complexes, la
-forme polaire, car la combinaison du module et de l'argument suffit à indiquer la
-position d'un point sur le plan. Obtenir les coordonnées du rectangle d'origine
-à partir de la forme polaire se fait par la formule appelée forme trigonométrique :
-
-![Polar Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)
-
-En utilisant la formule d'Euler, cela peut être écrit comme suit:
-
-![Euler's Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)
-
-## Opérations de base
-
-### Addition
-
-Pour ajouter deux nombres complexes, nous ajoutons chaque partie séparément :
-
-```text
-(a + b * i) + (c + d * i) = (a + c) + (b + d) * i
-```
-
-**Exemple**
-
-```text
-(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i
-```
-
-Dans un plan complexe, l'addition ressemblera à ceci:
-
-![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)
-
-### Soustraction
-
-Pour soustraire deux nombres complexes, on soustrait chaque partie séparément :
-
-```text
-(a + b * i) - (c + d * i) = (a - c) + (b - d) * i
-```
-
-**Exemple**
-
-```text
-(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i
-```
-
-### Multiplication
-
-Pour multiplier les nombres complexes, chaque partie du premier nombre complexe est multipliée
-par chaque partie du deuxième nombre complexe:
-
-On peut utiliser le "FOIL" (parfois traduit PEID en français), acronyme de
-**F**irsts (Premiers), **O**uters (Extérieurs), **I**nners (Intérieurs), **L**asts (Derniers)" (
-voir [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) pour plus de détails):
-
-![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)
-
-- Firsts: `a × c`
-- Outers: `a × di`
-- Inners: `bi × c`
-- Lasts: `bi × di`
-
-En général, cela ressemble à:
-
-```text
-(a + bi)(c + di) = ac + adi + bci + bdi^2
-```
-
-Mais il existe aussi un moyen plus rapide !
-
-Utiliser cette loi:
-
-```text
-(a + bi)(c + di) = (ac − bd) + (ad + bc)i
-```
-
-**Exemple**
-
-```text
-(3 + 2i)(1 + 7i)
-= 3×1 + 3×7i + 2i×1+ 2i×7i
-= 3 + 21i + 2i + 14i^2
-= 3 + 21i + 2i − 14   (because i^2 = −1)
-= −11 + 23i
-```
-
-```text
-(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i
-```
-
-### Conjugués
-
-En mathématiques, le conjugué d'un nombre complexe z
-est le nombre complexe formé de la même partie réelle que z
-mais de partie imaginaire opposée.
-
-Un conjugué vois son signe changer au milieu comme suit:
-
-![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)
-
-Un conjugué est souvent écrit avec un trait suscrit (barre au-dessus):
-
-```text
-______
-5 − 3i   =   5 + 3i
-```
-
-Dans un plan complexe, le nombre conjugué sera mirroir par rapport aux axes réels.
-
-![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)
-
-### Division
-
-Le conjugué est utiliser pour aider à la division de nombres complexes
-
-L'astuce est de _multiplier le haut et le bas par le conjugué du bas_.
-
-**Exemple**
-
-```text
-2 + 3i
-------
-4 − 5i
-```
-
-Multiplier le haut et le bas par le conjugué de `4 − 5i`:
-
-```text
-  (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2
-= ------------------- = ----------------------
-  (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2
-```
-
-Et puisque `i^2 = −1`, il s'ensuit que:
-
-```text
-  8 + 10i + 12i − 15    −7 + 22i   −7   22
-= ------------------- = -------- = -- + -- * i
-  16 + 20i − 20i + 25      41      41   41
-
-```
-
-Il existe cependant un moyen plus direct.
-
-Dans l'exemple précédent, ce qui s'est passé en bas était intéressant:
-
-```text
-(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i
-```
-
-Les termes du milieu `(20i − 20i)` s'annule! Et pusique `i^2 = −1` on retrouve:
-
-```text
-(4 − 5i)(4 + 5i) = 4^2 + 5^2
-```
-
-Ce qui est vraiment un résultat assez simple. La règle générale est:
-
-```text
-(a + bi)(a − bi) = a^2 + b^2
-```
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Nombre_complexe)
-- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)
diff --git a/src/algorithms/math/complex-number/README.md b/src/algorithms/math/complex-number/README.md
index 7629aad3f0..33785b7a99 100644
--- a/src/algorithms/math/complex-number/README.md
+++ b/src/algorithms/math/complex-number/README.md
@@ -1,150 +1,134 @@
-# Complex Number
+# Số Phức
 
-_Read this in other languages:_
-[français](README.fr-FR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-A **complex number** is a number that can be expressed in the
-form `a + b * i`, where `a` and `b` are real numbers, and `i` is a solution of
-the equation `x^2 = −1`. Because no _real number_ satisfies this
-equation, `i` is called an _imaginary number_. For the complex
-number `a + b * i`, `a` is called the _real part_, and `b` is called
-the _imaginary part_.
+Một **số phức** là một số có thể được biểu diễn dưới dạng `a + b * i`, trong đó `a` và `b` là các số thực, và `i` là một giải pháp của phương trình `x^2 = −1`. Vì không có _số thực_ nào thỏa mãn phương trình này, `i` được gọi là một _số ảo_. Đối với số phức `a + b * i`, `a` được gọi là _phần thực_, và `b` được gọi là _phần ảo_.
 
-![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)
+![Số Phức](https://www.mathsisfun.com/numbers/images/complex-example.svg)
 
-A Complex Number is a combination of a Real Number and an Imaginary Number:
+Một Số Phức là sự kết hợp của một Số Thực và một Số Ảo:
 
-![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)
+![Số Phức](https://www.mathsisfun.com/numbers/images/complex-number.svg)
 
-Geometrically, complex numbers extend the concept of the one-dimensional number
-line to the _two-dimensional complex plane_ by using the horizontal axis for the
-real part and the vertical axis for the imaginary part. The complex
-number `a + b * i` can be identified with the point `(a, b)` in the complex plane.
+Về mặt hình học, số phức mở rộng khái niệm của đường số một chiều sang _mặt phẳng phức hai chiều_ bằng cách sử dụng trục hoành cho phần thực và trục tung cho phần ảo. Số phức `a + b * i` có thể được xác định với điểm `(a, b)` trên mặt phẳng phức.
 
-A complex number whose real part is zero is said to be _purely imaginary_; the
-points for these numbers lie on the vertical axis of the complex plane. A complex
-number whose imaginary part is zero can be viewed as a _real number_; its point
-lies on the horizontal axis of the complex plane.
+Một số phức có phần thực bằng không được gọi là _số ảo tuyệt đối_; các điểm cho những số này nằm trên trục thẳng đứng của mặt phẳng phức. Một số phức có phần ảo bằng không có thể được xem như một _số thực_; điểm của nó nằm trên trục hoành của mặt phẳng phức.
 
-| Complex Number | Real Part | Imaginary Part |                  |
-| :------------- | :-------: | :------------: | ---------------- |
-| 3 + 2i         |     3     |       2        |                  |
-| 5              |     5     |     **0**      | Purely Real      |
-| −6i            |   **0**   |       -6       | Purely Imaginary |
+| Số Phức | Phần Thực | Phần Ảo |              |
+| :------ | :-------: | :-----: | ------------ |
+| 3 + 2i  |     3     |    2    |              |
+| 5       |     5     |  **0**  | Ảo Tuyệt Đối |
+| −6i     |   **0**   |   -6    | Ảo Tuyệt Đối |
 
-A complex number can be visually represented as a pair of numbers `(a, b)` forming
-a vector on a diagram called an _Argand diagram_, representing the _complex plane_.
-`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.
+Một số phức có thể được biểu diễn hình thức bằng cách sử dụng một cặp số `(a, b)` tạo thành một vector trên một biểu đồ gọi là _biểu đồ Argand_, đại diện cho _mặt phẳng phức_. `Re` là trục thực, `Im` là trục ảo, và `i` thỏa mãn `i^2 = −1`.
 
-![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)
+![Số Phức](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)
 
-> Complex does not mean complicated. It means the two types of numbers, real and
-> imaginary, together form a complex, just like a building complex (buildings
-> joined together).
+> Số phức không có nghĩa là phức tạp. Nó có nghĩa là hai loại số, thực và ảo,
+> cùng tạo thành một số phức, giống như một khu phức hợp (những tòa nhà
+> được kết nối với nhau).
 
-## Polar Form
+## Dạng Cực
 
-An alternative way of defining a point `P` in the complex plane, other than using
-the x- and y-coordinates, is to use the distance of the point from `O`, the point
-whose coordinates are `(0, 0)` (the origin), together with the angle subtended
-between the positive real axis and the line segment `OP` in a counterclockwise
-direction. This idea leads to the polar form of complex numbers.
+Một cách khác để định nghĩa một điểm `P` trong mặt phẳng phức, ngoài việc sử dụng
+các tọa độ x và y, là sử dụng khoảng cách từ điểm `O`, điểm
+có tọa độ `(0, 0)` (nguồn gốc), cùng với góc được chia đều
+giữa trục thực dương và đoạn thẳng `OP` theo hướng ngược chiều kim đồng hồ. Ý tưởng này dẫn đến dạng cực của số phức.
 
-![Polar Form](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)
+![Dạng Cực](https://upload.wikimedia.org/wikipedia/commons/7/7a/Complex_number_illustration_modarg.svg)
 
-The _absolute value_ (or modulus or magnitude) of a complex number `z = x + yi` is:
+Giá trị tuyệt đối (hoặc độ lớn) của một số phức `z = x + yi` là:
 
-![Radius](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)
+![Bán Kính](https://wikimedia.org/api/rest_v1/media/math/render/svg/b59629c801aa0ddcdf17ee489e028fb9f8d4ea75)
 
-The argument of `z` (in many applications referred to as the "phase") is the angle
-of the radius `OP` with the positive real axis, and is written as `arg(z)`. As
-with the modulus, the argument can be found from the rectangular form `x+yi`:
+Góc của `z` (trong nhiều ứng dụng được gọi là "pha") là góc
+của bán kính `OP` với trục thực dương, và được viết dưới dạng `arg(z)`. Như
+với giá trị tuyệt đối, góc có thể được tìm từ dạng hình chữ nhật `x+yi`:
 
-![Phase](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)
+![Góc](https://wikimedia.org/api/rest_v1/media/math/render/svg/7cbbdd9bb1dd5df86dd2b820b20f82995023e566)
 
-Together, `r` and `φ` give another way of representing complex numbers, the
-polar form, as the combination of modulus and argument fully specify the
-position of a point on the plane. Recovering the original rectangular
-co-ordinates from the polar form is done by the formula called trigonometric
-form:
+Cả `r` và `φ` cùng cung cấp một cách khác để biểu diễn số phức, là
+dạng cực, vì sự kết hợp của độ lớn và góc hoàn toàn xác định vị trí
+của một điểm trên mặt phẳng. Việc khôi phục lại các tọa độ hình chữ nhật ban đầu từ dạng cực được thực hiện thông qua công thức gọi là dạng lượng giác:
 
-![Polar Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)
+![Dạng Cực](https://wikimedia.org/api/rest_v1/media/math/render/svg/b03de1e1b7b049880b5e4870b68a57bc180ff6ce)
 
-Using Euler's formula this can be written as:
+Sử dụng công thức Euler, điều này có thể được viết dưới dạng:
 
-![Euler's Form](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)
+![Dạng Euler](https://wikimedia.org/api/rest_v1/media/math/render/svg/0a087c772212e7375cb321d83fc1fcc715cd0ed2)
 
-## Basic Operations
+## Các Phép Tính Cơ Bản
 
-### Adding
+### Cộng
 
-To add two complex numbers we add each part separately:
+Để cộng hai số phức, chúng ta cộng từng phần một riêng lẻ:
 
 ```text
 (a + b * i) + (c + d * i) = (a + c) + (b + d) * i
 ```
 
-**Example**
+**Ví dụ**
 
 ```text
 (3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i
 ```
 
-On complex plane the adding operation will look like the following:
+Trên mặt phẳng phức, phép cộng sẽ trông như sau:
 
-![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)
+![Cộng Số Phức](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)
 
-### Subtracting
+### Trừ
 
-To subtract two complex numbers we subtract each part separately:
+Để trừ hai số phức, chúng ta trừ từng phần một riêng lẻ:
 
 ```text
 (a + b * i) - (c + d * i) = (a - c) + (b - d) * i
 ```
 
-**Example**
+**Ví dụ**
 
 ```text
 (3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i
 ```
 
-### Multiplying
+### Nhân
 
-To multiply complex numbers each part of the first complex number gets multiplied
-by each part of the second complex number:
+Để nhân số phức, mỗi phần của số phức đầu tiên được nhân
+với mỗi phần của số phức thứ hai:
 
-Just use "FOIL", which stands for "**F**irsts, **O**uters, **I**nners, **L**asts" (
-see [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) for
-more details):
+Chỉ cần sử dụng "FOIL", viết tắt của "**F**irsts, **O**uters, **I**nners, **L**asts"
+(see [Nhân Đa Thức](https://www.mathsisfun.com/algebra/polynomials-multiplying.html) để
+biết thêm chi tiết):
 
-![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)
+![Nhân Số Phức](https://www.mathsisfun.com/algebra/images/foil-complex.svg)
 
 - Firsts: `a × c`
 - Outers: `a × di`
 - Inners: `bi × c`
 - Lasts: `bi × di`
 
-In general it looks like this:
+Nhìn chung, nó trông như thế này:
 
 ```text
 (a + bi)(c + di) = ac + adi + bci + bdi^2
 ```
 
-But there is also a quicker way!
+Nhưng cũng có một cách nhanh hơn!
 
-Use this rule:
+Sử dụng quy tắc này:
 
 ```text
 (a + bi)(c + di) = (ac − bd) + (ad + bc)i
 ```
 
-**Example**
+**Ví dụ**
 
 ```text
 (3 + 2i)(1 + 7i)
 = 3×1 + 3×7i + 2i×1+ 2i×7i
 = 3 + 21i + 2i + 14i^2
-= 3 + 21i + 2i − 14   (because i^2 = −1)
+= 3 + 21i + 2i − 14   (bởi vì i^2 = −1)
 = −11 + 23i
 ```
 
@@ -152,32 +136,32 @@ Use this rule:
 (3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i
 ```
 
-### Conjugates
+### Phức Hợp
 
-We will need to know about conjugates in a minute!
+Chúng ta sẽ cần biết về phức hợp trong một phút nữa!
 
-A conjugate is where we change the sign in the middle like this:
+Phức hợp là khi chúng ta thay đổi dấu ở giữa như thế này:
 
-![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)
+![Phức Hợp Số Phức](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)
 
-A conjugate is often written with a bar over it:
+Một phức hợp thường được viết với một dấu than trên:
 
 ```text
 ______
 5 − 3i   =   5 + 3i
 ```
 
-On the complex plane the conjugate number will be mirrored against real axes.
+Trên mặt phẳng phức, số phức phức hợp sẽ được phản chiếu qua trục số thực.
 
-![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)
+![Phức Hợp Số Phức](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)
 
-### Dividing
+### Chia
 
-The conjugate is used to help complex division.
+Phức hợp được sử dụng để giúp phép chia số phức.
 
-The trick is to _multiply both top and bottom by the conjugate of the bottom_.
+Mánh là _nhân cả trên và dưới với phức hợp của dưới_.
 
-**Example**
+**Ví dụ**
 
 ```text
 2 + 3i
@@ -185,7 +169,7 @@ The trick is to _multiply both top and bottom by the conjugate of the bottom_.
 4 − 5i
 ```
 
-Multiply top and bottom by the conjugate of `4 − 5i`:
+Nhân cả trên và dưới với phức hợp của `4 − 5i`:
 
 ```text
   (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2
@@ -193,7 +177,7 @@ Multiply top and bottom by the conjugate of `4 − 5i`:
   (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2
 ```
 
-Now remember that `i^2 = −1`, so:
+Bây giờ hãy nhớ rằng `i^2 = −1`, vì vậy:
 
 ```text
   8 + 10i + 12i − 15    −7 + 22i   −7   22
@@ -202,27 +186,27 @@ Now remember that `i^2 = −1`, so:
 
 ```
 
-There is a faster way though.
+Tuy nhiên, có một cách nhanh hơn.
 
-In the previous example, what happened on the bottom was interesting:
+Trong ví dụ trước, điều gì đã xảy ra ở dưới là thú vị:
 
 ```text
 (4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i
 ```
 
-The middle terms `(20i − 20i)` cancel out! Also `i^2 = −1` so we end up with this:
+Các thuật ngữ giữa `(20i − 20i)` bị loại bỏ! Hơn nữa, `i^2 = −1` nên chúng ta kết thúc với điều này:
 
 ```text
 (4 − 5i)(4 + 5i) = 4^2 + 5^2
 ```
 
-Which is really quite a simple result. The general rule is:
+Điều này thực sự là một kết quả khá đơn giản. Quy tắc chung là:
 
 ```text
 (a + bi)(a − bi) = a^2 + b^2
 ```
 
-## References
+## Tài Liệu Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Complex_number)
 - [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)
diff --git a/src/algorithms/math/euclidean-algorithm/README.en-EN.md b/src/algorithms/math/euclidean-algorithm/README.en-EN.md
new file mode 100644
index 0000000000..fe2ddbb5b0
--- /dev/null
+++ b/src/algorithms/math/euclidean-algorithm/README.en-EN.md
@@ -0,0 +1,60 @@
+# Euclidean algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, the Euclidean algorithm, or Euclid's algorithm,
+is an efficient method for computing the greatest common divisor
+(GCD) of two numbers, the largest number that divides both of
+them without leaving a remainder.
+
+The Euclidean algorithm is based on the principle that the
+greatest common divisor of two numbers does not change if
+the larger number is replaced by its difference with the
+smaller number. For example, `21` is the GCD of `252` and
+`105` (as `252 = 21 × 12` and `105 = 21 × 5`), and the same
+number `21` is also the GCD of `105` and `252 − 105 = 147`.
+Since this replacement reduces the larger of the two numbers,
+repeating this process gives successively smaller pairs of
+numbers until the two numbers become equal.
+When that occurs, they are the GCD of the original two numbers.
+
+By reversing the steps, the GCD can be expressed as a sum of
+the two original numbers each multiplied by a positive or
+negative integer, e.g., `21 = 5 × 105 + (−2) × 252`.
+The fact that the GCD can always be expressed in this way is
+known as Bézout's identity.
+
+![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)
+
+Euclid's method for finding the greatest common divisor (GCD)
+of two starting lengths `BA` and `DC`, both defined to be
+multiples of a common "unit" length. The length `DC` being
+shorter, it is used to "measure" `BA`, but only once because
+remainder `EA` is less than `DC`. EA now measures (twice)
+the shorter length `DC`, with remainder `FC` shorter than `EA`.
+Then `FC` measures (three times) length `EA`. Because there is
+no remainder, the process ends with `FC` being the `GCD`.
+On the right Nicomachus' example with numbers `49` and `21`
+resulting in their GCD of `7` (derived from Heath 1908:300).
+
+![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)
+
+A `24-by-60` rectangle is covered with ten `12-by-12` square
+tiles, where `12` is the GCD of `24` and `60`. More generally,
+an `a-by-b` rectangle can be covered with square tiles of
+side-length `c` only if `c` is a common divisor of `a` and `b`.
+
+![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)
+
+Subtraction-based animation of the Euclidean algorithm.
+The initial rectangle has dimensions `a = 1071` and `b = 462`.
+Squares of size `462×462` are placed within it leaving a
+`462×147` rectangle. This rectangle is tiled with `147×147`
+squares until a `21×147` rectangle is left, which in turn is
+tiled with `21×21` squares, leaving no uncovered area.
+The smallest square size, `21`, is the GCD of `1071` and `462`.
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Euclidean_algorithm)
diff --git a/src/algorithms/math/euclidean-algorithm/README.fr-FR.md b/src/algorithms/math/euclidean-algorithm/README.fr-FR.md
deleted file mode 100644
index 75b6a90b88..0000000000
--- a/src/algorithms/math/euclidean-algorithm/README.fr-FR.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Algorithme d'Euclide
-
-_Read this in other languages:_
-[english](README.md).
-
-En mathématiques, l'algorithme d'Euclide est un algorithme qui calcule le plus grand commun diviseur (PGCD) de deux entiers, c'est-à-dire le plus grand entier qui divise les deux entiers, en laissant un reste nul. L'algorithme ne connaît pas la factorisation de ces deux nombres.
-
-Le PGCD de deux entiers relatifs est égal au PGCD de leurs valeurs absolues : de ce fait, on se restreint dans cette section aux entiers positifs. L'algorithme part du constat suivant : le PGCD de deux nombres n'est pas changé si on remplace le plus grand d'entre eux par leur différence. Autrement dit, `pgcd(a, b) = pgcd(b, a - b)`. Par exemple, le PGCD de `252` et `105` vaut `21` (en effet, `252 = 21 × 12` and `105 = 21 × 5`), mais c'est aussi le PGCD de `252 - 105 = 147` et `105`. Ainsi, comme le remplacement de ces nombres diminue strictement le plus grand d'entre eux, on peut continuer le processus, jusqu'à obtenir deux nombres égaux.
-
-En inversant les étapes, le PGCD peut être exprimé comme une somme de
-les deux nombres originaux, chacun étant multiplié
-par un entier positif ou négatif, par exemple `21 = 5 × 105 + (-2) × 252`.
-Le fait que le PGCD puisse toujours être exprimé de cette manière est
-connue sous le nom de Théorème de Bachet-Bézout.
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)
-
-La Méthode d'Euclide pour trouver le plus grand diviseur commun (PGCD)
-de deux longueurs de départ`BA` et `DC`, toutes deux définies comme étant
-multiples d'une longueur commune. La longueur `DC` étant
-plus courte, elle est utilisée pour « mesurer » `BA`, mais une seule fois car
-le reste `EA` est inférieur à `DC`. `EA` mesure maintenant (deux fois)
-la longueur la plus courte `DC`, le reste `FC` étant plus court que `EA`.
-Alors `FC` mesure (trois fois) la longueur `EA`. Parce qu'il y a
-pas de reste, le processus se termine par `FC` étant le « PGCD ».
-À droite, l'exemple de Nicomaque de Gérase avec les nombres `49` et `21`
-ayan un PGCD de `7` (dérivé de Heath 1908: 300).
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)
-
-Un de rectangle de dimensions `24 par 60` peux se carreler en carrés de `12 par 12`,
-puisque `12` est le PGCD ed `24` et `60`. De façon générale,
-un rectangle de dimension `a par b` peut se carreler en carrés
-de côté `c`, seulement si `c` est un diviseur commun de `a` et `b`.
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)
-
-Animation basée sur la soustraction via l'algorithme euclidien.
-Le rectangle initial a les dimensions `a = 1071` et `b = 462`.
-Des carrés de taille `462 × 462` y sont placés en laissant un
-rectangle de `462 × 147`. Ce rectangle est carrelé avec des
-carrés de `147 × 147` jusqu'à ce qu'un rectangle de `21 × 147` soit laissé,
-qui à son tour estcarrelé avec des carrés `21 × 21`,
-ne laissant aucune zone non couverte.
-La plus petite taille carrée, `21`, est le PGCD de `1071` et `462`.
-
-## References
-
-[Wikipedia](https://fr.wikipedia.org/wiki/Algorithme_d%27Euclide)
diff --git a/src/algorithms/math/euclidean-algorithm/README.md b/src/algorithms/math/euclidean-algorithm/README.md
index 89af03b15e..b708a1b19a 100644
--- a/src/algorithms/math/euclidean-algorithm/README.md
+++ b/src/algorithms/math/euclidean-algorithm/README.md
@@ -1,60 +1,57 @@
-# Euclidean algorithm
-
-_Read this in other languages:_
-[français](README.fr-FR.md).
-
-In mathematics, the Euclidean algorithm, or Euclid's algorithm,
-is an efficient method for computing the greatest common divisor
-(GCD) of two numbers, the largest number that divides both of
-them without leaving a remainder.
-
-The Euclidean algorithm is based on the principle that the
-greatest common divisor of two numbers does not change if
-the larger number is replaced by its difference with the
-smaller number. For example, `21` is the GCD of `252` and
-`105` (as `252 = 21 × 12` and `105 = 21 × 5`), and the same
-number `21` is also the GCD of `105` and `252 − 105 = 147`.
-Since this replacement reduces the larger of the two numbers,
-repeating this process gives successively smaller pairs of
-numbers until the two numbers become equal.
-When that occurs, they are the GCD of the original two numbers.
-
-By reversing the steps, the GCD can be expressed as a sum of
-the two original numbers each multiplied by a positive or
-negative integer, e.g., `21 = 5 × 105 + (−2) × 252`.
-The fact that the GCD can always be expressed in this way is
-known as Bézout's identity.
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)
-
-Euclid's method for finding the greatest common divisor (GCD)
-of two starting lengths `BA` and `DC`, both defined to be
-multiples of a common "unit" length. The length `DC` being
-shorter, it is used to "measure" `BA`, but only once because
-remainder `EA` is less than `DC`. EA now measures (twice)
-the shorter length `DC`, with remainder `FC` shorter than `EA`.
-Then `FC` measures (three times) length `EA`. Because there is
-no remainder, the process ends with `FC` being the `GCD`.
-On the right Nicomachus' example with numbers `49` and `21`
-resulting in their GCD of `7` (derived from Heath 1908:300).
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)
-
-A `24-by-60` rectangle is covered with ten `12-by-12` square
-tiles, where `12` is the GCD of `24` and `60`. More generally,
-an `a-by-b` rectangle can be covered with square tiles of
-side-length `c` only if `c` is a common divisor of `a` and `b`.
-
-![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)
-
-Subtraction-based animation of the Euclidean algorithm.
-The initial rectangle has dimensions `a = 1071` and `b = 462`.
-Squares of size `462×462` are placed within it leaving a
-`462×147` rectangle. This rectangle is tiled with `147×147`
-squares until a `21×147` rectangle is left, which in turn is
-tiled with `21×21` squares, leaving no uncovered area.
-The smallest square size, `21`, is the GCD of `1071` and `462`.
-
-## References
+# Euclidean algorithm - Thuật toán Euclid
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong toán học, thuật toán Euclid, hay còn gọi là thuật toán của Euclid,
+là một phương pháp hiệu quả để tính ước số chung lớn nhất
+(GCD) của hai số, đó là số lớn nhất chia cả hai số đó mà không
+có phần dư.
+
+Thuật toán Euclid dựa trên nguyên tắc rằng ước số chung lớn nhất
+của hai số không thay đổi nếu số lớn hơn được thay thế bằng hiệu của nó
+với số nhỏ hơn. Ví dụ, `21` là ước số chung lớn nhất của `252` và
+`105` (vì `252 = 21 × 12` và `105 = 21 × 5`), và cũng là
+số `21` là ước số chung lớn nhất của `105` và `252 − 105 = 147`.
+Khi quá trình thay thế này giảm số lớn hơn trong hai số đó,
+lặp lại quá trình này cho đến khi hai số trở thành bằng nhau.
+Khi điều đó xảy ra, chúng là ước số chung lớn nhất của hai số ban đầu.
+
+Bằng cách đảo ngược các bước, ước số chung lớn nhất có thể được biểu diễn
+dưới dạng tổng của hai số ban đầu mỗi số được nhân với một số nguyên
+dương hoặc âm, ví dụ, `21 = 5 × 105 + (−2) × 252`.
+Việc rằng ước số chung lớn nhất luôn có thể được biểu diễn theo cách này được
+biết đến với tên gọi là định lý Bézout.
+
+![USCLN](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)
+
+Phương pháp của Euclid để tìm ước số chung lớn nhất (GCD)
+của hai độ dài ban đầu `BA` và `DC`, đều được định nghĩa là
+bội số của một độ dài "đơn vị" chung. Độ dài `DC` ngắn hơn,
+nó được sử dụng để "đo" `BA`, nhưng chỉ một lần vì
+phần dư `EA` nhỏ hơn `DC`. EA bây giờ đo độ dài ngắn hơn `DC` (hai lần),
+với phần dư `FC` còn ngắn hơn `EA`. Sau đó, `FC` đo độ dài `EA` (ba lần).
+Bởi vì không có phần dư, quá trình kết thúc với `FC` là `USCLN`.
+Bên phải là ví dụ của Nicomachus với các số `49` và `21`,
+kết quả là `USCLN` của chúng là `7` (được suy ra từ Heath 1908:300).
+
+![USCLN](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)
+
+Một hình chữ nhật `24-by-60` được phủ bằng mười viên gạch vuông `12-by-12`,
+trong đó `12` là ước số chung lớn nhất của `24` và `60`. Nói chung hơn,
+một hình chữ nhật `a-by-b` có thể được phủ bằng các viên gạch vuông có cạnh
+dài `c` chỉ khi `c` là ước số chung của `a` và `b`.
+
+![USCLN](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)
+
+Hoạt hình dựa trên phép trừ của thuật toán Euclid.
+Hình chữ nhật ban đầu có kích thước `a = 1071` và `b = 462`.
+Các hình vuông có kích thước `462×462` được đặt vào trong đó,
+để lại một hình chữ nhật `462×147`. Hình chữ nhật này được phủ bằng các
+hình vuông `147×147` cho đến khi chỉ còn lại một hình chữ nhật `21×147`,
+rồi tiếp tục được phủ bằng các hình vuông `21×21`, không còn diện tích không được phủ.
+Kích thước hình vuông nhỏ nhất, `21`, chính là `USCLN` của `1071` và `462`.
+
+## Tài Liệu Tham Khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_algorithm)
diff --git a/src/algorithms/math/euclidean-distance/README.en-EN.md b/src/algorithms/math/euclidean-distance/README.en-EN.md
new file mode 100644
index 0000000000..e1cecd72e1
--- /dev/null
+++ b/src/algorithms/math/euclidean-distance/README.en-EN.md
@@ -0,0 +1,39 @@
+# Euclidean Distance
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, the **Euclidean distance** between two points in Euclidean space is the length of a line segment between the two points. It can be calculated from the Cartesian coordinates of the points using the Pythagorean theorem, therefore occasionally being called the Pythagorean distance.
+
+![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+
+## Distance formulas
+
+### One dimension
+
+The distance between any two points on the real line is the absolute value of the numerical difference of their coordinates
+
+![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9)
+
+### Two dimensions
+
+![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773)
+
+### Higher dimensions
+
+In three dimensions, for points given by their Cartesian coordinates, the distance is
+
+![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625)
+
+Example: the distance between the two points `(8,2,6)` and `(3,5,7)`:
+
+![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg)
+
+In general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is
+
+![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc)
+
+## References
+
+- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html)
+- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)
diff --git a/src/algorithms/math/euclidean-distance/README.md b/src/algorithms/math/euclidean-distance/README.md
index d67c217efe..52bd91e3bf 100644
--- a/src/algorithms/math/euclidean-distance/README.md
+++ b/src/algorithms/math/euclidean-distance/README.md
@@ -1,36 +1,39 @@
-# Euclidean Distance
+# Khoảng Cách Euclid - Khoảng cách Euclid
 
-In mathematics, the **Euclidean distance** between two points in Euclidean space is the length of a line segment between the two points. It can be calculated from the Cartesian coordinates of the points using the Pythagorean theorem, therefore occasionally being called the Pythagorean distance.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+Trong toán học, **khoảng cách Euclid** giữa hai điểm trong không gian Euclid là độ dài của một đoạn thẳng nối hai điểm đó. Nó có thể được tính từ các tọa độ Descartes của các điểm bằng định lý Pythagoras, nên đôi khi còn được gọi là khoảng cách Pythagoras.
 
-## Distance formulas
+![Khoảng cách Euclid giữa hai điểm](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
 
-### One dimension
+## Công thức Khoảng cách
 
-The distance between any two points on the real line is the absolute value of the numerical difference of their coordinates
+### Một chiều
 
-![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9)
+Khoảng cách giữa hai điểm bất kỳ trên đường thẳng số thực là giá trị tuyệt đối của sự khác biệt số học của các tọa độ của chúng
 
-### Two dimensions
+![Công thức một chiều](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9)
 
-![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773)
+### Hai chiều
 
-### Higher dimensions
+![Công thức hai chiều](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773)
 
-In three dimensions, for points given by their Cartesian coordinates, the distance is
+### Các chiều cao hơn
 
-![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625)
+Trong ba chiều, cho các điểm được cho bởi các tọa độ Descartes của chúng, khoảng cách là
 
-Example: the distance between the two points `(8,2,6)` and `(3,5,7)`:
+![Công thức ba chiều](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625)
 
-![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg)
+Ví dụ: khoảng cách giữa hai điểm `(8,2,6)` và `(3,5,7)`:
 
-In general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is
+![Ví dụ ba chiều](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg)
 
-![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc)
+Nhìn chung, cho các điểm được cho bởi các tọa độ Descartes trong không gian Euclid `n` chiều, khoảng cách là
 
-## References
+![Công thức n chiều](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc)
 
-- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html)
-- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)
+## Tham khảo
+
+- [Khoảng Cách Euclid trên MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html)
+- [Khoảng Cách Euclid trên Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)
diff --git a/src/algorithms/math/factorial/README.fr-FR.md b/src/algorithms/math/factorial/README.en-EN.md
similarity index 60%
rename from src/algorithms/math/factorial/README.fr-FR.md
rename to src/algorithms/math/factorial/README.en-EN.md
index aa092c1b78..b86a44b282 100644
--- a/src/algorithms/math/factorial/README.fr-FR.md
+++ b/src/algorithms/math/factorial/README.en-EN.md
@@ -1,11 +1,11 @@
-# Factorielle
+# Factorial
 
-_Lisez ceci dans d'autres langues:_
-[english](README.md), [_简体中文_](README.zh-CN.md).
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
 
-En mathématiques, la factorielle d'un entier naturel `n`,
-notée avec un point d'exclamation `n!`, est le produit des nombres entiers
-strictement positifs inférieurs ou égaux à n. Par exemple:
+In mathematics, the factorial of a non-negative integer `n`,
+denoted by `n!`, is the product of all positive integers less
+than or equal to `n`. For example:
 
 ```
 5! = 5 * 4 * 3 * 2 * 1 = 120
@@ -32,4 +32,4 @@ strictement positifs inférieurs ou égaux à n. Par exemple:
 
 ## References
 
-[Wikipedia](https://fr.wikipedia.org/wiki/Factorielle)
+[Wikipedia](https://en.wikipedia.org/wiki/Factorial)
diff --git a/src/algorithms/math/factorial/README.ka-GE.md b/src/algorithms/math/factorial/README.ka-GE.md
deleted file mode 100644
index 1d02b9f7d3..0000000000
--- a/src/algorithms/math/factorial/README.ka-GE.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# ფაქტორიალი
-
-მათემატიკაში `n` ნატურალური რიცხვის ფაქტორიალი
-(აღინიშნება `n!` სიმბოლოთი)
-არის ყველა ნატურალური რიცხვის ნამრავლი 1-იდან `n`-ის ჩათვლით. მაგალითად:
-
-```
-5! = 5 * 4 * 3 * 2 * 1 = 120
-```
-
-| n   |                n! |
-| --- | ----------------: |
-| 0   |                 1 |
-| 1   |                 1 |
-| 2   |                 2 |
-| 3   |                 6 |
-| 4   |                24 |
-| 5   |               120 |
-| 6   |               720 |
-| 7   |             5 040 |
-| 8   |            40 320 |
-| 9   |           362 880 |
-| 10  |         3 628 800 |
-| 11  |        39 916 800 |
-| 12  |       479 001 600 |
-| 13  |     6 227 020 800 |
-| 14  |    87 178 291 200 |
-| 15  | 1 307 674 368 000 |
-
-## სქოლიო
-
-[Wikipedia](https://ka.wikipedia.org/wiki/%E1%83%9B%E1%83%90%E1%83%97%E1%83%94%E1%83%9B%E1%83%90%E1%83%A2%E1%83%98%E1%83%99%E1%83%A3%E1%83%A0%E1%83%98_%E1%83%A4%E1%83%90%E1%83%A5%E1%83%A2%E1%83%9D%E1%83%A0%E1%83%98%E1%83%90%E1%83%9A%E1%83%98)
diff --git a/src/algorithms/math/factorial/README.md b/src/algorithms/math/factorial/README.md
index 9c75b41aae..c7aa1d1fe0 100644
--- a/src/algorithms/math/factorial/README.md
+++ b/src/algorithms/math/factorial/README.md
@@ -1,11 +1,9 @@
-# Factorial
+# Giai thừa - Factorial
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md), [_Français_](README.fr-FR.md), [_Türkçe_](README.tr-TR.md), [_ქართული_](README.ka-GE.md), [_Українська_](README.uk-UA.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In mathematics, the factorial of a non-negative integer `n`,
-denoted by `n!`, is the product of all positive integers less
-than or equal to `n`. For example:
+Trong toán học, giai thừa của một số nguyên không âm `n`, ký hiệu là `n!`, là tích của tất cả các số nguyên dương nhỏ hơn hoặc bằng `n`. Ví dụ:
 
 ```
 5! = 5 * 4 * 3 * 2 * 1 = 120
@@ -30,6 +28,6 @@ than or equal to `n`. For example:
 | 14  |    87 178 291 200 |
 | 15  | 1 307 674 368 000 |
 
-## References
+## Tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Factorial)
diff --git a/src/algorithms/math/factorial/README.tr-TR.md b/src/algorithms/math/factorial/README.tr-TR.md
deleted file mode 100644
index 68ce21a299..0000000000
--- a/src/algorithms/math/factorial/README.tr-TR.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# Faktöriyel
-
-_Bunu diğer dillerde okuyun:_
-[_简体中文_](README.zh-CN.md), [français](README.fr-FR.md).
-
-Faktöriyel, matematikte, sağına ünlem işareti konulmuş sayıya
-verilen isim, daha genel olan Gama fonksiyonunun tam sayılarla
-sınırlanmış özel bir durumudur. 1'den başlayarak belirli bir
-sayma sayısına kadar olan sayıların çarpımına o sayının
-faktöriyeli denir. Basit bir şekilde faktöriyel, n tane ayrık
-elemanın kaç farklı şekilde sıralanabileceğidir.
-
-```
-5! = 5 * 4 * 3 * 2 * 1 = 120
-```
-
-| n   |                n! |
-| --- | ----------------: |
-| 0   |                 1 |
-| 1   |                 1 |
-| 2   |                 2 |
-| 3   |                 6 |
-| 4   |                24 |
-| 5   |               120 |
-| 6   |               720 |
-| 7   |             5 040 |
-| 8   |            40 320 |
-| 9   |           362 880 |
-| 10  |         3 628 800 |
-| 11  |        39 916 800 |
-| 12  |       479 001 600 |
-| 13  |     6 227 020 800 |
-| 14  |    87 178 291 200 |
-| 15  | 1 307 674 368 000 |
-
-## Referanslar
-
-[Wikipedia](https://en.wikipedia.org/wiki/Factorial)
diff --git a/src/algorithms/math/factorial/README.uk-UA.md b/src/algorithms/math/factorial/README.uk-UA.md
deleted file mode 100644
index bf75963113..0000000000
--- a/src/algorithms/math/factorial/README.uk-UA.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Факторіал
-
-_Прочитайте це іншими мовами:_
-[_English_](README.md), [_简体中文_](README.zh-CN.md), [_Français_](README.fr-FR.md), [_Türkçe_](README.tr-TR.md), [_ქართული_](README.ka-GE.md).
-
-У математиці факторіал невід'ємного цілого числа `n`, позначений `n!`, є добутком усіх натуральних чисел, менших або рівних `n`. Наприклад:
-
-```
-5! = 5 * 4 * 3 * 2 * 1 = 120
-```
-
-| n   |                n! |
-| --- | ----------------: |
-| 0   |                 1 |
-| 1   |                 1 |
-| 2   |                 2 |
-| 3   |                 6 |
-| 4   |                24 |
-| 5   |               120 |
-| 6   |               720 |
-| 7   |             5 040 |
-| 8   |            40 320 |
-| 9   |           362 880 |
-| 10  |         3 628 800 |
-| 11  |        39 916 800 |
-| 12  |       479 001 600 |
-| 13  |     6 227 020 800 |
-| 14  |    87 178 291 200 |
-| 15  | 1 307 674 368 000 |
-
-## Посилання
-
-[Wikipedia](https://uk.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D1%96%D0%B0%D0%BB)
diff --git a/src/algorithms/math/factorial/README.zh-CN.md b/src/algorithms/math/factorial/README.zh-CN.md
deleted file mode 100644
index 89bcff1ff2..0000000000
--- a/src/algorithms/math/factorial/README.zh-CN.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# 阶乘
-
-在数学上, 一个正整数 `n` 的阶乘 (写作 `n!`), 就是所有小于等于 `n` 的正整数的乘积. 比如:
-
-```
-5! = 5 * 4 * 3 * 2 * 1 = 120
-```
-
-| n     | n!                          | 
-| ----- | --------------------------: |
-| 0     | 1                           |
-| 1     | 1                           |
-| 2     | 2                           |
-| 3     | 6                           |
-| 4     | 24                          |
-| 5     | 120                         |
-| 6     | 720                         |
-| 7     | 5 040                       |
-| 8     | 40 320                      |
-| 9     | 362 880                     |
-| 10    | 3 628 800                   |
-| 11    | 39 916 800                  |
-| 12    | 479 001 600                 |
-| 13    | 6 227 020 800               |
-| 14    | 87 178 291 200              |
-| 15    | 1 307 674 368 000           |
-
diff --git a/src/algorithms/math/fast-powering/README.en-EN.md b/src/algorithms/math/fast-powering/README.en-EN.md
new file mode 100644
index 0000000000..8c4c7e0069
--- /dev/null
+++ b/src/algorithms/math/fast-powering/README.en-EN.md
@@ -0,0 +1,71 @@
+# Fast Powering Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**The power of a number** says how many times to use the number in a
+multiplication.
+
+It is written as a small number to the right and above the base number.
+
+![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)
+
+## Naive Algorithm Complexity
+
+How to find `a` raised to the power `b`?
+
+We multiply `a` to itself, `b` times. That
+is, `a^b = a * a * a * ... * a` (`b` occurrences of `a`).
+
+This operation will take `O(n)` time since we need to do multiplication operation
+exactly `n` times.
+
+## Fast Power Algorithm
+
+Can we do better than naive algorithm does? Yes we may solve the task of
+powering in `O(log(n))` time.
+
+The algorithm uses divide and conquer approach to compute power. Currently the
+algorithm work for two positive integers `X` and `Y`.
+
+The idea behind the algorithm is based on the fact that:
+
+For **even** `Y`:
+
+```text
+X^Y = X^(Y/2) * X^(Y/2)
+```
+
+For **odd** `Y`:
+
+```text
+X^Y = X^(Y//2) * X^(Y//2) * X
+where Y//2 is result of division of Y by 2 without reminder.
+```
+
+**For example**
+
+```text
+2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)
+```
+
+```text
+2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)
+```
+
+Now, since on each step we need to compute the same `X^(Y/2)` power twice we may optimise
+it by saving it to some intermediate variable to avoid its duplicate calculation.
+
+**Time Complexity**
+
+Since each iteration we split the power by half then we will call function
+recursively `log(n)` times. This the time complexity of the algorithm is reduced to:
+
+```text
+O(log(n))
+```
+
+## References
+
+- [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
+- [Wikipedia](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
diff --git a/src/algorithms/math/fast-powering/README.fr-FR.md b/src/algorithms/math/fast-powering/README.fr-FR.md
deleted file mode 100644
index ba44244cc8..0000000000
--- a/src/algorithms/math/fast-powering/README.fr-FR.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Algorithme d'exponentiation rapide
-
-_Read this in other languages:_
-[english](README.md).
-
-En algèbre, une **puissance** d'un nombre est le résultat de la multiplication répétée de ce nombre avec lui-même.
-
-Elle est souvent notée en assortissant le nombre d'un entier, typographié en exposant, qui indique le nombre de fois qu'apparaît le nombre comme facteur dans cette multiplication.
-
-![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)
-
-## Implémentation « naïve »
-
-Comment trouver `a` élevé à la puissance `b` ?
-
-On multiplie `a` avec lui-même, `b` nombre de fois.
-Ainsi, `a^b = a * a * a * ... * a` (`b` occurrences de `a`).
-
-Cette opération aura un complexité linéaire, notée `O(n)`,
-car la multiplication aura lieu exactement `n` fois.
-
-## Algorithme d'exponentiation rapide
-
-Peut-on faire mieux que cette implémentation naïve?
-Oui, on peut réduire le nombre de puissance à un complexité de `O(log(n))`.
-
-Cet algorithme utilise l'approche « diviser pour mieux régner »
-pour calculer cette puissance.
-En l'état, cet algorithme fonctionne pour deux entiers positifs `X` et `Y`.
-
-L'idée derrière cet algorithme est basée sur l'observation suivante.
-
-Lorsque `Y` est **pair**:
-
-```text
-X^Y = X^(Y/2) * X^(Y/2)
-```
-
-Lorsque `Y` est **impair**:
-
-```text
-X^Y = X^(Y//2) * X^(Y//2) * X
-où Y//2 est le résultat de la division entière de Y par 2.
-```
-
-**Par exemple**
-
-```text
-2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)
-```
-
-```text
-2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)
-```
-
-Ainsi, puisqu'à chaque étape on doits calculer
-deux fois la même puissance `X ^ (Y / 2)`,
-on peut optimiser en l'enregistrant dans une variable intermédiaire
-pour éviter son calcul en double.
-
-**Complexité en temps**
-
-Comme à chaque itération nous réduisons la puissance de moitié,
-nous appelons récursivement la fonction `log(n)` fois. Le complexité de temps de cet algorithme est donc réduite à:
-
-```text
-O(log(n))
-```
-
-## Références
-
-- [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
-- [Wikipedia](https://fr.wikipedia.org/wiki/Exponentiation_rapide)
diff --git a/src/algorithms/math/fast-powering/README.md b/src/algorithms/math/fast-powering/README.md
index 2c2619d2ef..094474e5ae 100644
--- a/src/algorithms/math/fast-powering/README.md
+++ b/src/algorithms/math/fast-powering/README.md
@@ -1,49 +1,44 @@
-# Fast Powering Algorithm
+# Thuật toán lũy thừa nhanh
 
-_Read this in other languages:_
-[français](README.fr-FR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-**The power of a number** says how many times to use the number in a
-multiplication.
+**Sức mạnh của một số** cho biết phải sử dụng số đó bao nhiêu lần trong một phép nhân.
 
-It is written as a small number to the right and above the base number.
+Nó được viết dưới dạng một số nhỏ bên phải và phía trên số cơ bản.
 
-![Power](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)
+![Lũy thừa](https://www.mathsisfun.com/algebra/images/exponent-8-2.svg)
 
-## Naive Algorithm Complexity
+## Độ phức tạp của thuật toán ngây thơ
 
-How to find `a` raised to the power `b`?
+Làm thế nào để tính `a` mũ `b`?
 
-We multiply `a` to itself, `b` times. That
-is, `a^b = a * a * a * ... * a` (`b` occurrences of `a`).
+Chúng ta nhân `a` cho chính nó, `b` lần. Tức là, `a^b = a * a * a * ... * a` (`b` lần của `a`).
 
-This operation will take `O(n)` time since we need to do multiplication operation
-exactly `n` times.
+Phép tính này sẽ mất `O(n)` thời gian vì chúng ta cần thực hiện phép nhân chính xác `n` lần.
 
-## Fast Power Algorithm
+## Thuật toán lũy thừa nhanh
 
-Can we do better than naive algorithm does? Yes we may solve the task of
-powering in `O(log(n))` time.
+Liệu chúng ta có thể làm tốt hơn so với thuật toán ngây thơ không? Có, chúng ta có thể giải quyết bài toán lũy thừa trong thời gian `O(log(n))`.
 
-The algorithm uses divide and conquer approach to compute power. Currently the
-algorithm work for two positive integers `X` and `Y`.
+Thuật toán sử dụng phương pháp chia để trị để tính lũy thừa. Hiện tại, thuật toán này hoạt động cho hai số nguyên dương `X` và `Y`.
 
-The idea behind the algorithm is based on the fact that:
+Ý tưởng đằng sau thuật toán dựa trên sự thật rằng:
 
-For **even** `Y`:
+Đối với `Y` **chẵn**:
 
 ```text
 X^Y = X^(Y/2) * X^(Y/2)
 ```
 
-For **odd** `Y`:
+Đối với `Y` **lẻ**:
 
 ```text
 X^Y = X^(Y//2) * X^(Y//2) * X
-where Y//2 is result of division of Y by 2 without reminder.
+trong đó Y//2 là kết quả của phép chia của Y cho 2 mà không có phần dư.
 ```
 
-**For example**
+**Ví dụ**
 
 ```text
 2^4 = (2 * 2) * (2 * 2) = (2^2) * (2^2)
@@ -53,19 +48,17 @@ where Y//2 is result of division of Y by 2 without reminder.
 2^5 = (2 * 2) * (2 * 2) * 2 = (2^2) * (2^2) * (2)
 ```
 
-Now, since on each step we need to compute the same `X^(Y/2)` power twice we may optimise
-it by saving it to some intermediate variable to avoid its duplicate calculation.
+Bây giờ, vì ở mỗi bước chúng ta cần tính lũy thừa `X^(Y/2)` giống nhau hai lần, chúng ta có thể tối ưu hóa nó bằng cách lưu trữ vào một biến trung gian để tránh tính toán trùng lặp.
 
-**Time Complexity**
+**Độ phức tạp thời gian**
 
-Since each iteration we split the power by half then we will call function
-recursively `log(n)` times. This the time complexity of the algorithm is reduced to:
+Vì mỗi lần lặp chúng ta chia mũ cho hai, sau đó chúng ta sẽ gọi hàm đệ quy `log(n)` lần. Do đó, độ phức tạp thời gian của thuật toán được giảm xuống thành:
 
 ```text
 O(log(n))
 ```
 
-## References
+## Tham khảo
 
 - [YouTube](https://www.youtube.com/watch?v=LUWavfN9zEo&index=80&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
 - [Wikipedia](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
diff --git a/src/algorithms/math/fibonacci/README.en-EN.md b/src/algorithms/math/fibonacci/README.en-EN.md
new file mode 100644
index 0000000000..7f42fba388
--- /dev/null
+++ b/src/algorithms/math/fibonacci/README.en-EN.md
@@ -0,0 +1,23 @@
+# Fibonacci Number
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, the Fibonacci numbers are the numbers in the following
+integer sequence, called the Fibonacci sequence, and characterized by
+the fact that every number after the first two is the sum of the two
+preceding ones:
+
+`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`
+
+A tiling with squares whose side lengths are successive Fibonacci numbers
+
+![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)
+
+The Fibonacci spiral: an approximation of the golden spiral created by drawing circular arcs connecting the opposite corners of squares in the Fibonacci tiling;[4] this one uses squares of sizes 1, 1, 2, 3, 5, 8, 13 and 21.
+
+![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)
diff --git a/src/algorithms/math/fibonacci/README.fr-FR.md b/src/algorithms/math/fibonacci/README.fr-FR.md
deleted file mode 100644
index 81e3549b0d..0000000000
--- a/src/algorithms/math/fibonacci/README.fr-FR.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Nombre de Fibonacci
-
-_Read this in other languages:_
-[english](README.md),
-[ქართული](README.ka-GE.md).
-
-En mathématiques, la suite de Fibonacci est une suite d'entiers
-dans laquelle chaque terme (après les deux premiers)
-est la somme des deux termes qui le précèdent.
-Les termes de cette suite sont appelés nombres de Fibonacci:
-
-`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`
-
-Les carrés de Fibonacci en spirale s'ajustent ensemble pour former une spirale d'or.
-
-![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)
-
-La spirale de Fibonacci: approximation d'une spirale d'or créée en dessinant des arcs de cercle reliant les coins opposés de carrés dans un pavage Fibonacci[4] . Celui-ci utilise des carrés de tailles 1, 1, 2, 3, 5, 8, 13, 21, et 34.
-
-![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)
-
-## References
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Suite_de_Fibonacci)
diff --git a/src/algorithms/math/fibonacci/README.ka-GE.md b/src/algorithms/math/fibonacci/README.ka-GE.md
deleted file mode 100644
index ae7e11218b..0000000000
--- a/src/algorithms/math/fibonacci/README.ka-GE.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# ფიბონაჩის რიცხვი
-
-მათემატიკაში ფიბონაჩის მიმდევრობა წარმოადგენს მთელ რიცხვთა მიმდევრობას,
-რომელშიც ყოველი რიცხვი (პირველი ორი რიცხვის შემდეგ)
-მისი წინამორბედი ორი რიცხვის
-ჯამის ტოლია:
-
-`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`
-
-კვადრატების წყობა, სადაც ყოველი კვადრატის გვერდების სიგრძე, თანმიმდევრობით, ფიბონაჩის რიცხვებს შეესაბამება
-
-![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)
-
-ფიბონაჩის სპირალი: ოქროს სპირალის აპროქსიმაცია, რომელიც შექმნილია კვადრატების მოპირდაპირე კუთხეებს შორის შემაერთებელი რკალების გავლებით;[4] ამ შემთხვევაში, გამოყენებულ კვადრატთა [გვერდების] ზომებია: 1, 1, 2, 3, 5, 8, 13 და 21.
-
-![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)
-
-## სქოლიო
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)
diff --git a/src/algorithms/math/fibonacci/README.md b/src/algorithms/math/fibonacci/README.md
index 3d476c5020..2656156b40 100644
--- a/src/algorithms/math/fibonacci/README.md
+++ b/src/algorithms/math/fibonacci/README.md
@@ -1,25 +1,20 @@
-# Fibonacci Number
+# Số Fibonacci
 
-_Read this in other languages:_
-[français](README.fr-FR.md),
-[简体中文](README.zh-CN.md),
-[ქართული](README.ka-GE.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In mathematics, the Fibonacci numbers are the numbers in the following
-integer sequence, called the Fibonacci sequence, and characterized by
-the fact that every number after the first two is the sum of the two
-preceding ones:
+Trong toán học, các số Fibonacci là các số trong chuỗi số nguyên sau đây, gọi là chuỗi Fibonacci, và được đặc trưng bởi việc mỗi số sau hai số đầu tiên là tổng của hai số liền trước:
 
 `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`
 
-A tiling with squares whose side lengths are successive Fibonacci numbers
+Một lát với các hình vuông có độ dài cạnh lần lượt là các số Fibonacci liên tiếp
 
 ![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)
 
-The Fibonacci spiral: an approximation of the golden spiral created by drawing circular arcs connecting the opposite corners of squares in the Fibonacci tiling;[4] this one uses squares of sizes 1, 1, 2, 3, 5, 8, 13 and 21.
+Spiral Fibonacci: một xấp xỉ của vòng xoắn vàng được tạo ra bằng cách vẽ các cung tròn kết nối các góc đối diện của các hình vuông trong việc lát Fibonacci;[4] hình này sử dụng các hình vuông có kích thước 1, 1, 2, 3, 5, 8, 13 và 21.
 
 ![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)
diff --git a/src/algorithms/math/fibonacci/README.zh-CN.md b/src/algorithms/math/fibonacci/README.zh-CN.md
deleted file mode 100644
index 20378000d4..0000000000
--- a/src/algorithms/math/fibonacci/README.zh-CN.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# 斐波那契数
-
-_Read this in other languages:_
-[français](README.fr-FR.md),
-[english](README.md),
-[ქართული](README.ka-GE.md).
-
-在数学中，斐波那契数是以下整数序列（称为斐波那契数列）中的数字，其特征在于前两个数字之后的每个数字都是前两个数字的和：
-
-`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...`
-
-边长为连续斐波纳契数的正方形平铺
-
-![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png)
-
-
-斐波那契螺旋：通过绘制连接斐波那契平铺中正方形的相对角的圆弧而创建的金色螺旋的近似值； [4]该三角形使用大小为1、1、2、3、5、8、13和21的正方形。
-
-![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg)
-
-## References
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number)
diff --git a/src/algorithms/math/fourier-transform/README.en-EN.md b/src/algorithms/math/fourier-transform/README.en-EN.md
new file mode 100644
index 0000000000..7639caeb86
--- /dev/null
+++ b/src/algorithms/math/fourier-transform/README.en-EN.md
@@ -0,0 +1,133 @@
+# Fourier Transform
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## Definitions
+
+The **Fourier Transform** (**FT**) decomposes a function of time (a signal) into
+the frequencies that make it up, in a way similar to how a musical chord can be
+expressed as the frequencies (or pitches) of its constituent notes.
+
+The **Discrete Fourier Transform** (**DFT**) converts a finite sequence of
+equally-spaced samples of a function into a same-length sequence of
+equally-spaced samples of the discrete-time Fourier transform (DTFT), which is a
+complex-valued function of frequency. The interval at which the DTFT is sampled
+is the reciprocal of the duration of the input sequence. An inverse DFT is a
+Fourier series, using the DTFT samples as coefficients of complex sinusoids at
+the corresponding DTFT frequencies. It has the same sample-values as the original
+input sequence. The DFT is therefore said to be a frequency domain representation
+of the original input sequence. If the original sequence spans all the non-zero
+values of a function, its DTFT is continuous (and periodic), and the DFT provides
+discrete samples of one cycle. If the original sequence is one cycle of a periodic
+function, the DFT provides all the non-zero values of one DTFT cycle.
+
+The Discrete Fourier transform transforms a sequence of `N` complex numbers:
+
+{x<sub>n</sub>} = x<sub>0</sub>, x<sub>1</sub>, x<sub>2</sub> ..., x<sub>N-1</sub>
+
+into another sequence of complex numbers:
+
+{X<sub>k</sub>} = X<sub>0</sub>, X<sub>1</sub>, X<sub>2</sub> ..., X<sub>N-1</sub>
+
+which is defined by:
+
+![DFT](https://wikimedia.org/api/rest_v1/media/math/render/svg/1af0a78dc50bbf118ab6bd4c4dcc3c4ff8502223)
+
+The **Discrete-Time Fourier Transform** (**DTFT**) is a form of Fourier analysis
+that is applicable to the uniformly-spaced samples of a continuous function. The
+term discrete-time refers to the fact that the transform operates on discrete data
+(samples) whose interval often has units of time. From only the samples, it
+produces a function of frequency that is a periodic summation of the continuous
+Fourier transform of the original continuous function.
+
+A **Fast Fourier Transform** (**FFT**) is an algorithm that samples a signal over
+a period of time (or space) and divides it into its frequency components. These
+components are single sinusoidal oscillations at distinct frequencies each with
+their own amplitude and phase.
+
+This transformation is illustrated in Diagram below. Over the time period measured
+in the diagram, the signal contains 3 distinct dominant frequencies.
+
+View of a signal in the time and frequency domain:
+
+![FFT](https://upload.wikimedia.org/wikipedia/commons/6/61/FFT-Time-Frequency-View.png)
+
+An FFT algorithm computes the discrete Fourier transform (DFT) of a sequence, or
+its inverse (IFFT). Fourier analysis converts a signal from its original domain
+to a representation in the frequency domain and vice versa. An FFT rapidly
+computes such transformations by factorizing the DFT matrix into a product of
+sparse (mostly zero) factors. As a result, it manages to reduce the complexity of
+computing the DFT from O(n<sup>2</sup>), which arises if one simply applies the
+definition of DFT, to O(n log n), where n is the data size.
+
+Here a discrete Fourier analysis of a sum of cosine waves at 10, 20, 30, 40,
+and 50 Hz:
+
+![FFT](https://upload.wikimedia.org/wikipedia/commons/6/64/FFT_of_Cosine_Summation_Function.png)
+
+## Explanation
+
+The Fourier Transform is one of deepest insights ever made. Unfortunately, the
+meaning is buried within dense equations:
+
+![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/45c088dbb767150fc0bacfeb49dd49e5.png)
+
+and
+
+![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/faeb9c5bf2e60add63ae4a70b293c7b4.png)
+
+Rather than jumping into the symbols, let's experience the key idea firsthand. Here's a plain-English metaphor:
+
+- _What does the Fourier Transform do?_ Given a smoothie, it finds the recipe.
+- _How?_ Run the smoothie through filters to extract each ingredient.
+- _Why?_ Recipes are easier to analyze, compare, and modify than the smoothie itself.
+- _How do we get the smoothie back?_ Blend the ingredients.
+
+**Think With Circles, Not Just Sinusoids**
+
+The Fourier Transform is about circular paths (not 1-d sinusoids) and Euler's
+formula is a clever way to generate one:
+
+![](https://betterexplained.com/wp-content/uploads/euler/equal_paths.png)
+
+Must we use imaginary exponents to move in a circle? Nope. But it's convenient
+and compact. And sure, we can describe our path as coordinated motion in two
+dimensions (real and imaginary), but don't forget the big picture: we're just
+moving in a circle.
+
+**Discovering The Full Transform**
+
+The big insight: our signal is just a bunch of time spikes! If we merge the
+recipes for each time spike, we should get the recipe for the full signal.
+
+The Fourier Transform builds the recipe frequency-by-frequency:
+
+![](https://betterexplained.com/wp-content/uploads/images/fourier-explained-20121219-224649.png)
+
+A few notes:
+
+- N = number of time samples we have
+- n = current sample we're considering (0 ... N-1)
+- x<sub>n</sub> = value of the signal at time n
+- k = current frequency we're considering (0 Hertz up to N-1 Hertz)
+- X<sub>k</sub> = amount of frequency k in the signal (amplitude and phase, a complex number)
+- The 1/N factor is usually moved to the reverse transform (going from frequencies back to time). This is allowed, though I prefer 1/N in the forward transform since it gives the actual sizes for the time spikes. You can get wild and even use 1/sqrt(N) on both transforms (going forward and back creates the 1/N factor).
+- n/N is the percent of the time we've gone through. 2 _ pi _ k is our speed in radians / sec. e^-ix is our backwards-moving circular path. The combination is how far we've moved, for this speed and time.
+- The raw equations for the Fourier Transform just say "add the complex numbers". Many programming languages cannot handle complex numbers directly, so you convert everything to rectangular coordinates and add those.
+
+Stuart Riffle has a great interpretation of the Fourier Transform:
+
+![](https://betterexplained.com/wp-content/uploads/images/DerivedDFT.png)
+
+## References
+
+- [An Interactive Guide To The Fourier Transform](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)
+- [DFT on YouTube by Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [FT on YouTube by 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [FFT on YouTube by Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
+- Wikipedia
+  - [FT](https://en.wikipedia.org/wiki/Fourier_transform)
+  - [DFT](https://www.wikiwand.com/en/Discrete_Fourier_transform)
+  - [DTFT](https://en.wikipedia.org/wiki/Discrete-time_Fourier_transform)
+  - [FFT](https://www.wikiwand.com/en/Fast_Fourier_transform)
diff --git a/src/algorithms/math/fourier-transform/README.fr-FR.md b/src/algorithms/math/fourier-transform/README.fr-FR.md
deleted file mode 100644
index 0d345164c7..0000000000
--- a/src/algorithms/math/fourier-transform/README.fr-FR.md
+++ /dev/null
@@ -1,135 +0,0 @@
-# Transformation de Fourier
-
-_Read this in other languages:_
-[english](README.md).
-
-## Définitions
-
-La transformation de Fourier (**ℱ**) est une opération qui transforme
-une fonction intégrable sur ℝ en une autre fonction,
-décrivant le spectre fréquentiel de cette dernière
-
-La **Transformée de Fourier Discrète** (**TFD**) convertit une séquence finie d'échantillons également espacés d'une fonction, dans une séquence de même longueur d'échantillons, également espacés de la Transformée de Fourier à temps discret (TFtd), qui est une fonction complexe de la fréquence.
-L'intervalle auquel le TFtd est échantillonné est l'inverse de la durée de la séquence d'entrée.
-Une TFD inverse est une série de Fourier, utilisant les échantillons TFtd comme coefficients de sinusoïdes complexes aux fréquences TFtd correspondantes. Elle a les mêmes valeurs d'échantillonnage que la
-séquence d'entrée originale. On dit donc que la TFD est une représentation du domaine fréquentiel
-de la séquence d'entrée d'origine. Si la séquence d'origine couvre toutes les
-valeurs non nulles d'une fonction, sa TFtd est continue (et périodique), et la TFD fournit
-les échantillons discrets d'une fenêtre. Si la séquence d'origine est un cycle d'une fonction périodique, la TFD fournit toutes les valeurs non nulles d'une fenêtre TFtd.
-
-Transformée de Fourier Discrète converti une séquence de `N` nombres complexes:
-
-{x<sub>n</sub>} = x<sub>0</sub>, x<sub>1</sub>, x<sub>2</sub> ..., x<sub>N-1</sub>
-
-en une atre séquence de nombres complexes::
-
-{X<sub>k</sub>} = X<sub>0</sub>, X<sub>1</sub>, X<sub>2</sub> ..., X<sub>N-1</sub>
-
-décrite par:
-
-![DFT](https://wikimedia.org/api/rest_v1/media/math/render/svg/1af0a78dc50bbf118ab6bd4c4dcc3c4ff8502223)
-
-The **Transformée de Fourier à temps discret** (**TFtd**) est une forme d'analyse de Fourier
-qui s'applique aux échantillons uniformément espacés d'une fonction continue. Le terme "temps discret" fait référence au fait que la transformée fonctionne sur des données discrètes
-(échantillons) dont l'intervalle a souvent des unités de temps.
-À partir des seuls échantillons, elle produit une fonction de fréquence qui est une somme périodique de la
-Transformée de Fourier continue de la fonction continue d'origine.
-
-A **Transformation de Fourier rapide** (**FFT** pour Fast Fourier Transform) est un algorithme de calcul de la transformation de Fourier discrète (TFD). Il est couramment utilisé en traitement numérique du signal pour transformer des données discrètes du domaine temporel dans le domaine fréquentiel, en particulier dans les oscilloscopes numériques (les analyseurs de spectre utilisant plutôt des filtres analogiques, plus précis). Son efficacité permet de réaliser des filtrages en modifiant le spectre et en utilisant la transformation inverse (filtre à réponse impulsionnelle finie).
-
-Cette transformation peut être illustée par la formule suivante. Sur la période de temps mesurée
-dans le diagramme, le signal contient 3 fréquences dominantes distinctes.
-
-Vue d'un signal dans le domaine temporel et fréquentiel:
-
-![FFT](https://upload.wikimedia.org/wikipedia/commons/6/61/FFT-Time-Frequency-View.png)
-
-An FFT algorithm computes the discrete Fourier transform (DFT) of a sequence, or
-its inverse (IFFT). Fourier analysis converts a signal from its original domain
-to a representation in the frequency domain and vice versa. An FFT rapidly
-computes such transformations by factorizing the DFT matrix into a product of
-sparse (mostly zero) factors. As a result, it manages to reduce the complexity of
-computing the DFT from O(n<sup>2</sup>), which arises if one simply applies the
-definition of DFT, to O(n log n), where n is the data size.
-
-Un algorithme FFT calcule la Transformée de Fourier discrète (TFD) d'une séquence, ou
-son inverse (IFFT). L'analyse de Fourier convertit un signal de son domaine d'origine
-en une représentation dans le domaine fréquentiel et vice versa. Une FFT
-calcule rapidement ces transformations en factorisant la matrice TFD en un produit de
-facteurs dispersés (généralement nuls). En conséquence, il parvient à réduire la complexité de
-calcul de la TFD de O (n <sup> 2 </sup>), qui survient si l'on applique simplement la
-définition de TFD, à O (n log n), où n est la taille des données.
-
-Voici une analyse de Fourier discrète d'une somme d'ondes cosinus à 10, 20, 30, 40,
-et 50 Hz:
-
-![FFT](https://upload.wikimedia.org/wikipedia/commons/6/64/FFT_of_Cosine_Summation_Function.png)
-
-## Explanation
-
-La Transformée de Fourier est l'une des connaissances les plus importante jamais découverte. Malheureusement, le
-son sens est enfoui dans des équations denses::
-
-![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/45c088dbb767150fc0bacfeb49dd49e5.png)
-
-et
-
-![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/faeb9c5bf2e60add63ae4a70b293c7b4.png)
-
-Plutôt que se noyer dans les symboles, faisons en premier lieu l'expérience de l'idée principale. Voici une métaphore en français simple:
-
-- _Que fait la transformée de Fourier ?_ A partir d'un smoothie, elle trouve sa recette.
-- _Comment ?_ Elle passe le smoothie dans un filtre pour en extraire chaque ingrédient.
-- _Pourquoi ?_ Les recettes sont plus faciles à analyser, comparer et modifier que le smoothie lui-même.
-- _Comment récupérer le smoothie ?_ Re-mélanger les ingrédients.
-
-**Pensez en cercles, pas seulement en sinusoïdes**
-
-La transformée de Fourier concerne des trajectoires circulaires (pas les sinusoïdes 1-d)
-et la formuled'Euler est une manière intelligente d'en générer une:
-
-![](https://betterexplained.com/wp-content/uploads/euler/equal_paths.png)
-
-Doit-on utiliser des exposants imaginaires pour se déplacer en cercle ? Non. Mais c'est pratique
-et compact. Et bien sûr, nous pouvons décrire notre chemin comme un mouvement coordonné en deux
-dimensions (réelle et imaginaire), mais n'oubliez pas la vue d'ensemble: nous sommes juste
-en déplacement dans un cercle.
-
-**À la découverte de la transformation complète**
-
-L'idée générale: notre signal n'est qu'un tas de pics de temps, d'instant T ! Si nous combinons les
-recettes pour chaque pic de temps, nous devrions obtenir la recette du signal complet.
-
-La transformée de Fourier construit cette recette fréquence par fréquence:
-
-![](https://betterexplained.com/wp-content/uploads/images/fourier-explained-20121219-224649.png)
-
-Quelques notes
-
-- N = nombre d'échantillons de temps dont nous disposons
-- n = échantillon actuellement étudié (0 ... N-1)
-- x<sub>n</sub> = valeur du signal au temps n
-- k = fréquence actuellement étudiée (0 Hertz up to N-1 Hertz)
-- X<sub>k</sub> = quantité de fréquence k dans le signal (amplitude et phase, un nombre complexe)
-- Le facteur 1 / N est généralement déplacé vers la transformée inverse (passant des fréquences au temps). Ceci est autorisé, bien que je préfère 1 / N dans la transformation directe car cela donne les tailles réelles des pics de temps. Vous pouvez être plus ambitieux et utiliser 1 / racine carrée de (N) sur les deux transformations (aller en avant et en arrière crée le facteur 1 / N).
-- n/N est le pourcentage du temps que nous avons passé. 2 _ pi _ k est notre vitesse en radians/s. e ^ -ix est notre chemin circulaire vers l'arrière. La combinaison est la distance parcourue, pour cette vitesse et ce temps.
-- Les équations brutes de la transformée de Fourier consiste simplement à "ajouter les nombres complexes". De nombreux langages de programmation ne peuvent pas gérer directement les nombres complexes, on converti donc tout en coordonnées rectangulaires, pour les ajouter.
-
-Stuart Riffle a une excellente interprétation de la transformée de Fourier:
-
-![](https://betterexplained.com/wp-content/uploads/images/DerivedDFT.png)
-
-## Références
-
-- Wikipedia
-
-  - [TF](https://fr.wikipedia.org/wiki/Transformation_de_Fourier)
-  - [TFD](https://fr.wikipedia.org/wiki/Transformation_de_Fourier_discr%C3%A8te)
-  - [FFT](https://fr.wikipedia.org/wiki/Transformation_de_Fourier_rapide)
-  - [TFtd (en anglais)](https://en.wikipedia.org/wiki/Discrete-time_Fourier_transform)
-
-- en Anglais
-  - [An Interactive Guide To The Fourier Transform](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)
-  - [DFT on YouTube by Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-  - [FT on YouTube by 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-  - [FFT on YouTube by Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
diff --git a/src/algorithms/math/fourier-transform/README.md b/src/algorithms/math/fourier-transform/README.md
index f7969ddd5c..6330cf57bb 100644
--- a/src/algorithms/math/fourier-transform/README.md
+++ b/src/algorithms/math/fourier-transform/README.md
@@ -1,131 +1,97 @@
-# Fourier Transform
+# Phép Biến Đổi Fourier
 
-_Read this in other languages:_
-[français](README.fr-FR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Definitions
+## Định nghĩa
 
-The **Fourier Transform** (**FT**) decomposes a function of time (a signal) into
-the frequencies that make it up, in a way similar to how a musical chord can be
-expressed as the frequencies (or pitches) of its constituent notes.
+**Phép biến đổi Fourier** (**FT**) phân tách một hàm của thời gian (một tín hiệu) thành các tần số tạo thành nó, tương tự như cách một hợp âm nhạc có thể được biểu diễn dưới dạng các tần số (hoặc nốt âm) của các nốt nhạc thành phần của nó.
 
-The **Discrete Fourier Transform** (**DFT**) converts a finite sequence of
-equally-spaced samples of a function into a same-length sequence of
-equally-spaced samples of the discrete-time Fourier transform (DTFT), which is a
-complex-valued function of frequency. The interval at which the DTFT is sampled
-is the reciprocal of the duration of the input sequence. An inverse DFT is a
-Fourier series, using the DTFT samples as coefficients of complex sinusoids at
-the corresponding DTFT frequencies. It has the same sample-values as the original
-input sequence. The DFT is therefore said to be a frequency domain representation
-of the original input sequence. If the original sequence spans all the non-zero
-values of a function, its DTFT is continuous (and periodic), and the DFT provides
-discrete samples of one cycle. If the original sequence is one cycle of a periodic
-function, the DFT provides all the non-zero values of one DTFT cycle.
+**Biến đổi Fourier Rời rạc** (**DFT**) chuyển đổi một chuỗi hữu hạn các mẫu cách đều của một hàm thành một chuỗi cùng chiều dài các mẫu cách đều của phép biến đổi Fourier trong thời gian rời rạc (DTFT), mà là một hàm phức giá trị của tần số. Khoảng cách mà DTFT được lấy mẫu là nghịch đảo của thời gian của chuỗi đầu vào. Một DFT nghịch đảo là một chuỗi Fourier, sử dụng các mẫu DTFT như các hệ số của các hàm sin phức ở các tần số tương ứng với DTFT. Nó có các giá trị mẫu giống như chuỗi đầu vào ban đầu. Do đó, DFT được coi là biểu diễn miền tần số của chuỗi đầu vào ban đầu. Nếu chuỗi ban đầu bao gồm tất cả các giá trị khác không của một hàm, thì DTFT của nó là liên tục (và tuần hoàn), và DFT cung cấp các mẫu cách đều của một chu kỳ. Nếu chuỗi ban đầu là một chu kỳ của một hàm tuần hoàn, thì DFT cung cấp tất cả các giá trị khác không của một chu kỳ DTFT.
 
-The Discrete Fourier transform transforms a sequence of `N` complex numbers:
+Phép biến đổi Fourier rời rạc chuyển đổi một chuỗi `N` số phức:
 
 {x<sub>n</sub>} = x<sub>0</sub>, x<sub>1</sub>, x<sub>2</sub> ..., x<sub>N-1</sub>
 
-into another sequence of complex numbers:
+thành một chuỗi khác của các số phức:
 
 {X<sub>k</sub>} = X<sub>0</sub>, X<sub>1</sub>, X<sub>2</sub> ..., X<sub>N-1</sub>
 
-which is defined by:
+được xác định bởi:
 
 ![DFT](https://wikimedia.org/api/rest_v1/media/math/render/svg/1af0a78dc50bbf118ab6bd4c4dcc3c4ff8502223)
 
-The **Discrete-Time Fourier Transform** (**DTFT**) is a form of Fourier analysis
-that is applicable to the uniformly-spaced samples of a continuous function. The
-term discrete-time refers to the fact that the transform operates on discrete data
-(samples) whose interval often has units of time. From only the samples, it
-produces a function of frequency that is a periodic summation of the continuous
-Fourier transform of the original continuous function.
+**Biến đổi Fourier Rời rạc Thời gian** (**DTFT**) là một dạng của phân tích Fourier mà áp dụng cho các mẫu cách đều của một hàm liên tục. Thuật ngữ thời gian rời rạc chỉ đến việc phép biến đổi hoạt động trên dữ liệu rời rạc (mẫu) mà khoảng cách của nó thường có đơn vị thời gian. Từ chỉ các mẫu, nó tạo ra một hàm của tần số là sự tổng của chu kỳ tuần hoàn của biến đổi Fourier của hàm liên tục ban đầu.
 
-A **Fast Fourier Transform** (**FFT**) is an algorithm that samples a signal over
-a period of time (or space) and divides it into its frequency components. These
-components are single sinusoidal oscillations at distinct frequencies each with
-their own amplitude and phase.
+**Phép Biến Đổi Fourier Nhanh** (**FFT**) là một thuật toán mẫu một tín hiệu trong một khoảng thời gian (hoặc không gian) và phân chia nó thành các thành phần tần số của nó. Các thành phần này là các dao động sin đơn tần số riêng biệt mỗi cái có biên độ và pha riêng.
 
-This transformation is illustrated in Diagram below. Over the time period measured
-in the diagram, the signal contains 3 distinct dominant frequencies.
+Phép biến đổi này được minh họa trong biểu đồ dưới đây. Trong khoảng thời gian được đo trong biểu đồ, tín hiệu chứa 3 tần số quan trọng riêng biệt.
 
-View of a signal in the time and frequency domain:
+Xem tín hiệu trong miền thời gian và tần số:
 
 ![FFT](https://upload.wikimedia.org/wikipedia/commons/6/61/FFT-Time-Frequency-View.png)
 
-An FFT algorithm computes the discrete Fourier transform (DFT) of a sequence, or
-its inverse (IFFT). Fourier analysis converts a signal from its original domain
-to a representation in the frequency domain and vice versa. An FFT rapidly
-computes such transformations by factorizing the DFT matrix into a product of
-sparse (mostly zero) factors. As a result, it manages to reduce the complexity of
-computing the DFT from O(n<sup>2</sup>), which arises if one simply applies the
-definition of DFT, to O(n log n), where n is the data size.
+Một thuật toán FFT tính phép biến đổi Fourier rời rạc (DFT) của một chuỗi, hoặc phép nghịch đảo của nó (IFFT). Phân tích Fourier chuyển đổi một tín hiệu từ miền ban đầu của nó thành một biểu diễn trong miền tần số và ngược lại. Một FFT tính toán nhanh chóng các biến đổi như vậy bằng cách phân tách ma trận DFT thành một tích của các yếu tố thưa (phần lớn là không) số lượng. Do đó, nó quản lý giảm độ phức tạp của việc tính toán DFT từ O(n<sup>2</sup>), mà phát sinh nếu một cách đơn giản áp dụng định nghĩa của DFT, xuống O(n log n), trong đó n là kích thước dữ liệu.
 
-Here a discrete Fourier analysis of a sum of cosine waves at 10, 20, 30, 40,
-and 50 Hz:
+Dưới đây là một phân tích Fourier rời rạc của một tổng của sóng cosin tại 10, 20, 30, 40 và 50 Hz:
 
 ![FFT](https://upload.wikimedia.org/wikipedia/commons/6/64/FFT_of_Cosine_Summation_Function.png)
 
-## Explanation
+## Giải thích
 
-The Fourier Transform is one of deepest insights ever made. Unfortunately, the
-meaning is buried within dense equations:
+Phép Biến Đổi Fourier là một trong những hiểu biết sâu sắc nhất từng được thực hiện. Thật không may, ý nghĩa bị chôn vùi trong các phương trình dày đặc:
 
 ![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/45c088dbb767150fc0bacfeb49dd49e5.png)
 
-and
+và
 
 ![](https://betterexplained.com/wp-content/plugins/wp-latexrender/pictures/faeb9c5bf2e60add63ae4a70b293c7b4.png)
 
-Rather than jumping into the symbols, let's experience the key idea firsthand. Here's a plain-English metaphor:
+Thay vì nhảy vào các biểu tượng, hãy trải nghiệm ý tưởng chính trực tiếp. Dưới đây là một phép phép dụng ngôn ngữ bằng tiếng Anh:
 
-- _What does the Fourier Transform do?_ Given a smoothie, it finds the recipe.
-- _How?_ Run the smoothie through filters to extract each ingredient.
-- _Why?_ Recipes are easier to analyze, compare, and modify than the smoothie itself.
-- _How do we get the smoothie back?_ Blend the ingredients.
+- _Phép Biến Đổi Fourier làm gì?_ Cho một smoothie, nó tìm ra công thức.
+- _Làm thế nào?_ Chạy smoothie qua bộ lọc để trích xuất mỗi thành phần.
+- _Tại sao?_ Công thức dễ phân tích, so sánh và sửa đổi hơn smoothie.
+- _Làm sao để có smoothie trở lại?_ Trộn các thành phần.
 
-**Think With Circles, Not Just Sinusoids**
+**Hãy Suy Nghĩ Với Hình Tròn, Không Chỉ Các Hàm Sin**
 
-The Fourier Transform is about circular paths (not 1-d sinusoids) and Euler's
-formula is a clever way to generate one:
+Phép Biến Đổi Fourier liên quan đến các đường tròn (không chỉ là các hàm sin 1 chiều) và công thức Euler là một cách thông minh để tạo ra chúng:
 
 ![](https://betterexplained.com/wp-content/uploads/euler/equal_paths.png)
 
-Must we use imaginary exponents to move in a circle? Nope. But it's convenient
-and compact. And sure, we can describe our path as coordinated motion in two
-dimensions (real and imaginary), but don't forget the big picture: we're just
-moving in a circle.
+Chúng ta phải sử dụng số mũ ảo để di chuyển trong một vòng tròn không? Không cần. Nhưng nó tiện lợi và gọn gàng. Và đương nhiên, chúng ta có thể mô tả quỹ đạo của mình như là sự di chuyển đồng tọa độ trong hai chiều (thực và ảo), nhưng đừng quên cái nhìn tổng thể: chúng ta chỉ đang di chuyển trong một vòng tròn.
 
-**Discovering The Full Transform**
+**Khám Phá Toàn Bộ Biến Đổi**
 
-The big insight: our signal is just a bunch of time spikes! If we merge the
-recipes for each time spike, we should get the recipe for the full signal.
+Ý tưởng lớn: tín hiệu của chúng ta chỉ là một loạt các tín hiệu spike thời gian! Nếu chúng ta kết hợp các công thức cho mỗi tín hiệu spike thời gian, chúng ta sẽ có công thức cho tín hiệu đầy đủ.
 
-The Fourier Transform builds the recipe frequency-by-frequency:
+Phép Biến Đổi Fourier xây dựng công thức theo tần số:
 
 ![](https://betterexplained.com/wp-content/uploads/images/fourier-explained-20121219-224649.png)
 
-A few notes:
+Một vài ghi chú:
 
-- N = number of time samples we have
-- n = current sample we're considering (0 ... N-1)
-- x<sub>n</sub> = value of the signal at time n
-- k = current frequency we're considering (0 Hertz up to N-1 Hertz)
-- X<sub>k</sub> = amount of frequency k in the signal (amplitude and phase, a complex number)
-- The 1/N factor is usually moved to the reverse transform (going from frequencies back to time). This is allowed, though I prefer 1/N in the forward transform since it gives the actual sizes for the time spikes. You can get wild and even use 1/sqrt(N) on both transforms (going forward and back creates the 1/N factor).
-- n/N is the percent of the time we've gone through. 2 _ pi _ k is our speed in radians / sec. e^-ix is our backwards-moving circular path. The combination is how far we've moved, for this speed and time.
-- The raw equations for the Fourier Transform just say "add the complex numbers". Many programming languages cannot handle complex numbers directly, so you convert everything to rectangular coordinates and add those.
+- N = số lượng mẫu thời gian chúng ta có
+- n = mẫu hiện tại chúng ta đang xem xét (0 ... N-1)
+- x<sub>n</sub> = giá trị của tín hiệu tại thời gian n
+- k = tần số hiện tại chúng ta đang xem xét (0 Hertz lên tới N-1 Hertz)
+- X<sub>k</sub> = lượng tần số k trong tín hiệu (biên độ và pha, một số phức)
+- Yếu tố 1/N thường được di chuyển sang biến đổi nghịch đảo (đi từ tần số trở lại thời gian). Điều này được cho phép, mặc dù tôi thích 1/N trong biến đổi xuất phát vì nó cung cấp các kích thước thực sự cho các tín hiệu spike thời gian. Bạn có thể trở nên hoang đường và thậm chí sử dụng 1/sqrt(N) trên cả hai biến đổi (đi từ trước và đi lại tạo ra yếu tố 1/N).
 
-Stuart Riffle has a great interpretation of the Fourier Transform:
+- n/N là phần trăm thời gian chúng ta đã đi qua. 2 _ pi _ k là tốc độ của chúng ta theo radian / giây. e^-ix là quỹ đạo tròn di chuyển ngược của chúng ta. Sự kết hợp là chúng ta đã di chuyển bao xa, cho tốc độ và thời gian này.
+- Các phương trình gốc cho Biến Đổi Fourier chỉ đơn giản nói "thêm các số phức". Nhiều ngôn ngữ lập trình không thể xử lý trực tiếp các số phức, vì vậy bạn chuyển tất cả mọi thứ sang tọa độ hình chữ nhật và thêm chúng.
+
+Stuart Riffle có một cách giải thích tuyệt vời về Phép Biến Đổi Fourier:
 
 ![](https://betterexplained.com/wp-content/uploads/images/DerivedDFT.png)
 
-## References
+## Tài Liệu Tham Khảo
 
-- [An Interactive Guide To The Fourier Transform](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)
-- [DFT on YouTube by Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [FT on YouTube by 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [FFT on YouTube by Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
+- [Hướng dẫn tương tác về Biến Đổi Fourier](https://betterexplained.com/articles/an-interactive-guide-to-the-fourier-transform/)
+- [DFT trên YouTube bởi Better Explained](https://www.youtube.com/watch?v=iN0VG9N2q0U&t=0s&index=77&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [FT trên YouTube bởi 3Blue1Brown](https://www.youtube.com/watch?v=spUNpyF58BY&t=0s&index=76&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [FFT trên YouTube bởi Simon Xu](https://www.youtube.com/watch?v=htCj9exbGo0&index=78&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&t=0s)
 - Wikipedia
   - [FT](https://en.wikipedia.org/wiki/Fourier_transform)
   - [DFT](https://www.wikiwand.com/en/Discrete_Fourier_transform)
diff --git a/src/algorithms/math/horner-method/README.en-EN.md b/src/algorithms/math/horner-method/README.en-EN.md
new file mode 100644
index 0000000000..691b5862d7
--- /dev/null
+++ b/src/algorithms/math/horner-method/README.en-EN.md
@@ -0,0 +1,23 @@
+# Horner's Method
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, Horner's method (or Horner's scheme) is an algorithm for polynomial evaluation. With this method, it is possible to evaluate a polynomial with only `n` additions and `n` multiplications. Hence, its storage requirements are `n` times the number of bits of `x`.
+
+Horner's method can be based on the following identity:
+
+![Horner's rule](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4)
+
+This identity is called _Horner's rule_.
+
+To solve the right part of the identity above, for a given `x`, we start by iterating through the polynomial from the inside out, accumulating each iteration result. After `n` iterations, with `n` being the order of the polynomial, the accumulated result gives us the polynomial evaluation.
+
+**Using the polynomial:**
+`4 * x^4 + 2 * x^3 + 3 * x^2 + x^1 + 3`, a traditional approach to evaluate it at `x = 2`, could be representing it as an array `[3, 1, 3, 2, 4]` and iterate over it saving each iteration value at an accumulator, such as `acc += pow(x=2, index) * array[index]`. In essence, each power of a number (`pow`) operation is `n-1` multiplications. So, in this scenario, a total of `14` operations would have happened, composed of `4` additions, `5` multiplications, and `5` pows (we're assuming that each power is calculated by repeated multiplication).
+
+Now, **using the same scenario but with Horner's rule**, the polynomial can be re-written as `x * (x * (x * (4 * x + 2) + 3) + 1) + 3`, representing it as `[4, 2, 3, 1, 3]` it is possible to save the first iteration as `acc = arr[0] * (x=2) + arr[1]`, and then finish iterations for `acc *= (x=2) + arr[index]`. In the same scenario but using Horner's rule, a total of `10` operations would have happened, composed of only `4` additions and `4` multiplications.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Horner%27s_method)
diff --git a/src/algorithms/math/horner-method/README.md b/src/algorithms/math/horner-method/README.md
index 991a674deb..c58847dea6 100644
--- a/src/algorithms/math/horner-method/README.md
+++ b/src/algorithms/math/horner-method/README.md
@@ -1,20 +1,23 @@
-# Horner's Method
+# Phương Pháp của Horner
 
-In mathematics, Horner's method (or Horner's scheme) is an algorithm for polynomial evaluation. With this method, it is possible to evaluate a polynomial with only `n` additions and `n` multiplications. Hence, its storage requirements are `n` times the number of bits of `x`.
+_Xem bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Horner's method can be based on the following identity:
+Trong toán học, phương pháp của Horner (hoặc còn gọi là phương pháp Horner) là một thuật toán để tính giá trị của đa thức. Với phương pháp này, có thể tính giá trị của một đa thức chỉ với `n` phép cộng và `n` phép nhân. Do đó, yêu cầu lưu trữ của nó là `n` lần số bit của `x`.
 
-![Horner's rule](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4)
+Phương pháp của Horner có thể được dựa trên công thức sau đây:
 
-This identity is called _Horner's rule_.
+![Quy tắc của Horner](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4)
 
-To solve the right part of the identity above, for a given `x`, we start by iterating through the polynomial from the inside out, accumulating each iteration result. After `n` iterations, with `n` being the order of the polynomial, the accumulated result gives us the polynomial evaluation. 
+Công thức này được gọi là _quy tắc của Horner_.
 
-**Using the polynomial:**
-`4 * x^4 + 2 * x^3 + 3 * x^2 + x^1 + 3`, a traditional approach to evaluate it at `x = 2`, could be representing it as an array `[3, 1, 3, 2, 4]` and iterate over it saving each iteration value at an accumulator, such as `acc += pow(x=2, index) * array[index]`. In essence, each power of a number (`pow`) operation is `n-1` multiplications. So, in this scenario, a total of `14` operations would have happened, composed of `4` additions, `5` multiplications, and `5` pows (we're assuming that each power is calculated by repeated multiplication).
+Để giải quyết phần bên phải của công thức trên, với một `x` cụ thể, chúng ta bắt đầu bằng cách lặp qua đa thức từ bên trong ra ngoài, tích lũy kết quả của mỗi lần lặp. Sau `n` lần lặp, với `n` là bậc của đa thức, kết quả tích lũy sẽ cho chúng ta giá trị của đa thức.
 
-Now, **using the same scenario but with Horner's rule**, the polynomial can be re-written as `x * (x * (x * (4 * x + 2) + 3) + 1) + 3`, representing it as `[4, 2, 3, 1, 3]` it is possible to save the first iteration as `acc = arr[0] * (x=2) + arr[1]`, and then finish iterations for `acc *= (x=2) + arr[index]`. In the same scenario but using Horner's rule, a total of `10` operations would have happened, composed of only `4` additions and `4` multiplications.
+**Sử dụng đa thức:**
+`4 * x^4 + 2 * x^3 + 3 * x^2 + x^1 + 3`, một cách tiếp cận truyền thống để tính giá trị của nó tại `x = 2`, có thể được biểu diễn dưới dạng một mảng `[3, 1, 3, 2, 4]` và lặp qua nó, lưu mỗi giá trị lặp lại vào một biến tích lũy, ví dụ như `acc += pow(x=2, index) * array[index]`. Về bản chất, mỗi phép tính lũy thừa của một số (`pow`) đều có `n-1` phép nhân. Vì vậy, trong kịch bản này, tổng cộng sẽ có `14` phép tính đã xảy ra, bao gồm `4` phép cộng, `5` phép nhân và `5` phép lũy thừa (chúng ta giả định rằng mỗi lũy thừa được tính bằng cách nhân lặp lại).
 
-## References
+Bây giờ, **sử dụng cùng một kịch bản nhưng với quy tắc của Horner**, đa thức có thể được viết lại thành `x * (x * (x * (4 * x + 2) + 3) + 1) + 3`, biểu diễn nó dưới dạng `[4, 2, 3, 1, 3]`, có thể lưu giá trị của lần lặp đầu tiên là `acc = arr[0] * (x=2) + arr[1]`, và sau đó kết thúc các lần lặp cho `acc *= (x=2) + arr[index]`. Trong cùng một kịch bản nhưng sử dụng quy tắc của Horner, tổng cộng sẽ có `10` phép tính đã xảy ra, bao gồm chỉ `4` phép cộng và `4` phép nhân.
+
+## Tài Liệu Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Horner%27s_method)
diff --git a/src/algorithms/math/integer-partition/README.en-EN.md b/src/algorithms/math/integer-partition/README.en-EN.md
new file mode 100644
index 0000000000..77b5428997
--- /dev/null
+++ b/src/algorithms/math/integer-partition/README.en-EN.md
@@ -0,0 +1,37 @@
+# Integer Partition
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In number theory and combinatorics, a partition of a positive
+integer `n`, also called an **integer partition**, is a way of
+writing `n` as a sum of positive integers.
+
+Two sums that differ only in the order of their summands are
+considered the same partition. For example, `4` can be partitioned
+in five distinct ways:
+
+```
+4
+3 + 1
+2 + 2
+2 + 1 + 1
+1 + 1 + 1 + 1
+```
+
+The order-dependent composition `1 + 3` is the same partition
+as `3 + 1`, while the two distinct
+compositions `1 + 2 + 1` and `1 + 1 + 2` represent the same
+partition `2 + 1 + 1`.
+
+Young diagrams associated to the partitions of the positive
+integers `1` through `8`. They are arranged so that images
+under the reflection about the main diagonal of the square
+are conjugate partitions.
+
+![Integer Partition](https://upload.wikimedia.org/wikipedia/commons/d/d8/Ferrer_partitioning_diagrams.svg)
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Partition_(number_theory)>)
+- [YouTube](https://www.youtube.com/watch?v=ZaVM057DuzE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/math/integer-partition/README.md b/src/algorithms/math/integer-partition/README.md
index 6023e1505a..3b2f69da5e 100644
--- a/src/algorithms/math/integer-partition/README.md
+++ b/src/algorithms/math/integer-partition/README.md
@@ -1,12 +1,11 @@
-# Integer Partition
+# Phân Phối Số Nguyên
 
-In number theory and combinatorics, a partition of a positive 
-integer `n`, also called an **integer partition**, is a way of 
-writing `n` as a sum of positive integers. 
+_Xem bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Two sums that differ only in the order of their summands are 
-considered the same partition. For example, `4` can be partitioned 
-in five distinct ways:
+Trong lý thuyết số học và tổ hợp học, một phân phối của một số nguyên dương `n`, còn được gọi là một **phân phối số nguyên**, là một cách viết `n` dưới dạng tổng của các số nguyên dương.
+
+Hai tổng chỉ khác nhau về thứ tự của các số hạng được coi là cùng một phân phối. Ví dụ, `4` có thể được phân phối thành năm cách khác nhau:
 
 ```
 4
@@ -16,19 +15,13 @@ in five distinct ways:
 1 + 1 + 1 + 1
 ```
 
-The order-dependent composition `1 + 3` is the same partition
-as `3 + 1`, while the two distinct 
-compositions `1 + 2 + 1` and `1 + 1 + 2` represent the same 
-partition `2 + 1 + 1`.
+Tổ hợp phụ thuộc vào thứ tự `1 + 3` là cùng một phân phối với `3 + 1`, trong khi hai tổ hợp phân biệt `1 + 2 + 1` và `1 + 1 + 2` đại diện cho cùng một phân phối `2 + 1 + 1`.
 
-Young diagrams associated to the partitions of the positive
-integers `1` through `8`. They are arranged so that images 
-under the reflection about the main diagonal of the square 
-are conjugate partitions.
+Biểu đồ Young liên quan đến các phân phối của các số nguyên dương từ `1` đến `8`. Chúng được sắp xếp sao cho các hình ảnh qua phản chiếu về đường chéo chính của hình vuông là các phân phối liên kết.
 
-![Integer Partition](https://upload.wikimedia.org/wikipedia/commons/d/d8/Ferrer_partitioning_diagrams.svg)
+![Phân Phối Số Nguyên](https://upload.wikimedia.org/wikipedia/commons/d/d8/Ferrer_partitioning_diagrams.svg)
 
-## References
+## Tài Liệu Tham Khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Partition_(number_theory))
+- [Wikipedia](<https://en.wikipedia.org/wiki/Partition_(number_theory)>)
 - [YouTube](https://www.youtube.com/watch?v=ZaVM057DuzE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/math/is-power-of-two/README.en-EN.md b/src/algorithms/math/is-power-of-two/README.en-EN.md
new file mode 100644
index 0000000000..e2ddf507c7
--- /dev/null
+++ b/src/algorithms/math/is-power-of-two/README.en-EN.md
@@ -0,0 +1,54 @@
+# Is a power of two
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Given a positive integer, write a function to find if it is
+a power of two or not.
+
+**Naive solution**
+
+In naive solution we just keep dividing the number by two
+unless the number becomes `1` and every time we do so, we
+check that remainder after division is always `0`. Otherwise, the number can't be a power of two.
+
+**Bitwise solution**
+
+Powers of two in binary form always have just one bit set.
+The only exception is with a signed integer (e.g. an 8-bit
+signed integer with a value of -128 looks like: `10000000`)
+
+```
+1: 0001
+2: 0010
+4: 0100
+8: 1000
+```
+
+So after checking that the number is greater than zero,
+we can use a bitwise hack to test that one and only one
+bit is set.
+
+```
+number & (number - 1)
+```
+
+For example for number `8` that operations will look like:
+
+```
+  1000
+- 0001
+  ----
+  0111
+
+  1000
+& 0111
+  ----
+  0000
+```
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)
+- [Bitwise Solution on Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
+- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)
diff --git a/src/algorithms/math/is-power-of-two/README.md b/src/algorithms/math/is-power-of-two/README.md
index 6ed1e92568..c48f4a6f45 100644
--- a/src/algorithms/math/is-power-of-two/README.md
+++ b/src/algorithms/math/is-power-of-two/README.md
@@ -1,19 +1,17 @@
-# Is a power of two
+# Is a power of two - Là Lũy Thừa Của Hai
 
-Given a positive integer, write a function to find if it is
-a power of two or not.
+_Xem bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-**Naive solution**
+Cho một số nguyên dương, hãy viết một hàm để kiểm tra xem nó có phải là lũy thừa của hai hay không.
 
-In naive solution we just keep dividing the number by two
-unless the number becomes `1` and every time we do so, we
-check that remainder after division is always `0`. Otherwise, the number can't be a power of two.
+**Giải pháp Naive**
 
-**Bitwise solution**
+Trong giải pháp Naive, chúng ta chỉ cần tiếp tục chia số cho hai cho đến khi số trở thành `1` và mỗi lần làm như vậy, chúng ta kiểm tra rằng phần dư sau khi chia luôn là `0`. Nếu không, số đó không thể là một lũy thừa của hai.
 
-Powers of two in binary form always have just one bit set.
-The only exception is with a signed integer (e.g. an 8-bit
-signed integer with a value of -128 looks like: `10000000`)
+**Giải pháp Bitwise**
+
+Các lũy thừa của hai trong hệ nhị phân luôn chỉ có một bit được thiết lập. Duy nhất ngoại lệ là với một số nguyên có dấu (ví dụ: một số nguyên có dấu 8 bit với giá trị -128 sẽ trông như sau: `10000000`)
 
 ```
 1: 0001
@@ -22,15 +20,13 @@ signed integer with a value of -128 looks like: `10000000`)
 8: 1000
 ```
 
-So after checking that the number is greater than zero,
-we can use a bitwise hack to test that one and only one
-bit is set.
+Vì vậy, sau khi kiểm tra số có lớn hơn không, chúng ta có thể sử dụng một phép toán bitwise để kiểm tra rằng chỉ có một bit được thiết lập.
 
 ```
-number & (number - 1)
+số & (số - 1)
 ```
 
-For example for number `8` that operations will look like:
+Ví dụ cho số `8`, phép toán đó sẽ như sau:
 
 ```
   1000
@@ -44,8 +40,8 @@ For example for number `8` that operations will look like:
   0000
 ```
 
-## References
+## Tài Liệu Tham Khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)
-- [Bitwise Solution on Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
-- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)
+- [Giải pháp Bitwise trên Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
+- [Phép trừ số nhị phân trên YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)
diff --git a/src/algorithms/math/least-common-multiple/README.en-EN.md b/src/algorithms/math/least-common-multiple/README.en-EN.md
new file mode 100644
index 0000000000..0f79604143
--- /dev/null
+++ b/src/algorithms/math/least-common-multiple/README.en-EN.md
@@ -0,0 +1,65 @@
+# Least common multiple
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In arithmetic and number theory, the least common multiple,
+lowest common multiple, or smallest common multiple of
+two integers `a` and `b`, usually denoted by `LCM(a, b)`, is
+the smallest positive integer that is divisible by
+both `a` and `b`. Since division of integers by zero is
+undefined, this definition has meaning only if `a` and `b` are
+both different from zero. However, some authors define `lcm(a,0)`
+as `0` for all `a`, which is the result of taking the `lcm`
+to be the least upper bound in the lattice of divisibility.
+
+## Example
+
+What is the LCM of 4 and 6?
+
+Multiples of `4` are:
+
+```
+4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, ...
+```
+
+and the multiples of `6` are:
+
+```
+6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, ...
+```
+
+Common multiples of `4` and `6` are simply the numbers
+that are in both lists:
+
+```
+12, 24, 36, 48, 60, 72, ....
+```
+
+So, from this list of the first few common multiples of
+the numbers `4` and `6`, their least common multiple is `12`.
+
+## Computing the least common multiple
+
+The following formula reduces the problem of computing the
+least common multiple to the problem of computing the greatest
+common divisor (GCD), also known as the greatest common factor:
+
+```
+lcm(a, b) = |a * b| / gcd(a, b)
+```
+
+![LCM](https://upload.wikimedia.org/wikipedia/commons/c/c9/Symmetrical_5-set_Venn_diagram_LCM_2_3_4_5_7.svg)
+
+A Venn diagram showing the least common multiples of
+combinations of `2`, `3`, `4`, `5` and `7` (`6` is skipped as
+it is `2 × 3`, both of which are already represented).
+
+For example, a card game which requires its cards to be
+divided equally among up to `5` players requires at least `60`
+cards, the number at the intersection of the `2`, `3`, `4`
+and `5` sets, but not the `7` set.
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Least_common_multiple)
diff --git a/src/algorithms/math/least-common-multiple/README.md b/src/algorithms/math/least-common-multiple/README.md
index 3e49af9a5f..bc4b0bad85 100644
--- a/src/algorithms/math/least-common-multiple/README.md
+++ b/src/algorithms/math/least-common-multiple/README.md
@@ -1,46 +1,47 @@
-# Least common multiple
+# Least common multiple - Bội số chung nhỏ nhất
 
-In arithmetic and number theory, the least common multiple, 
-lowest common multiple, or smallest common multiple of 
-two integers `a` and `b`, usually denoted by `LCM(a, b)`, is 
-the smallest positive integer that is divisible by 
-both `a` and `b`. Since division of integers by zero is 
-undefined, this definition has meaning only if `a` and `b` are 
-both different from zero. However, some authors define `lcm(a,0)`
-as `0` for all `a`, which is the result of taking the `lcm`
-to be the least upper bound in the lattice of divisibility.
+_Xem bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Example
+Trong toán học và lý thuyết số, bội số chung nhỏ nhất,
+hoặc bội số chung nhỏ nhất của hai số nguyên dương `a` và `b`,
+thường được ký hiệu là `LCM(a, b)`, là số nguyên dương nhỏ nhất
+mà chia hết cho cả `a` và `b`. Vì phép chia của số nguyên cho không
+là không xác định, định nghĩa này chỉ có ý nghĩa khi `a` và `b` đều
+khác không. Tuy nhiên, một số tác giả định nghĩa `lcm(a,0)`
+là `0` cho tất cả các `a`, điều này là kết quả của việc lấy
+`lcm` là giá trị nhỏ nhất trong lưới của tính chia hết.
 
-What is the LCM of 4 and 6?
+## Ví dụ
 
-Multiples of `4` are:
+LCM của 4 và 6 là gì?
+
+Các bội số của `4` là:
 
 ```
 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, ...
 ```
 
-and the multiples of `6` are:
+và các bội số của `6` là:
 
 ```
 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, ...
 ```
 
-Common multiples of `4` and `6` are simply the numbers 
-that are in both lists:
+Các bội số chung của `4` và `6` đơn giản là các số
+nằm trong cả hai danh sách:
 
 ```
 12, 24, 36, 48, 60, 72, ....
 ```
 
-So, from this list of the first few common multiples of 
-the numbers `4` and `6`, their least common multiple is `12`.
+Vậy, từ danh sách này của một số bội số chung đầu tiên của
+các số `4` và `6`, bội số chung nhỏ nhất của chúng là `12`.
 
-## Computing the least common multiple
+## Tính bội số chung nhỏ nhất
 
-The following formula reduces the problem of computing the 
-least common multiple to the problem of computing the greatest 
-common divisor (GCD), also known as the greatest common factor:
+Công thức sau đây giảm bài toán tính bội số chung nhỏ nhất
+xuống thành bài toán tính ước số chung lớn nhất (GCD), còn được gọi là ước số chung lớn nhất:
 
 ```
 lcm(a, b) = |a * b| / gcd(a, b)
@@ -48,15 +49,15 @@ lcm(a, b) = |a * b| / gcd(a, b)
 
 ![LCM](https://upload.wikimedia.org/wikipedia/commons/c/c9/Symmetrical_5-set_Venn_diagram_LCM_2_3_4_5_7.svg)
 
-A Venn diagram showing the least common multiples of 
-combinations of `2`, `3`, `4`, `5` and `7` (`6` is skipped as 
-it is `2 × 3`, both of which are already represented).
+Một biểu đồ Venn hiển thị các bội số chung nhỏ nhất của
+các tổ hợp của `2`, `3`, `4`, `5` và `7` (`6` bị bỏ qua vì
+nó là `2 × 3`, cả hai đều đã được đại diện).
 
-For example, a card game which requires its cards to be 
-divided equally among up to `5` players requires at least `60`
-cards, the number at the intersection of the `2`, `3`, `4`
-and `5` sets, but not the `7` set.
+Ví dụ, một trò chơi bài yêu cầu các lá bài của nó
+phải được chia đều cho tối đa `5` người chơi yêu cầu ít nhất `60`
+lá bài, số tại giao của các tập hợp `2`, `3`, `4`
+và `5`, nhưng không phải là tập hợp `7`.
 
-## References
+## Tài Liệu Tham Khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Least_common_multiple)
diff --git a/src/algorithms/math/liu-hui/README.en-EN.md b/src/algorithms/math/liu-hui/README.en-EN.md
new file mode 100644
index 0000000000..e26effbe89
--- /dev/null
+++ b/src/algorithms/math/liu-hui/README.en-EN.md
@@ -0,0 +1,94 @@
+# Liu Hui's π Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Liu Hui remarked in his commentary to The Nine Chapters on the Mathematical Art,
+that the ratio of the circumference of an inscribed hexagon to the diameter of
+the circle was `three`, hence `π` must be greater than three. He went on to provide
+a detailed step-by-step description of an iterative algorithm to calculate `π` to
+any required accuracy based on bisecting polygons; he calculated `π` to
+between `3.141024` and `3.142708` with a 96-gon; he suggested that `3.14` was
+a good enough approximation, and expressed `π` as `157/50`; he admitted that
+this number was a bit small. Later he invented an ingenious quick method to
+improve on it, and obtained `π ≈ 3.1416` with only a 96-gon, with an accuracy
+comparable to that from a 1536-gon. His most important contribution in this
+area was his simple iterative `π` algorithm.
+
+## Area of a circle
+
+Liu Hui argued:
+
+> Multiply one side of a hexagon by the radius (of its
+> circumcircle), then multiply this by three, to yield the
+> area of a dodecagon; if we cut a hexagon into a
+> dodecagon, multiply its side by its radius, then again
+> multiply by six, we get the area of a 24-gon; the finer
+> we cut, the smaller the loss with respect to the area
+> of circle, thus with further cut after cut, the area of
+> the resulting polygon will coincide and become one with
+> the circle; there will be no loss
+
+![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/6/69/Cutcircle2.svg)
+
+Liu Hui's method of calculating the area of a circle.
+
+Further, Liu Hui proved that the area of a circle is half of its circumference
+multiplied by its radius. He said:
+
+> Between a polygon and a circle, there is excess radius. Multiply the excess
+> radius by a side of the polygon. The resulting area exceeds the boundary of
+> the circle
+
+In the diagram `d = excess radius`. Multiplying `d` by one side results in
+oblong `ABCD` which exceeds the boundary of the circle. If a side of the polygon
+is small (i.e. there is a very large number of sides), then the excess radius
+will be small, hence excess area will be small.
+
+> Multiply the side of a polygon by its radius, and the area doubles;
+> hence multiply half the circumference by the radius to yield the area of circle.
+
+![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/9/95/Cutcircle.svg)
+
+The area within a circle is equal to the radius multiplied by half the
+circumference, or `A = r x C/2 = r x r x π`.
+
+## Iterative algorithm
+
+Liu Hui began with an inscribed hexagon. Let `M` be the length of one side `AB` of
+hexagon, `r` is the radius of circle.
+
+![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/4/46/Liuhui_geyuanshu.svg)
+
+Bisect `AB` with line `OPC`, `AC` becomes one side of dodecagon (12-gon), let
+its length be `m`. Let the length of `PC` be `j` and the length of `OP` be `G`.
+
+`AOP`, `APC` are two right angle triangles. Liu Hui used
+the [Gou Gu](https://en.wikipedia.org/wiki/Pythagorean_theorem) (Pythagorean theorem)
+theorem repetitively:
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/dbfc192c78539c3901c7bad470302ededb76f813)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/ccd12a402367c2d6614c88e75006d50bfc3a9929)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/65d77869fc02c302d2d46d45f75ad7e79ae524fb)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/a7a0d0d7f505a0f434e5dd80c2fef6d2b30d6100)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/c31b9acf38f9d1a248d4023c3bf286bd03007f37)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/0dee798efb0b1e3e64d6b3542106cb3ecaa4a383)
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/3ffeafe88d2983b364ad3442746063e3207fe842)
+
+From here, there is now a technique to determine `m` from `M`, which gives the
+side length for a polygon with twice the number of edges. Starting with a
+hexagon, Liu Hui could determine the side length of a dodecagon using this
+formula. Then continue repetitively to determine the side length of a
+24-gon given the side length of a dodecagon. He could do this recursively as
+many times as necessary. Knowing how to determine the area of these polygons,
+Liu Hui could then approximate `π`.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Liu_Hui%27s_%CF%80_algorithm)
diff --git a/src/algorithms/math/liu-hui/README.md b/src/algorithms/math/liu-hui/README.md
index c53257f8dd..0d2be71348 100644
--- a/src/algorithms/math/liu-hui/README.md
+++ b/src/algorithms/math/liu-hui/README.md
@@ -1,68 +1,71 @@
-# Liu Hui's π Algorithm
-
-Liu Hui remarked in his commentary to The Nine Chapters on the Mathematical Art,
-that the ratio of the circumference of an inscribed hexagon to the diameter of 
-the circle was `three`, hence `π` must be greater than three. He went on to provide 
-a detailed step-by-step description of an iterative algorithm to calculate `π` to 
-any required accuracy based on bisecting polygons; he calculated `π` to 
-between `3.141024` and `3.142708` with a 96-gon; he suggested that `3.14` was 
-a good enough approximation, and expressed `π` as `157/50`; he admitted that 
-this number was a bit small. Later he invented an ingenious quick method to 
-improve on it, and obtained `π ≈ 3.1416` with only a 96-gon, with an accuracy 
-comparable to that from a 1536-gon. His most important contribution in this 
-area was his simple iterative `π` algorithm.
-
-## Area of a circle
-
-Liu Hui argued:
-
-> Multiply one side of a hexagon by the radius (of its 
-circumcircle), then multiply this by three, to yield the 
-area of a dodecagon; if we cut a hexagon into a 
-dodecagon, multiply its side by its radius, then again 
-multiply by six, we get the area of a 24-gon; the finer 
-we cut, the smaller the loss with respect to the area 
-of circle, thus with further cut after cut, the area of 
-the resulting polygon will coincide and become one with 
-the circle; there will be no loss
+# Thuật toán π của Liu Hui
+
+_Xem bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong bình luận của mình về Tám Chương về Nghệ Thuật Toán Học,
+Liu Hui đã chú ý rằng tỉ lệ của chu vi của một hình lục giác nội tiếp với đường
+kính của hình tròn là `ba`, vì vậy `π` phải lớn hơn ba. Ông tiếp tục cung cấp
+một mô tả chi tiết từng bước của một thuật toán lặp để tính `π` với
+bất kỳ độ chính xác cần thiết dựa trên việc chia đôi các đa giác; ông tính `π` tới
+từ `3.141024` đến `3.142708` với một hình 96 cạnh; ông đề xuất rằng `3.14`
+là một xấp xỉ đủ tốt, và diễn đạt `π` là `157/50`; ông thừa nhận rằng
+số này nhỏ hơn một chút. Sau đó, ông đã phát minh ra một phương pháp nhanh chóng và
+tinh tế để cải thiện nó, và thu được `π ≈ 3.1416` chỉ với một hình 96 cạnh, với một độ chính xác
+tương đương với một hình 1536 cạnh. Đó là đóng góp quan trọng nhất của ông trong
+lĩnh vực này là thuật toán `π` lặp lại đơn giản của ông.
+
+## Diện tích của một hình tròn
+
+Liu Hui lập luận:
+
+> Nhân một cạnh của một hình lục giác với bán kính (của nó
+> vòng ngoài), sau đó nhân tiếp điều này với ba, để thu được
+> diện tích của một hình đa giác dodecagon; nếu chúng ta chia một hình lục giác thành
+> dodecagon, nhân cạnh của nó với bán kính của nó, sau đó lại
+> nhân với sáu, chúng ta thu được diện tích của một hình đa giác 24 cạnh; càng tinh tế
+> chúng ta cắt, mất mát càng nhỏ so với diện tích
+> của hình tròn, do đó với mỗi lần cắt sau, diện tích của
+> hình đa giác kết quả sẽ trùng khớp và trở thành một với
+> hình tròn; không có mất mát nào sẽ xảy ra
 
 ![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/6/69/Cutcircle2.svg)
 
-Liu Hui's method of calculating the area of a circle.
+Phương pháp của Liu Hui để tính diện tích của một hình tròn.
 
-Further, Liu Hui proved that the area of a circle is half of its circumference 
-multiplied by its radius. He said:
+Hơn nữa, Liu Hui chứng minh rằng diện tích của một hình tròn bằng một nửa chu vi của nó
+nhân với bán kính của nó. Ông nói:
 
-> Between a polygon and a circle, there is excess radius. Multiply the excess 
-radius by a side of the polygon. The resulting area exceeds the boundary of 
-the circle
+> Giữa một đa giác và một hình tròn, có sự dư thừa về bán kính. Nhân sự
+> dư thừa bán kính với một cạnh của đa giác. Kết quả là diện tích vượt quá biên của
+> hình tròn
 
-In the diagram `d = excess radius`. Multiplying `d` by one side results in 
-oblong `ABCD` which exceeds the boundary of the circle. If a side of the polygon 
-is small (i.e. there is a very large number of sides), then the excess radius 
-will be small, hence excess area will be small.
+Trong biểu đồ `d = dư thừa bán kính`. Nhân `d` với một cạnh sẽ dẫn đến
+hình chữ nhật `ABCD` vượt quá biên của hình tròn. Nếu một cạnh của đa giác
+nhỏ (tức là có một số lượng rất lớn các cạnh), thì dư thừa bán kính
+sẽ nhỏ, do đó diện tích dư thừa sẽ nhỏ.
 
-> Multiply the side of a polygon by its radius, and the area doubles; 
-hence multiply half the circumference by the radius to yield the area of circle.
+> Nhân một cạnh của một đa giác với bán kính của nó, và diện tích tăng gấp đôi;
+> do đó nhân nửa chu vi với bán kính để thu được diện tích của hình tròn.
 
 ![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/9/95/Cutcircle.svg)
 
-The area within a circle is equal to the radius multiplied by half the 
-circumference, or `A = r x C/2 = r x r x π`.
+Diện tích bên trong một hình tròn bằng cách nhân bán kính với một nửa của
+chu vi, hoặc `A = r x C/2 = r x r x π`.
 
-## Iterative algorithm
+## Thuật toán lặp lại
 
-Liu Hui began with an inscribed hexagon. Let `M` be the length of one side `AB` of 
-hexagon, `r` is the radius of circle.
+Liu Hui bắt đầu với một hình lục giác nội tiếp. Hãy cho `M` là chiều dài của một cạnh `AB` của
+hình lục giác, `r` là bán kính của hình tròn.
 
 ![Liu Hui](https://upload.wikimedia.org/wikipedia/commons/4/46/Liuhui_geyuanshu.svg)
 
-Bisect `AB` with line `OPC`, `AC` becomes one side of dodecagon (12-gon), let 
-its length be `m`. Let the length of `PC` be `j` and the length of `OP` be `G`.
+Chia `AB` đôi với đoạn thẳng `OPC`, `AC` trở thành một cạnh của dodecagon (12 cạnh), hãy
+chiều dài của nó là `m`. Hãy cho chiều dài của `PC` là `j` và chiều dài của `OP` là `G`.
 
-`AOP`, `APC` are two right angle triangles. Liu Hui used 
-the [Gou Gu](https://en.wikipedia.org/wiki/Pythagorean_theorem) (Pythagorean theorem)
-theorem repetitively:
+`AOP`, `APC` là hai tam giác vuông. Liu Hui đã sử dụng
+[Định lý Gou Gu](https://en.wikipedia.org/wiki/Pythagorean_theorem) (Định lý Pythagoras)
+lặp đi lặp lại:
 
 ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/dbfc192c78539c3901c7bad470302ededb76f813)
 
@@ -78,15 +81,14 @@ theorem repetitively:
 
 ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/3ffeafe88d2983b364ad3442746063e3207fe842)
 
+Từ đây, bây giờ có một kỹ thuật để xác định `m` từ `M`, cho biết
+độ dài cạnh cho một đa giác với gấp đôi số cạnh. Bắt đầu với một
+hình lục giác, Liu Hui có thể xác định chiều dài cạnh của một dodecagon bằng cách sử dụng công thức này.
+Sau đó tiếp tục lặp lại để xác định chiều dài cạnh của một
+24-gon cho trước chiều dài cạnh của một dodecagon. Ông có thể làm điều này đệ quy như
+nhiều lần cần thiết. Biết cách xác định diện tích của các đa giác này,
+Liu Hui sau đó có thể ước lượng `π`.
 
-From here, there is now a technique to determine `m` from `M`, which gives the 
-side length for a polygon with twice the number of edges. Starting with a 
-hexagon, Liu Hui could determine the side length of a dodecagon using this 
-formula. Then continue repetitively to determine the side length of a 
-24-gon given the side length of a dodecagon. He could do this recursively as 
-many times as necessary. Knowing how to determine the area of these polygons, 
-Liu Hui could then approximate `π`.
-
-## References
+## Tài Liệu Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Liu_Hui%27s_%CF%80_algorithm)
diff --git a/src/algorithms/math/matrix/README.en-EN.md b/src/algorithms/math/matrix/README.en-EN.md
new file mode 100644
index 0000000000..10270fb3e7
--- /dev/null
+++ b/src/algorithms/math/matrix/README.en-EN.md
@@ -0,0 +1,66 @@
+# Matrices
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, a **matrix** (plural **matrices**) is a rectangular array or table of numbers, symbols, or expressions, arranged in rows and columns. For example, the dimension of the matrix below is `2 × 3` (read "two by three"), because there are two rows and three columns:
+
+```
+| 1  9 -13 |
+| 20 5 -6  |
+```
+
+![An `m × n` matrix](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png)
+
+An `m × n` matrix: the `m` rows are horizontal, and the `n` columns are vertical. Each element of a matrix is often denoted by a variable with two subscripts. For example, <i>a<sub>2,1</sub></i> represents the element at the second row and first column of the matrix
+
+## Operations on matrices
+
+### Addition
+
+To add two matrices: add the numbers in the matching positions:
+
+![Matrices addition](https://www.mathsisfun.com/algebra/images/matrix-addition.gif)
+
+The two matrices must be the same size, i.e. the rows must match in size, and the columns must match in size.
+
+### Subtracting
+
+To subtract two matrices: subtract the numbers in the matching positions:
+
+![Matrices subtraction](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif)
+
+### Multiply by a Constant
+
+We can multiply a matrix by a constant (the value 2 in this case):
+
+![Matrices multiplication be a constant](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif)
+
+### Multiplying by Another Matrix
+
+To multiply a matrix by another matrix we need to do the [dot product](https://www.mathsisfun.com/algebra/vectors-dot-product.html) of rows and columns.
+
+To work out the answer for the **1st row** and **1st column**:
+
+![Matrices multiplication - 1st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg)
+
+Here it is for the 1st row and 2nd column:
+
+![Matrices multiplication - 2st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg)
+
+If we'll do the same for the rest of the rows and columns we'll get the following resulting matrix:
+
+![Matrices multiplication - Result](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg)
+
+### Transposing
+
+To "transpose" a matrix, swap the rows and columns.
+
+We put a "T" in the top right-hand corner to mean transpose:
+
+![Transposing](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif)
+
+## References
+
+- [Matrices on MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html)
+- [Matrix on Wikipedia](<https://en.wikipedia.org/wiki/Matrix_(mathematics)>)
diff --git a/src/algorithms/math/matrix/README.md b/src/algorithms/math/matrix/README.md
index 8e084403b0..bbf364583c 100644
--- a/src/algorithms/math/matrix/README.md
+++ b/src/algorithms/math/matrix/README.md
@@ -1,63 +1,66 @@
-# Matrices
+# Ma trận
 
-In mathematics, a **matrix** (plural **matrices**) is a rectangular array or table of numbers, symbols, or expressions, arranged in rows and columns. For example, the dimension of the matrix below is `2 × 3` (read "two by three"), because there are two rows and three columns:
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong toán học, một **ma trận** (số ít **ma trận**, số nhiều **ma trận**) là một mảng chữ nhật hoặc bảng các số, ký hiệu hoặc biểu thức, được sắp xếp thành các hàng và cột. Ví dụ, kích thước của ma trận dưới đây là `2 × 3` (đọc là "hai lần ba"), bởi vì có hai hàng và ba cột:
 
 ```
 | 1  9 -13 |
 | 20 5 -6  |
 ```
 
-![An `m × n` matrix](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png)
+![Một ma trận `m × n`](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png)
 
-An `m × n` matrix: the `m` rows are horizontal, and the `n` columns are vertical. Each element of a matrix is often denoted by a variable with two subscripts. For example, <i>a<sub>2,1</sub></i> represents the element at the second row and first column of the matrix
+Một ma trận `m × n`: `m` hàng là ngang, và `n` cột là dọc. Mỗi phần tử của một ma trận thường được ký hiệu bằng một biến với hai chỉ số. Ví dụ, <i>a<sub>2,1</sub></i> đại diện cho phần tử ở hàng thứ hai và cột thứ nhất của ma trận.
 
-## Operations on matrices
+## Các phép toán trên ma trận
 
-### Addition
+### Cộng
 
-To add two matrices: add the numbers in the matching positions:
+Để cộng hai ma trận: cộng các số ở vị trí tương ứng:
 
-![Matrices addition](https://www.mathsisfun.com/algebra/images/matrix-addition.gif)
+![Cộng ma trận](https://www.mathsisfun.com/algebra/images/matrix-addition.gif)
 
-The two matrices must be the same size, i.e. the rows must match in size, and the columns must match in size.
+Hai ma trận phải có cùng kích thước, tức là số hàng phải giống nhau, và số cột phải giống nhau.
 
-### Subtracting
+### Trừ
 
-To subtract two matrices: subtract the numbers in the matching positions:
+Để trừ hai ma trận: trừ các số ở vị trí tương ứng:
 
-![Matrices subtraction](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif)
+![Trừ ma trận](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif)
 
-### Multiply by a Constant
+### Nhân với một Hằng số
 
-We can multiply a matrix by a constant (the value 2 in this case):
+Chúng ta có thể nhân một ma trận với một hằng số (giá trị 2 trong trường hợp này):
 
-![Matrices multiplication be a constant](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif)
+![Nhân ma trận với một hằng số](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif)
 
-### Multiplying by Another Matrix
+### Nhân với Một Ma trận Khác
 
-To multiply a matrix by another matrix we need to do the [dot product](https://www.mathsisfun.com/algebra/vectors-dot-product.html) of rows and columns.
+Để nhân một ma trận với một ma trận khác, chúng ta cần thực hiện [tích vô hướng](https://www.mathsisfun.com/algebra/vectors-dot-product.html) của các hàng và cột.
 
-To work out the answer for the **1st row** and **1st column**:
+Để tính kết quả cho **hàng thứ nhất** và **cột thứ nhất**:
 
-![Matrices multiplication - 1st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg)
+![Nhân ma trận - Bước 1](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg)
 
-Here it is for the 1st row and 2nd column:
+Đây là cho hàng thứ nhất và cột thứ hai:
 
-![Matrices multiplication - 2st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg)
+![Nhân ma trận - Bước 2](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg)
 
-If we'll do the same for the rest of the rows and columns we'll get the following resulting matrix:
+Nếu chúng ta làm tương tự cho phần còn lại của các hàng và cột, chúng ta sẽ nhận được ma trận kết quả sau:
 
-![Matrices multiplication - Result](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg)
+![Nhân ma trận - Kết quả](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg)
 
-### Transposing
+### Chuyển vị
 
-To "transpose" a matrix, swap the rows and columns.
+Để "chuyển vị" một ma trận, đổi chỗ các hàng và cột.
 
-We put a "T" in the top right-hand corner to mean transpose:
+Chúng ta đặt một "T" ở góc trên bên phải để biểu thị chuyển vị:
 
-![Transposing](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif)
+![Chuyển vị](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif)
 
-## References
+## Tham khảo
 
-- [Matrices on MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html)
-- [Matrix on Wikipedia](https://en.wikipedia.org/wiki/Matrix_(mathematics))
+- [Ma trận trên MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html)
+- [Ma trận trên Wikipedia](<https://en.wikipedia.org/wiki/Matrix_(mathematics)>)
diff --git a/src/algorithms/math/pascal-triangle/README.en-EN.md b/src/algorithms/math/pascal-triangle/README.en-EN.md
new file mode 100644
index 0000000000..91cef5eca1
--- /dev/null
+++ b/src/algorithms/math/pascal-triangle/README.en-EN.md
@@ -0,0 +1,67 @@
+# Pascal's Triangle
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In mathematics, **Pascal's triangle** is a triangular array of
+the [binomial coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient).
+
+The rows of Pascal's triangle are conventionally enumerated
+starting with row `n = 0` at the top (the `0th` row). The
+entries in each row are numbered from the left beginning
+with `k = 0` and are usually staggered relative to the
+numbers in the adjacent rows. The triangle may be constructed
+in the following manner: In row `0` (the topmost row), there
+is a unique nonzero entry `1`. Each entry of each subsequent
+row is constructed by adding the number above and to the
+left with the number above and to the right, treating blank
+entries as `0`. For example, the initial number in the
+first (or any other) row is `1` (the sum of `0` and `1`),
+whereas the numbers `1` and `3` in the third row are added
+to produce the number `4` in the fourth row.
+
+![Pascal's Triangle](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)
+
+## Formula
+
+The entry in the `nth` row and `kth` column of Pascal's
+triangle is denoted ![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/206415d3742167e319b2e52c2ca7563b799abad7).
+For example, the unique nonzero entry in the topmost
+row is ![Formula example](https://wikimedia.org/api/rest_v1/media/math/render/svg/b7e35f86368d5978b46c07fd6dddca86bd6e635c).
+
+With this notation, the construction of the previous
+paragraph may be written as follows:
+
+![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/203b128a098e18cbb8cf36d004bd7282b28461bf)
+
+for any non-negative integer `n` and any
+integer `k` between `0` and `n`, inclusive.
+
+![Binomial Coefficient](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181)
+
+## Calculating triangle entries in O(n) time
+
+We know that `i`-th entry in a line number `lineNumber` is
+Binomial Coefficient `C(lineNumber, i)` and all lines start
+with value `1`. The idea is to
+calculate `C(lineNumber, i)` using `C(lineNumber, i-1)`. It
+can be calculated in `O(1)` time using the following:
+
+```
+C(lineNumber, i)   = lineNumber! / ((lineNumber - i)! * i!)
+C(lineNumber, i - 1) = lineNumber! / ((lineNumber - i + 1)! * (i - 1)!)
+```
+
+We can derive following expression from above two expressions:
+
+```
+C(lineNumber, i) = C(lineNumber, i - 1) * (lineNumber - i + 1) / i
+```
+
+So `C(lineNumber, i)` can be calculated
+from `C(lineNumber, i - 1)` in `O(1)` time.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Pascal%27s_triangle)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/pascal-triangle/)
diff --git a/src/algorithms/math/pascal-triangle/README.md b/src/algorithms/math/pascal-triangle/README.md
index ff5075414c..60012c9400 100644
--- a/src/algorithms/math/pascal-triangle/README.md
+++ b/src/algorithms/math/pascal-triangle/README.md
@@ -1,64 +1,44 @@
-# Pascal's Triangle
+# Tam giác Pascal
 
-In mathematics, **Pascal's triangle** is a triangular array of 
-the [binomial coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The rows of Pascal's triangle are conventionally enumerated 
-starting with row `n = 0` at the top (the `0th` row). The 
-entries in each row are numbered from the left beginning 
-with `k = 0` and are usually staggered relative to the 
-numbers in the adjacent rows. The triangle may be constructed
-in the following manner: In row `0` (the topmost row), there 
-is a unique nonzero entry `1`. Each entry of each subsequent
-row is constructed by adding the number above and to the 
-left with the number above and to the right, treating blank 
-entries as `0`. For example, the initial number in the 
-first (or any other) row is `1` (the sum of `0` and `1`),
-whereas the numbers `1` and `3` in the third row are added 
-to produce the number `4` in the fourth row.
+Trong toán học, **tam giác Pascal** là một mảng tam giác của [hệ số nhị thức](https://en.wikipedia.org/wiki/Binomial_coefficient).
 
-![Pascal's Triangle](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)
+Các hàng của tam giác Pascal thường được đánh số từ hàng `n = 0` ở phía trên cùng (hàng `0`). Các phần tử trong mỗi hàng được đánh số từ trái sang phải, bắt đầu từ `k = 0` và thường được xếp lệch so với các số trong các hàng liền kề. Tam giác có thể được xây dựng theo cách sau: Ở hàng `0` (hàng trên cùng), có một phần tử duy nhất khác `0` là `1`. Mỗi phần tử của mỗi hàng tiếp theo được xây dựng bằng cách cộng số phía trên bên trái với số phía trên bên phải, coi các phần tử trống như `0`. Ví dụ, số ban đầu trong hàng đầu tiên (hoặc bất kỳ hàng nào khác) là `1` (tổng của `0` và `1`), trong khi số `1` và `3` trong hàng thứ ba được cộng lại để tạo ra số `4` trong hàng thứ tư.
 
-## Formula
+![Tam giác Pascal](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)
 
-The entry in the `nth` row and `kth` column of Pascal's 
-triangle is denoted ![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/206415d3742167e319b2e52c2ca7563b799abad7).
-For example, the unique nonzero entry in the topmost 
-row is ![Formula example](https://wikimedia.org/api/rest_v1/media/math/render/svg/b7e35f86368d5978b46c07fd6dddca86bd6e635c).
+## Công thức
 
-With this notation, the construction of the previous 
-paragraph may be written as follows:
+Phần tử ở hàng thứ `n` và cột thứ `k` của tam giác Pascal được ký hiệu là ![Công thức](https://wikimedia.org/api/rest_v1/media/math/render/svg/206415d3742167e319b2e52c2ca7563b799abad7). Ví dụ, phần tử duy nhất khác `0` trong hàng trên cùng là ![Ví dụ về công thức](https://wikimedia.org/api/rest_v1/media/math/render/svg/b7e35f86368d5978b46c07fd6dddca86bd6e635c).
 
-![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/203b128a098e18cbb8cf36d004bd7282b28461bf)
+Với ký hiệu này, việc xây dựng trong đoạn trước có thể được viết như sau:
 
-for any non-negative integer `n` and any 
-integer `k` between `0` and `n`, inclusive.
+![Công thức](https://wikimedia.org/api/rest_v1/media/math/render/svg/203b128a098e18cbb8cf36d004bd7282b28461bf)
 
-![Binomial Coefficient](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181)
+cho mọi số nguyên không âm `n` và mọi số nguyên `k` nằm giữa `0` và `n`, bao gồm cả `0` và `n`.
 
-## Calculating triangle entries in O(n) time
+![Hệ số nhị thức](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181)
 
-We know that `i`-th entry in a line number `lineNumber` is 
-Binomial Coefficient `C(lineNumber, i)` and all lines start 
-with value `1`. The idea is to 
-calculate `C(lineNumber, i)` using `C(lineNumber, i-1)`. It 
-can be calculated in `O(1)` time using the following:
+## Tính các phần tử trong tam giác trong thời gian O(n)
+
+Chúng ta biết rằng phần tử thứ `i` trong hàng số `lineNumber` là Hệ số nhị thức `C(lineNumber, i)` và tất cả các hàng bắt đầu với giá trị `1`. Ý tưởng là tính `C(lineNumber, i)` bằng cách sử dụng `C(lineNumber, i-1)`. Nó có thể được tính trong thời gian `O(1)` bằng cách sau:
 
 ```
 C(lineNumber, i)   = lineNumber! / ((lineNumber - i)! * i!)
 C(lineNumber, i - 1) = lineNumber! / ((lineNumber - i + 1)! * (i - 1)!)
 ```
 
-We can derive following expression from above two expressions:
+Chúng ta có thể suy ra biểu thức sau từ hai biểu thức trên:
 
 ```
 C(lineNumber, i) = C(lineNumber, i - 1) * (lineNumber - i + 1) / i
 ```
 
-So `C(lineNumber, i)` can be calculated 
-from `C(lineNumber, i - 1)` in `O(1)` time.
+Vì vậy, `C(lineNumber, i)` có thể được tính từ `C(lineNumber, i - 1)` trong thời gian `O(1)`.
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Pascal%27s_triangle)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/pascal-triangle/)
diff --git a/src/algorithms/math/primality-test/README.en-EN.md b/src/algorithms/math/primality-test/README.en-EN.md
new file mode 100644
index 0000000000..7423c3c206
--- /dev/null
+++ b/src/algorithms/math/primality-test/README.en-EN.md
@@ -0,0 +1,28 @@
+# Primality Test
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **prime number** (or a **prime**) is a natural number greater than `1` that
+cannot be formed by multiplying two smaller natural numbers. A natural number
+greater than `1` that is not prime is called a composite number. For
+example, `5` is prime because the only ways of writing it as a
+product, `1 × 5` or `5 × 1`, involve `5` itself. However, `6` is
+composite because it is the product of two numbers `(2 × 3)` that are
+both smaller than `6`.
+
+![Prime Numbers](https://upload.wikimedia.org/wikipedia/commons/f/f0/Primes-vs-composites.svg)
+
+A **primality test** is an algorithm for determining whether an input
+number is prime. Among other fields of mathematics, it is used
+for cryptography. Unlike integer factorization, primality tests
+do not generally give prime factors, only stating whether the
+input number is prime or not. Factorization is thought to be
+a computationally difficult problem, whereas primality testing
+is comparatively easy (its running time is polynomial in the
+size of the input).
+
+## References
+
+- [Prime Numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
+- [Primality Test on Wikipedia](https://en.wikipedia.org/wiki/Primality_test)
diff --git a/src/algorithms/math/primality-test/README.md b/src/algorithms/math/primality-test/README.md
index 8a9852dc31..6f1e94a91b 100644
--- a/src/algorithms/math/primality-test/README.md
+++ b/src/algorithms/math/primality-test/README.md
@@ -1,25 +1,15 @@
-# Primality Test
+# Kiểm tra số nguyên tố
 
-A **prime number** (or a **prime**) is a natural number greater than `1` that 
-cannot be formed by multiplying two smaller natural numbers. A natural number 
-greater than `1` that is not prime is called a composite number. For 
-example, `5` is prime because the only ways of writing it as a 
-product, `1 × 5` or `5 × 1`, involve `5` itself. However, `6` is 
-composite because it is the product of two numbers `(2 × 3)` that are 
-both smaller than `6`. 
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-![Prime Numbers](https://upload.wikimedia.org/wikipedia/commons/f/f0/Primes-vs-composites.svg)
+Một **số nguyên tố** (hoặc một **số nguyên tố**) là một số tự nhiên lớn hơn `1` mà không thể được tạo ra bằng cách nhân hai số tự nhiên nhỏ hơn. Một số tự nhiên lớn hơn `1` mà không phải là số nguyên tố được gọi là số hợp số. Ví dụ, `5` là số nguyên tố vì cách duy nhất để viết nó dưới dạng một tích, `1 × 5` hoặc `5 × 1`, đều liên quan đến chính `5`. Tuy nhiên, `6` là số hợp vì nó là tích của hai số `(2 × 3)` mà đều nhỏ hơn `6`.
 
-A **primality test** is an algorithm for determining whether an input 
-number is prime. Among other fields of mathematics, it is used 
-for cryptography. Unlike integer factorization, primality tests 
-do not generally give prime factors, only stating whether the 
-input number is prime or not. Factorization is thought to be 
-a computationally difficult problem, whereas primality testing 
-is comparatively easy (its running time is polynomial in the 
-size of the input). 
+![Số nguyên tố](https://upload.wikimedia.org/wikipedia/commons/f/f0/Primes-vs-composites.svg)
 
-## References
+Một **thử nghiệm tính nguyên tố** là một thuật toán để xác định xem một số đầu vào có phải là số nguyên tố hay không. Giữa các lĩnh vực toán học khác, nó được sử dụng cho mật mã học. Không giống như phân tích thành phần số nguyên, các thử nghiệm tính nguyên tố không cung cấp thông tin về các số nguyên tố, chỉ nói xem số đầu vào có phải là số nguyên tố hay không. Phân tích thành phần được cho là một vấn đề khó tính toán, trong khi kiểm tra tính nguyên tố dễ dàng hơn nhiều (thời gian chạy của nó là đa thức theo kích thước của đầu vào).
 
-- [Prime Numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
-- [Primality Test on Wikipedia](https://en.wikipedia.org/wiki/Primality_test)
+## Tham khảo
+
+- [Số nguyên tố trên Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
+- [Kiểm tra tính nguyên tố trên Wikipedia](https://en.wikipedia.org/wiki/Primality_test)
diff --git a/src/algorithms/math/prime-factors/README.en-EN.md b/src/algorithms/math/prime-factors/README.en-EN.md
new file mode 100644
index 0000000000..2518ff6630
--- /dev/null
+++ b/src/algorithms/math/prime-factors/README.en-EN.md
@@ -0,0 +1,37 @@
+# Prime Factors
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**Prime number** is a whole number greater than `1` that **cannot** be made by multiplying other whole numbers. The first few prime numbers are: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19` and so on.
+
+If we **can** make it by multiplying other whole numbers it is a **Composite Number**.
+
+![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg)
+
+_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
+
+**Prime factors** are those [prime numbers](https://en.wikipedia.org/wiki/Prime_number) which multiply together to give the original number. For example `39` will have prime factors of `3` and `13` which are also prime numbers. Another example is `15` whose prime factors are `3` and `5`.
+
+![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)
+
+_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
+
+## Finding the prime factors and their count accurately
+
+The approach is to keep on dividing the natural number `n` by indexes from `i = 2` to `i = n` (by prime indexes only). The value of `n` is being overridden by `(n / i)` on each iteration.
+
+The time complexity till now is `O(n)` in the worst case scenario since the loop runs from index `i = 2` to `i = n`. This time complexity can be reduced from `O(n)` to `O(sqrt(n))`. The optimisation is achievable when loop runs from `i = 2` to `i = sqrt(n)`. Now, we go only till `O(sqrt(n))` because when `i` becomes greater than `sqrt(n)`, we have the confirmation that there is no index `i` left which can divide `n` completely other than `n` itself.
+
+## Hardy-Ramanujan formula for approximate calculation of prime-factor count
+
+In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which states that the normal order of the number `ω(n)` of distinct prime factors of a number `n` is `log(log(n))`.
+
+Roughly speaking, this means that most numbers have about this number of distinct prime factors.
+
+## References
+
+- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html)
+- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
+- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)
+- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)
diff --git a/src/algorithms/math/prime-factors/README.md b/src/algorithms/math/prime-factors/README.md
index d8e0f96e3f..f85f77d88b 100644
--- a/src/algorithms/math/prime-factors/README.md
+++ b/src/algorithms/math/prime-factors/README.md
@@ -1,37 +1,37 @@
-# Prime Factors
+# Các Thừa số Nguyên tố
 
-_Read this in other languages:_
-[简体中文](README.zh-CN.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-**Prime number** is a whole number greater than `1` that **cannot** be made by multiplying other whole numbers. The first few prime numbers are: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19` and so on.
+**Số nguyên tố** là một số tự nhiên lớn hơn `1` mà **không thể** được tạo ra bằng cách nhân với các số tự nhiên khác. Một số nguyên tố đầu tiên là: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19` và cứ tiếp tục như vậy.
 
-If we **can** make it by multiplying other whole numbers it is a **Composite Number**.
+Nếu chúng ta **có thể** tạo ra nó bằng cách nhân với các số tự nhiên khác thì đó là một **Số Hợp**.
 
-![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg)
+![Các số hợp](https://www.mathsisfun.com/numbers/images/prime-composite.svg)
 
-_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
+_Nguồn hình ảnh: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
 
-**Prime factors** are those [prime numbers](https://en.wikipedia.org/wiki/Prime_number) which multiply together to give the original number. For example `39` will have prime factors of `3` and `13` which are also prime numbers. Another example is `15` whose prime factors are `3` and `5`.
+**Các thừa số nguyên tố** là những [số nguyên tố](https://en.wikipedia.org/wiki/Prime_number) mà khi nhân lại với nhau sẽ cho ra số gốc. Ví dụ `39` sẽ có các thừa số nguyên tố là `3` và `13` đều là số nguyên tố. Một ví dụ khác là `15` có các thừa số nguyên tố là `3` và `5`.
 
-![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)
+![Thừa số](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)
 
-_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
+_Nguồn hình ảnh: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
 
-## Finding the prime factors and their count accurately
+## Tìm các thừa số nguyên tố và số lượng chính xác của chúng
 
-The approach is to keep on dividing the natural number `n` by indexes from `i = 2` to `i = n` (by prime indexes only). The value of `n` is being overridden by `(n / i)` on each iteration.
+Phương pháp là tiếp tục chia số tự nhiên `n` cho các chỉ số từ `i = 2` đến `i = n` (chỉ số nguyên tố). Giá trị của `n` sẽ bị ghi đè bởi `(n / i)` trong mỗi lần lặp.
 
-The time complexity till now is `O(n)` in the worst case scenario since the loop runs from index `i = 2` to `i = n`. This time complexity can be reduced from `O(n)` to `O(sqrt(n))`. The optimisation is achievable when loop runs from `i = 2` to `i = sqrt(n)`. Now, we go only till `O(sqrt(n))` because when `i` becomes greater than `sqrt(n)`, we have the confirmation that there is no index `i` left which can divide `n` completely other than `n` itself.
+Độ phức tạp thời gian cho đến bây giờ là `O(n)` trong trường hợp xấu nhất vì vòng lặp chạy từ chỉ số `i = 2` đến `i = n`. Độ phức tạp thời gian này có thể được giảm từ `O(n)` xuống `O(sqrt(n))`. Sự tối ưu hóa được đạt được khi vòng lặp chạy từ `i = 2` đến `i = sqrt(n)`. Bây giờ, chúng ta chỉ cần đi đến `O(sqrt(n))` vì khi `i` trở nên lớn hơn `sqrt(n)`, chúng ta đã xác nhận rằng không có chỉ số `i` nào còn lại có thể chia `n` hoàn toàn ngoại trừ `n` chính nó.
 
-## Hardy-Ramanujan formula for approximate calculation of prime-factor count
+## Công thức Hardy-Ramanujan để tính xấp xỉ số lượng thừa số nguyên tố
 
-In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which states that the normal order of the number `ω(n)` of distinct prime factors of a number `n` is `log(log(n))`.
+Năm 1917, G.H Hardy và Srinivasa Ramanujan đã sáng tạo ra một định lý khẳng định rằng số thứ tự bình thường của số `ω(n)` của các thừa số nguyên tố phân biệt của một số `n` là `log(log(n))`.
 
-Roughly speaking, this means that most numbers have about this number of distinct prime factors.
+Nói một cách ngắn gọn, điều này có nghĩa là hầu hết các số có khoảng cách giữa chúng là số lượng thừa số nguyên tố phân biệt này.
 
-## References
+## Tham khảo
 
-- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html)
-- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
-- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)
-- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)
+- [Các số nguyên tố trên Math is Fun](https://www.mathsisfun.com/prime-factorization.html)
+- [Các số nguyên tố trên Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
+- [Định lý Hardy-Ramanujan trên Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)
+- [Phân tích thừa số nguyên tố của một số trên Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)
diff --git a/src/algorithms/math/prime-factors/README.zh-CN.md b/src/algorithms/math/prime-factors/README.zh-CN.md
deleted file mode 100644
index c6ab82e39b..0000000000
--- a/src/algorithms/math/prime-factors/README.zh-CN.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# 质数因子
-
-_Read this in other languages:_
-[english](README.md).
-
-**质数** 是一个比 `1` 大的整数，且 **不能**由其它整数相乘得出。前几个质数是: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19`,依此类推。
-
-如果我们**能**通过其它整数相乘得出，我们则称它为**合数**
-
-![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg)
-
-_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
-
-
-**质数因子**是那些相乘得到原始数的[质数](https://en.wikipedia.org/wiki/Prime_number)。例如`39`的质数因子是`3`和`13`，`15`的质数因子是`3`和`5`。
-
-![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg)
-
-_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_
-
-## 正确计算所有的质数因子及其数量
-
-这个方法将自然数`n`从`i = 2`除到`i = n`（仅按质数索引）。且每次循环后`n`的值被`(n / i)`的值替换。
-
-在最坏的情况下，即循环从`i = 2`执行到 `i = n`，上述方法的时间复杂度为`O(n)`。时间复杂度其实可以从`O(n)`减少到`O(sqrt(n))`，通过减少循环的执行次数，从`i = 2`执行到 `i = sqrt(n)`。因为可以确认，当`i`大于`sqrt(n)`时，除了`n`本身，再没有数可以被整除了。
-
-## Hardy-Ramanujan公式用于计算质数因子的个数
-
-1917年，G.H Hardy和Srinivasa Ramanujan提出了一个定理，该定理指出，自然数 `n` 的不同素数的数 `ω(n)` 的正态次序是`log(log(n))`。
-
-粗略地讲，这意味着大多数数字具有这个数量的质数因子。
-
-## References
-
-- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html)
-- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number)
-- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)
-- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82)
diff --git a/src/algorithms/math/radian/README.en-EN.md b/src/algorithms/math/radian/README.en-EN.md
new file mode 100644
index 0000000000..2908c04a0f
--- /dev/null
+++ b/src/algorithms/math/radian/README.en-EN.md
@@ -0,0 +1,38 @@
+# Radian
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **radian** (symbol **rad**) is the unit for measuring angles, and is the
+standard unit of angular measure used in many areas of mathematics.
+
+The length of an arc of a unit circle is numerically equal to the measurement
+in radians of the angle that it subtends; one radian is just under `57.3` degrees.
+
+An arc of a circle with the same length as the radius of that circle subtends an
+angle of `1 radian`. The circumference subtends an angle of `2π radians`.
+
+![Radian](https://upload.wikimedia.org/wikipedia/commons/4/4e/Circle_radians.gif)
+
+A complete revolution is 2π radians (shown here with a circle of radius one and
+thus circumference `2π`).
+
+![2 pi Radian](https://upload.wikimedia.org/wikipedia/commons/6/67/2pi-unrolled.gif)
+
+**Conversions**
+
+| Radians | Degrees |
+| :-----: | :-----: |
+|    0    |   0°    |
+|  π/12   |   15°   |
+|   π/6   |   30°   |
+|   π/4   |   45°   |
+|    1    |  57.3°  |
+|   π/3   |   60°   |
+|   π/2   |   90°   |
+|    π    |  180°   |
+|   2π    |  360°   |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Radian)
diff --git a/src/algorithms/math/radian/README.md b/src/algorithms/math/radian/README.md
index 2de4655e7d..b62312b0cd 100644
--- a/src/algorithms/math/radian/README.md
+++ b/src/algorithms/math/radian/README.md
@@ -1,36 +1,34 @@
-# Radian
+# Radian - Đơn vị Đo Góc
 
-The **radian** (symbol **rad**) is the unit for measuring angles, and is the 
-standard unit of angular measure used in many areas of mathematics.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The length of an arc of a unit circle is numerically equal to the measurement 
-in radians of the angle that it subtends; one radian is just under `57.3` degrees.
+**Radian** (biểu tượng **rad**) là đơn vị đo góc, và là đơn vị đo góc tiêu chuẩn được sử dụng trong nhiều lĩnh vực toán học.
 
-An arc of a circle with the same length as the radius of that circle subtends an 
-angle of `1 radian`. The circumference subtends an angle of `2π radians`.
+Độ dài của một cung tròn với bán kính `1` đơn vị bằng với đo lường trong radian của góc mà nó chứa; một radian gần bằng `57.3` độ.
+
+Một cung tròn có độ dài bằng với bán kính của hình tròn đó là một góc là `1 radian`. Chu vi của hình tròn tạo ra một góc là `2π radians`.
 
 ![Radian](https://upload.wikimedia.org/wikipedia/commons/4/4e/Circle_radians.gif)
 
-A complete revolution is 2π radians (shown here with a circle of radius one and 
-thus circumference `2π`).
+Một vòng tròn hoàn chỉnh là `2π` radian (được hiển thị ở đây với một vòng tròn bán kính một và do đó có chu vi `2π`).
 
 ![2 pi Radian](https://upload.wikimedia.org/wikipedia/commons/6/67/2pi-unrolled.gif)
 
-**Conversions**
-
-| Radians | Degrees |
-| :-----: | :-----: |
-| 0       | 0°      |
-| π/12    | 15°     |
-| π/6     | 30°     |
-| π/4     | 45°     |
-| 1       | 57.3°   |
-| π/3     | 60°     |
-| π/2     | 90°     |
-| π       | 180°    |
-| 2π      | 360°    |
-
-
-## References
+**Chuyển đổi**
+
+| Radians |  Độ   |
+| :-----: | :---: |
+|    0    |  0°   |
+|  π/12   |  15°  |
+|   π/6   |  30°  |
+|   π/4   |  45°  |
+|    1    | 57.3° |
+|   π/3   |  60°  |
+|   π/2   |  90°  |
+|    π    | 180°  |
+|   2π    | 360°  |
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Radian)
diff --git a/src/algorithms/math/sieve-of-eratosthenes/README.en-EN.md b/src/algorithms/math/sieve-of-eratosthenes/README.en-EN.md
new file mode 100644
index 0000000000..0f0fab0c68
--- /dev/null
+++ b/src/algorithms/math/sieve-of-eratosthenes/README.en-EN.md
@@ -0,0 +1,35 @@
+# Sieve of Eratosthenes
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Sieve of Eratosthenes is an algorithm for finding all prime numbers up to some limit `n`.
+
+It is attributed to Eratosthenes of Cyrene, an ancient Greek mathematician.
+
+## How it works
+
+1. Create a boolean array of `n + 1` positions (to represent the numbers `0` through `n`)
+2. Set positions `0` and `1` to `false`, and the rest to `true`
+3. Start at position `p = 2` (the first prime number)
+4. Mark as `false` all the multiples of `p` (that is, positions `2 * p`, `3 * p`, `4 * p`... until you reach the end of the array)
+5. Find the first position greater than `p` that is `true` in the array. If there is no such position, stop. Otherwise, let `p` equal this new number (which is the next prime), and repeat from step 4
+
+When the algorithm terminates, the numbers remaining `true` in the array are all
+the primes below `n`.
+
+An improvement of this algorithm is, in step 4, start marking multiples
+of `p` from `p * p`, and not from `2 * p`. The reason why this works is because,
+at that point, smaller multiples of `p` will have already been marked `false`.
+
+## Example
+
+![Sieve](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif)
+
+## Complexity
+
+The algorithm has a complexity of `O(n log(log n))`.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)
diff --git a/src/algorithms/math/sieve-of-eratosthenes/README.md b/src/algorithms/math/sieve-of-eratosthenes/README.md
index 876379a006..a0ee9e7b0e 100644
--- a/src/algorithms/math/sieve-of-eratosthenes/README.md
+++ b/src/algorithms/math/sieve-of-eratosthenes/README.md
@@ -1,32 +1,32 @@
-# Sieve of Eratosthenes
+# Sieve of Eratosthenes - Sàng Eratosthenes
 
-The Sieve of Eratosthenes is an algorithm for finding all prime numbers up to some limit `n`.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-It is attributed to Eratosthenes of Cyrene, an ancient Greek mathematician.
+Sàng Eratosthenes là một thuật toán để tìm tất cả các số nguyên tố đến một giới hạn `n` nào đó.
 
-## How it works
+Thuật toán này được cho là của Eratosthenes, một nhà toán học cổ Hy Lạp.
 
-1. Create a boolean array of `n + 1` positions (to represent the numbers `0` through `n`)
-2. Set positions `0` and `1` to `false`, and the rest to `true`
-3. Start at position `p = 2` (the first prime number)
-4. Mark as `false` all the multiples of `p` (that is, positions `2 * p`, `3 * p`, `4 * p`... until you reach the end of the array)
-5. Find the first position greater than `p` that is `true` in the array. If there is no such position, stop. Otherwise, let `p` equal this new number (which is the next prime), and repeat from step 4
+## Cách hoạt động
 
-When the algorithm terminates, the numbers remaining `true` in the array are all 
-the primes below `n`.
+1. Tạo một mảng boolean có `n + 1` vị trí (để biểu diễn các số từ `0` đến `n`)
+2. Đặt các vị trí `0` và `1` thành `false`, và các vị trí còn lại thành `true`
+3. Bắt đầu từ vị trí `p = 2` (số nguyên tố đầu tiên)
+4. Đánh dấu các bội số của `p` là `false` (tức là, các vị trí `2 * p`, `3 * p`, `4 * p`... cho đến khi bạn đạt đến cuối mảng)
+5. Tìm vị trí đầu tiên lớn hơn `p` mà là `true` trong mảng. Nếu không có vị trí nào như vậy, dừng lại. Nếu có, gán `p` bằng số này (là số nguyên tố tiếp theo), và lặp lại từ bước 4
 
-An improvement of this algorithm is, in step 4, start marking multiples 
-of `p` from `p * p`, and not from `2 * p`. The reason why this works is because, 
-at that point, smaller multiples of `p` will have already been marked `false`.
+Khi thuật toán kết thúc, các số còn lại là `true` trong mảng là tất cả các số nguyên tố nhỏ hơn `n`.
 
-## Example
+Một cải tiến của thuật toán này là, ở bước 4, bắt đầu đánh dấu các bội số của `p` từ `p * p`, và không phải từ `2 * p`. Lý do tại sao điều này hoạt động là vì, tại thời điểm đó, các bội số nhỏ hơn của `p` đã được đánh dấu `false`.
 
-![Sieve](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif)
+## Ví dụ
 
-## Complexity
+![Sàng](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif)
 
-The algorithm has a complexity of `O(n log(log n))`.
+## Độ phức tạp
 
-## References
+Thuật toán có độ phức tạp là `O(n log(log n))`.
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)
diff --git a/src/algorithms/math/square-root/README.en-EN.md b/src/algorithms/math/square-root/README.en-EN.md
new file mode 100644
index 0000000000..3cf4fb1db0
--- /dev/null
+++ b/src/algorithms/math/square-root/README.en-EN.md
@@ -0,0 +1,65 @@
+# Square Root (Newton's Method)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In numerical analysis, a branch of mathematics, there are several square root
+algorithms or methods of computing the principal square root of a non-negative real
+number. As, generally, the roots of a function cannot be computed exactly.
+The root-finding algorithms provide approximations to roots expressed as floating
+point numbers.
+
+Finding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is
+the same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a
+positive `x`. Therefore, any general numerical root-finding algorithm can be used.
+
+**Newton's method** (also known as the Newton–Raphson method), named after
+_Isaac Newton_ and _Joseph Raphson_, is one example of a root-finding algorithm. It is a
+method for finding successively better approximations to the roots of a real-valued function.
+
+Let's start by explaining the general idea of Newton's method and then apply it to our particular
+case with finding a square root of the number.
+
+## Newton's Method General Idea
+
+The Newton–Raphson method in one variable is implemented as follows:
+
+The method starts with a function `f` defined over the real numbers `x`, the function's derivative `f'`, and an
+initial guess `x0` for a root of the function `f`. If the function satisfies the assumptions made in the derivation
+of the formula and the initial guess is close, then a better approximation `x1` is:
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/52c50eca0b7c4d64ef2fdca678665b73e944cb84)
+
+Geometrically, `(x1, 0)` is the intersection of the `x`-axis and the tangent of
+the graph of `f` at `(x0, f (x0))`.
+
+The process is repeated as:
+
+![](https://wikimedia.org/api/rest_v1/media/math/render/svg/710c11b9ec4568d1cfff49b7c7d41e0a7829a736)
+
+until a sufficiently accurate value is reached.
+
+![](https://upload.wikimedia.org/wikipedia/commons/e/e0/NewtonIteration_Ani.gif)
+
+## Newton's Method of Finding a Square Root
+
+As it was mentioned above, finding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is
+the same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a
+positive `x`.
+
+The derivative of the function `f(x)` in case of square root problem is `2x`.
+
+After applying the Newton's formula (see above) we get the following equation for our algorithm iterations:
+
+```text
+x := x - (x² - S) / (2x)
+```
+
+The `x² − S` above is how far away `x²` is from where it needs to be, and the
+division by `2x` is the derivative of `x²`, to scale how much we adjust `x` by how
+quickly `x²` is changing.
+
+## References
+
+- [Methods of computing square roots on Wikipedia](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots)
+- [Newton's method on Wikipedia](https://en.wikipedia.org/wiki/Newton%27s_method)
diff --git a/src/algorithms/math/square-root/README.md b/src/algorithms/math/square-root/README.md
index 7f9713b5f6..eaf7cd1b46 100644
--- a/src/algorithms/math/square-root/README.md
+++ b/src/algorithms/math/square-root/README.md
@@ -1,62 +1,56 @@
-# Square Root (Newton's Method)
+# Phương pháp căn bậc hai (Phương pháp Newton)
 
-In numerical analysis, a branch of mathematics, there are several square root 
-algorithms or methods of computing the principal square root of a non-negative real 
-number. As, generally, the roots of a function cannot be computed exactly.
-The root-finding algorithms provide approximations to roots expressed as floating
-point numbers.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Finding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is
-the same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a
-positive `x`. Therefore, any general numerical root-finding algorithm can be used.
+Trong phân tích số, một nhánh của toán học, có một số thuật toán hoặc phương pháp để tính căn bậc hai chính của một số thực không âm. Như, nói chung, các căn bậc của một hàm không thể tính chính xác. Các thuật toán tìm gốc cung cấp các xấp xỉ cho các căn được biểu diễn dưới dạng số dấu chấm động.
 
-**Newton's method** (also known as the Newton–Raphson method), named after 
-_Isaac Newton_ and _Joseph Raphson_, is one example of a root-finding algorithm. It is a 
-method for finding successively better approximations to the roots of a real-valued function.
+Việc tìm ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) là
+giống như giải phương trình ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) cho một
+`x` dương. Do đó, bất kỳ thuật toán tìm gốc số nào cũng có thể được sử dụng.
 
-Let's start by explaining the general idea of Newton's method and then apply it to our particular
-case with finding a square root of the number.
+**Phương pháp Newton** (còn được gọi là phương pháp Newton–Raphson), được đặt theo
+_Isaac Newton_ và _Joseph Raphson_, là một ví dụ về một thuật toán tìm gốc. Đây là một
+phương pháp để tìm các xấp xỉ tốt hơn đối với các gốc của một hàm có giá trị thực.
 
-## Newton's Method General Idea
+Hãy bắt đầu bằng cách giải thích ý tưởng chung của phương pháp Newton và sau đó áp dụng nó vào trường hợp cụ thể của chúng ta với việc tìm căn bậc hai của số.
 
-The Newton–Raphson method in one variable is implemented as follows:
+## Ý tưởng chung của Phương pháp Newton
 
-The method starts with a function `f` defined over the real numbers `x`, the function's derivative `f'`, and an 
-initial guess `x0` for a root of the function `f`. If the function satisfies the assumptions made in the derivation 
-of the formula and the initial guess is close, then a better approximation `x1` is:
+Phương pháp Newton–Raphson trong một biến được thực hiện như sau:
+
+Phương pháp bắt đầu với một hàm `f` được xác định trên các số thực `x`, đạo hàm của hàm `f` `f'`, và một
+đoán đầu `x0` cho một gốc của hàm `f`. Nếu hàm thỏa mãn các giả định được đưa ra trong công thức và đoán đầu tiên gần, thì xấp xỉ tốt hơn `x1` là:
 
 ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/52c50eca0b7c4d64ef2fdca678665b73e944cb84)
 
-Geometrically, `(x1, 0)` is the intersection of the `x`-axis and the tangent of 
-the graph of `f` at `(x0, f (x0))`.
+Hình học, `(x1, 0)` là sự giao nhau của trục `x` và tiếp tuyến của đồ thị của `f` tại `(x0, f (x0))`.
 
-The process is repeated as:
+Quá trình được lặp lại như sau:
 
 ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/710c11b9ec4568d1cfff49b7c7d41e0a7829a736)
 
-until a sufficiently accurate value is reached.
+cho đến khi đạt được giá trị đủ chính xác.
 
 ![](https://upload.wikimedia.org/wikipedia/commons/e/e0/NewtonIteration_Ani.gif)
 
-## Newton's Method of Finding a Square Root
+## Phương pháp Newton để Tìm Căn bậc hai
 
-As it was mentioned above, finding ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) is
-the same as solving the equation ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) for a
-positive `x`.
+Như đã đề cập ở trên, việc tìm ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/bff86975b0e7944720b3e635c53c22c032a7a6f1) là
+giống như giải phương trình ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/6cf57722151ef19ba1ca918d702b95c335e21cad) cho một
+`x` dương.
 
-The derivative of the function `f(x)` in case of square root problem is `2x`.
+Đạo hàm của hàm `f(x)` trong trường hợp của vấn đề căn bậc hai là `2x`.
 
-After applying the Newton's formula (see above) we get the following equation for our algorithm iterations:
+Sau khi áp dụng công thức Newton (xem ở trên) chúng ta có phương trình sau cho các lần lặp của thuật toán:
 
 ```text
 x := x - (x² - S) / (2x)
 ```
 
-The `x² − S` above is how far away `x²` is from where it needs to be, and the 
-division by `2x` is the derivative of `x²`, to scale how much we adjust `x` by how 
-quickly `x²` is changing.
+Phần `x² − S` ở trên là khoảng cách `x²` so với nơi cần phải đến, và phép chia cho `2x` là đạo hàm của `x²`, để tỷ lệ điều chỉnh `x` bằng cách nhanh chóng `x²` đang thay đổi.
 
-## References
+## Tham khảo
 
-- [Methods of computing square roots on Wikipedia](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots)
-- [Newton's method on Wikipedia](https://en.wikipedia.org/wiki/Newton%27s_method)
+- [Các phương pháp tính căn bậc hai trên Wikipedia](https://en.wikipedia.org/wiki/Methods_of_computing_square_roots)
+- [Phương pháp Newton trên Wikipedia](https://en.wikipedia.org/wiki/Newton%27s_method)
diff --git a/src/algorithms/ml/k-means/README.en-EN.md b/src/algorithms/ml/k-means/README.en-EN.md
new file mode 100644
index 0000000000..1245142d33
--- /dev/null
+++ b/src/algorithms/ml/k-means/README.en-EN.md
@@ -0,0 +1,40 @@
+# k-Means Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **k-Means algorithm** is an unsupervised Machine Learning algorithm. It's a clustering algorithm, which groups the sample data on the basis of similarity between dimensions of vectors.
+
+In k-Means classification, the output is a set of classes assigned to each vector. Each cluster location is continuously optimized in order to get the accurate locations of each cluster such that they represent each group clearly.
+
+The idea is to calculate the similarity between cluster location and data vectors, and reassign clusters based on it. [Euclidean distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) is used mostly for this task.
+
+![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+
+_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
+
+The algorithm is as follows:
+
+1. Check for errors like invalid/inconsistent data
+2. Initialize the `k` cluster locations with initial/random `k` points
+3. Calculate the distance of each data point from each cluster
+4. Assign the cluster label of each data point equal to that of the cluster at its minimum distance
+5. Calculate the centroid of each cluster based on the data points it contains
+6. Repeat each of the above steps until the centroid locations are varying
+
+Here is a visualization of k-Means clustering for better understanding:
+
+![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)
+
+_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_
+
+The centroids are moving continuously in order to create better distinction between the different set of data points. As we can see, after a few iterations, the difference in centroids is quite low between iterations. For example between iterations `13` and `14` the difference is quite small because there the optimizer is tuning boundary cases.
+
+## Code Examples
+
+- [kMeans.js](./kMeans.js)
+- [kMeans.test.js](./__test__/kMeans.test.js) (test cases)
+
+## References
+
+- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)
diff --git a/src/algorithms/ml/k-means/README.md b/src/algorithms/ml/k-means/README.md
index fb58c1bfa4..81d0f06cef 100644
--- a/src/algorithms/ml/k-means/README.md
+++ b/src/algorithms/ml/k-means/README.md
@@ -1,40 +1,37 @@
-# k-Means Algorithm
+# Thuật toán k-Means
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+**Thuật toán k-Means** là một thuật toán Học máy không giám sát. Đây là một thuật toán phân cụm, nhóm dữ liệu mẫu dựa trên sự tương đồng giữa các chiều của các vector.
 
-The **k-Means algorithm** is an unsupervised Machine Learning algorithm. It's a clustering algorithm, which groups the sample data on the basis of similarity between dimensions of vectors.
+Trong phân loại k-Means, đầu ra là một tập hợp các lớp được gán cho mỗi vector. Vị trí của mỗi cụm được tối ưu liên tục để có được các vị trí chính xác của mỗi cụm sao cho chúng đại diện cho mỗi nhóm một cách rõ ràng.
 
-In k-Means classification, the output is a set of classes assigned to each vector. Each cluster location is continuously optimized in order to get the accurate locations of each cluster such that they represent each group clearly.
+Ý tưởng là tính toán sự tương đồng giữa vị trí của cụm và các vector dữ liệu, và gán lại các cụm dựa trên điều đó. [Khoảng cách Euclid](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) thường được sử dụng cho nhiệm vụ này.
 
-The idea is to calculate the similarity between cluster location and data vectors, and reassign clusters based on it. [Euclidean distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) is used mostly for this task.
+![Khoảng cách Euclid giữa hai điểm](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
 
-![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+_Nguồn ảnh: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
 
-_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
+Thuật toán được thực hiện như sau:
 
-The algorithm is as follows:
+1. Kiểm tra lỗi như dữ liệu không hợp lệ/không nhất quán
+2. Khởi tạo vị trí của `k` cụm với `k` điểm ban đầu/ngẫu nhiên
+3. Tính khoảng cách từ mỗi điểm dữ liệu đến mỗi cụm
+4. Gán nhãn cụm của mỗi điểm dữ liệu bằng nhãn của cụm ở khoảng cách tối thiểu của nó
+5. Tính trọng tâm của mỗi cụm dựa trên các điểm dữ liệu mà nó chứa
+6. Lặp lại từng bước trên cho đến khi vị trí trọng tâm thay đổi
 
-1. Check for errors like invalid/inconsistent data
-2. Initialize the `k` cluster locations with initial/random `k` points
-3. Calculate the distance of each data point from each cluster
-4. Assign the cluster label of each data point equal to that of the cluster at its minimum distance
-5. Calculate the centroid of each cluster based on the data points it contains
-6. Repeat each of the above steps until the centroid locations are varying
+Dưới đây là một hình dung về phân cụm k-Means để hiểu rõ hơn:
 
-Here is a visualization of k-Means clustering for better understanding:
+![Trực quan hóa k-Means](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)
 
-![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)
+_Nguồn ảnh: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_
 
-_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_
+Trọng tâm di chuyển liên tục để tạo ra sự phân biệt tốt hơn giữa các tập hợp dữ liệu khác nhau. Như chúng ta có thể thấy, sau một số lần lặp, sự khác biệt về trọng tâm khá thấp giữa các lần lặp. Ví dụ, giữa các lần lặp `13` và `14`, sự khác biệt khá nhỏ vì ở đó trình tối ưu hóa đang điều chỉnh các trường hợp ranh giới.
 
-The centroids are moving continuously in order to create better distinction between the different set of data points. As we can see, after a few iterations, the difference in centroids is quite low between iterations. For example between iterations `13` and `14` the difference is quite small because there the optimizer is tuning boundary cases.
-
-## Code Examples
+## Ví dụ mã
 
 - [kMeans.js](./kMeans.js)
-- [kMeans.test.js](./__test__/kMeans.test.js) (test cases)
+- [kMeans.test.js](./__test__/kMeans.test.js) (các ca kiểm thử)
 
-## References
+## Tham khảo
 
-- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)
+- [Thuật toán k-Means trên Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)
diff --git a/src/algorithms/ml/k-means/README.pt-BR.md b/src/algorithms/ml/k-means/README.pt-BR.md
deleted file mode 100644
index d814ac19bc..0000000000
--- a/src/algorithms/ml/k-means/README.pt-BR.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Algoritmo k-Means
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-O **algoritmo k-Means** é um algoritmo de aprendizado de máquina não supervisionado. É um algoritmo de agrupamento, que agrupa os dados da amostra com base na semelhança entre as dimensões dos vetores.
-
-Na classificação k-Means, a saída é um conjunto de classes atribuídas a cada vetor. Cada localização de cluster é continuamente otimizada para obter as localizações precisas de cada cluster de forma que representem cada grupo claramente.
-
-A ideia é calcular a similaridade entre a localização do cluster e os vetores de dados e reatribuir os clusters com base nela. [Distância Euclidiana](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) é usado principalmente para esta tarefa.
-
-![Distância Euclidiana entre dois pontos](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
-
-_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
-
-O algoritmo é o seguinte:
-
-1. Verifique se há erros como dados inválidos/inconsistentes
-2. Inicialize os locais do cluster `k` com pontos `k` iniciais/aleatórios
-3. Calcule a distância de cada ponto de dados de cada cluster
-4. Atribua o rótulo do cluster de cada ponto de dados igual ao do cluster em sua distância mínima
-5. Calcule o centroide de cada cluster com base nos pontos de dados que ele contém
-6. Repita cada uma das etapas acima até que as localizações do centroide estejam variando
-
-Aqui está uma visualização do agrupamento k-Means para melhor compreensão:
-
-![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif)
-
-_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_
-
-Os centroides estão se movendo continuamente para criar uma melhor distinção entre os diferentes conjuntos de pontos de dados. Como podemos ver, após algumas iterações, a diferença de centroides é bastante baixa entre as iterações. Por exemplo, entre as iterações `13` e `14` a diferença é bem pequena porque o otimizador está ajustando os casos limite.
-
-## Referências
-
-- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)
diff --git a/src/algorithms/ml/knn/README.en-EN.md b/src/algorithms/ml/knn/README.en-EN.md
new file mode 100644
index 0000000000..de219240a9
--- /dev/null
+++ b/src/algorithms/ml/knn/README.en-EN.md
@@ -0,0 +1,44 @@
+# k-Nearest Neighbors Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **k-nearest neighbors algorithm (k-NN)** is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data.
+
+In k-NN classification, the output is a class membership. An object is classified by a plurality vote of its neighbors, with the object being assigned to the class most common among its `k` nearest neighbors (`k` is a positive integer, typically small). If `k = 1`, then the object is simply assigned to the class of that single nearest neighbor.
+
+The idea is to calculate the similarity between two data points on the basis of a distance metric. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task.
+
+![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+
+_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
+
+The algorithm is as follows:
+
+1. Check for errors like invalid data/labels.
+2. Calculate the euclidean distance of all the data points in training data with the classification point
+3. Sort the distances of points along with their classes in ascending order
+4. Take the initial `K` classes and find the mode to get the most similar class
+5. Report the most similar class
+
+Here is a visualization of k-NN classification for better understanding:
+
+![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)
+
+_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_
+
+The test sample (green dot) should be classified either to blue squares or to red triangles. If `k = 3` (solid line circle) it is assigned to the red triangles because there are `2` triangles and only `1` square inside the inner circle. If `k = 5` (dashed line circle) it is assigned to the blue squares (`3` squares vs. `2` triangles inside the outer circle).
+
+Another k-NN classification example:
+
+![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)
+
+_Image source: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_
+
+Here, as we can see, the classification of unknown points will be judged by their proximity to other points.
+
+It is important to note that `K` is preferred to have odd values in order to break ties. Usually `K` is taken as `3` or `5`.
+
+## References
+
+- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)
diff --git a/src/algorithms/ml/knn/README.md b/src/algorithms/ml/knn/README.md
index 1fc168eaf2..66b74fa24e 100644
--- a/src/algorithms/ml/knn/README.md
+++ b/src/algorithms/ml/knn/README.md
@@ -1,44 +1,44 @@
-# k-Nearest Neighbors Algorithm
+# Thuật toán k-Nearest Neighbors (k-NN)
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The **k-nearest neighbors algorithm (k-NN)** is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data.
+**Thuật toán k-Nearest Neighbors (k-NN)** là một thuật toán Học máy có giám sát. Đây là một thuật toán phân loại, xác định lớp của một vector mẫu bằng cách sử dụng dữ liệu mẫu.
 
-In k-NN classification, the output is a class membership. An object is classified by a plurality vote of its neighbors, with the object being assigned to the class most common among its `k` nearest neighbors (`k` is a positive integer, typically small). If `k = 1`, then the object is simply assigned to the class of that single nearest neighbor.
+Trong phân loại k-NN, đầu ra là một lớp. Một đối tượng được phân loại bằng cách bầu chọn đa số của các láng giềng của nó, với đối tượng được gán cho lớp phổ biến nhất trong `k` láng giềng gần nhất của nó (`k` là một số nguyên dương, thường nhỏ). Nếu `k = 1`, thì đối tượng được gán đơn giản cho lớp của láng giềng gần nhất duy nhất đó.
 
-The idea is to calculate the similarity between two data points on the basis of a distance metric. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task.
+Ý tưởng là tính toán sự tương đồng giữa hai điểm dữ liệu dựa trên một phép đo khoảng cách. [Khoảng cách Euclid](https://en.wikipedia.org/wiki/Euclidean_distance) thường được sử dụng cho nhiệm vụ này.
 
-![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
+![Khoảng cách Euclid giữa hai điểm](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
 
-_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
+_Nguồn ảnh: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
 
-The algorithm is as follows:
+Thuật toán được thực hiện như sau:
 
-1. Check for errors like invalid data/labels.
-2. Calculate the euclidean distance of all the data points in training data with the classification point
-3. Sort the distances of points along with their classes in ascending order
-4. Take the initial `K` classes and find the mode to get the most similar class
-5. Report the most similar class
+1. Kiểm tra lỗi như dữ liệu/nhãn không hợp lệ.
+2. Tính khoảng cách Euclid của tất cả các điểm dữ liệu trong dữ liệu huấn luyện với điểm phân loại
+3. Sắp xếp các khoảng cách của các điểm cùng với lớp của chúng theo thứ tự tăng dần
+4. Lấy `K` lớp ban đầu và tìm chế độ để có được lớp giống nhất nhất
+5. Báo cáo lớp giống nhất
 
-Here is a visualization of k-NN classification for better understanding:
+Dưới đây là một hình dung về phân loại k-NN để hiểu rõ hơn:
 
-![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)
+![Trực quan hóa k-NN](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)
 
-_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_
+_Nguồn ảnh: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_
 
-The test sample (green dot) should be classified either to blue squares or to red triangles. If `k = 3` (solid line circle) it is assigned to the red triangles because there are `2` triangles and only `1` square inside the inner circle. If `k = 5` (dashed line circle) it is assigned to the blue squares (`3` squares vs. `2` triangles inside the outer circle).
+Mẫu kiểm tra (chấm xanh lá cây) sẽ được phân loại vào các hình vuông màu xanh lá cây hoặc các tam giác màu đỏ. Nếu `k = 3` (vòng tròn đường kín) nó được gán cho các tam giác màu đỏ vì có `2` tam giác và chỉ có `1` hình vuông trong vòng tròn trong. Nếu `k = 5` (vòng tròn đường kẻ đứt) nó được gán cho các hình vuông màu xanh (`3` hình vuông so với `2` tam giác trong vòng tròn bên ngoài).
 
-Another k-NN classification example:
+Một ví dụ khác về phân loại k-NN:
 
-![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)
+![Trực quan hóa k-NN](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)
 
-_Image source: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_
+_Nguồn ảnh: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_
 
-Here, as we can see, the classification of unknown points will be judged by their proximity to other points.
+Ở đây, như chúng ta có thể thấy, việc phân loại các điểm không xác định sẽ được đánh giá bằng sự gần gũi của chúng đối với các điểm khác.
 
-It is important to note that `K` is preferred to have odd values in order to break ties. Usually `K` is taken as `3` or `5`.
+Lưu ý rằng `K` được ưa chuộng là có các giá trị lẻ để phá vỡ sự ràng buộc. Thông thường `K` được lấy là `3` hoặc `5`.
 
-## References
+## Tham khảo
 
-- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)
+- [Thuật toán k-nearest neighbors trên Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)
diff --git a/src/algorithms/ml/knn/README.pt-BR.md b/src/algorithms/ml/knn/README.pt-BR.md
deleted file mode 100644
index b2abdd784f..0000000000
--- a/src/algorithms/ml/knn/README.pt-BR.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Algoritmo de k-vizinhos mais próximos
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-O **algoritmo de k-vizinhos mais próximos (k-NN)** é um algoritmo de aprendizado de máquina supervisionado. É um algoritmo de classificação, determinando a classe de um vetor de amostra usando dados de amostra.
-
-Na classificação k-NN, a saída é uma associação de classe. Um objeto é classificado por uma pluralidade de votos de seus vizinhos, com o objeto sendo atribuído à classe mais comum entre seus `k` vizinhos mais próximos (`k` é um inteiro positivo, tipicamente pequeno). Se `k = 1`, então o objeto é simplesmente atribuído à classe daquele único vizinho mais próximo.
-
-The idea is to calculate the similarity between two data points on the basis of a distance metric. [Distância Euclidiana](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) é usado principalmente para esta tarefa.
-
-![Distância Euclidiana entre dois pontos](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
-
-_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
-
-O algoritmo é o seguinte:
-
-1. Verifique se há erros como dados/rótulos inválidos.
-2. Calcule a distância euclidiana de todos os pontos de dados nos dados de treinamento com o ponto de classificação
-3. Classifique as distâncias dos pontos junto com suas classes em ordem crescente
-4. Pegue as classes iniciais `K` e encontre o modo para obter a classe mais semelhante
-5. Informe a classe mais semelhante
-
-Aqui está uma visualização da classificação k-NN para melhor compreensão:
-
-![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)
-
-_Fonte: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_
-
-A amostra de teste (ponto verde) deve ser classificada em quadrados azuis ou em triângulos vermelhos. Se `k = 3` (círculo de linha sólida) é atribuído aos triângulos vermelhos porque existem `2` triângulos e apenas `1` quadrado dentro do círculo interno. Se `k = 5` (círculo de linha tracejada) é atribuído aos quadrados azuis (`3` quadrados vs. `2` triângulos dentro do círculo externo).
-
-Outro exemplo de classificação k-NN:
-
-![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)
-
-_Fonte: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_
-
-Aqui, como podemos ver, a classificação dos pontos desconhecidos será julgada pela proximidade com outros pontos.
-
-É importante notar que `K` é preferível ter valores ímpares para desempate. Normalmente `K` é tomado como `3` ou `5`.
-
-## Referências
-
-- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)
diff --git a/src/algorithms/search/binary-search/README.en-EN.md b/src/algorithms/search/binary-search/README.en-EN.md
new file mode 100644
index 0000000000..f9767d9bb9
--- /dev/null
+++ b/src/algorithms/search/binary-search/README.en-EN.md
@@ -0,0 +1,26 @@
+# Binary Search
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, binary search, also known as half-interval
+search, logarithmic search, or binary chop, is a search algorithm
+that finds the position of a target value within a sorted
+array. Binary search compares the target value to the middle
+element of the array; if they are unequal, the half in which
+the target cannot lie is eliminated and the search continues
+on the remaining half until it is successful. If the search
+ends with the remaining half being empty, the target is not
+in the array.
+
+![Binary Search](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)
+
+## Complexity
+
+**Time Complexity**: `O(log(n))` - since we split search area by two for every
+next iteration.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)
+- [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/search/binary-search/README.md b/src/algorithms/search/binary-search/README.md
index ebf3e123e0..3178b8e122 100644
--- a/src/algorithms/search/binary-search/README.md
+++ b/src/algorithms/search/binary-search/README.md
@@ -1,26 +1,17 @@
-# Binary Search
+# Tìm kiếm nhị phân
 
-_Read this in other languages:_
-[Português brasileiro](README.pt-BR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, binary search, also known as half-interval 
-search, logarithmic search, or binary chop, is a search algorithm 
-that finds the position of a target value within a sorted 
-array. Binary search compares the target value to the middle 
-element of the array; if they are unequal, the half in which 
-the target cannot lie is eliminated and the search continues 
-on the remaining half until it is successful. If the search 
-ends with the remaining half being empty, the target is not 
-in the array.
+Trong khoa học máy tính, tìm kiếm nhị phân, còn được gọi là tìm kiếm nửa khoảng, tìm kiếm theo logarithmic, hoặc chia nhị phân, là một thuật toán tìm kiếm mục tiêu trong một mảng đã được sắp xếp. Tìm kiếm nhị phân so sánh giá trị mục tiêu với phần tử ở giữa của mảng; nếu chúng không bằng nhau, một nửa mà mục tiêu không thể nằm ở đó sẽ bị loại bỏ và tìm kiếm tiếp tục trên nửa còn lại cho đến khi thành công. Nếu tìm kiếm kết thúc với nửa còn lại là trống, mục tiêu không có trong mảng.
 
-![Binary Search](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)
+![Tìm kiếm nhị phân](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)
 
-## Complexity
+## Phức tạp
 
-**Time Complexity**: `O(log(n))` - since we split search area by two for every
-next iteration.
+**Phức tạp thời gian**: `O(log(n))` - vì chúng ta chia khu vực tìm kiếm thành hai cho mỗi vòng lặp tiếp theo.
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)
 - [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/search/binary-search/README.pt-BR.md b/src/algorithms/search/binary-search/README.pt-BR.md
deleted file mode 100644
index 14445a048e..0000000000
--- a/src/algorithms/search/binary-search/README.pt-BR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Busca Binária
-
-_Leia isso em outras línguas:_
-[english](README.md).
-
-Em ciência da computação, busca binária, também conhecida como busca de meio-intervalo, busca logarítmica ou corte binário, é um algoritmo de pesquisa
-que encontra a posição de um elemento alvo dentro de um
-vetor ordenado. O algoritmo compara o elemento alvo com o elemento central do vetor; se eles são diferentes, a metade em que
-o elemento alvo não pode estar é eliminada e a busca continua
-na metade remanescente até que o elemento alvo seja encontrado. Se a busca
-terminar com a metade remanescente vazia, o elemento alvo não está presente no vetor.
-
-![Busca Binária](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg)
-
-## Complexidade
-
-**Complexidade de Tempo**: `O(log(n))` - pois a área de busca é dividida por dois a cada iteração.
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm)
-- [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/search/interpolation-search/README.en-EN.md b/src/algorithms/search/interpolation-search/README.en-EN.md
new file mode 100644
index 0000000000..84e74c6783
--- /dev/null
+++ b/src/algorithms/search/interpolation-search/README.en-EN.md
@@ -0,0 +1,43 @@
+# Interpolation Search
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**Interpolation search** is an algorithm for searching for a key in an array that
+has been ordered by numerical values assigned to the keys (key values).
+
+For example we have a sorted array of `n` uniformly distributed values `arr[]`,
+and we need to write a function to search for a particular element `x` in the array.
+
+**Linear Search** finds the element in `O(n)` time, **Jump Search** takes `O(√ n)` time
+and **Binary Search** take `O(Log n)` time.
+
+The **Interpolation Search** is an improvement over Binary Search for instances,
+where the values in a sorted array are _uniformly_ distributed. Binary Search
+always goes to the middle element to check. On the other hand, interpolation
+search may go to different locations according to the value of the key being
+searched. For example, if the value of the key is closer to the last element,
+interpolation search is likely to start search toward the end side.
+
+To find the position to be searched, it uses following formula:
+
+```
+// The idea of formula is to return higher value of pos
+// when element to be searched is closer to arr[hi]. And
+// smaller value when closer to arr[lo]
+pos = lo + ((x - arr[lo]) * (hi - lo) / (arr[hi] - arr[Lo]))
+
+arr[] - Array where elements need to be searched
+x - Element to be searched
+lo - Starting index in arr[]
+hi - Ending index in arr[]
+```
+
+## Complexity
+
+**Time complexity**: `O(log(log(n))`
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/interpolation-search/)
+- [Wikipedia](https://en.wikipedia.org/wiki/Interpolation_search)
diff --git a/src/algorithms/search/interpolation-search/README.md b/src/algorithms/search/interpolation-search/README.md
index e91154a8ff..c5ec311299 100644
--- a/src/algorithms/search/interpolation-search/README.md
+++ b/src/algorithms/search/interpolation-search/README.md
@@ -1,40 +1,35 @@
-# Interpolation Search
+# Tìm kiếm nội suy
 
-**Interpolation search** is an algorithm for searching for a key in an array that 
-has been ordered by numerical values assigned to the keys (key values).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-For example we have a sorted array of `n` uniformly distributed values `arr[]`, 
-and we need to write a function to search for a particular element `x` in the array.
+**Tìm kiếm nội suy** là một thuật toán để tìm kiếm một khóa trong một mảng đã được sắp xếp theo các giá trị số được gán cho các khóa (giá trị khóa).
 
-**Linear Search** finds the element in `O(n)` time, **Jump Search** takes `O(√ n)` time 
-and **Binary Search** take `O(Log n)` time.
+Ví dụ, chúng ta có một mảng đã được sắp xếp của `n` giá trị phân phối đều `arr[]`, và chúng ta cần viết một hàm để tìm kiếm một phần tử cụ thể `x` trong mảng đó.
 
-The **Interpolation Search** is an improvement over Binary Search for instances, 
-where the values in a sorted array are _uniformly_ distributed. Binary Search 
-always goes to the middle element to check. On the other hand, interpolation 
-search may go to different locations according to the value of the key being 
-searched. For example, if the value of the key is closer to the last element, 
-interpolation search is likely to start search toward the end side.
+**Tìm kiếm tuyến tính** tìm phần tử trong thời gian `O(n)`, **Tìm kiếm nhảy** mất thời gian `O(√ n)` và **Tìm kiếm nhị phân** mất thời gian `O(Log n)`.
 
-To find the position to be searched, it uses following formula:
+**Tìm kiếm nội suy** là một cải tiến so với Tìm kiếm nhị phân trong các trường hợp, nơi các giá trị trong một mảng đã được sắp xếp _đều nhau_. Tìm kiếm nhị phân luôn đi đến phần tử giữa để kiểm tra. Ngược lại, tìm kiếm nội suy có thể đi đến các vị trí khác nhau tùy theo giá trị của khóa đang được tìm kiếm. Ví dụ, nếu giá trị của khóa gần với phần tử cuối cùng, tìm kiếm nội suy có thể bắt đầu tìm kiếm về phía cuối.
+
+Để tìm vị trí cần tìm kiếm, nó sử dụng công thức sau:
 
 ```
-// The idea of formula is to return higher value of pos
-// when element to be searched is closer to arr[hi]. And
-// smaller value when closer to arr[lo]
+// Ý tưởng của công thức là trả về giá trị cao hơn của pos
+// khi phần tử cần tìm kiếm gần với arr[hi]. Và
+// giá trị nhỏ hơn khi gần với arr[lo]
 pos = lo + ((x - arr[lo]) * (hi - lo) / (arr[hi] - arr[Lo]))
 
-arr[] - Array where elements need to be searched
-x - Element to be searched
-lo - Starting index in arr[]
-hi - Ending index in arr[]
+arr[] - Mảng chứa các phần tử cần tìm kiếm
+x - Phần tử cần tìm kiếm
+lo - Chỉ số bắt đầu trong arr[]
+hi - Chỉ số kết thúc trong arr[]
 ```
 
-## Complexity
+## Phức tạp
 
-**Time complexity**: `O(log(log(n))`
+**Phức tạp thời gian**: `O(log(log(n))`
 
-## References
+## Tham khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/interpolation-search/)
 - [Wikipedia](https://en.wikipedia.org/wiki/Interpolation_search)
diff --git a/src/algorithms/search/jump-search/README.en-EN.md b/src/algorithms/search/jump-search/README.en-EN.md
new file mode 100644
index 0000000000..5aac7bb3eb
--- /dev/null
+++ b/src/algorithms/search/jump-search/README.en-EN.md
@@ -0,0 +1,30 @@
+# Jump Search
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Like Binary Search, **Jump Search** (or **Block Search**) is a searching algorithm
+for sorted arrays. The basic idea is to check fewer elements (than linear search)
+by jumping ahead by fixed steps or skipping some elements in place of searching all
+elements.
+
+For example, suppose we have an array `arr[]` of size `n` and block (to be jumped)
+of size `m`. Then we search at the indexes `arr[0]`, `arr[m]`, `arr[2 * m]`, ..., `arr[k * m]` and
+so on. Once we find the interval `arr[k * m] < x < arr[(k+1) * m]`, we perform a
+linear search operation from the index `k * m` to find the element `x`.
+
+**What is the optimal block size to be skipped?**
+In the worst case, we have to do `n/m` jumps and if the last checked value is
+greater than the element to be searched for, we perform `m - 1` comparisons more
+for linear search. Therefore the total number of comparisons in the worst case
+will be `((n/m) + m - 1)`. The value of the function `((n/m) + m - 1)` will be
+minimum when `m = √n`. Therefore, the best step size is `m = √n`.
+
+## Complexity
+
+**Time complexity**: `O(√n)` - because we do search by blocks of size `√n`.
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/jump-search/)
+- [Wikipedia](https://en.wikipedia.org/wiki/Jump_search)
diff --git a/src/algorithms/search/jump-search/README.md b/src/algorithms/search/jump-search/README.md
index b711a7732d..b86ee080db 100644
--- a/src/algorithms/search/jump-search/README.md
+++ b/src/algorithms/search/jump-search/README.md
@@ -1,27 +1,25 @@
-# Jump Search
+# Tìm Kiếm Bước Nhảy
 
-Like Binary Search, **Jump Search** (or **Block Search**) is a searching algorithm 
-for sorted arrays. The basic idea is to check fewer elements (than linear search) 
-by jumping ahead by fixed steps or skipping some elements in place of searching all 
-elements.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-For example, suppose we have an array `arr[]` of size `n` and block (to be jumped)
-of size `m`. Then we search at the indexes `arr[0]`, `arr[m]`, `arr[2 * m]`, ..., `arr[k * m]` and 
-so on. Once we find the interval `arr[k * m] < x < arr[(k+1) * m]`, we perform a 
-linear search operation from the index `k * m` to find the element `x`.
+Giống như Tìm kiếm nhị phân, **Tìm kiếm bước nhảy** (hoặc **Tìm kiếm khối**) là một thuật toán tìm kiếm
+cho các mảng đã được sắp xếp. Ý tưởng cơ bản là kiểm tra ít phần tử hơn
+(so với tìm kiếm tuyến tính) bằng cách nhảy về phía trước theo các bước cố định hoặc bỏ qua một số phần tử thay vì tìm kiếm tất cả
+các phần tử.
 
-**What is the optimal block size to be skipped?**
-In the worst case, we have to do `n/m` jumps and if the last checked value is 
-greater than the element to be searched for, we perform `m - 1` comparisons more 
-for linear search. Therefore the total number of comparisons in the worst case 
-will be `((n/m) + m - 1)`. The value of the function `((n/m) + m - 1)` will be 
-minimum when `m = √n`. Therefore, the best step size is `m = √n`.
+Ví dụ, giả sử chúng ta có một mảng `arr[]` có kích thước `n` và khối (để nhảy) có kích thước `m`. Sau đó, chúng ta tìm kiếm tại các chỉ số `arr[0]`, `arr[m]`, `arr[2 * m]`, ..., `arr[k * m]` và
+vân vân. Khi chúng ta tìm được khoảng `arr[k * m] < x < arr[(k+1) * m]`, chúng ta thực hiện một
+thao tác tìm kiếm tuyến tính từ chỉ số `k * m` để tìm phần tử `x`.
 
-## Complexity
+**Kích thước khối tối ưu là bao nhiêu để bỏ qua?**
+Trong trường hợp xấu nhất, chúng ta phải thực hiện `n/m` bước nhảy và nếu giá trị cuối cùng đã kiểm tra lớn hơn phần tử cần tìm, chúng ta thực hiện `m - 1` so sánh nữa cho tìm kiếm tuyến tính. Do đó, tổng số so sánh trong trường hợp xấu nhất sẽ là `((n/m) + m - 1)`. Giá trị của hàm `((n/m) + m - 1)` sẽ là tối thiểu khi `m = √n`. Do đó, kích thước bước tốt nhất là `m = √n`.
 
-**Time complexity**: `O(√n)` - because we do search by blocks of size `√n`.
+## Phức Tạp
 
-## References
+**Phức tạp thời gian**: `O(√n)` - bởi vì chúng ta tìm kiếm theo khối có kích thước `√n`.
+
+## Tham Khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/jump-search/)
 - [Wikipedia](https://en.wikipedia.org/wiki/Jump_search)
diff --git a/src/algorithms/search/linear-search/README.en-EN.md b/src/algorithms/search/linear-search/README.en-EN.md
new file mode 100644
index 0000000000..605e1f5152
--- /dev/null
+++ b/src/algorithms/search/linear-search/README.en-EN.md
@@ -0,0 +1,24 @@
+# Linear Search
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, linear search or sequential search is a
+method for finding a target value within a list. It sequentially
+checks each element of the list for the target value until a
+match is found or until all the elements have been searched.
+Linear search runs in at worst linear time and makes at most `n`
+comparisons, where `n` is the length of the list.
+
+![Linear Search](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)
+
+## Complexity
+
+**Time Complexity**: `O(n)` - since in worst case we're checking each element
+exactly once.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Linear_search)
+- [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm)
+- [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w)
diff --git a/src/algorithms/search/linear-search/README.md b/src/algorithms/search/linear-search/README.md
index 8feb422eb2..b5aa04bc16 100644
--- a/src/algorithms/search/linear-search/README.md
+++ b/src/algorithms/search/linear-search/README.md
@@ -1,23 +1,24 @@
-# Linear Search
+# Tìm Kiếm Tuyến Tính
 
-_Read this in other languages:_
-[Português brasileiro](README.pt-BR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, linear search or sequential search is a 
-method for finding a target value within a list. It sequentially 
-checks each element of the list for the target value until a 
-match is found or until all the elements have been searched.
-Linear search runs in at worst linear time and makes at most `n` 
-comparisons, where `n` is the length of the list. 
+Trong khoa học máy tính, tìm kiếm tuyến tính hoặc tìm kiếm tuần tự là một
+phương pháp để tìm một giá trị mục tiêu trong một danh sách. Nó kiểm tra
+từng phần tử của danh sách một cách tuần tự để tìm giá trị mục tiêu cho đến khi
+tìm thấy một kết quả phù hợp hoặc cho đến khi tất cả các phần tử đã được kiểm tra.
+Tìm kiếm tuyến tính chạy trong trường hợp xấu nhất là thời gian tuyến tính và tạo ra tối đa `n`
+so sánh, trong đó `n` là độ dài của danh sách.
 
-![Linear Search](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)
+![Tìm Kiếm Tuyến Tính](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)
 
-## Complexity
+## Phức Tạp
 
-**Time Complexity**: `O(n)` - since in worst case we're checking each element
-exactly once.
+**Phức Tạp Thời Gian**: `O(n)` - vì trong trường hợp xấu nhất chúng ta kiểm tra từng phần tử
+một lần.
+
+## Tham Khảo
 
-## References
 - [Wikipedia](https://en.wikipedia.org/wiki/Linear_search)
 - [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm)
 - [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w)
diff --git a/src/algorithms/search/linear-search/README.pt-BR.md b/src/algorithms/search/linear-search/README.pt-BR.md
deleted file mode 100644
index e0af42f4ea..0000000000
--- a/src/algorithms/search/linear-search/README.pt-BR.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Busca Linear
-
-_Leia isso em outras línguas:_
-[english](README.md).
-
-Na Ciência da Computação, busca linear ou busca sequencial é um método para encontrar um elemento alvo em uma lista. 
-O algoritmo verifica sequencialmente cada elemento da lista procurando o elemento alvo até ele ser encontrado ou até ter verificado todos os elementos.
-A Busca linear realiza no máximo `n` comparações, onde `n` é o tamanho da lista.
-
-![Busca Linear](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif)
-
-## Complexidade
-
-**Complexidade de Tempo**: `O(n)` - pois no pior caso devemos verificar cada elemento exatamente uma vez.
-
-## Referências
-- [Wikipedia](https://en.wikipedia.org/wiki/Linear_search)
-- [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm)
-- [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w)
diff --git a/src/algorithms/sets/cartesian-product/README.en-EN.md b/src/algorithms/sets/cartesian-product/README.en-EN.md
new file mode 100644
index 0000000000..c3245e8b64
--- /dev/null
+++ b/src/algorithms/sets/cartesian-product/README.en-EN.md
@@ -0,0 +1,18 @@
+# Cartesian Product
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In set theory a Cartesian product is a mathematical operation that returns a set
+(or product set or simply product) from multiple sets. That is, for sets A and B,
+the Cartesian product A × B is the set of all ordered pairs (a, b)
+where a ∈ A and b ∈ B.
+
+Cartesian product `AxB` of two sets `A={x,y,z}` and `B={1,2,3}`
+
+![Cartesian Product of Two Sets](https://upload.wikimedia.org/wikipedia/commons/4/4e/Cartesian_Product_qtl1.svg)
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Cartesian_product)
+s
diff --git a/src/algorithms/sets/cartesian-product/README.md b/src/algorithms/sets/cartesian-product/README.md
index ae58a15df1..95aa82ffc3 100644
--- a/src/algorithms/sets/cartesian-product/README.md
+++ b/src/algorithms/sets/cartesian-product/README.md
@@ -1,14 +1,17 @@
-# Cartesian Product
+# Cartesian Product - Tích Descartes
 
-In set theory a Cartesian product is a mathematical operation that returns a set 
-(or product set or simply product) from multiple sets. That is, for sets A and B,
-the Cartesian product A × B is the set of all ordered pairs (a, b)
-where a ∈ A and b ∈ B. 
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Cartesian product `AxB` of two sets `A={x,y,z}` and `B={1,2,3}`
+Trong lý thuyết tập hợp, tích Descartes là một phép toán toán học trả về một tập hợp
+(hoặc tập hợp tích hoặc đơn giản là tích) từ nhiều tập hợp. Đó là, đối với các tập hợp A và B,
+tích Descartes A × B là tập hợp của tất cả các cặp có thứ tự (a, b)
+trong đó a ∈ A và b ∈ B.
 
-![Cartesian Product of Two Sets](https://upload.wikimedia.org/wikipedia/commons/4/4e/Cartesian_Product_qtl1.svg)
+Tích Descartes `AxB` của hai tập hợp `A={x,y,z}` và `B={1,2,3}`
 
-## References
+![Tích Descartes của Hai Tập Hợp](https://upload.wikimedia.org/wikipedia/commons/4/4e/Cartesian_Product_qtl1.svg)
+
+## Tham Khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Cartesian_product)
diff --git a/src/algorithms/sets/combination-sum/README.en-EN.md b/src/algorithms/sets/combination-sum/README.en-EN.md
new file mode 100644
index 0000000000..db4279255e
--- /dev/null
+++ b/src/algorithms/sets/combination-sum/README.en-EN.md
@@ -0,0 +1,63 @@
+# Combination Sum Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Given a **set** of candidate numbers (`candidates`) **(without duplicates)** and
+a target number (`target`), find all unique combinations in `candidates` where
+the candidate numbers sums to `target`.
+
+The **same** repeated number may be chosen from `candidates` unlimited number
+of times.
+
+**Note:**
+
+- All numbers (including `target`) will be positive integers.
+- The solution set must not contain duplicate combinations.
+
+## Examples
+
+```
+Input: candidates = [2,3,6,7], target = 7,
+
+A solution set is:
+[
+  [7],
+  [2,2,3]
+]
+```
+
+```
+Input: candidates = [2,3,5], target = 8,
+
+A solution set is:
+[
+  [2,2,2,2],
+  [2,3,3],
+  [3,5]
+]
+```
+
+## Explanations
+
+Since the problem is to get all the possible results, not the best or the
+number of result, thus we don’t need to consider DP (dynamic programming),
+backtracking approach using recursion is needed to handle it.
+
+Here is an example of decision tree for the situation when `candidates = [2, 3]` and `target = 6`:
+
+```
+                0
+              /   \
+           +2      +3
+          /   \      \
+       +2       +3    +3
+      /  \     /  \     \
+    +2    ✘   ✘   ✘     ✓
+   /  \
+  ✓    ✘
+```
+
+## References
+
+- [LeetCode](https://leetcode.com/problems/combination-sum/description/)
diff --git a/src/algorithms/sets/combination-sum/README.md b/src/algorithms/sets/combination-sum/README.md
index cb14f1bae8..4361589383 100644
--- a/src/algorithms/sets/combination-sum/README.md
+++ b/src/algorithms/sets/combination-sum/README.md
@@ -1,23 +1,23 @@
-# Combination Sum Problem
+# Combination Sum Problem - Vấn đề Tổ hợp Tổng
 
-Given a **set** of candidate numbers (`candidates`) **(without duplicates)** and 
-a target number (`target`), find all unique combinations in `candidates` where 
-the candidate numbers sums to `target`.
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The **same** repeated number may be chosen from `candidates` unlimited number 
-of times.
+Cho một **tập hợp** các số ứng viên (`candidates`) **(không có phần tử trùng lặp)** và một số mục tiêu (`target`), hãy tìm tất cả các tổ hợp duy nhất trong `candidates` sao cho tổng các số ứng viên bằng `target`.
 
-**Note:**
+**Cùng** một số lặp lại có thể được chọn từ `candidates` không giới hạn lần.
 
-- All numbers (including `target`) will be positive integers.
-- The solution set must not contain duplicate combinations.
+**Ghi chú:**
 
-## Examples
+- Tất cả các số (bao gồm cả `target`) sẽ là các số nguyên dương.
+- Tập hợp giải pháp không được chứa các tổ hợp trùng lặp.
+
+## Ví dụ
 
 ```
 Input: candidates = [2,3,6,7], target = 7,
 
-A solution set is:
+Một tập hợp giải pháp là:
 [
   [7],
   [2,2,3]
@@ -27,7 +27,7 @@ A solution set is:
 ```
 Input: candidates = [2,3,5], target = 8,
 
-A solution set is:
+Một tập hợp giải pháp là:
 [
   [2,2,2,2],
   [2,3,3],
@@ -35,13 +35,11 @@ A solution set is:
 ]
 ```
 
-## Explanations
+## Giải thích
 
-Since the problem is to get all the possible results, not the best or the 
-number of result, thus we don’t need to consider DP (dynamic programming),
-backtracking approach using recursion is needed to handle it.
+Vì vấn đề là lấy tất cả các kết quả có thể, không phải là tốt nhất hoặc số lượng kết quả, do đó chúng ta không cần xem xét DP (programing dynamic), cần sử dụng phương pháp backtracking sử dụng đệ quy để xử lý nó.
 
-Here is an example of decision tree for the situation when `candidates = [2, 3]` and `target = 6`:
+Dưới đây là một ví dụ về cây quyết định cho tình huống khi `candidates = [2, 3]` và `target = 6`:
 
 ```
                 0
@@ -52,9 +50,9 @@ Here is an example of decision tree for the situation when `candidates = [2, 3]`
       /  \     /  \     \
     +2    ✘   ✘   ✘     ✓
    /  \
-  ✓    ✘    
+  ✓    ✘
 ```
 
-## References
+## Tài liệu tham khảo
 
 - [LeetCode](https://leetcode.com/problems/combination-sum/description/)
diff --git a/src/algorithms/sets/combinations/README.en-EN.md b/src/algorithms/sets/combinations/README.en-EN.md
new file mode 100644
index 0000000000..5ac0ead29e
--- /dev/null
+++ b/src/algorithms/sets/combinations/README.en-EN.md
@@ -0,0 +1,71 @@
+# Combinations
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+When the order doesn't matter, it is a **Combination**.
+
+When the order **does** matter it is a **Permutation**.
+
+**"My fruit salad is a combination of apples, grapes and bananas"**
+We don't care what order the fruits are in, they could also be
+"bananas, grapes and apples" or "grapes, apples and bananas",
+its the same fruit salad.
+
+## Combinations without repetitions
+
+This is how lotteries work. The numbers are drawn one at a
+time, and if we have the lucky numbers (no matter what order)
+we win!
+
+No Repetition: such as lottery numbers `(2,14,15,27,30,33)`
+
+**Number of combinations**
+
+![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-no-repeat.png)
+
+where `n` is the number of things to choose from, and we choose `r` of them,
+no repetition, order doesn't matter.
+
+It is often called "n choose r" (such as "16 choose 3"). And is also known as the Binomial Coefficient.
+
+## Combinations with repetitions
+
+Repetition is Allowed: such as coins in your pocket `(5,5,5,10,10)`
+
+Or let us say there are five flavours of ice cream:
+`banana`, `chocolate`, `lemon`, `strawberry` and `vanilla`.
+
+We can have three scoops. How many variations will there be?
+
+Let's use letters for the flavours: `{b, c, l, s, v}`.
+Example selections include:
+
+- `{c, c, c}` (3 scoops of chocolate)
+- `{b, l, v}` (one each of banana, lemon and vanilla)
+- `{b, v, v}` (one of banana, two of vanilla)
+
+**Number of combinations**
+
+![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-repeat.gif)
+
+Where `n` is the number of things to choose from, and we
+choose `r` of them. Repetition allowed,
+order doesn't matter.
+
+## Cheatsheet
+
+![Permutations and Combinations Overview](./images/overview.png)
+
+![Combinations overview](./images/combinations-overview.jpg)
+
+|                                                                             |                                                                                   |
+| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
+| ![Combinations with repetition](./images/combinations-with-repetitions.jpg) | ![Combinations without repetition](./images/combinations-without-repetitions.jpg) |
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
+- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
diff --git a/src/algorithms/sets/combinations/README.md b/src/algorithms/sets/combinations/README.md
index 69fc0603f9..f369ccea70 100644
--- a/src/algorithms/sets/combinations/README.md
+++ b/src/algorithms/sets/combinations/README.md
@@ -1,68 +1,71 @@
-# Combinations
+# Combinations - Tổ Hợp
 
-When the order doesn't matter, it is a **Combination**.
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-When the order **does** matter it is a **Permutation**.
+Khi thứ tự không quan trọng, đó là **Tổ hợp**.
 
-**"My fruit salad is a combination of apples, grapes and bananas"**
-We don't care what order the fruits are in, they could also be
-"bananas, grapes and apples" or "grapes, apples and bananas",
-its the same fruit salad.
+Khi thứ tự **quan trọng** thì đó là **Hoán vị**.
 
-## Combinations without repetitions
+**"Món tráng miệng của tôi là một tổ hợp của táo, nho và chuối"**
+Chúng tôi không quan tâm thứ tự của các loại trái cây, chúng cũng có thể là
+"chuối, nho và táo" hoặc "nho, táo và chuối",
+đó là một món tráng miệng giống nhau.
 
-This is how lotteries work. The numbers are drawn one at a
-time, and if we have the lucky numbers (no matter what order)
-we win!
+## Tổ hợp không lặp lại
 
-No Repetition: such as lottery numbers `(2,14,15,27,30,33)`
+Đây là cách làm việc của các trò chơi xổ số. Các số được rút ra một cách
+lần lượt, và nếu chúng ta có các số may mắn (bất kể thứ tự)
+thì chúng ta sẽ chiến thắng!
 
-**Number of combinations**
+Không Lặp Lại: chẳng hạn như các số xổ số `(2,14,15,27,30,33)`
 
-![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-no-repeat.png)
+**Số lượng tổ hợp**
 
-where `n` is the number of things to choose from, and we choose `r` of them,
-no repetition, order doesn't matter.
+![Công thức](https://www.mathsisfun.com/combinatorics/images/combinations-no-repeat.png)
 
-It is often called "n choose r" (such as "16 choose 3"). And is also known as the Binomial Coefficient.
+trong đó `n` là số lượng thứ cần chọn từ, và chúng ta chọn `r` trong số đó,
+không lặp lại, thứ tự không quan trọng.
 
-## Combinations with repetitions
+Nó thường được gọi là "n chọn r" (như "16 chọn 3"). Và còn được gọi là Hệ số Nhị thức.
 
-Repetition is Allowed: such as coins in your pocket `(5,5,5,10,10)`
+## Tổ hợp có lặp lại
 
-Or let us say there are five flavours of ice cream:
-`banana`, `chocolate`, `lemon`, `strawberry` and `vanilla`.
+Cho phép Lặp Lại: chẳng hạn như các đồng xu trong túi của bạn `(5,5,5,10,10)`
 
-We can have three scoops. How many variations will there be?
+Hoặc cho rằng có năm hương vị kem:
+`chuối`, `sô-cô-la`, `chanh`, `dâu` và `vanilla`.
 
-Let's use letters for the flavours: `{b, c, l, s, v}`.
-Example selections include:
+Chúng tôi có thể chọn ba phần. Sẽ có bao nhiêu biến thể?
 
-- `{c, c, c}` (3 scoops of chocolate)
-- `{b, l, v}` (one each of banana, lemon and vanilla)
-- `{b, v, v}` (one of banana, two of vanilla)
+Hãy sử dụng các chữ cái để đại diện cho các hương vị: `{b, c, l, s, v}`.
+Các lựa chọn ví dụ bao gồm:
 
-**Number of combinations**
+- `{c, c, c}` (3 phần kem sô-cô-la)
+- `{b, l, v}` (mỗi loại một phần của chuối, chanh và vanilla)
+- `{b, v, v}` (một phần của chuối, hai phần của vanilla)
 
-![Formula](https://www.mathsisfun.com/combinatorics/images/combinations-repeat.gif)
+**Số lượng tổ hợp**
 
-Where `n` is the number of things to choose from, and we
-choose `r` of them. Repetition allowed,
-order doesn't matter.
+![Công thức](https://www.mathsisfun.com/combinatorics/images/combinations-repeat.gif)
 
-## Cheatsheet
+Trong đó `n` là số lượng thứ để chọn từ, và chúng ta
+chọn `r` trong số đó. Cho phép lặp lại,
+thứ tự không quan trọng.
 
-![Permutations and Combinations Overview](./images/overview.png)
+## Bảng Tóm Tắt
 
-![Combinations overview](./images/combinations-overview.jpg)
+![Tổng quan về Hoán vị và Tổ hợp](./images/overview.png)
 
-| | |
-| --- | --- |
-|![Combinations with repetition](./images/combinations-with-repetitions.jpg) | ![Combinations without repetition](./images/combinations-without-repetitions.jpg) |
+![Tổng quan về Tổ hợp](./images/combinations-overview.jpg)
 
-*Made with [okso.app](https://okso.app)*
+|                                                                  |                                                                        |
+| ---------------------------------------------------------------- | ---------------------------------------------------------------------- |
+| ![Tổ hợp có lặp lại](./images/combinations-with-repetitions.jpg) | ![Tổ hợp không lặp lại](./images/combinations-without-repetitions.jpg) |
 
-## References
+_Tạo với [okso.app](https://okso.app)_
+
+## Tài liệu tham khảo
 
 - [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
-- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
+- [Bảng Tóm Tắt Hoán vị/tổ hợp](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
diff --git a/src/algorithms/sets/fisher-yates/README.en-EN.md b/src/algorithms/sets/fisher-yates/README.en-EN.md
new file mode 100644
index 0000000000..4bbfeccaff
--- /dev/null
+++ b/src/algorithms/sets/fisher-yates/README.en-EN.md
@@ -0,0 +1,18 @@
+# Fisher–Yates shuffle
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Fisher–Yates shuffle is an algorithm for generating a random
+permutation of a finite sequence—in plain terms, the algorithm
+shuffles the sequence. The algorithm effectively puts all the
+elements into a hat; it continually determines the next element
+by randomly drawing an element from the hat until no elements
+remain. The algorithm produces an unbiased permutation: every
+permutation is equally likely. The modern version of the
+algorithm is efficient: it takes time proportional to the
+number of items being shuffled and shuffles them in place.
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
diff --git a/src/algorithms/sets/fisher-yates/README.md b/src/algorithms/sets/fisher-yates/README.md
index 36278d34e7..6b9aa56fd6 100644
--- a/src/algorithms/sets/fisher-yates/README.md
+++ b/src/algorithms/sets/fisher-yates/README.md
@@ -1,15 +1,10 @@
-# Fisher–Yates shuffle
-
-The Fisher–Yates shuffle is an algorithm for generating a random 
-permutation of a finite sequence—in plain terms, the algorithm 
-shuffles the sequence. The algorithm effectively puts all the 
-elements into a hat; it continually determines the next element 
-by randomly drawing an element from the hat until no elements 
-remain. The algorithm produces an unbiased permutation: every 
-permutation is equally likely. The modern version of the 
-algorithm is efficient: it takes time proportional to the 
-number of items being shuffled and shuffles them in place.
-
-## References
+# Fisher–Yates shuffle - Trộn Fisher–Yates
+
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trộn Fisher–Yates là một thuật toán để tạo ra một hoán vị ngẫu nhiên của một chuỗi hữu hạn—nói một cách đơn giản, thuật toán này trộn lẫn chuỗi. Thuật toán hiệu quả đặt tất cả các phần tử vào trong một cái mũ; nó liên tục xác định phần tử tiếp theo bằng cách lựa chọn một phần tử ngẫu nhiên từ cái mũ cho đến khi không còn phần tử nào còn lại. Thuật toán tạo ra một hoán vị không thiên vị: mỗi hoán vị có cùng khả năng xuất hiện. Phiên bản hiện đại của thuật toán là hiệu quả: nó tốn thời gian tỉ lệ với số lượng mục đang được trộn lẫn và trộn chúng tại chỗ.
+
+## Tài liệu tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
diff --git a/src/algorithms/sets/knapsack-problem/README.en-EN.md b/src/algorithms/sets/knapsack-problem/README.en-EN.md
new file mode 100644
index 0000000000..df9fb08a6c
--- /dev/null
+++ b/src/algorithms/sets/knapsack-problem/README.en-EN.md
@@ -0,0 +1,72 @@
+# Knapsack Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The knapsack problem or rucksack problem is a problem in
+combinatorial optimization: Given a set of items, each with
+a weight and a value, determine the number of each item to
+include in a collection so that the total weight is less
+than or equal to a given limit and the total value is as
+large as possible.
+
+It derives its name from the problem faced by someone who is
+constrained by a fixed-size knapsack and must fill it with the
+most valuable items.
+
+Example of a one-dimensional (constraint) knapsack problem:
+which boxes should be chosen to maximize the amount of money
+while still keeping the overall weight under or equal to 15 kg?
+
+![knapsack problem](https://upload.wikimedia.org/wikipedia/commons/f/fd/Knapsack.svg)
+
+## Definition
+
+### 0/1 knapsack problem
+
+The most common problem being solved is the **0/1 knapsack problem**,
+which restricts the number `xi` of copies of each kind of item to zero or one.
+
+Given a set of n items numbered from `1` up to `n`, each with a
+weight `wi` and a value `vi`, along with a maximum weight
+capacity `W`,
+
+maximize ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+
+subject to ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+and ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/07dda71da2a630762c7b21b51ea54f86f422f951)
+
+Here `xi` represents the number of instances of item `i` to
+include in the knapsack. Informally, the problem is to maximize
+the sum of the values of the items in the knapsack so that the
+sum of the weights is less than or equal to the knapsack's
+capacity.
+
+### Bounded knapsack problem (BKP)
+
+The **bounded knapsack problem (BKP)** removes the restriction
+that there is only one of each item, but restricts the number
+`xi` of copies of each kind of item to a maximum non-negative
+integer value `c`:
+
+maximize ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+
+subject to ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+and ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c8c5ac4f8247b3b8e01e89de76a1df0ea969821)
+
+### Unbounded knapsack problem (UKP)
+
+The **unbounded knapsack problem (UKP)** places no upper bound
+on the number of copies of each kind of item and can be
+formulated as above except for that the only restriction
+on `xi` is that it is a non-negative integer.
+
+maximize ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+
+subject to ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+and ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/90a99710f61d5dea19e49ae5b31164d2b56b07e3)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Knapsack_problem)
+- [0/1 Knapsack Problem on YouTube](https://www.youtube.com/watch?v=8LusJS5-AGo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/knapsack-problem/README.md b/src/algorithms/sets/knapsack-problem/README.md
index 1d86019f62..5e0e25e8ec 100644
--- a/src/algorithms/sets/knapsack-problem/README.md
+++ b/src/algorithms/sets/knapsack-problem/README.md
@@ -1,69 +1,50 @@
-# Knapsack Problem
+# Knapsack Problem - Vấn đề Knapsack (Ba lô)
 
-The knapsack problem or rucksack problem is a problem in 
-combinatorial optimization: Given a set of items, each with 
-a weight and a value, determine the number of each item to 
-include in a collection so that the total weight is less 
-than or equal to a given limit and the total value is as 
-large as possible.
+_Bạn đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-It derives its name from the problem faced by someone who is 
-constrained by a fixed-size knapsack and must fill it with the 
-most valuable items.
+Vấn đề ba lô, hay còn gọi là vấn đề túi rủ, là một vấn đề trong tối ưu hóa tổ hợp: Cho một tập hợp các mặt hàng, mỗi mặt hàng có trọng lượng và giá trị, hãy xác định số lượng của mỗi mặt hàng để bao gồm trong một bộ sưu tập sao cho tổng trọng lượng nhỏ hơn hoặc bằng một ngưỡng cho trước và tổng giá trị là lớn nhất có thể.
 
-Example of a one-dimensional (constraint) knapsack problem: 
-which boxes should be chosen to maximize the amount of money 
-while still keeping the overall weight under or equal to 15 kg?
+Tên của vấn đề được lấy từ tình huống mà ai đó bị ràng buộc bởi một chiếc ba lô có kích thước cố định và phải điền đầy nó với những mặt hàng có giá trị nhất.
 
-![knapsack problem](https://upload.wikimedia.org/wikipedia/commons/f/fd/Knapsack.svg)
+Ví dụ về vấn đề túi rủ một chiều (hạn chế): cần chọn những hộp nào để tối đa hóa số tiền trong khi vẫn giữ trọng lượng tổng thể dưới hoặc bằng 15 kg?
 
-## Definition
+![vấn đề ba lô](https://upload.wikimedia.org/wikipedia/commons/f/fd/Knapsack.svg)
 
-### 0/1 knapsack problem
+## Định nghĩa
 
-The most common problem being solved is the **0/1 knapsack problem**, 
-which restricts the number `xi` of copies of each kind of item to zero or one.
+### Vấn đề túi rủ 0/1
 
-Given a set of n items numbered from `1` up to `n`, each with a 
-weight `wi` and a value `vi`, along with a maximum weight 
-capacity `W`,
+Vấn đề phổ biến nhất được giải quyết là **vấn đề túi rủ 0/1**, giới hạn số lượng `xi` của mỗi loại mặt hàng là không hoặc một.
 
-maximize ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+Cho một tập hợp các mặt hàng có số thứ tự từ `1` đến `n`, mỗi mặt hàng có trọng lượng `wi` và giá trị `vi`, cùng với một trọng lượng tối đa `W`,
 
-subject to ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
-and ![0/1 knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/07dda71da2a630762c7b21b51ea54f86f422f951)
+tối đa ![vấn đề túi rủ 0/1](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
 
-Here `xi` represents the number of instances of item `i` to 
-include in the knapsack. Informally, the problem is to maximize 
-the sum of the values of the items in the knapsack so that the 
-sum of the weights is less than or equal to the knapsack's 
-capacity.
+điều kiện ![vấn đề túi rủ 0/1](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+và ![vấn đề túi rủ 0/1](https://wikimedia.org/api/rest_v1/media/math/render/svg/07dda71da2a630762c7b21b51ea54f86f422f951)
 
-### Bounded knapsack problem (BKP)
+Ở đây, `xi` đại diện cho số lượng của mỗi mặt hàng để bao gồm trong ba lô. Một cách không chính thức, vấn đề là tối đa hóa tổng giá trị của các mặt hàng trong ba lô sao cho tổng trọng lượng nhỏ hơn hoặc bằng khả năng chứa của ba lô.
 
-The **bounded knapsack problem (BKP)** removes the restriction 
-that there is only one of each item, but restricts the number 
-`xi` of copies of each kind of item to a maximum non-negative 
-integer value `c`:
+### Vấn đề túi rủ có giới hạn (BKP)
 
-maximize ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+**Vấn đề túi rủ có giới hạn (BKP)** loại bỏ ràng buộc là chỉ có một của mỗi mặt hàng, nhưng hạn chế số lượng `xi` bản sao của mỗi loại mặt hàng thành một giá trị số nguyên không âm tối đa `c`:
 
-subject to ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
-and ![bounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c8c5ac4f8247b3b8e01e89de76a1df0ea969821)
+tối đa ![vấn đề túi rủ có giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
 
-### Unbounded knapsack problem (UKP)
+điều kiện ![vấn đề túi rủ có giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+và ![vấn đề túi rủ có giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/6c8c5ac4f8247b3b8e01e89de76a1df0ea969821)
 
-The **unbounded knapsack problem (UKP)** places no upper bound 
-on the number of copies of each kind of item and can be 
-formulated as above except for that the only restriction 
-on `xi` is that it is a non-negative integer.
+### Vấn đề túi rủ không giới hạn (UKP)
 
-maximize ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
+**Vấn đề túi rủ không giới hạn (UKP)** không đặt ra hạn chế trên số lượng bản sao của mỗi loại mặt hàng và có thể được sắp xếp như trên ngoại trừ việc rằng ràng buộc duy nhất đối với `xi` là nó phải là số nguyên không âm.
 
-subject to ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176) 
-and ![unbounded knapsack](https://wikimedia.org/api/rest_v1/media/math/render/svg/90a99710f61d5dea19e49ae5b31164d2b56b07e3)
+tối đa ![vấn đề túi rủ không giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/85620037d368d2136fb3361702df6a489416931b)
 
-## References
+điều kiện ![vấn đề túi rủ không giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/dd6e7c9bca4397980976ea6d19237500ce3b8176)
+và ![vấn đề túi rủ không giới hạn](https://wikimedia.org/api/rest_v1/media/math/render/svg/90a99710f61d5dea19e49ae5b31164d2b56b07e3)
+
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Knapsack_problem)
-- [0/1 Knapsack Problem on YouTube](https://www.youtube.com/watch?v=8LusJS5-AGo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Vấn đề túi rủ 0/1 trên YouTube](https://www.youtube.com/watch?v=8LusJS5-AGo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/longest-common-subsequence/README.en-EN.md b/src/algorithms/sets/longest-common-subsequence/README.en-EN.md
new file mode 100644
index 0000000000..5a1e3a46f0
--- /dev/null
+++ b/src/algorithms/sets/longest-common-subsequence/README.en-EN.md
@@ -0,0 +1,28 @@
+# Longest common subsequence problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The longest common subsequence (LCS) problem is the problem of finding
+the longest subsequence common to all sequences in a set of sequences
+(often just two sequences). It differs from the longest common substring
+problem: unlike substrings, subsequences are not required to occupy
+consecutive positions within the original sequences.
+
+## Application
+
+The longest common subsequence problem is a classic computer science
+problem, the basis of data comparison programs such as the diff utility,
+and has applications in bioinformatics. It is also widely used by
+revision control systems such as Git for reconciling multiple changes
+made to a revision-controlled collection of files.
+
+## Example
+
+- LCS for input Sequences `ABCDGH` and `AEDFHR` is `ADH` of length 3.
+- LCS for input Sequences `AGGTAB` and `GXTXAYB` is `GTAB` of length 4.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)
+- [YouTube](https://www.youtube.com/watch?v=NnD96abizww&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/longest-common-subsequence/README.md b/src/algorithms/sets/longest-common-subsequence/README.md
index 7c9328e073..4572a3e65d 100644
--- a/src/algorithms/sets/longest-common-subsequence/README.md
+++ b/src/algorithms/sets/longest-common-subsequence/README.md
@@ -1,25 +1,20 @@
-# Longest common subsequence problem
+# Bài toán dãy con chung dài nhất
 
-The longest common subsequence (LCS) problem is the problem of finding 
-the longest subsequence common to all sequences in a set of sequences 
-(often just two sequences). It differs from the longest common substring
-problem: unlike substrings, subsequences are not required to occupy 
-consecutive positions within the original sequences. 
+_Bạn đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Application
+Bài toán dãy con chung dài nhất (LCS) là bài toán tìm dãy con dài nhất chung cho tất cả các dãy trong một tập hợp các dãy (thường chỉ là hai dãy). Nó khác với bài toán dãy con chung dài nhất: so với các dãy con, các dãy con không yêu cầu chiếm vị trí liên tiếp trong các dãy gốc.
 
-The longest common subsequence problem is a classic computer science 
-problem, the basis of data comparison programs such as the diff utility, 
-and has applications in bioinformatics. It is also widely used by 
-revision control systems such as Git for reconciling multiple changes 
-made to a revision-controlled collection of files.
+## Ứng dụng
 
-## Example
+Bài toán dãy con chung dài nhất là một bài toán kinh điển trong khoa học máy tính, là cơ sở của các chương trình so sánh dữ liệu như tiện ích diff, và có ứng dụng trong sinh học tin học. Nó cũng được sử dụng rộng rãi bởi các hệ thống kiểm soát phiên bản như Git để điều hòa nhiều thay đổi được thực hiện đối với một bộ sưu tập các tập tin được kiểm soát bản.
 
-- LCS for input Sequences `ABCDGH` and `AEDFHR` is `ADH` of length 3.
-- LCS for input Sequences `AGGTAB` and `GXTXAYB` is `GTAB` of length 4.
+## Ví dụ
 
-## References
+- LCS cho các dãy đầu vào `ABCDGH` và `AEDFHR` là `ADH` có độ dài là 3.
+- LCS cho các dãy đầu vào `AGGTAB` và `GXTXAYB` là `GTAB` có độ dài là 4.
+
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)
 - [YouTube](https://www.youtube.com/watch?v=NnD96abizww&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/longest-increasing-subsequence/README.en-EN.md b/src/algorithms/sets/longest-increasing-subsequence/README.en-EN.md
new file mode 100644
index 0000000000..b6e2a41b4b
--- /dev/null
+++ b/src/algorithms/sets/longest-increasing-subsequence/README.en-EN.md
@@ -0,0 +1,49 @@
+# Longest Increasing Subsequence
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The longest increasing subsequence problem is to find a subsequence of a
+given sequence in which the subsequence's elements are in sorted order,
+lowest to highest, and in which the subsequence is as long as possible.
+This subsequence is not necessarily contiguous, or unique.
+
+## Complexity
+
+The longest increasing subsequence problem is solvable in
+time `O(n log n)`, where `n` denotes the length of the input sequence.
+
+Dynamic programming approach has complexity `O(n * n)`.
+
+## Example
+
+In the first 16 terms of the binary Van der Corput sequence
+
+```
+0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
+```
+
+a longest increasing subsequence is
+
+```
+0, 2, 6, 9, 11, 15.
+```
+
+This subsequence has length six;
+the input sequence has no seven-member increasing subsequences.
+The longest increasing subsequence in this example is not unique: for
+instance,
+
+```
+0, 4, 6, 9, 11, 15 or
+0, 2, 6, 9, 13, 15 or
+0, 4, 6, 9, 13, 15
+```
+
+are other increasing subsequences of equal length in the same
+input sequence.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Longest_increasing_subsequence)
+- [Dynamic Programming Approach on YouTube](https://www.youtube.com/watch?v=CE2b_-XfVDk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/longest-increasing-subsequence/README.md b/src/algorithms/sets/longest-increasing-subsequence/README.md
index bcb2665c2d..6388799579 100644
--- a/src/algorithms/sets/longest-increasing-subsequence/README.md
+++ b/src/algorithms/sets/longest-increasing-subsequence/README.md
@@ -1,46 +1,43 @@
-# Longest Increasing Subsequence
+# Dãy con tăng dài nhất
 
-The longest increasing subsequence problem is to find a subsequence of a 
-given sequence in which the subsequence's elements are in sorted order, 
-lowest to highest, and in which the subsequence is as long as possible. 
-This subsequence is not necessarily contiguous, or unique. 
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Complexity
+Bài toán dãy con tăng dài nhất là tìm một dãy con của một dãy cho trước sao cho các phần tử của dãy con đó được sắp xếp theo thứ tự tăng dần, từ thấp đến cao, và dãy con đó có độ dài lớn nhất có thể. Dãy con này không nhất thiết phải là liên tục hoặc duy nhất.
 
-The longest increasing subsequence problem is solvable in 
-time `O(n log n)`, where `n` denotes the length of the input sequence.
+## Độ phức tạp
 
-Dynamic programming approach has complexity `O(n * n)`.
+Bài toán dãy con tăng dài nhất có thể được giải quyết trong thời gian `O(n log n)`, trong đó `n` là độ dài của dãy đầu vào.
 
-## Example
+Phương pháp lập trình động có độ phức tạp là `O(n * n)`.
 
-In the first 16 terms of the binary Van der Corput sequence
+## Ví dụ
+
+Trong 16 số đầu tiên của dãy Van der Corput nhị phân
 
 ```
 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
 ```
 
-a longest increasing subsequence is
+một dãy con tăng dài nhất là
 
 ```
 0, 2, 6, 9, 11, 15.
 ```
 
-This subsequence has length six; 
-the input sequence has no seven-member increasing subsequences. 
-The longest increasing subsequence in this example is not unique: for 
-instance,
+Dãy con này có độ dài là sáu;
+dãy đầu vào không có dãy con tăng gồm bảy phần tử.
+Dãy con tăng dài nhất trong ví dụ này không phải là duy nhất: ví dụ,
 
 ```
-0, 4, 6, 9, 11, 15 or
-0, 2, 6, 9, 13, 15 or
+0, 4, 6, 9, 11, 15 hoặc
+0, 2, 6, 9, 13, 15 hoặc
 0, 4, 6, 9, 13, 15
 ```
 
-are other increasing subsequences of equal length in the same 
-input sequence.
+là các dãy con tăng có cùng độ dài trong cùng một dãy đầu vào.
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Longest_increasing_subsequence)
-- [Dynamic Programming Approach on YouTube](https://www.youtube.com/watch?v=CE2b_-XfVDk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Phương pháp lập trình động trên YouTube](https://www.youtube.com/watch?v=CE2b_-XfVDk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/maximum-subarray/README.en-EN.md b/src/algorithms/sets/maximum-subarray/README.en-EN.md
new file mode 100644
index 0000000000..e6f8570da5
--- /dev/null
+++ b/src/algorithms/sets/maximum-subarray/README.en-EN.md
@@ -0,0 +1,32 @@
+# Maximum subarray problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The maximum subarray problem is the task of finding the contiguous
+subarray within a one-dimensional array, `a[1...n]`, of numbers
+which has the largest sum, where,
+
+![Maximum subarray](https://wikimedia.org/api/rest_v1/media/math/render/svg/e8960f093107b71b21827e726e2bad8b023779b2)
+
+![Maximum subarray](https://www.geeksforgeeks.org/wp-content/uploads/kadane-Algorithm.png)
+
+## Example
+
+The list usually contains both positive and negative numbers along
+with `0`. For example, for the array of
+values `−2, 1, −3, 4, −1, 2, 1, −5, 4` the contiguous subarray
+with the largest sum is `4, −1, 2, 1`, with sum `6`.
+
+## Solutions
+
+- Brute Force solution `O(n^2)`: [bfMaximumSubarray.js](./bfMaximumSubarray.js)
+- Divide and Conquer solution `O(n^2)`: [dcMaximumSubarraySum.js](./dcMaximumSubarraySum.js)
+- Dynamic Programming solution `O(n)`: [dpMaximumSubarray.js](./dpMaximumSubarray.js)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Maximum_subarray_problem)
+- [YouTube](https://www.youtube.com/watch?v=ohHWQf1HDfU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/)
+- [LeetCode](https://leetcode.com/explore/interview/card/top-interview-questions-easy/97/dynamic-programming/566/discuss/1595195/C++Python-7-Simple-Solutions-w-Explanation-or-Brute-Force-+-DP-+-Kadane-+-Divide-and-Conquer)
diff --git a/src/algorithms/sets/maximum-subarray/README.md b/src/algorithms/sets/maximum-subarray/README.md
index f06300f500..d6af9a046d 100644
--- a/src/algorithms/sets/maximum-subarray/README.md
+++ b/src/algorithms/sets/maximum-subarray/README.md
@@ -1,27 +1,25 @@
-# Maximum subarray problem
+# Bài toán dãy con liên tục có tổng lớn nhất
 
-The maximum subarray problem is the task of finding the contiguous
-subarray within a one-dimensional array, `a[1...n]`, of numbers
-which has the largest sum, where,
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Bài toán dãy con liên tục có tổng lớn nhất là nhiệm vụ của việc tìm dãy con liên tục trong một mảng một chiều, `a[1...n]`, các số trong đó có tổng lớn nhất, trong đó,
 
 ![Maximum subarray](https://wikimedia.org/api/rest_v1/media/math/render/svg/e8960f093107b71b21827e726e2bad8b023779b2)
 
 ![Maximum subarray](https://www.geeksforgeeks.org/wp-content/uploads/kadane-Algorithm.png)
 
-## Example
+## Ví dụ
 
-The list usually contains both positive and negative numbers along
-with `0`. For example, for the array of
-values `−2, 1, −3, 4, −1, 2, 1, −5, 4` the contiguous subarray
-with the largest sum is `4, −1, 2, 1`, with sum `6`.
+Danh sách thường chứa cả số dương và số âm cùng với số `0`. Ví dụ, với mảng giá trị `−2, 1, −3, 4, −1, 2, 1, −5, 4` dãy con liên tục có tổng lớn nhất là `4, −1, 2, 1`, với tổng là `6`.
 
-## Solutions
+## Các giải pháp
 
-- Brute Force solution `O(n^2)`: [bfMaximumSubarray.js](./bfMaximumSubarray.js)
-- Divide and Conquer solution `O(n^2)`: [dcMaximumSubarraySum.js](./dcMaximumSubarraySum.js)
-- Dynamic Programming solution `O(n)`: [dpMaximumSubarray.js](./dpMaximumSubarray.js)
+- Giải pháp Brute Force `O(n^2)`: [bfMaximumSubarray.js](./bfMaximumSubarray.js)
+- Giải pháp Chia để trị `O(n^2)`: [dcMaximumSubarraySum.js](./dcMaximumSubarraySum.js)
+- Giải pháp Lập trình động `O(n)`: [dpMaximumSubarray.js](./dpMaximumSubarray.js)
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Maximum_subarray_problem)
 - [YouTube](https://www.youtube.com/watch?v=ohHWQf1HDfU&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sets/permutations/README.en-EN.md b/src/algorithms/sets/permutations/README.en-EN.md
new file mode 100644
index 0000000000..f2dcf86770
--- /dev/null
+++ b/src/algorithms/sets/permutations/README.en-EN.md
@@ -0,0 +1,58 @@
+# Permutations
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+When the order doesn't matter, it is a **Combination**.
+
+When the order **does** matter it is a **Permutation**.
+
+**"The combination to the safe is 472"**. We do care about the order. `724` won't work, nor will `247`.
+It has to be exactly `4-7-2`.
+
+## Permutations without repetitions
+
+A permutation, also called an “arrangement number” or “order”, is a rearrangement of
+the elements of an ordered list `S` into a one-to-one correspondence with `S` itself.
+
+Below are the permutations of string `ABC`.
+
+`ABC ACB BAC BCA CBA CAB`
+
+Or for example the first three people in a running race: you can't be first and second.
+
+**Number of combinations**
+
+```
+n * (n-1) * (n -2) * ... * 1 = n!
+```
+
+## Permutations with repetitions
+
+When repetition is allowed we have permutations with repetitions.
+For example the the lock below: it could be `333`.
+
+![Permutation Lock](https://www.mathsisfun.com/combinatorics/images/combination-lock.jpg)
+
+**Number of combinations**
+
+```
+n * n * n ... (r times) = n^r
+```
+
+## Cheatsheet
+
+![Permutations and Combinations Overview](./images/overview.png)
+
+![Permutations overview](./images/permutations-overview.jpeg)
+
+|                                                                             |                                                                                   |
+| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
+| ![Permutations with repetition](./images/permutations-with-repetitions.jpg) | ![Permutations without repetition](./images/permutations-without-repetitions.jpg) |
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
+- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
diff --git a/src/algorithms/sets/permutations/README.md b/src/algorithms/sets/permutations/README.md
index 4b6a268adc..1081773099 100644
--- a/src/algorithms/sets/permutations/README.md
+++ b/src/algorithms/sets/permutations/README.md
@@ -1,55 +1,58 @@
-# Permutations
+# Hoán vị
 
-When the order doesn't matter, it is a **Combination**.
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-When the order **does** matter it is a **Permutation**.
+Khi thứ tự không quan trọng, đó là một **Tổ hợp**.
 
-**"The combination to the safe is 472"**. We do care about the order. `724` won't work, nor will `247`.
-It has to be exactly `4-7-2`.
+Khi thứ tự **quan trọng**, đó là một **Hoán vị**.
 
-## Permutations without repetitions
+**"Mật khẩu của két là 472"**. Chúng ta quan tâm đến thứ tự. `724` không hoạt động, cũng như `247`.
+Nó phải chính xác là `4-7-2`.
 
-A permutation, also called an “arrangement number” or “order”, is a rearrangement of
-the elements of an ordered list `S` into a one-to-one correspondence with `S` itself.
+## Hoán vị không lặp lại
 
-Below are the permutations of string `ABC`.
+Một hoán vị, còn được gọi là “số sắp xếp” hoặc “thứ tự”, là một sắp xếp lại của
+các phần tử của một danh sách có thứ tự `S` thành một một-một tương ứng với `S` chính nó.
+
+Dưới đây là các hoán vị của chuỗi `ABC`.
 
 `ABC ACB BAC BCA CBA CAB`
 
-Or for example the first three people in a running race: you can't be first and second.
+Hoặc ví dụ về ba người đầu tiên trong một cuộc đua: bạn không thể là người đầu tiên và thứ hai.
 
-**Number of combinations**
+**Số lượng tổ hợp**
 
 ```
 n * (n-1) * (n -2) * ... * 1 = n!
 ```
 
-## Permutations with repetitions
+## Hoán vị có lặp lại
 
-When repetition is allowed we have permutations with repetitions.
-For example the the lock below: it could be `333`.
+Khi lặp lại được phép, chúng ta có các hoán vị có lặp lại.
+Ví dụ, khóa dưới đây: nó có thể là `333`.
 
-![Permutation Lock](https://www.mathsisfun.com/combinatorics/images/combination-lock.jpg)
+![Khóa hoán vị](https://www.mathsisfun.com/combinatorics/images/combination-lock.jpg)
 
-**Number of combinations**
+**Số lượng tổ hợp**
 
 ```
-n * n * n ... (r times) = n^r
+n * n * n ... (r lần) = n^r
 ```
 
-## Cheatsheet
+## Bảng tóm tắt
 
-![Permutations and Combinations Overview](./images/overview.png)
+![Tổ hợp và Hoán vị Tổng quan](./images/overview.png)
 
-![Permutations overview](./images/permutations-overview.jpeg)
+![Tổ hợp Tổng quan](./images/permutations-overview.jpeg)
 
-| | |
-| --- | --- |
-|![Permutations with repetition](./images/permutations-with-repetitions.jpg) | ![Permutations without repetition](./images/permutations-without-repetitions.jpg) |
+|                                                                   |                                                                         |
+| ----------------------------------------------------------------- | ----------------------------------------------------------------------- |
+| ![Hoán vị có lặp lại](./images/permutations-with-repetitions.jpg) | ![Hoán vị không lặp lại](./images/permutations-without-repetitions.jpg) |
 
-*Made with [okso.app](https://okso.app)*
+_Tạo với [okso.app](https://okso.app)_
 
-## References
+## Tài liệu tham khảo
 
-- [Math Is Fun](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
-- [Permutations/combinations cheat sheets](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
+- [Toán vui vẻ](https://www.mathsisfun.com/combinatorics/combinations-permutations.html)
+- [Tài liệu hỗ trợ hoán vị/tổ hợp](https://medium.com/@trekhleb/permutations-combinations-algorithms-cheat-sheet-68c14879aba5)
diff --git a/src/algorithms/sets/power-set/README.en-EN.md b/src/algorithms/sets/power-set/README.en-EN.md
new file mode 100644
index 0000000000..1d9980ebfd
--- /dev/null
+++ b/src/algorithms/sets/power-set/README.en-EN.md
@@ -0,0 +1,115 @@
+# Power Set
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Power set of a set `S` is the set of all of the subsets of `S`, including the
+empty set and `S` itself. Power set of set `S` is denoted as `P(S)`.
+
+For example for `{x, y, z}`, the subsets
+are:
+
+```text
+{
+  {}, // (also denoted empty set ∅ or the null set)
+  {x},
+  {y},
+  {z},
+  {x, y},
+  {x, z},
+  {y, z},
+  {x, y, z}
+}
+```
+
+![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)
+
+Here is how we may illustrate the elements of the power set of the set `{x, y, z}` ordered with respect to
+inclusion:
+
+![](https://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg)
+
+**Number of Subsets**
+
+If `S` is a finite set with `|S| = n` elements, then the number of subsets
+of `S` is `|P(S)| = 2^n`. This fact, which is the motivation for the
+notation `2^S`, may be demonstrated simply as follows:
+
+> First, order the elements of `S` in any manner. We write any subset of `S` in
+> the format `{γ1, γ2, ..., γn}` where `γi , 1 ≤ i ≤ n`, can take the value
+> of `0` or `1`. If `γi = 1`, the `i`-th element of `S` is in the subset;
+> otherwise, the `i`-th element is not in the subset. Clearly the number of
+> distinct subsets that can be constructed this way is `2^n` as `γi ∈ {0, 1}`.
+
+## Algorithms
+
+### Bitwise Solution
+
+Each number in binary representation in a range from `0` to `2^n` does exactly
+what we need: it shows by its bits (`0` or `1`) whether to include related
+element from the set or not. For example, for the set `{1, 2, 3}` the binary
+number of `0b010` would mean that we need to include only `2` to the current set.
+
+|     | `abc` |   Subset    |
+| :-: | :---: | :---------: |
+| `0` | `000` |    `{}`     |
+| `1` | `001` |    `{c}`    |
+| `2` | `010` |    `{b}`    |
+| `3` | `011` |  `{c, b}`   |
+| `4` | `100` |    `{a}`    |
+| `5` | `101` |  `{a, c}`   |
+| `6` | `110` |  `{a, b}`   |
+| `7` | `111` | `{a, b, c}` |
+
+> See [bwPowerSet.js](./bwPowerSet.js) file for bitwise solution.
+
+### Backtracking Solution
+
+In backtracking approach we're constantly trying to add next element of the set
+to the subset, memorizing it and then removing it and try the same with the next
+element.
+
+> See [btPowerSet.js](./btPowerSet.js) file for backtracking solution.
+
+### Cascading Solution
+
+This is, arguably, the simplest solution to generate a Power Set.
+
+We start with an empty set:
+
+```text
+powerSets = [[]]
+```
+
+Now, let's say:
+
+```text
+originalSet = [1, 2, 3]
+```
+
+Let's add the 1st element from the originalSet to all existing sets:
+
+```text
+[[]] ← 1 = [[], [1]]
+```
+
+Adding the 2nd element to all existing sets:
+
+```text
+[[], [1]] ← 2 = [[], [1], [2], [1, 2]]
+```
+
+Adding the 3nd element to all existing sets:
+
+```
+[[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
+```
+
+And so on, for the rest of the elements from the `originalSet`. On every iteration the number of sets is doubled, so we'll get `2^n` sets.
+
+> See [caPowerSet.js](./caPowerSet.js) file for cascading solution.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
+- [Math is Fun](https://www.mathsisfun.com/sets/power-set.html)
diff --git a/src/algorithms/sets/power-set/README.md b/src/algorithms/sets/power-set/README.md
index e96961dd8f..78a99eab77 100644
--- a/src/algorithms/sets/power-set/README.md
+++ b/src/algorithms/sets/power-set/README.md
@@ -1,14 +1,15 @@
-# Power Set
+# Tập con lớn nhất
 
-Power set of a set `S` is the set of all of the subsets of `S`, including the
-empty set and `S` itself. Power set of set `S` is denoted as `P(S)`.
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-For example for `{x, y, z}`, the subsets
-are:
+Tập con lớn nhất (Power set) của một tập hợp `S` là tập hợp của tất cả các tập con của `S`, bao gồm cả tập rỗng và `S` chính nó. Tập con lớn nhất của tập hợp `S` được ký hiệu là `P(S)`.
+
+Ví dụ với `{x, y, z}`, các tập con là:
 
 ```text
 {
-  {}, // (also denoted empty set ∅ or the null set)
+  {}, // (cũng được ký hiệu là tập rỗng ∅ hoặc tập con null)
   {x},
   {y},
   {z},
@@ -19,94 +20,82 @@ are:
 }
 ```
 
-![Power Set](https://www.mathsisfun.com/sets/images/power-set.svg)
+![Tập con lớn nhất](https://www.mathsisfun.com/sets/images/power-set.svg)
 
-Here is how we may illustrate the elements of the power set of the set `{x, y, z}` ordered with respect to
-inclusion:
+Dưới đây là cách chúng ta có thể minh họa các phần tử của tập con lớn nhất của tập hợp `{x, y, z}` được sắp xếp theo thứ tự bao gồm:
 
 ![](https://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg)
 
-**Number of Subsets**
+**Số lượng Tập con**
 
-If `S` is a finite set with `|S| = n` elements, then the number of subsets
-of `S` is `|P(S)| = 2^n`. This fact, which is the motivation for the
-notation `2^S`, may be demonstrated simply as follows:
+Nếu `S` là một tập hợp hữu hạn có `|S| = n` phần tử, thì số lượng tập con của `S` là `|P(S)| = 2^n`. Sự thật này, là động lực cho ký hiệu `2^S`, có thể được chứng minh một cách đơn giản như sau:
 
-> First, order the elements of `S` in any manner. We write any subset of `S` in
-the format `{γ1, γ2, ..., γn}` where `γi , 1 ≤ i ≤ n`, can take the value
-of `0` or `1`. If `γi = 1`, the `i`-th element of `S` is in the subset;
-otherwise, the `i`-th element is not in the subset. Clearly the number of
-distinct subsets that can be constructed this way is `2^n` as `γi ∈ {0, 1}`.
+> Trước tiên, sắp xếp các phần tử của `S` theo bất kỳ cách nào. Chúng ta viết bất kỳ tập con của `S` nào trong định dạng `{γ1, γ2, ..., γn}` với `γi , 1 ≤ i ≤ n`, có thể nhận giá trị là `0` hoặc `1`. Nếu `γi = 1`, phần tử thứ `i` của `S` được chọn; ngược lại, phần tử thứ `i` không được chọn. Rõ ràng số lượng tập con riêng biệt có thể được xây dựng theo cách này là `2^n` vì `γi ∈ {0, 1}`.
 
-## Algorithms
+## Thuật toán
 
-### Bitwise Solution
+### Giải pháp Bitwise
 
-Each number in binary representation in a range from `0` to `2^n` does exactly
-what we need: it shows by its bits (`0` or `1`) whether to include related
-element from the set or not. For example, for the set `{1, 2, 3}` the binary
-number of `0b010` would mean that we need to include only `2` to the current set.
+Mỗi số trong biểu diễn nhị phân trong khoảng từ `0` đến `2^n` chính xác làm những gì chúng ta cần: nó cho biết bằng các bit (`0` hoặc `1`) liệu có nên bao gồm phần tử tương ứng từ tập hợp hay không. Ví dụ, đối với tập hợp `{1, 2, 3}` số nhị phân `0b010` sẽ cho biết rằng chúng ta cần chỉ bao gồm `2` vào tập hiện tại.
 
-|       | `abc` | Subset        |
-| :---: | :---: | :-----------: |
-| `0`   | `000` | `{}`          |
-| `1`   | `001` | `{c}`         |
-| `2`   | `010` | `{b}`         |
-| `3`   | `011` | `{c, b}`      |
-| `4`   | `100` | `{a}`         |
-| `5`   | `101` | `{a, c}`      |
-| `6`   | `110` | `{a, b}`      |
-| `7`   | `111` | `{a, b, c}`   |
+|     | `abc` |   Tập con   |
+| :-: | :---: | :---------: |
+| `0` | `000` |    `{}`     |
+| `1` | `001` |    `{c}`    |
+| `2` | `010` |    `{b}`    |
+| `3` | `011` |  `{c, b}`   |
+| `4` | `100` |    `{a}`    |
+| `5` | `101` |  `{a, c}`   |
+| `6` | `110` |  `{a, b}`   |
+| `7` | `111` | `{a, b, c}` |
 
-> See [bwPowerSet.js](./bwPowerSet.js) file for bitwise solution.
+> Xem tệp [bwPowerSet.js](./bwPowerSet.js) cho giải pháp bitwise.
 
-### Backtracking Solution
+### Giải pháp Backtracking
 
-In backtracking approach we're constantly trying to add next element of the set
-to the subset, memorizing it and then removing it and try the same with the next
-element.
+Trong phương pháp quay lui, chúng ta liên tục cố gắng thêm phần tử tiếp theo của tập hợp vào tập con, ghi nhớ nó và sau đó loại bỏ nó và thử cùng với phần tử tiếp theo.
 
-> See [btPowerSet.js](./btPowerSet.js) file for backtracking solution.
+> Xem tệp [btPowerSet.js](./btPowerSet.js) cho giải pháp backtracking.
 
-### Cascading Solution
+### Giải pháp Lan truyền
 
-This is, arguably, the simplest solution to generate a Power Set.
+Đây có lẽ là giải pháp đơn giản nhất để tạo ra một tập con lớn nhất.
 
-We start with an empty set:
+Chúng ta bắt đầu với một tập hợp rỗng:
 
 ```text
 powerSets = [[]]
 ```
 
-Now, let's say:
+Bây giờ, giả sử:
 
 ```text
-originalSet = [1, 2, 3]
+tập ban đầu = [1, 2, 3]
 ```
 
-Let's add the 1st element from the originalSet to all existing sets:
+Thêm phần tử thứ nhất từ tập ban đầu vào tất cả các tập con hiện có:
 
 ```text
 [[]] ← 1 = [[], [1]]
 ```
 
-Adding the 2nd element to all existing sets:
+Thêm phần tử thứ hai vào tất cả các tập con hiện có:
 
 ```text
 [[], [1]] ← 2 = [[], [1], [2], [1, 2]]
 ```
 
-Adding the 3nd element to all existing sets:
+Thêm phần tử thứ ba vào tất cả các tập con hiện có:
 
 ```
 [[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
 ```
 
-And so on, for the rest of the elements from the `originalSet`. On every iteration the number of sets is doubled, so we'll get `2^n` sets.
+Và tiếp tục như vậy, cho đến phần còn lại của các phần tử từ `tập ban đầu`. Trong mỗi lần lặp lại, số lượng tập được nhân đôi, vì vậy chúng ta sẽ có `2^n` tập.
 
-> See [caPowerSet.js](./caPowerSet.js) file for cascading solution.
+> Xem tệp [caPowerSet.js](./caPowerSet.js) cho giải pháp cascading.
 
-## References
+## Tài liệu tham khảo
 
-* [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
-* [Math is Fun](https://www.mathsisfun.com/sets/power-set.html)
+- [Wikipedia](https://en.wikipedia.org/wiki/Power_set)
+- [Math is Fun](https://www.mathsisfun.com/sets/power-set.html)
diff --git a/src/algorithms/sets/shortest-common-supersequence/README.en-EN.md b/src/algorithms/sets/shortest-common-supersequence/README.en-EN.md
new file mode 100644
index 0000000000..ff2c74e928
--- /dev/null
+++ b/src/algorithms/sets/shortest-common-supersequence/README.en-EN.md
@@ -0,0 +1,27 @@
+# Shortest Common Supersequence
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The shortest common supersequence (SCS) of two sequences `X` and `Y`
+is the shortest sequence which has `X` and `Y` as subsequences.
+
+In other words assume we're given two strings str1 and str2, find
+the shortest string that has both str1 and str2 as subsequences.
+
+This is a problem closely related to the longest common
+subsequence problem.
+
+## Example
+
+```
+Input:   str1 = "geek",  str2 = "eke"
+Output: "geeke"
+
+Input:   str1 = "AGGTAB",  str2 = "GXTXAYB"
+Output:  "AGXGTXAYB"
+```
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/shortest-common-supersequence/)
diff --git a/src/algorithms/sets/shortest-common-supersequence/README.md b/src/algorithms/sets/shortest-common-supersequence/README.md
index 5af90a8337..b4404a2a65 100644
--- a/src/algorithms/sets/shortest-common-supersequence/README.md
+++ b/src/algorithms/sets/shortest-common-supersequence/README.md
@@ -1,24 +1,27 @@
-# Shortest Common Supersequence
+# Dãy con siêu dài ngắn nhất
 
-The shortest common supersequence (SCS) of two sequences `X` and `Y` 
-is the shortest sequence which has `X` and `Y` as subsequences.
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In other words assume we're given two strings str1 and str2, find 
-the shortest string that has both str1 and str2 as subsequences.
+Dãy con siêu dài ngắn nhất (SCS) của hai chuỗi `X` và `Y`
+là chuỗi ngắn nhất có `X` và `Y` là các dãy con.
 
-This is a problem closely related to the longest common 
-subsequence problem.
+Nói cách khác, giả sử chúng ta được cho hai chuỗi str1 và str2, hãy tìm
+chuỗi ngắn nhất mà có cả str1 và str2 là các dãy con của nó.
 
-## Example
+Đây là một vấn đề có liên quan chặt chẽ đến vấn đề dãy con chung
+dài nhất.
+
+## Ví dụ
 
 ```
-Input:   str1 = "geek",  str2 = "eke"
-Output: "geeke"
+Đầu vào:   str1 = "geek",  str2 = "eke"
+Đầu ra: "geeke"
 
-Input:   str1 = "AGGTAB",  str2 = "GXTXAYB"
-Output:  "AGXGTXAYB"
+Đầu vào:   str1 = "AGGTAB",  str2 = "GXTXAYB"
+Đầu ra:  "AGXGTXAYB"
 ```
 
-## References
+## Tài liệu tham khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/shortest-common-supersequence/)
diff --git a/src/algorithms/sorting/bubble-sort/README.en-EN.md b/src/algorithms/sorting/bubble-sort/README.en-EN.md
new file mode 100644
index 0000000000..fccd42b2ad
--- /dev/null
+++ b/src/algorithms/sorting/bubble-sort/README.en-EN.md
@@ -0,0 +1,25 @@
+# Bubble Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Bubble sort, sometimes referred to as sinking sort, is a
+simple sorting algorithm that repeatedly steps through
+the list to be sorted, compares each pair of adjacent
+items and swaps them if they are in the wrong order
+(ascending or descending arrangement). The pass through
+the list is repeated until no swaps are needed, which
+indicates that the list is sorted.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)
+
+## Complexity
+
+| Name            | Best |    Average    |     Worst     | Memory | Stable | Comments |
+| --------------- | :--: | :-----------: | :-----------: | :----: | :----: | :------- |
+| **Bubble sort** |  n   | n<sup>2</sup> | n<sup>2</sup> |   1    |  Yes   |          |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort)
+- [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/bubble-sort/README.md b/src/algorithms/sorting/bubble-sort/README.md
index 66347d86c7..a776ba6683 100644
--- a/src/algorithms/sorting/bubble-sort/README.md
+++ b/src/algorithms/sorting/bubble-sort/README.md
@@ -1,25 +1,25 @@
-# Bubble Sort
+# Sắp xếp nổi bọt
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Đọc bản dịch này bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Bubble sort, sometimes referred to as sinking sort, is a
-simple sorting algorithm that repeatedly steps through
-the list to be sorted, compares each pair of adjacent
-items and swaps them if they are in the wrong order
-(ascending or descending arrangement). The pass through
-the list is repeated until no swaps are needed, which
-indicates that the list is sorted.
+Sắp xếp nổi bọt, đôi khi được gọi là sắp xếp chìm, là
+một thuật toán sắp xếp đơn giản mà lặp đi lặp lại
+qua danh sách cần sắp xếp, so sánh từng cặp
+phần tử kề nhau và đổi chỗ chúng nếu chúng ở sai thứ tự
+(sắp xếp tăng dần hoặc giảm dần). Việc đi qua
+danh sách được lặp lại cho đến khi không cần đổi chỗ nào nữa, điều này
+chứng tỏ danh sách đã được sắp xếp.
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)
 
-## Complexity
+## Độ phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
+| Tên                 | Tốt nhất |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Ghi chú |
+| ------------------- | :------: | :-----------: | :-----------: | :----: | :-----: | :-----: |
+| **Sắp xếp nổi bọt** |    n     | n<sup>2</sup> | n<sup>2</sup> |   1    |   Có    |         |
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort)
 - [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/bubble-sort/README.pt-BR.md b/src/algorithms/sorting/bubble-sort/README.pt-BR.md
deleted file mode 100644
index e650523d71..0000000000
--- a/src/algorithms/sorting/bubble-sort/README.pt-BR.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Bubble Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo.
-
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Bubble sort**       | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |           |
-
-## Referências
-
-- [Wikipedia](https://pt.wikipedia.org/wiki/Bubble_sort)
-- [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
diff --git a/src/algorithms/sorting/bucket-sort/README.en-EN.md b/src/algorithms/sorting/bucket-sort/README.en-EN.md
new file mode 100644
index 0000000000..e7976fcb31
--- /dev/null
+++ b/src/algorithms/sorting/bucket-sort/README.en-EN.md
@@ -0,0 +1,37 @@
+# Bucket Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**Bucket sort**, or **bin sort**, is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm.
+
+## Algorithm
+
+Bucket sort works as follows:
+
+1. Set up an array of initially empty `buckets`.
+2. **Scatter:** Go over the original array, putting each object in its `bucket`.
+3. Sort each non-empty `bucket`.
+4. **Gather:** Visit the `buckets` in order and put all elements back into the original array.
+
+Elements are distributed among bins:
+
+![Elements are distributed among bins](./images/bucket_sort_1.png)
+
+Then, elements are sorted within each bin:
+
+![Elements are sorted within each bin](./images/bucket_sort_2.png)
+
+## Complexity
+
+The computational complexity depends on the algorithm used to sort each bucket, the number of buckets to use, and whether the input is uniformly distributed.
+
+The **worst-case** time complexity of bucket sort is
+`O(n^2)` if the sorting algorithm used on the bucket is _insertion sort_, which is the most common use case since the expectation is that buckets will not have too many elements relative to the entire list. In the worst case, all elements are placed in one bucket, causing the running time to reduce to the worst-case complexity of insertion sort (all elements are in reverse order). If the worst-case running time of the intermediate sort used is `O(n * log(n))`, then the worst-case running time of bucket sort will also be
+`O(n * log(n))`.
+
+On **average**, when the distribution of elements across buckets is reasonably uniform, it can be shown that bucket sort runs on average `O(n + k)` for `k` buckets.
+
+## References
+
+- [Bucket Sort on Wikipedia](https://en.wikipedia.org/wiki/Bucket_sort)
diff --git a/src/algorithms/sorting/bucket-sort/README.md b/src/algorithms/sorting/bucket-sort/README.md
index 673ba80b71..0f2730442c 100644
--- a/src/algorithms/sorting/bucket-sort/README.md
+++ b/src/algorithms/sorting/bucket-sort/README.md
@@ -1,35 +1,36 @@
-# Bucket Sort
+# Sắp xếp theo thùng - Bucket Sort
 
-**Bucket sort**, or **bin sort**, is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Algorithm
+**Bucket sort**, hoặc **bin sort**, là một thuật toán sắp xếp hoạt động bằng cách phân phối các phần tử của một mảng vào một số thùng. Sau đó, mỗi thùng được sắp xếp riêng lẻ, entweder bằng cách sử dụng một thuật toán sắp xếp khác, hoặc bằng cách áp dụng đệ quy thuật toán sắp xếp thùng.
 
-Bucket sort works as follows:
+## Thuật toán
 
-1. Set up an array of initially empty `buckets`.
-2. **Scatter:** Go over the original array, putting each object in its `bucket`.
-3. Sort each non-empty `bucket`.
-4. **Gather:** Visit the `buckets` in order and put all elements back into the original array.
+Bucket sort hoạt động như sau:
 
-Elements are distributed among bins:
+1. Thiết lập một mảng `thùng` ban đầu là trống.
+2. **Phân tán:** Duyệt qua mảng gốc, đặt mỗi đối tượng vào `thùng` của nó.
+3. Sắp xếp mỗi `thùng` không trống.
+4. **Tập hợp:** Ghé thăm các `thùng` theo thứ tự và đặt tất cả các phần tử lại vào mảng gốc.
+
+Các phần tử được phân phối trong các thùng:
 
 ![Elements are distributed among bins](./images/bucket_sort_1.png)
 
-Then, elements are sorted within each bin:
+Sau đó, các phần tử được sắp xếp trong mỗi thùng:
 
 ![Elements are sorted within each bin](./images/bucket_sort_2.png)
 
+## Phức tạp
 
-## Complexity
-
-The computational complexity depends on the algorithm used to sort each bucket, the number of buckets to use, and whether the input is uniformly distributed.
+Độ phức tạp tính toán phụ thuộc vào thuật toán được sử dụng để sắp xếp mỗi thùng, số lượng thùng được sử dụng, và liệu đầu vào có phân phối đồng đều không.
 
-The **worst-case** time complexity of bucket sort is
-`O(n^2)` if the sorting algorithm used on the bucket is *insertion sort*, which is the most common use case since the expectation is that buckets will not have too many elements relative to the entire list. In the worst case, all elements are placed in one bucket, causing the running time to reduce to the worst-case complexity of insertion sort (all elements are in reverse order). If the worst-case running time of the intermediate sort used is `O(n * log(n))`, then the worst-case running time of bucket sort will also be
+Trong trường hợp **tệ nhất**, độ phức tạp thời gian của bucket sort là `O(n^2)` nếu thuật toán sắp xếp được sử dụng trên thùng là _sắp xếp chèn_, là trường hợp sử dụng phổ biến nhất vì kỳ vọng là các thùng sẽ không có quá nhiều phần tử so với toàn bộ danh sách. Trong trường hợp tệ nhất, tất cả các phần tử được đặt vào một thùng, làm cho thời gian chạy giảm xuống đến độ phức tạp tệ nhất của sắp xếp chèn (tất cả các phần tử đều theo thứ tự ngược lại). Nếu độ phức tạp thời gian tệ nhất của sắp xếp trung gian được sử dụng là `O(n * log(n))`, thì độ phức tạp thời gian tệ nhất của bucket sort cũng sẽ là
 `O(n * log(n))`.
 
-On **average**, when the distribution of elements across buckets is reasonably uniform, it can be shown that bucket sort runs on average `O(n + k)` for `k` buckets.
+Trên **trung bình**, khi phân phối các phần tử qua các thùng khá đồng đều, có thể chứng minh rằng bucket sort chạy trung bình là `O(n + k)` cho `k` thùng.
 
-## References
+## Tham khảo
 
-- [Bucket Sort on Wikipedia](https://en.wikipedia.org/wiki/Bucket_sort)
+- [Bucket Sort trên Wikipedia](https://en.wikipedia.org/wiki/Bucket_sort)
diff --git a/src/algorithms/sorting/counting-sort/README.en-EN.md b/src/algorithms/sorting/counting-sort/README.en-EN.md
new file mode 100644
index 0000000000..eb3c22be31
--- /dev/null
+++ b/src/algorithms/sorting/counting-sort/README.en-EN.md
@@ -0,0 +1,70 @@
+# Counting Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, **counting sort** is an algorithm for sorting
+a collection of objects according to keys that are small integers;
+that is, it is an integer sorting algorithm. It operates by
+counting the number of objects that have each distinct key value,
+and using arithmetic on those counts to determine the positions
+of each key value in the output sequence. Its running time is
+linear in the number of items and the difference between the
+maximum and minimum key values, so it is only suitable for direct
+use in situations where the variation in keys is not significantly
+greater than the number of items. However, it is often used as a
+subroutine in another sorting algorithm, radix sort, that can
+handle larger keys more efficiently.
+
+Because counting sort uses key values as indexes into an array,
+it is not a comparison sort, and the `Ω(n log n)` lower bound for
+comparison sorting does not apply to it. Bucket sort may be used
+for many of the same tasks as counting sort, with a similar time
+analysis; however, compared to counting sort, bucket sort requires
+linked lists, dynamic arrays or a large amount of preallocated
+memory to hold the sets of items within each bucket, whereas
+counting sort instead stores a single number (the count of items)
+per bucket.
+
+Counting sorting works best when the range of numbers for each array
+element is very small.
+
+## Algorithm
+
+**Step I**
+
+In first step we calculate the count of all the elements of the
+input array `A`. Then Store the result in the count array `C`.
+The way we count is depicted below.
+
+![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)
+
+**Step II**
+
+In second step we calculate how many elements exist in the input
+array `A` which are less than or equals for the given index.
+`Ci` = numbers of elements less than or equals to `i` in input array.
+
+![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)
+
+**Step III**
+
+In this step we place the input array `A` element at sorted
+position by taking help of constructed count array `C` ,i.e what
+we constructed in step two. We used the result array `B` to store
+the sorted elements. Here we handled the index of `B` start from
+zero.
+
+![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)
+
+## Complexity
+
+| Name              | Best  | Average | Worst | Memory | Stable | Comments                    |
+| ----------------- | :---: | :-----: | :---: | :----: | :----: | :-------------------------- |
+| **Counting sort** | n + r |  n + r  | n + r | n + r  |  Yes   | r - biggest number in array |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)
+- [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [EfficientAlgorithms](https://efficientalgorithms.blogspot.com/2016/09/lenear-sorting-counting-sort.html)
diff --git a/src/algorithms/sorting/counting-sort/README.md b/src/algorithms/sorting/counting-sort/README.md
index 40a9539a22..c86356ac2b 100644
--- a/src/algorithms/sorting/counting-sort/README.md
+++ b/src/algorithms/sorting/counting-sort/README.md
@@ -1,69 +1,41 @@
-# Counting Sort
+# Sắp xếp đếm - Counting Sort
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, **counting sort** is an algorithm for sorting 
-a collection of objects according to keys that are small integers; 
-that is, it is an integer sorting algorithm. It operates by 
-counting the number of objects that have each distinct key value, 
-and using arithmetic on those counts to determine the positions 
-of each key value in the output sequence. Its running time is 
-linear in the number of items and the difference between the 
-maximum and minimum key values, so it is only suitable for direct 
-use in situations where the variation in keys is not significantly 
-greater than the number of items. However, it is often used as a 
-subroutine in another sorting algorithm, radix sort, that can 
-handle larger keys more efficiently.
+Trong khoa học máy tính, **sắp xếp đếm** là một thuật toán để sắp xếp một tập hợp các đối tượng theo các khóa là số nguyên nhỏ; tức là, đó là một thuật toán sắp xếp số nguyên. Thuật toán này hoạt động bằng cách đếm số lượng đối tượng có cùng giá trị khóa riêng biệt, và sử dụng các phép toán số học trên các số lượng đó để xác định vị trí của mỗi giá trị khóa trong chuỗi kết quả. Thời gian chạy của nó là tuyến tính theo số lượng phần tử và sự khác biệt giữa giá trị khóa lớn nhất và nhỏ nhất, vì vậy nó chỉ thích hợp cho việc sử dụng trực tiếp trong các tình huống mà sự biến động về khóa không đáng kể hơn số lượng phần tử. Tuy nhiên, nó thường được sử dụng như một phụ thuộc trong một thuật toán sắp xếp khác, radix sort, có thể xử lý các khóa lớn hơn một cách hiệu quả hơn.
 
-Because counting sort uses key values as indexes into an array, 
-it is not a comparison sort, and the `Ω(n log n)` lower bound for 
-comparison sorting does not apply to it. Bucket sort may be used 
-for many of the same tasks as counting sort, with a similar time 
-analysis; however, compared to counting sort, bucket sort requires 
-linked lists, dynamic arrays or a large amount of preallocated 
-memory to hold the sets of items within each bucket, whereas 
-counting sort instead stores a single number (the count of items) 
-per bucket.
+Bởi vì sắp xếp đếm sử dụng các giá trị khóa như là chỉ số vào một mảng, nó không phải là một sắp xếp so sánh, và giới hạn dưới `Ω(n log n)` cho sắp xếp so sánh không áp dụng cho nó. Bucket sort có thể được sử dụng cho nhiều công việc tương tự như sắp xếp đếm, với một phân tích thời gian tương tự; tuy nhiên, so với sắp xếp đếm, bucket sort yêu cầu các danh sách liên kết, mảng động hoặc một lượng lớn bộ nhớ được cấp phát trước để giữ các tập hợp các phần tử trong mỗi thùng, trong khi sắp xếp đếm thay vào đó lưu trữ một con số duy nhất (số lượng phần tử) mỗi thùng.
 
-Counting sorting works best when the range of numbers for each array
-element is very small.
+Sắp xếp đếm hoạt động tốt nhất khi phạm vi số cho mỗi phần tử mảng rất nhỏ.
 
-## Algorithm
+## Thuật toán
 
-**Step I**
+**Bước I**
 
-In first step we calculate the count of all the elements of the 
-input array `A`. Then Store the result in the count array `C`.
-The way we count is depicted below.
+Trong bước đầu tiên, chúng tôi tính toán số lượng tất cả các phần tử của mảng đầu vào `A`. Sau đó, lưu kết quả vào mảng đếm `C`. Cách chúng tôi đếm được mô tả như sau.
 
-![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)
+![Sắp xếp đếm](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)
 
-**Step II**
+**Bước II**
 
-In second step we calculate how many elements exist in the input 
-array `A` which are less than or equals for the given index. 
-`Ci` = numbers of elements less than or equals to `i` in input array.
+Trong bước thứ hai, chúng tôi tính toán có bao nhiêu phần tử tồn tại trong mảng đầu vào `A` mà nhỏ hơn hoặc bằng chỉ số cho trước. `Ci` = số lượng phần tử nhỏ hơn hoặc bằng `i` trong mảng đầu vào.
 
-![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)
+![Sắp xếp đếm](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)
 
-**Step III**
+**Bước III**
 
-In this step we place the input array `A` element at sorted 
-position by taking help of constructed count array `C` ,i.e what 
-we constructed in step two. We used the result array `B` to store 
-the sorted elements. Here we handled the index of `B` start from
-zero.
- 
-![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)
+Trong bước này, chúng tôi đặt phần tử mảng đầu vào `A` vào vị trí đã sắp xếp bằng cách sử dụng mảng đếm đã xây dựng trong bước hai. Chúng tôi sử dụng mảng kết quả `B` để lưu trữ các phần tử đã sắp xếp. Ở đây, chúng tôi xử lý chỉ số của `B` bắt đầu từ số không.
 
-## Complexity
+![Sắp xếp đếm](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Yes       | r - biggest number in array |
+## Phức tạp
 
-## References
+| Tên             | Tốt nhất | Trung bình | Tệ nhất | Bộ nhớ | Ổn định | Bình luận                  |
+| --------------- | :------: | :--------: | :-----: | :----: | :-----: | :------------------------- |
+| **Sắp xếp đếm** |  n + r   |   n + r    |  n + r  | n + r  |   Có    | r - số lớn nhất trong mảng |
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)
 - [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/counting-sort/README.pt-br.md b/src/algorithms/sorting/counting-sort/README.pt-br.md
deleted file mode 100644
index af2c75f6af..0000000000
--- a/src/algorithms/sorting/counting-sort/README.pt-br.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# Counting Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-Em ciência da computação, **counting sort** é um algoritmo para ordenar
-uma coleção de objetos de acordo com chaves que são pequenos inteiros;
-ou seja, é um algoritmo de ordenação de inteiros. Ele opera por
-contando o número de objetos que têm cada valor de chave distinto,
-e usando aritmética nessas contagens para determinar as posições
-de cada valor de chave na sequência de saída. Seu tempo de execução é
-linear no número de itens e a diferença entre o
-valores de chave máximo e mínimo, portanto, é adequado apenas para
-uso em situações em que a variação de tonalidades não é significativamente
-maior que o número de itens. No entanto, muitas vezes é usado como
-sub-rotina em outro algoritmo de ordenação, radix sort, que pode
-lidar com chaves maiores de forma mais eficiente.
-
-Como a classificação por contagem usa valores-chave como índices em um vetor,
-não é uma ordenação por comparação, e o limite inferior `Ω(n log n)` para
-a ordenação por comparação não se aplica a ele. A classificação por bucket pode ser usada
-para muitas das mesmas tarefas que a ordenação por contagem, com um tempo semelhante
-análise; no entanto, em comparação com a classificação por contagem, a classificação por bucket requer
-listas vinculadas, arrays dinâmicos ou uma grande quantidade de pré-alocados
-memória para armazenar os conjuntos de itens dentro de cada bucket, enquanto
-A classificação por contagem armazena um único número (a contagem de itens)
-por balde.
-
-A classificação por contagem funciona melhor quando o intervalo de números para cada
-elemento do vetor é muito pequeno.
-
-## Algoritmo
-
-**Passo I**
-
-Na primeira etapa, calculamos a contagem de todos os elementos do
-vetor de entrada 'A'. Em seguida, armazene o resultado no vetor de contagem `C`.
-A maneira como contamos é descrita abaixo.
-
-![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)
-
-**Passo II**
-
-Na segunda etapa, calculamos quantos elementos existem na entrada
-do vetor `A` que são menores ou iguais para o índice fornecido.
-`Ci` = números de elementos menores ou iguais a `i` no vetor de entrada.
-
-![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)
-
-**Passo III**
-
-Nesta etapa, colocamos o elemento `A` do vetor de entrada em classificado
-posição usando a ajuda do vetor de contagem construída `C`, ou seja, o que
-construímos no passo dois. Usamos o vetor de resultados `B` para armazenar
-os elementos ordenados. Aqui nós lidamos com o índice de `B` começando de
-zero.
- 
-![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Counting sort**     | n + r           | n + r               | n + r               | n + r     | Sim       | r - Maior número no vetor |
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)
-- [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [EfficientAlgorithms](https://efficientalgorithms.blogspot.com/2016/09/lenear-sorting-counting-sort.html)
diff --git a/src/algorithms/sorting/heap-sort/README.en-EN.md b/src/algorithms/sorting/heap-sort/README.en-EN.md
new file mode 100644
index 0000000000..0afa5380a8
--- /dev/null
+++ b/src/algorithms/sorting/heap-sort/README.en-EN.md
@@ -0,0 +1,27 @@
+# Heap Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Heapsort is a comparison-based sorting algorithm.
+Heapsort can be thought of as an improved selection
+sort: like that algorithm, it divides its input into
+a sorted and an unsorted region, and it iteratively
+shrinks the unsorted region by extracting the largest
+element and moving that to the sorted region. The
+improvement consists of the use of a heap data structure
+rather than a linear-time search to find the maximum.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)
+
+## Complexity
+
+| Name          |     Best      |    Average    |     Worst     | Memory | Stable | Comments |
+| ------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------- |
+| **Heap sort** | n&nbsp;log(n) | n&nbsp;log(n) | n&nbsp;log(n) |   1    |   No   |          |
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Heapsort)
diff --git a/src/algorithms/sorting/heap-sort/README.md b/src/algorithms/sorting/heap-sort/README.md
index 2370776f1b..6eb87cd0e7 100644
--- a/src/algorithms/sorting/heap-sort/README.md
+++ b/src/algorithms/sorting/heap-sort/README.md
@@ -1,27 +1,20 @@
-# Heap Sort
+# Sắp xếp Heap - Heap Sort
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Heapsort is a comparison-based sorting algorithm.
-Heapsort can be thought of as an improved selection
-sort: like that algorithm, it divides its input into
-a sorted and an unsorted region, and it iteratively
-shrinks the unsorted region by extracting the largest
-element and moving that to the sorted region. The 
-improvement consists of the use of a heap data structure
-rather than a linear-time search to find the maximum.
+Heap Sort là một thuật toán sắp xếp dựa trên so sánh. Heap Sort có thể được coi như một cải tiến của thuật toán sắp xếp chọn: giống như thuật toán đó, nó chia đầu vào của mình thành một khu vực đã sắp xếp và một khu vực chưa sắp xếp, và nó lặp lại việc thu nhỏ khu vực chưa sắp xếp bằng cách trích xuất phần tử lớn nhất và di chuyển nó vào khu vực đã sắp xếp. Sự cải tiến này bao gồm việc sử dụng cấu trúc dữ liệu heap thay vì tìm kiếm thời gian tuyến tính để tìm phần tử lớn nhất.
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)
 
-## Complexity
+## Phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | No        |           |
+| Tên           |   Tốt nhất    |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Bình luận |
+| ------------- | :-----------: | :-----------: | :-----------: | :----: | :-----: | :-------- |
+| **Heap sort** | n&nbsp;log(n) | n&nbsp;log(n) | n&nbsp;log(n) |   1    |  Không  |           |
 
-## References
+## Tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Heapsort)
diff --git a/src/algorithms/sorting/heap-sort/README.pt-BR.md b/src/algorithms/sorting/heap-sort/README.pt-BR.md
deleted file mode 100644
index 6d5a2d4849..0000000000
--- a/src/algorithms/sorting/heap-sort/README.pt-BR.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Heap Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-Heapsort é um algoritmo de ordenação baseado em comparação. O Heapsort pode ser pensado como uma seleção aprimorada sort: como esse algoritmo, ele divide sua entrada em uma região classificada e uma região não classificada, e iterativamente encolhe a região não classificada extraindo o maior elemento e movendo-o para a região classificada. A melhoria consiste no uso de uma estrutura de dados heap em vez de uma busca em tempo linear para encontrar o máximo.
-
-![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif)
-
-![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Heap sort**         | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | 1         | Não        |           |
-
-## Referências
-
-[Wikipedia](https://en.wikipedia.org/wiki/Heapsort)
diff --git a/src/algorithms/sorting/insertion-sort/README.en-EN.md b/src/algorithms/sorting/insertion-sort/README.en-EN.md
new file mode 100644
index 0000000000..3b04dd0047
--- /dev/null
+++ b/src/algorithms/sorting/insertion-sort/README.en-EN.md
@@ -0,0 +1,24 @@
+# Insertion Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Insertion sort is a simple sorting algorithm that builds
+the final sorted array (or list) one item at a time.
+It is much less efficient on large lists than more
+advanced algorithms such as quicksort, heapsort, or merge
+sort.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)
+
+## Complexity
+
+| Name               | Best |    Average    |     Worst     | Memory | Stable | Comments |
+| ------------------ | :--: | :-----------: | :-----------: | :----: | :----: | :------- |
+| **Insertion sort** |  n   | n<sup>2</sup> | n<sup>2</sup> |   1    |  Yes   |          |
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)
diff --git a/src/algorithms/sorting/insertion-sort/README.md b/src/algorithms/sorting/insertion-sort/README.md
index 8bc922683f..32ce0188a2 100644
--- a/src/algorithms/sorting/insertion-sort/README.md
+++ b/src/algorithms/sorting/insertion-sort/README.md
@@ -1,24 +1,20 @@
-# Insertion Sort
+# Sắp xếp chèn - Insertion Sort
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Insertion sort is a simple sorting algorithm that builds 
-the final sorted array (or list) one item at a time. 
-It is much less efficient on large lists than more 
-advanced algorithms such as quicksort, heapsort, or merge 
-sort.
+Sắp xếp chèn là một thuật toán sắp xếp đơn giản xây dựng mảng đã sắp xếp cuối cùng (hoặc danh sách) một phần tử vào một lần. Nó không hiệu quả bằng các thuật toán tiên tiến hơn như quicksort, heapsort hoặc merge sort trên danh sách lớn.
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)
 
-## Complexity
+## Phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Yes       |           |
+| Tên              | Tốt nhất |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Bình luận |
+| ---------------- | :------: | :-----------: | :-----------: | :----: | :-----: | :-------- |
+| **Sắp xếp chèn** |    n     | n<sup>2</sup> | n<sup>2</sup> |   1    |   Có    |           |
 
-## References
+## Tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)
diff --git a/src/algorithms/sorting/insertion-sort/README.pt-BR.md b/src/algorithms/sorting/insertion-sort/README.pt-BR.md
deleted file mode 100644
index a36d2742be..0000000000
--- a/src/algorithms/sorting/insertion-sort/README.pt-BR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Insertion Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-A ordenação por inserção é um algoritmo de ordenação simples que criaa matriz classificada final (ou lista) um item de cada vez.
-É muito menos eficiente em grandes listas do que mais algoritmos avançados, como quicksort, heapsort ou merge
-ordenar.
-
-![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif)
-
-![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Insertion sort**    | n               | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Sim       |           |
-
-## Referências
-
-[Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)
diff --git a/src/algorithms/sorting/merge-sort/README.en-EN.md b/src/algorithms/sorting/merge-sort/README.en-EN.md
new file mode 100644
index 0000000000..6f5e0c9fd2
--- /dev/null
+++ b/src/algorithms/sorting/merge-sort/README.en-EN.md
@@ -0,0 +1,37 @@
+# Merge Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, merge sort (also commonly spelled
+mergesort) is an efficient, general-purpose,
+comparison-based sorting algorithm. Most implementations
+produce a stable sort, which means that the implementation
+preserves the input order of equal elements in the sorted
+output. Mergesort is a divide and conquer algorithm that
+was invented by John von Neumann in 1945.
+
+An example of merge sort. First divide the list into
+the smallest unit (1 element), then compare each
+element with the adjacent list to sort and merge the
+two adjacent lists. Finally all the elements are sorted
+and merged.
+
+![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
+
+A recursive merge sort algorithm used to sort an array of 7
+integer values. These are the steps a human would take to
+emulate merge sort (top-down).
+
+![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
+
+## Complexity
+
+| Name           |     Best      |    Average    |     Worst     | Memory | Stable | Comments |
+| -------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------- |
+| **Merge sort** | n&nbsp;log(n) | n&nbsp;log(n) | n&nbsp;log(n) |   n    |  Yes   |          |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)
+- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/merge-sort/README.ko-KR.md b/src/algorithms/sorting/merge-sort/README.ko-KR.md
deleted file mode 100644
index 5447fd217e..0000000000
--- a/src/algorithms/sorting/merge-sort/README.ko-KR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# 병합 정렬
-
-컴퓨터과학에서, 병합 정렬(일반적으로 mergesort라고 쓰는)은 효율적이고, 범용적인, 비교 기반의 정렬 알고리즘입니다. 대부분의 구현들은 안정적인 정렬을 만들어내며, 이는 정렬된 산출물에서 동일한 요소들의 입력 순서가 유지된다는 것을 의미합니다. 병합 정렬은 1945년에 John von Neumann이 만든 분할 정복 알고리즘입니다.
-
-병합 정렬의 예시입니다. 우선 리스트를 가장 작은 단위로 나누고(한 개의 요소), 두 개의 인접한 리스트를 정렬하고 병합하기 위해 각 요소와 인접한 리스트를 비교합니다. 마지막으로 모든 요소들은 정렬되고 병합됩니다.
-
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
-
-재귀적인 병합 정렬 알고리즘은 7개의 정수값을 가진 배열을 정렬하는데 사용됩니다. 다음은 합병 정렬을 모방하기 위해 사람이 취하는 단계입니다.(하향식)
-
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
-
-## 복잡도
-
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |
-
-## 참조
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)
-- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/merge-sort/README.md b/src/algorithms/sorting/merge-sort/README.md
index 2931329482..bab8400c48 100644
--- a/src/algorithms/sorting/merge-sort/README.md
+++ b/src/algorithms/sorting/merge-sort/README.md
@@ -1,38 +1,25 @@
-# Merge Sort
+# Sắp xếp trộn - Merge Sort
 
-_Read this in other languages:_
-[_한국어_](README.ko-KR.md),
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, merge sort (also commonly spelled
-mergesort) is an efficient, general-purpose,
-comparison-based sorting algorithm. Most implementations
-produce a stable sort, which means that the implementation
-preserves the input order of equal elements in the sorted
-output. Mergesort is a divide and conquer algorithm that
-was invented by John von Neumann in 1945.
+Trong khoa học máy tính, sắp xếp trộn (thường được viết là mergesort) là một thuật toán sắp xếp hiệu quả, đa dụng, dựa trên so sánh. Hầu hết các phiên bản sản xuất một sắp xếp ổn định, có nghĩa là việc triển khai bảo tồn thứ tự đầu vào của các phần tử bằng nhau trong đầu ra đã sắp xếp. Mergesort là một thuật toán chia để trị được phát minh bởi John von Neumann vào năm 1945.
 
-An example of merge sort. First divide the list into
-the smallest unit (1 element), then compare each
-element with the adjacent list to sort and merge the
-two adjacent lists. Finally all the elements are sorted
-and merged.
+Một ví dụ về sắp xếp trộn. Đầu tiên chia danh sách thành đơn vị nhỏ nhất (1 phần tử), sau đó so sánh mỗi phần tử với danh sách liền kề để sắp xếp và trộn hai danh sách liền kề. Cuối cùng tất cả các phần tử được sắp xếp và trộn lại.
 
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
+![Sắp xếp Trộn](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
 
-A recursive merge sort algorithm used to sort an array of 7
-integer values. These are the steps a human would take to
-emulate merge sort (top-down).
+Một thuật toán sắp xếp trộn đệ quy được sử dụng để sắp xếp một mảng gồm 7 giá trị số nguyên. Đây là các bước mà một con người sẽ thực hiện để mô phỏng sắp xếp trộn (từ trên xuống).
 
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
+![Sắp xếp Trộn](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
 
-## Complexity
+## Phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Yes       |           |
+| Tên              |   Tốt nhất    |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Bình luận |
+| ---------------- | :-----------: | :-----------: | :-----------: | :----: | :-----: | :-------- |
+| **Sắp xếp trộn** | n&nbsp;log(n) | n&nbsp;log(n) | n&nbsp;log(n) |   n    |   Có    |           |
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)
 - [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/merge-sort/README.pt-BR.md b/src/algorithms/sorting/merge-sort/README.pt-BR.md
deleted file mode 100644
index f7be449f04..0000000000
--- a/src/algorithms/sorting/merge-sort/README.pt-BR.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# Merge Sort
-
-_Leia isso em outros idiomas:_
-[_한국어_](README.ko-KR.md),
-[_English_](README.md)
-
-Em ciência da computação, merge sort (também comumente escrito
-mergesort) é uma ferramenta eficiente, de propósito geral,
-algoritmo de ordenação baseado em comparação. A maioria das implementações
-produzir uma classificação estável, o que significa que a implementação
-preserva a ordem de entrada de elementos iguais na ordenação
-resultado. Mergesort é um algoritmo de divisão e conquista que
-foi inventado por John von Neumann em 1945.
-
-Um exemplo de classificação de mesclagem. Primeiro divida a lista em
-a menor unidade (1 elemento), então compare cada
-elemento com a lista adjacente para classificar e mesclar o
-duas listas adjacentes. Finalmente todos os elementos são ordenados
-e mesclado.
-
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif)
-
-Um algoritmo de classificação de mesclagem recursivo usado para classificar uma matriz de 7
-valores inteiros. Estes são os passos que um ser humano daria para
-emular merge sort (top-down).
-
-![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Merge sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n&nbsp;log(n)       | n         | Sim       |           |
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)
-- [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/quick-sort/README.en-EN.md b/src/algorithms/sorting/quick-sort/README.en-EN.md
new file mode 100644
index 0000000000..e05409bcb8
--- /dev/null
+++ b/src/algorithms/sorting/quick-sort/README.en-EN.md
@@ -0,0 +1,38 @@
+# Quicksort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Quicksort is a divide and conquer algorithm.
+Quicksort first divides a large array into two smaller
+sub-arrays: the low elements and the high elements.
+Quicksort can then recursively sort the sub-arrays
+
+The steps are:
+
+1. Pick an element, called a pivot, from the array.
+2. Partitioning: reorder the array so that all elements with
+   values less than the pivot come before the pivot, while all
+   elements with values greater than the pivot come after it
+   (equal values can go either way). After this partitioning,
+   the pivot is in its final position. This is called the
+   partition operation.
+3. Recursively apply the above steps to the sub-array of
+   elements with smaller values and separately to the
+   sub-array of elements with greater values.
+
+Animated visualization of the quicksort algorithm.
+The horizontal lines are pivot values.
+
+![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)
+
+## Complexity
+
+| Name           |     Best      |    Average    |     Worst     | Memory | Stable | Comments                                                      |
+| -------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------------------------------------------------------------ |
+| **Quick sort** | n&nbsp;log(n) | n&nbsp;log(n) | n<sup>2</sup> | log(n) |   No   | Quicksort is usually done in-place with O(log(n)) stack space |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)
+- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/quick-sort/README.md b/src/algorithms/sorting/quick-sort/README.md
index 9dcec0f12f..95bf743f4e 100644
--- a/src/algorithms/sorting/quick-sort/README.md
+++ b/src/algorithms/sorting/quick-sort/README.md
@@ -1,39 +1,38 @@
-# Quicksort
+# Sắp xếp nhanh - Quick Sort
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Quicksort is a divide and conquer algorithm.
-Quicksort first divides a large array into two smaller 
-sub-arrays: the low elements and the high elements.
-Quicksort can then recursively sort the sub-arrays
+Sắp xếp nhanh là một thuật toán chia để trị.
+Sắp xếp nhanh đầu tiên chia một mảng lớn thành hai mảng con nhỏ hơn:
+các phần tử thấp và các phần tử cao.
+Sắp xếp nhanh sau đó có thể sắp xếp đệ quy các mảng con
 
-The steps are:
+Các bước là:
 
-1. Pick an element, called a pivot, from the array.
-2. Partitioning: reorder the array so that all elements with 
-values less than the pivot come before the pivot, while all 
-elements with values greater than the pivot come after it 
-(equal values can go either way). After this partitioning, 
-the pivot is in its final position. This is called the 
-partition operation.
-3. Recursively apply the above steps to the sub-array of 
-elements with smaller values and separately to the 
-sub-array of elements with greater values.
+1. Chọn một phần tử, gọi là pivot, từ mảng.
+2. Phân chia: sắp xếp lại mảng sao cho tất cả các phần tử có
+   giá trị nhỏ hơn pivot đều đứng trước pivot, trong khi tất cả
+   các phần tử có giá trị lớn hơn pivot đứng sau nó
+   (các giá trị bằng nhau có thể điều này hoặc không). Sau phân chia này,
+   pivot nằm ở vị trí cuối cùng của nó. Điều này được gọi là
+   phép phân chia.
+3. Áp dụng đệ quy các bước trên cho mảng con của
+   các phần tử có giá trị nhỏ hơn và riêng biệt cho
+   mảng con của các phần tử có giá trị lớn hơn.
 
-Animated visualization of the quicksort algorithm.
-The horizontal lines are pivot values.
+Minh họa động của thuật toán sắp xếp nhanh.
+Các đường ngang là các giá trị pivot.
 
-![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)
+![Sắp xếp nhanh](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)
 
-## Complexity
+## Phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | No        |  Quicksort is usually done in-place with O(log(n)) stack space |
+| Tên               |   Tốt nhất    |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Bình luận                                                                  |
+| ----------------- | :-----------: | :-----------: | :-----------: | :----: | :-----: | :------------------------------------------------------------------------- |
+| **Sắp xếp nhanh** | n&nbsp;log(n) | n&nbsp;log(n) | n<sup>2</sup> | log(n) |  Không  | Sắp xếp nhanh thường được thực hiện tại chỗ với không gian stack O(log(n)) |
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)
 - [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/quick-sort/README.pt-BR.md b/src/algorithms/sorting/quick-sort/README.pt-BR.md
deleted file mode 100644
index ca3a45699f..0000000000
--- a/src/algorithms/sorting/quick-sort/README.pt-BR.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Quicksort
-
-_Leia isso em outros idiomas:_
-[_简体中文_](README.zh-CN.md),
-[_English_](README.md)
-
-Quicksort é um algoritmo de dividir para conquistar.
-Quicksort primeiro divide uma grande matriz em duas menores
-submatrizes: os elementos baixos e os elementos altos.
-O Quicksort pode então classificar recursivamente as submatrizes.
-
-As etapas são:
-
-1. Escolha um elemento, denominado pivô, na matriz.
-2. Particionamento: reordene a matriz para que todos os elementos com
-valores menores que o pivô estejam antes do pivô, enquanto todos
-elementos com valores maiores do que o pivô vêm depois dele
-(valores iguais podem ser usados em qualquer direção). Após este particionamento,
-o pivô está em sua posição final. Isso é chamado de
-operação de partição.
-3. Aplique recursivamente as etapas acima à submatriz de
-elementos com valores menores e separadamente para o
-submatriz de elementos com valores maiores.
-
-Visualização animada do algoritmo quicksort.
-As linhas horizontais são valores dinâmicos. 
-
-![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Quick sort**        | n&nbsp;log(n)   | n&nbsp;log(n)       | n<sup>2</sup>       | log(n)    | Não        |  Quicksort geralmente é feito no local com espaço de pilha O(log(n)) |
-
-## Referências
-
-- [Wikipedia](https://pt.wikipedia.org/wiki/Quicksort)
-- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/quick-sort/README.zh-CN.md b/src/algorithms/sorting/quick-sort/README.zh-CN.md
deleted file mode 100644
index 96b2e44de8..0000000000
--- a/src/algorithms/sorting/quick-sort/README.zh-CN.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# 快速排序
-
-快速排序是一种分而治之的算法。快速排序首先将一个大数组分成两个较小的子数组：比某个数小的元素和比某个数大的元素。然后快速排序可以递归地对子数组进行排序。
-
-步骤是：
-
-1. 从数组中选择一个元素，称为基点
-
-2. 分区：对数组重新排序，使所有值小于基点的元素都在它左边，而所有值大于基点的元素都在它右边（相等的值可以放在任何一边）。在此分区之后，基点处于其最终位置（左边和右边的中间位置）。这称为分区操作。
-
-3. 递归地将上述步骤应用于左边的数组和右边的数组。
-
-快速排序算法的动画可视化。水平线是基点值。
-
-![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif)
-
-## 复杂度
-
-| Name           |     Best      |    Average    |     Worst     | Memory | Stable | Comments                                                      |
-| -------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------------------------------------------------------------ |
-| **Quick sort** | n&nbsp;log(n) | n&nbsp;log(n) | n<sup>2</sup> | log(n) |   No   | Quicksort is usually done in-place with O(log(n)) stack space |
-
-## 引用
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)
-
-- [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/radix-sort/README.en-EN.md b/src/algorithms/sorting/radix-sort/README.en-EN.md
new file mode 100644
index 0000000000..1c9449adde
--- /dev/null
+++ b/src/algorithms/sorting/radix-sort/README.en-EN.md
@@ -0,0 +1,48 @@
+# Radix Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, **radix sort** is a non-comparative integer sorting
+algorithm that sorts data with integer keys by grouping keys by the individual
+digits which share the same significant position and value. A positional notation
+is required, but because integers can represent strings of characters
+(e.g., names or dates) and specially formatted floating point numbers, radix
+sort is not limited to integers.
+
+_Where does the name come from?_
+
+In mathematical numeral systems, the _radix_ or base is the number of unique digits,
+including the digit zero, used to represent numbers in a positional numeral system.
+For example, a binary system (using numbers 0 and 1) has a radix of 2 and a decimal
+system (using numbers 0 to 9) has a radix of 10.
+
+## Efficiency
+
+The topic of the efficiency of radix sort compared to other sorting algorithms is
+somewhat tricky and subject to quite a lot of misunderstandings. Whether radix
+sort is equally efficient, less efficient or more efficient than the best
+comparison-based algorithms depends on the details of the assumptions made.
+Radix sort complexity is `O(wn)` for `n` keys which are integers of word size `w`.
+Sometimes `w` is presented as a constant, which would make radix sort better
+(for sufficiently large `n`) than the best comparison-based sorting algorithms,
+which all perform `O(n log n)` comparisons to sort `n` keys. However, in
+general `w` cannot be considered a constant: if all `n` keys are distinct,
+then `w` has to be at least `log n` for a random-access machine to be able to
+store them in memory, which gives at best a time complexity `O(n log n)`. That
+would seem to make radix sort at most equally efficient as the best
+comparison-based sorts (and worse if keys are much longer than `log n`).
+
+![Radix Sort](./images/radix-sort.png)
+
+## Complexity
+
+| Name           |  Best  | Average | Worst  | Memory | Stable | Comments                  |
+| -------------- | :----: | :-----: | :----: | :----: | :----: | :------------------------ |
+| **Radix sort** | n \* k | n \* k  | n \* k | n + k  |  Yes   | k - length of longest key |
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort)
+- [YouTube](https://www.youtube.com/watch?v=XiuSW_mEn7g&index=62&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [ResearchGate](https://www.researchgate.net/figure/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the_fig1_291086231)
diff --git a/src/algorithms/sorting/radix-sort/README.md b/src/algorithms/sorting/radix-sort/README.md
index 108d7d19b6..435faca5cd 100644
--- a/src/algorithms/sorting/radix-sort/README.md
+++ b/src/algorithms/sorting/radix-sort/README.md
@@ -1,47 +1,47 @@
-# Radix Sort
-
-_Read this in other languages:_
-[_Português_](README.pt-BR.md),
-
-In computer science, **radix sort** is a non-comparative integer sorting
-algorithm that sorts data with integer keys by grouping keys by the individual
-digits which share the same significant position and value. A positional notation
-is required, but because integers can represent strings of characters
-(e.g., names or dates) and specially formatted floating point numbers, radix
-sort is not limited to integers.
-
-*Where does the name come from?*
-
-In mathematical numeral systems, the *radix* or base is the number of unique digits,
-including the digit zero, used to represent numbers in a positional numeral system.
-For example, a binary system (using numbers 0 and 1) has a radix of 2 and a decimal
-system (using numbers 0 to 9) has a radix of 10.
-
-## Efficiency
-
-The topic of the efficiency of radix sort compared to other sorting algorithms is
-somewhat tricky and subject to quite a lot of misunderstandings. Whether radix
-sort is equally efficient, less efficient or more efficient than the best
-comparison-based algorithms depends on the details of the assumptions made.
-Radix sort complexity is `O(wn)` for `n` keys which are integers of word size `w`.
-Sometimes `w` is presented as a constant, which would make radix sort better
-(for sufficiently large `n`) than the best comparison-based sorting algorithms,
-which all perform `O(n log n)` comparisons to sort `n` keys. However, in
-general `w` cannot be considered a constant: if all `n` keys are distinct,
-then `w` has to be at least `log n` for a random-access machine to be able to
-store them in memory, which gives at best a time complexity `O(n log n)`. That
-would seem to make radix sort at most equally efficient as the best
-comparison-based sorts (and worse if keys are much longer than `log n`).
-
-![Radix Sort](./images/radix-sort.png)
-
-## Complexity
-
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Yes       | k - length of longest key |
-
-## References
+# Sắp xếp Radix
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, **sắp xếp radix** là một thuật toán sắp xếp số nguyên không so sánh
+sắp xếp dữ liệu với các khóa số nguyên bằng cách nhóm các khóa theo từng chữ số
+chung vị trí và giá trị quan trọng. Cần có một ký hiệu vị trí,
+nhưng vì số nguyên có thể đại diện cho chuỗi ký tự
+(ví dụ, tên hoặc ngày) và số thực được định dạng đặc biệt,
+sắp xếp radix không giới hạn ở số nguyên.
+
+_Tên này đến từ đâu?_
+
+Trong hệ thống số toán học, _radix_ hoặc cơ số là số lượng chữ số duy nhất,
+bao gồm số không, được sử dụng để đại diện cho các số trong hệ thống số có vị trí.
+Ví dụ, hệ thống nhị phân (sử dụng số 0 và 1) có một radix là 2 và hệ thống thập phân
+(sử dụng số 0 đến 9) có một radix là 10.
+
+## Hiệu suất
+
+Chủ đề về hiệu suất của sắp xếp radix so với các thuật toán sắp xếp khác là
+một chút phức tạp và phụ thuộc vào nhiều hiểu biết sai lầm. Dù sắp xếp radix
+có hiệu suất bằng nhau, kém hiệu suất hoặc cao hơn so với các thuật toán
+so sánh tốt nhất phụ thuộc vào chi tiết của các giả định được thực hiện.
+Phức tạp của sắp xếp radix là `O(wn)` cho `n` khóa là số nguyên của kích thước từ `w`.
+Đôi khi `w` được hiển thị như một hằng số, điều này sẽ làm cho sắp xếp radix tốt hơn
+(đối với `n` đủ lớn) so với các thuật toán sắp xếp so sánh tốt nhất,
+tất cả đều thực hiện `O(n log n)` so sánh để sắp xếp `n` khóa. Tuy nhiên, trong
+tổng quát `w` không thể được xem xét là một hằng số: nếu tất cả các `n` khóa là phân biệt,
+thì `w` phải ít nhất là `log n` cho máy truy cập ngẫu nhiên có thể
+lưu trữ chúng trong bộ nhớ, điều này cho tối đa là một phức tạp thời gian `O(n log n)`.
+Điều này dường như làm cho sắp xếp radix tối đa là tương đương hiệu quả như các
+sắp xếp dựa trên so sánh tốt nhất (và tồi hơn nếu khóa dài hơn nhiều so với `log n`).
+
+![Sắp xếp Radix](./images/radix-sort.png)
+
+## Phức tạp
+
+| Tên               | Tốt nhất | Trung bình | Tệ nhất | Bộ nhớ | Ổn định | Bình luận                       |
+| ----------------- | :------: | :--------: | :-----: | :----: | :-----: | :------------------------------ |
+| **Sắp xếp radix** |  n \* k  |   n \* k   | n \* k  | n + k  |   Có    | k - chiều dài của khóa dài nhất |
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort)
 - [YouTube](https://www.youtube.com/watch?v=XiuSW_mEn7g&index=62&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/radix-sort/README.pt-BR.md b/src/algorithms/sorting/radix-sort/README.pt-BR.md
deleted file mode 100644
index 2274440984..0000000000
--- a/src/algorithms/sorting/radix-sort/README.pt-BR.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Radix Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md)
-
-Em ciência da computação, **radix sort** é uma classificação inteira não comparativa
-algoritmo que classifica os dados com chaves inteiras agrupando as chaves pelo indivíduo
-dígitos que compartilham a mesma posição e valor significativos. Uma notação posicional
-é necessário, mas porque os números inteiros podem representar cadeias de caracteres
-(por exemplo, nomes ou datas) e números de ponto flutuante especialmente formatados, base
-sort não está limitado a inteiros.
-
-*De onde vem o nome?*
-
-Em sistemas numéricos matemáticos, a *radix* ou base é o número de dígitos únicos,
-incluindo o dígito zero, usado para representar números em um sistema de numeração posicional.
-Por exemplo, um sistema binário (usando números 0 e 1) tem uma raiz de 2 e um decimal
-sistema (usando números de 0 a 9) tem uma raiz de 10.
-
-## Eficiência
-
-O tópico da eficiência do radix sort comparado a outros algoritmos de ordenação é
-um pouco complicado e sujeito a muitos mal-entendidos. Se raiz
-sort é igualmente eficiente, menos eficiente ou mais eficiente do que o melhor
-algoritmos baseados em comparação depende dos detalhes das suposições feitas.
-A complexidade de classificação de raiz é `O(wn)` para chaves `n` que são inteiros de tamanho de palavra `w`.
-Às vezes, `w` é apresentado como uma constante, o que tornaria a classificação radix melhor
-(para `n` suficientemente grande) do que os melhores algoritmos de ordenação baseados em comparação,
-que todos realizam comparações `O(n log n)` para classificar chaves `n`. No entanto, em
-geral `w` não pode ser considerado uma constante: se todas as chaves `n` forem distintas,
-então `w` tem que ser pelo menos `log n` para que uma máquina de acesso aleatório seja capaz de
-armazená-los na memória, o que dá na melhor das hipóteses uma complexidade de tempo `O(n log n)`. Este
-parece tornar a ordenação radix no máximo tão eficiente quanto a melhor
-ordenações baseadas em comparação (e pior se as chaves forem muito mais longas que `log n`).
-
-![Radix Sort](https://www.researchgate.net/publication/291086231/figure/fig1/AS:614214452404240@1523451545568/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the.png)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Radix sort**        | n * k           | n * k               | n * k               | n + k     | Sim       | k - comprimento da chave mais longa |
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort)
-- [YouTube](https://www.youtube.com/watch?v=XiuSW_mEn7g&index=62&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [ResearchGate](https://www.researchgate.net/figure/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the_fig1_291086231)
diff --git a/src/algorithms/sorting/selection-sort/README.en-EN.md b/src/algorithms/sorting/selection-sort/README.en-EN.md
new file mode 100644
index 0000000000..5c63b77cc2
--- /dev/null
+++ b/src/algorithms/sorting/selection-sort/README.en-EN.md
@@ -0,0 +1,27 @@
+# Selection Sort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Selection sort is a sorting algorithm, specifically an
+in-place comparison sort. It has O(n2) time complexity,
+making it inefficient on large lists, and generally
+performs worse than the similar insertion sort.
+Selection sort is noted for its simplicity, and it has
+performance advantages over more complicated algorithms
+in certain situations, particularly where auxiliary
+memory is limited.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)
+
+## Complexity
+
+| Name               |     Best      |    Average    |     Worst     | Memory | Stable | Comments |
+| ------------------ | :-----------: | :-----------: | :-----------: | :----: | :----: | :------- |
+| **Selection sort** | n<sup>2</sup> | n<sup>2</sup> | n<sup>2</sup> |   1    |   No   |          |
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)
diff --git a/src/algorithms/sorting/selection-sort/README.md b/src/algorithms/sorting/selection-sort/README.md
index 005c616131..6176d38587 100644
--- a/src/algorithms/sorting/selection-sort/README.md
+++ b/src/algorithms/sorting/selection-sort/README.md
@@ -1,27 +1,27 @@
-# Selection Sort
+# Sắp xếp Chọn
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Selection sort is a sorting algorithm, specifically an 
-in-place comparison sort. It has O(n2) time complexity, 
-making it inefficient on large lists, and generally 
-performs worse than the similar insertion sort. 
-Selection sort is noted for its simplicity, and it has 
-performance advantages over more complicated algorithms 
-in certain situations, particularly where auxiliary 
-memory is limited.
+Sắp xếp chọn là một thuật toán sắp xếp, cụ thể là một
+thuật toán so sánh in-place. Nó có độ phức tạp thời gian O(n2),
+làm cho nó không hiệu quả trên các danh sách lớn, và thường
+thực hiện kém hơn so với sắp xếp chèn tương tự.
+Sắp xếp chọn nổi tiếng với sự đơn giản của nó, và nó có
+những lợi ích về hiệu suất hơn so với các thuật toán
+phức tạp hơn trong một số tình huống, đặc biệt là khi
+bộ nhớ phụ hạn chế.
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)
 
-![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)
+![Hiển thị thuật toán](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)
 
-## Complexity
+## Phức tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | No        |           |
+| Tên              |   Tốt nhất    |  Trung bình   |    Tệ nhất    | Bộ nhớ | Ổn định | Bình luận |
+| ---------------- | :-----------: | :-----------: | :-----------: | :----: | :-----: | :-------- |
+| **Sắp xếp chọn** | n<sup>2</sup> | n<sup>2</sup> | n<sup>2</sup> |   1    |  Không  |           |
 
-## References
+## Tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)
diff --git a/src/algorithms/sorting/selection-sort/README.pt-BR.md b/src/algorithms/sorting/selection-sort/README.pt-BR.md
deleted file mode 100644
index 0c45b73f61..0000000000
--- a/src/algorithms/sorting/selection-sort/README.pt-BR.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Selection Sort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md).
-
-Selection Sort é um algoritmo de ordenação, mais especificamente um algoritmo de ordenação por comparação in-place (requer uma quantidade constante de espaço de memória adicional). Tem complexidade O(n²), tornando-o ineficiente em listas grandes e, geralmente, tem desempenho inferior ao similar Insertion Sort. O Selection Sort é conhecido por sua simplicidade e tem vantagens de desempenho sobre algoritmos mais complexos em certas situações, particularmente quando a memória auxiliar é limitada.
-
-![Visualização do algoritmo](https://upload.wikimedia.org/wikipedia/commons/b/b0/Selection_sort_animation.gif)
-
-![Visualização do algoritmo](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif)
-
-## Complexidade
-
-| Nome                  | Melhor          | Médio               | Pior                | Memória   | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------:  | :----------: |
-| **Selection sort**    | n<sup>2</sup>   | n<sup>2</sup>       | n<sup>2</sup>       | 1         | Não        |              |
-
-## Referências
-
-[Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)
diff --git a/src/algorithms/sorting/shell-sort/README.en-EN.md b/src/algorithms/sorting/shell-sort/README.en-EN.md
new file mode 100644
index 0000000000..5e86b89fed
--- /dev/null
+++ b/src/algorithms/sorting/shell-sort/README.en-EN.md
@@ -0,0 +1,61 @@
+# Shellsort
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Shellsort, also known as Shell sort or Shell's method,
+is an in-place comparison sort. It can be seen as either a
+generalization of sorting by exchange (bubble sort) or sorting
+by insertion (insertion sort). The method starts by sorting
+pairs of elements far apart from each other, then progressively
+reducing the gap between elements to be compared. Starting
+with far apart elements, it can move some out-of-place
+elements into position faster than a simple nearest neighbor
+exchange
+
+![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)
+
+## How Shell Sort Works
+
+For our example and ease of understanding, we take the interval
+of `4`. Make a virtual sub-list of all values located at the
+interval of 4 positions. Here these values are
+`{35, 14}`, `{33, 19}`, `{42, 27}` and `{10, 44}`
+
+![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)
+
+We compare values in each sub-list and swap them (if necessary)
+in the original array. After this step, the new array should
+look like this
+
+![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)
+
+Then, we take interval of 2 and this gap generates two sub-lists
+
+- `{14, 27, 35, 42}`, `{19, 10, 33, 44}`
+
+![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)
+
+We compare and swap the values, if required, in the original array.
+After this step, the array should look like this
+
+![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
+
+> UPD: On the picture below there is a typo and result array is supposed to be `[14, 10, 27, 19, 35, 33, 42, 44]`.
+
+Finally, we sort the rest of the array using interval of value 1.
+Shell sort uses insertion sort to sort the array.
+
+![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)
+
+## Complexity
+
+| Name           |     Best      |         Average         |            Worst            | Memory | Stable | Comments |
+| -------------- | :-----------: | :---------------------: | :-------------------------: | :----: | :----: | :------- |
+| **Shell sort** | n&nbsp;log(n) | depends on gap sequence | n&nbsp;(log(n))<sup>2</sup> |   1    |   No   |          |
+
+## References
+
+- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
+- [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
+- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/shell-sort/README.md b/src/algorithms/sorting/shell-sort/README.md
index f93338e2eb..755444846b 100644
--- a/src/algorithms/sorting/shell-sort/README.md
+++ b/src/algorithms/sorting/shell-sort/README.md
@@ -1,60 +1,60 @@
-# Shellsort
+# Sắp xếp Shell
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Shellsort, also known as Shell sort or Shell's method, 
-is an in-place comparison sort. It can be seen as either a 
-generalization of sorting by exchange (bubble sort) or sorting 
-by insertion (insertion sort). The method starts by sorting 
-pairs of elements far apart from each other, then progressively 
-reducing the gap between elements to be compared. Starting 
-with far apart elements, it can move some out-of-place 
-elements into position faster than a simple nearest neighbor 
-exchange
+Sắp xếp Shell, còn được biết đến như Shell sort hoặc phương pháp Shell,
+là một thuật toán so sánh in-place. Nó có thể được xem như là một
+sự tổng quát hóa của sắp xếp bằng trao đổi (sắp xếp nổi bọt) hoặc sắp xếp
+bằng chèn (sắp xếp chèn). Phương pháp bắt đầu bằng cách sắp xếp
+các cặp phần tử cách xa nhau, sau đó dần dần
+giảm khoảng cách giữa các phần tử cần so sánh. Bắt đầu
+với các phần tử cách xa nhau, nó có thể di chuyển một số phần tử
+nằm ngoài vị trí của chúng vào vị trí nhanh hơn so với việc trao đổi hàng xóm đơn giản.
 
-![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)
+![Sắp xếp Shell](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)
 
-## How Shell Sort Works
+## Cách Sắp Xếp Shell Hoạt Động
 
-For our example and ease of understanding, we take the interval 
-of `4`. Make a virtual sub-list of all values located at the 
-interval of 4 positions. Here these values are 
-`{35, 14}`, `{33, 19}`, `{42, 27}` and `{10, 44}`
+Đối với ví dụ của chúng tôi và sự dễ hiểu, chúng tôi lấy khoảng
+cách là `4`. Tạo một danh sách con ảo của tất cả các giá trị nằm ở
+khoảng cách 4 vị trí. Ở đây các giá trị này là
+`{35, 14}`, `{33, 19}`, `{42, 27}` và `{10, 44}`
 
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)
+![Sắp xếp Shell](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)
 
-We compare values in each sub-list and swap them (if necessary)
-in the original array. After this step, the new array should
-look like this
+Chúng tôi so sánh các giá trị trong mỗi danh sách con và trao đổi chúng (nếu cần)
+trong mảng ban đầu. Sau bước này, mảng mới nên
+nhìn như sau
 
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)
+![Sắp xếp Shell](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)
+
+Sau đó, chúng tôi lấy khoảng cách là 2 và khoảng cách này tạo ra hai danh sách con
 
-Then, we take interval of 2 and this gap generates two sub-lists 
 - `{14, 27, 35, 42}`, `{19, 10, 33, 44}`
 
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)
+![Sắp xếp Shell](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)
 
-We compare and swap the values, if required, in the original array.
-After this step, the array should look like this
+Chúng tôi so sánh và trao đổi các giá trị, nếu cần, trong mảng ban đầu.
+Sau bước này, mảng nên nhìn như sau
 
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
+![Sắp xếp Shell](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
 
-> UPD: On the picture below there is a typo and result array is supposed to be `[14, 10, 27, 19, 35, 33, 42, 44]`.
+> Cập nhật: Trên hình ảnh dưới đây có một lỗi đánh máy và mảng kết quả cần phải là `[14, 10, 27, 19, 35, 33, 42, 44]`.
 
-Finally, we sort the rest of the array using interval of value 1. 
-Shell sort uses insertion sort to sort the array.
+Cuối cùng, chúng tôi sắp xếp phần còn lại của mảng sử dụng khoảng cách có giá trị 1.
+Sắp xếp Shell sử dụng sắp xếp chèn để sắp xếp mảng.
 
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)
+![Sắp xếp Shell](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)
 
-## Complexity
+## Phức Tạp
 
-| Name                  | Best            | Average             | Worst               | Memory    | Stable    | Comments  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | No         |           |
+| Tên               |   Tốt nhất    |           Trung bình            |           Tệ nhất           | Bộ nhớ | Ổn định | Bình luận |
+| ----------------- | :-----------: | :-----------------------------: | :-------------------------: | :----: | :-----: | :-------- |
+| **Sắp xếp Shell** | n&nbsp;log(n) | phụ thuộc vào chuỗi khoảng cách | n&nbsp;(log(n))<sup>2</sup> |   1    |  Không  |           |
 
-## References
+## Tham Khảo
 
 - [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
 - [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
-- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [YouTube bởi Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/sorting/shell-sort/README.pt-BR.md b/src/algorithms/sorting/shell-sort/README.pt-BR.md
deleted file mode 100644
index 14de1a517e..0000000000
--- a/src/algorithms/sorting/shell-sort/README.pt-BR.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Shellsort
-
-_Leia isso em outros idiomas:_
-[_English_](README.md).
-
-Shellsort, também conhecido como Shell sort ou método de Shell,
-é uma classificação de comparação in-loco. Pode ser visto tanto como um
-generalização da ordenação por troca (bubble sort) ou ordenação
-por inserção (ordenação por inserção). O método começa classificando
-pares de elementos distantes um do outro, então progressivamente
-reduzindo a distância entre os elementos a serem comparados. Iniciando
-com elementos distantes, pode mover alguns fora do lugar
-elementos em posição mais rápido do que um simples vizinho mais próximo
-intercâmbio
-
-![Shellsort](https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif)
-
-## Como o Shellsort funciona?
-
-Para nosso exemplo e facilidade de compreensão, tomamos o intervalo
-de `4`. Faça uma sub-lista virtual de todos os valores localizados no
-intervalo de 4 posições. Aqui esses valores são
-`{35, 14}`, `{33, 19}`, `{42, 27}` e `{10, 44}`
-
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_4.jpg)
-
-Comparamos valores em cada sublista e os trocamos (se necessário)
-na matriz original. Após esta etapa, o novo array deve
-parece com isso
-
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_1.jpg)
-
-Então, pegamos o intervalo de 2 e essa lacuna gera duas sub-listas
-- `{14, 27, 35, 42}`, `{19, 10, 33, 44}`
-
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_gap_2.jpg)
-
-Comparamos e trocamos os valores, se necessário, no array original.
-Após esta etapa, a matriz deve ficar assim
-
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
-
-> OBS: Na imagem abaixo há um erro de digitação e a matriz de resultados deve ser `[14, 10, 27, 19, 35, 33, 42, 44]`.
-
-Finalmente, ordenamos o resto do array usando o intervalo de valor 1.
-A classificação de shell usa a classificação por inserção para classificar a matriz.
-
-![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg)
-
-## Complexidade
-
-| Nome                  | Melhor            | Média             | Pior               | Memória    | Estável    | Comentários  |
-| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- |
-| **Shell sort**        | n&nbsp;log(n)   | depends on gap sequence   | n&nbsp;(log(n))<sup>2</sup>  | 1         | Não         |           |
-
-## Referências
-
-- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
-- [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
-- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/statistics/weighted-random/README.en-EN.md b/src/algorithms/statistics/weighted-random/README.en-EN.md
new file mode 100644
index 0000000000..5e540c48fc
--- /dev/null
+++ b/src/algorithms/statistics/weighted-random/README.en-EN.md
@@ -0,0 +1,162 @@
+# Weighted Random
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+![Weighted Random](images/cover.png)
+
+## What is "Weighted Random"
+
+Let's say you have a list of **items**. Item could be anything. For example, we may have a list of fruits and vegetables that you like to eat: `[ '🍌', '🍎', '🥕' ]`.
+
+The list of **weights** represent the weight (or probability, or importance) of each item. Weights are numbers. For example, the weights like `[3, 7, 1]` would say that:
+
+- you would like to eat `🍎 apples` more often (`7` out of `3 + 7 + 1 = 11` times),
+- then you would like to eat `bananas 🍌` less often (only `3` out of `11` times),
+- and the `carrots 🥕` you really don't like (want to eat it only `1` out of `11` times).
+
+> If we speak in terms of probabilities than the weights list might be an array of floats that sum up to `1` (i.e. `[0.1, 0.5, 0.2, 0.2]`).
+
+The **Weighted Random** in this case will be the function that will randomly return you the item from the list, and it will take each item's weight into account, so that items with the higher weight will be picked more often.
+
+Example of the function interface:
+
+```javascript
+const items = ['🍌', '🍎', '🥕'];
+const weights = [3, 7, 1];
+
+function weightedRandom(items, weights) {
+  // implementation goes here ...
+}
+
+const nextSnackToEat = weightedRandom(items, weights); // Could be '🍎'
+```
+
+## Applications of Weighted Random
+
+- In [Genetic Algorithm](https://en.wikipedia.org/wiki/Genetic_algorithm) the weighted random is used during the "Selection" phase, when we need to select the fittest/strongest individuums based on their fitness score for mating and for producing the next stronger generation. You may find an **example** in the [Self-Parking Car in 500 Lines of Code](https://trekhleb.dev/blog/2021/self-parking-car-evolution/) article.
+- In [Recurrent Neural Networks (RNN)](https://en.wikipedia.org/wiki/Recurrent_neural_network) when trying to decide what letter to choose next (to form the sentence) based on the next letter probability. You may find an **example** in the [Recipe Generation using Recurrent Neural Network (RNN)](https://nbviewer.org/github/trekhleb/machine-learning-experiments/blob/master/experiments/recipe_generation_rnn/recipe_generation_rnn.ipynb) Jupyter notebook.
+- In [Nginx Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) to send HTTP requests more often to the servers with the higher weights.
+- And more...
+
+## The Algorithm
+
+The **straightforward approach** would be to:
+
+1. Repeat each item in the list according to its weight.
+2. Pick the random item from the list.
+
+For example in our case with fruits and vegetables we could generate the following list of size `3 + 7 + 1 = 11`:
+
+```javascript
+const items = ['🍌', '🍎', '🥕'];
+const weights = [3, 7, 1];
+
+// Repeating the items based on weights.
+const weightedItems = [
+  '🍌',
+  '🍌',
+  '🍌',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🥕',
+];
+
+// And now just pick the random item from weightedItems array.
+```
+
+However, as you may see, this approach may require a lot of memory, in case if we have a lot of items to repeat in `weightedItems` list. Think of it as if you would need to repeat a string like `"some-random-string"` (`18` bytes) a ten million times. You will need to allocate around `180Mb` of additional memory space just for this array.
+
+The **more efficient approach** would be to:
+
+1. Prepare the list of cumulative weights for each item (i.e. the `cumulativeWeights` list which will have the same number of elements as the original `weights` list). In our case it will look like this: `cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11]`
+2. Generate the random number `randomNumber` from `0` to the highest cumulative weight value. In our case the random number will be in a range of `[0..11]`. Let's say that we have `randomNumber = 8`.
+3. Go through the `cumulativeWeights` list from left to right and pick the first element which is higher or equal to the `randomNumber`. The index of such element we will use to pick the item from the `items` array.
+
+The idea behind this approach is that the higher weights will "occupy" more numeric space. Therefore, there is a higher chance that the random number will fall into the "higher weight numeric bucket".
+
+```javascript
+const weights = [3, 7, 1];
+const cumulativeWeights = [3, 10, 11];
+
+// In a pseudo-representation we may think about the cumulativeWeights array like this.
+const pseudoCumulativeWeights = [
+  1,
+  2,
+  3, // <-- [3] numbers
+  4,
+  5,
+  6,
+  7,
+  8,
+  9,
+  10, // <-- [7] numbers
+  11, // <-- [1] number
+];
+```
+
+Here is an example of how the `weightedRandom` function might be implemented:
+
+```javascript
+/**
+ * Picks the random item based on its weight.
+ * The items with higher weight will be picked more often (with a higher probability).
+ *
+ * For example:
+ * - items = ['banana', 'orange', 'apple']
+ * - weights = [0, 0.2, 0.8]
+ * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
+ * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)
+ *
+ * @param {any[]} items
+ * @param {number[]} weights
+ * @returns {{item: any, index: number}}
+ */
+export default function weightedRandom(items, weights) {
+  if (items.length !== weights.length) {
+    throw new Error('Items and weights must be of the same size');
+  }
+
+  if (!items.length) {
+    throw new Error('Items must not be empty');
+  }
+
+  // Preparing the cumulative weights array.
+  // For example:
+  // - weights = [1, 4, 3]
+  // - cumulativeWeights = [1, 5, 8]
+  const cumulativeWeights = [];
+  for (let i = 0; i < weights.length; i += 1) {
+    cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);
+  }
+
+  // Getting the random number in a range of [0...sum(weights)]
+  // For example:
+  // - weights = [1, 4, 3]
+  // - maxCumulativeWeight = 8
+  // - range for the random number is [0...8]
+  const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];
+  const randomNumber = maxCumulativeWeight * Math.random();
+
+  // Picking the random item based on its weight.
+  // The items with higher weight will be picked more often.
+  for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
+    if (cumulativeWeights[itemIndex] >= randomNumber) {
+      return {
+        item: items[itemIndex],
+        index: itemIndex,
+      };
+    }
+  }
+}
+```
+
+## Implementation
+
+- Check the [weightedRandom.js](weightedRandom.js) file for the implementation of the `weightedRandom()` function.
+- Check the [weightedRandom.test.js](__test__/weightedRandom.test.js) file for the tests-cases.
diff --git a/src/algorithms/statistics/weighted-random/README.md b/src/algorithms/statistics/weighted-random/README.md
index 16e459704b..360f2a34f5 100644
--- a/src/algorithms/statistics/weighted-random/README.md
+++ b/src/algorithms/statistics/weighted-random/README.md
@@ -1,98 +1,117 @@
-# Weighted Random
+# Ngẫu nhiên có trọng số
 
-![Weighted Random](images/cover.png)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## What is "Weighted Random"
+![Ngẫu nhiên có trọng số](images/cover.png)
 
-Let's say you have a list of **items**. Item could be anything. For example, we may have a list of fruits and vegetables that you like to eat: `[ '🍌', '🍎', '🥕' ]`.
+## Khái niệm "Ngẫu nhiên có trọng số"
 
-The list of **weights** represent the weight (or probability, or importance) of each item. Weights are numbers. For example, the weights like `[3, 7, 1]` would say that:
+Hãy tưởng tượng bạn có một danh sách các **mục**. Mục có thể là bất cứ thứ gì. Ví dụ, chúng ta có thể có một danh sách các loại hoa quả và rau mà bạn thích ăn: `[ '🍌', '🍎', '🥕' ]`.
 
-- you would like to eat `🍎 apples` more often (`7` out of `3 + 7 + 1 = 11` times),
-- then you would like to eat `bananas 🍌` less often (only `3` out of `11` times),
-- and the `carrots 🥕` you really don't like (want to eat it only `1` out of `11` times).
+Danh sách **trọng số** đại diện cho trọng số (hoặc xác suất, hoặc mức độ quan trọng) của mỗi mục. Trọng số là số. Ví dụ, các trọng số như `[3, 7, 1]` sẽ nói rằng:
 
-> If we speak in terms of probabilities than the weights list might be an array of floats that sum up to `1` (i.e. `[0.1, 0.5, 0.2, 0.2]`).
+- bạn muốn ăn `🍎 táo` thường xuyên hơn (`7` trên tổng số `3 + 7 + 1 = 11` lần),
+- sau đó bạn muốn ăn `chuối 🍌` ít hơn (chỉ `3` trên `11` lần),
+- và bạn thực sự không thích `cà rốt 🥕` (chỉ muốn ăn nó `1` trong `11` lần).
 
-The **Weighted Random** in this case will be the function that will randomly return you the item from the list, and it will take each item's weight into account, so that items with the higher weight will be picked more often.
+> Nếu nói về xác suất thì danh sách trọng số có thể là một mảng các số thập phân có tổng bằng `1` (ví dụ: `[0.1, 0.5, 0.2, 0.2]`).
 
-Example of the function interface:
+**Ngẫu nhiên có trọng số** trong trường hợp này sẽ là hàm sẽ ngẫu nhiên trả về một mục từ danh sách, và nó sẽ tính đến trọng số của mỗi mục, vì vậy các mục có trọng số cao sẽ được chọn thường xuyên hơn.
+
+Ví dụ về giao diện hàm:
 
 ```javascript
-const items =   [ '🍌', '🍎', '🥕' ];
-const weights = [  3,    7,    1  ];
+const items = ['🍌', '🍎', '🥕'];
+const weights = [3, 7, 1];
 
 function weightedRandom(items, weights) {
   // implementation goes here ...
 }
 
-const nextSnackToEat = weightedRandom(items, weights); // Could be '🍎'
+const nextSnackToEat = weightedRandom(items, weights); // Có thể là '🍎'
 ```
 
-## Applications of Weighted Random
+## Ứng dụng của Ngẫu nhiên có trọng số
 
-- In [Genetic Algorithm](https://en.wikipedia.org/wiki/Genetic_algorithm) the weighted random is used during the "Selection" phase, when we need to select the fittest/strongest individuums based on their fitness score for mating and for producing the next stronger generation. You may find an **example** in the [Self-Parking Car in 500 Lines of Code](https://trekhleb.dev/blog/2021/self-parking-car-evolution/) article.
-- In [Recurrent Neural Networks (RNN)](https://en.wikipedia.org/wiki/Recurrent_neural_network) when trying to decide what letter to choose next (to form the sentence) based on the next letter probability. You may find an **example** in the [Recipe Generation using Recurrent Neural Network (RNN)](https://nbviewer.org/github/trekhleb/machine-learning-experiments/blob/master/experiments/recipe_generation_rnn/recipe_generation_rnn.ipynb) Jupyter notebook.
-- In [Nginx Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) to send HTTP requests more often to the servers with the higher weights.
-- And more...
+- Trong [Giải thuật di truyền](https://en.wikipedia.org/wiki/Genetic_algorithm) ngẫu nhiên có trọng số được sử dụng trong giai đoạn "Lựa chọn", khi chúng ta cần lựa chọn các cá thể mạnh mẽ/dẻo dai dựa trên điểm thích hợp của họ để giao phối và tạo ra thế hệ tiếp theo mạnh mẽ hơn. Bạn có thể tìm thấy một **ví dụ** trong bài viết [Xe tự đỗ trong 500 dòng mã](https://trekhleb.dev/blog/2021/self-parking-car-evolution/).
+- Trong [Mạng nơ-ron tái phát (RNN)](https://en.wikipedia.org/wiki/Recurrent_neural_network) khi cố gắng quyết định chọn chữ cái tiếp theo (để tạo thành câu) dựa trên xác suất chọn chữ cái tiếp theo. Bạn có thể tìm thấy một **ví dụ** trong Jupyter notebook [Tạo ra công thức bằng Mạng nơ-ron tái phát (RNN)](https://nbviewer.org/github/trekhleb/machine-learning-experiments/blob/master/experiments/recipe_generation_rnn/recipe_generation_rnn.ipynb).
+- Trong [Cân bằng tải Nginx](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) để gửi các yêu cầu HTTP thường xuyên hơn đến các máy chủ có trọng số cao hơn.
+- Và nhiều hơn nữa...
 
-## The Algorithm
+## Thuật toán
 
-The **straightforward approach** would be to:
+**Cách tiếp cận trực tiếp** sẽ là:
 
-1. Repeat each item in the list according to its weight.
-2. Pick the random item from the list.
+1. Lặp lại mỗi mục trong danh sách theo trọng số của nó.
+2. Chọn ngẫu nhiên một mục từ danh sách.
 
-For example in our case with fruits and vegetables we could generate the following list of size `3 + 7 + 1 = 11`:
+Ví dụ trong trường hợp của chúng ta với hoa quả và rau chúng ta có thể tạo ra danh sách sau với kích thước `3 + 7 + 1 = 11`:
 
 ```javascript
-const items =   [ '🍌', '🍎', '🥕' ];
-const weights = [  3,    7,    1  ];
+const items = ['🍌', '🍎', '🥕'];
+const weights = [3, 7, 1];
 
-// Repeating the items based on weights.
+// Lặp lại các mục dựa trên trọng số.
 const weightedItems = [
-  '🍌', '🍌', '🍌',
-  '🍎', '🍎', '🍎', '🍎', '🍎', '🍎', '🍎',
+  '🍌',
+  '🍌',
+  '🍌',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
+  '🍎',
   '🥕',
 ];
 
-// And now just pick the random item from weightedItems array.
+// Và bây giờ chỉ cần chọn một mục ngẫu nhiên từ mảng weightedItems.
 ```
 
-However, as you may see, this approach may require a lot of memory, in case if we have a lot of items to repeat in `weightedItems` list. Think of it as if you would need to repeat a string like `"some-random-string"` (`18` bytes) a ten million times. You will need to allocate around `180Mb` of additional memory space just for this array.
+Tuy nhiên, như bạn có thể thấy, cách tiếp cận này có thể yêu cầu rất nhiều bộ nhớ, trong trường hợp nếu chúng ta có nhiều mục cần lặp lại trong danh sách `weightedItems`. Hãy tưởng tượng nếu bạn cần lặp lại một chuỗi như `"một-đoạn-chuỗi-ngẫu-nhiên"` (`18` byte) mười triệu lần. Bạn sẽ cần cấp khoảng `180Mb` bộ nhớ phụ thêm chỉ để mảng này.
 
-The **more efficient approach** would be to:
+**Cách tiếp cận hiệu quả hơn** sẽ là:
 
-1. Prepare the list of cumulative weights for each item (i.e. the `cumulativeWeights` list which will have the same number of elements as the original `weights` list). In our case it will look like this: `cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11]`
-2. Generate the random number `randomNumber` from `0` to the highest cumulative weight value. In our case the random number will be in a range of `[0..11]`. Let's say that we have `randomNumber = 8`.
-3. Go through the `cumulativeWeights` list from left to right and pick the first element which is higher or equal to the `randomNumber`. The index of such element we will use to pick the item from the `items` array.
+1. Chuẩn bị danh sách trọng số tích lũy cho mỗi mục (tức là danh sách `cumulativeWeights` sẽ có cùng số phần tử như danh sách `weights` ban đầu). Trong trường hợp của chúng ta, nó sẽ trông như thế này: `cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11]`.
+2. Tạo số ngẫu nhiên `randomNumber` trong khoảng từ `0` đến giá trị trọng số tích lũy cao nhất. Trong trường hợp của chúng ta, số ngẫu nhiên sẽ nằm trong khoảng `[0..11]`. Hãy giả sử rằng chúng ta có `randomNumber = 8`.
+3. Duyệt qua danh sách `cumulativeWeights` từ trái sang phải và chọn phần tử đầu tiên mà lớn hơn hoặc bằng `randomNumber`. Chỉ số của phần tử như vậy chúng ta sẽ sử dụng để chọn mục từ mảng `items`.
 
-The idea behind this approach is that the higher weights will "occupy" more numeric space. Therefore, there is a higher chance that the random number will fall into the "higher weight numeric bucket".
+Ý tưởng đằng sau cách tiếp cận này là các trọng số cao sẽ "chiếm" nhiều không gian số học hơn. Do đó, có khả năng cao rằng số ngẫu nhiên sẽ rơi vào "hộp số cao hơn".
 
 ```javascript
-const weights =           [3, 7,  1 ];
+const weights = [3, 7, 1];
 const cumulativeWeights = [3, 10, 11];
 
-// In a pseudo-representation we may think about the cumulativeWeights array like this.
+// Trong một biểu diễn giả định chúng ta có thể nghĩ về mảng cumulativeWeights như sau.
 const pseudoCumulativeWeights = [
-  1, 2, 3,               // <-- [3] numbers
-  4, 5, 6, 7, 8, 9, 10,  // <-- [7] numbers
-  11,                    // <-- [1] number
+  1,
+  2,
+  3, // <-- [3] số
+  4,
+  5,
+  6,
+  7,
+  8,
+  9,
+  10, // <-- [7] số
+  11, // <-- [1] số
 ];
 ```
 
-Here is an example of how the `weightedRandom` function might be implemented:
+Dưới đây là một ví dụ về cách hàm `weightedRandom` có thể được triển khai:
 
 ```javascript
 /**
- * Picks the random item based on its weight.
- * The items with higher weight will be picked more often (with a higher probability).
+ * Chọn mục ngẫu nhiên dựa trên trọng số của nó.
+ * Các mục có trọng số cao sẽ được chọn thường xuyên hơn (với xác suất cao hơn).
  *
- * For example:
- * - items = ['banana', 'orange', 'apple']
+ * Ví dụ:
+ * - items = ['chuối', 'cam', 'táo']
  * - weights = [0, 0.2, 0.8]
- * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
- * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)
+ * - weightedRandom(items, weights) trong 80% trường hợp sẽ trả về 'táo', trong 20% trường hợp sẽ trả về
+ * 'cam' và nó sẽ không bao giờ trả về 'chuối' (vì xác suất chọn chuối là 0%)
  *
  * @param {any[]} items
  * @param {number[]} weights
@@ -107,8 +126,8 @@ export default function weightedRandom(items, weights) {
     throw new Error('Items must not be empty');
   }
 
-  // Preparing the cumulative weights array.
-  // For example:
+  // Chuẩn bị mảng trọng số tích lũy.
+  // Ví dụ:
   // - weights = [1, 4, 3]
   // - cumulativeWeights = [1, 5, 8]
   const cumulativeWeights = [];
@@ -116,16 +135,16 @@ export default function weightedRandom(items, weights) {
     cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);
   }
 
-  // Getting the random number in a range of [0...sum(weights)]
-  // For example:
+  // Lấy số ngẫu nhiên trong khoảng [0...tổng(weights)]
+  // Ví dụ:
   // - weights = [1, 4, 3]
   // - maxCumulativeWeight = 8
-  // - range for the random number is [0...8]
+  // - phạm vi cho số ngẫu nhiên là [0...8]
   const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];
   const randomNumber = maxCumulativeWeight * Math.random();
 
-  // Picking the random item based on its weight.
-  // The items with higher weight will be picked more often.
+  // Chọn mục ngẫu nhiên dựa trên trọng số của nó.
+  // Các mục có trọng số cao sẽ được chọn thường xuyên.
   for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
     if (cumulativeWeights[itemIndex] >= randomNumber) {
       return {
@@ -137,7 +156,8 @@ export default function weightedRandom(items, weights) {
 }
 ```
 
-## Implementation
+## Triển khai
+
+- Kiểm tra tệp [weightedRandom.js](weightedRandom.js) để xem cách triển khai của hàm `weightedRandom()`.
 
-- Check the [weightedRandom.js](weightedRandom.js) file for the implementation of the `weightedRandom()` function.
-- Check the [weightedRandom.test.js](__test__/weightedRandom.test.js) file for the tests-cases.
+- Kiểm tra tệp [weightedRandom.test.js](__test__/weightedRandom.test.js) để xem các trường hợp kiểm tra.
diff --git a/src/algorithms/string/hamming-distance/README.en-EN.md b/src/algorithms/string/hamming-distance/README.en-EN.md
new file mode 100644
index 0000000000..f1b00eda59
--- /dev/null
+++ b/src/algorithms/string/hamming-distance/README.en-EN.md
@@ -0,0 +1,26 @@
+# Hamming Distance
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+the Hamming distance between two strings of equal length is the
+number of positions at which the corresponding symbols are
+different. In other words, it measures the minimum number of
+substitutions required to change one string into the other, or
+the minimum number of errors that could have transformed one
+string into the other. In a more general context, the Hamming
+distance is one of several string metrics for measuring the
+edit distance between two sequences.
+
+## Examples
+
+The Hamming distance between:
+
+- "ka**rol**in" and "ka**thr**in" is **3**.
+- "k**a**r**ol**in" and "k**e**r**st**in" is **3**.
+- 10**1**1**1**01 and 10**0**1**0**01 is **2**.
+- 2**17**3**8**96 and 2**23**3**7**96 is **3**.
+
+## References
+
+[Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance)
diff --git a/src/algorithms/string/hamming-distance/README.md b/src/algorithms/string/hamming-distance/README.md
index 516a8e0372..8ebd821328 100644
--- a/src/algorithms/string/hamming-distance/README.md
+++ b/src/algorithms/string/hamming-distance/README.md
@@ -1,23 +1,19 @@
-# Hamming Distance
+# Khoảng cách Hamming
 
-the Hamming distance between two strings of equal length is the 
-number of positions at which the corresponding symbols are 
-different. In other words, it measures the minimum number of
-substitutions required to change one string into the other, or 
-the minimum number of errors that could have transformed one 
-string into the other. In a more general context, the Hamming 
-distance is one of several string metrics for measuring the 
-edit distance between two sequences.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Examples
+Khoảng cách Hamming giữa hai chuỗi có cùng độ dài là số lượng vị trí mà các ký tự tương ứng khác nhau. Nó đo lường số lượng thay thế tối thiểu cần thiết để biến đổi một chuỗi thành chuỗi khác, hoặc số lượng lỗi tối thiểu có thể đã biến đổi một chuỗi thành chuỗi khác. Trong ngữ cảnh tổng quát hơn, khoảng cách Hamming là một trong các phương pháp đo lường khoảng cách chỉnh sửa giữa hai chuỗi.
 
-The Hamming distance between:
+## Ví dụ
 
-- "ka**rol**in" and "ka**thr**in" is **3**.
-- "k**a**r**ol**in" and "k**e**r**st**in" is **3**.
-- 10**1**1**1**01 and 10**0**1**0**01 is **2**.
-- 2**17**3**8**96 and 2**23**3**7**96 is **3**.
+Khoảng cách Hamming giữa:
 
-## References
+- "ka**rol**in" và "ka**thr**in" là **3**.
+- "k**a**r**ol**in" và "k**e**r**st**in" là **3**.
+- 10**1**1**1**01 và 10**0**1**0**01 là **2**.
+- 2**17**3**8**96 và 2**23**3**7**96 là **3**.
+
+## Tham khảo
 
 [Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance)
diff --git a/src/algorithms/string/knuth-morris-pratt/README.en-EN.md b/src/algorithms/string/knuth-morris-pratt/README.en-EN.md
new file mode 100644
index 0000000000..49051f2863
--- /dev/null
+++ b/src/algorithms/string/knuth-morris-pratt/README.en-EN.md
@@ -0,0 +1,22 @@
+# Knuth–Morris–Pratt Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Knuth–Morris–Pratt string searching algorithm (or
+KMP algorithm) searches for occurrences of a "word" `W`
+within a main "text string" `T` by employing the
+observation that when a mismatch occurs, the word itself
+embodies sufficient information to determine where the
+next match could begin, thus bypassing re-examination
+of previously matched characters.
+
+## Complexity
+
+- **Time:** `O(|W| + |T|)` (much faster comparing to trivial `O(|W| * |T|)`)
+- **Space:** `O(|W|)`
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)
+- [YouTube](https://www.youtube.com/watch?v=GTJr8OvyEVQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/knuth-morris-pratt/README.md b/src/algorithms/string/knuth-morris-pratt/README.md
index 907ff60c06..dd0bceab8f 100644
--- a/src/algorithms/string/knuth-morris-pratt/README.md
+++ b/src/algorithms/string/knuth-morris-pratt/README.md
@@ -1,19 +1,16 @@
-# Knuth–Morris–Pratt Algorithm
+# Thuật toán Knuth–Morris–Pratt
 
-The Knuth–Morris–Pratt string searching algorithm (or 
-KMP algorithm) searches for occurrences of a "word" `W` 
-within a main "text string" `T` by employing the 
-observation that when a mismatch occurs, the word itself 
-embodies sufficient information to determine where the 
-next match could begin, thus bypassing re-examination 
-of previously matched characters.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Complexity
+Thuật toán tìm kiếm chuỗi Knuth–Morris–Pratt (hoặc thuật toán KMP) tìm kiếm các lần xuất hiện của một "từ" `W` trong một "chuỗi văn bản chính" `T` bằng cách sử dụng quan sát rằng khi một không khớp xảy ra, từ chính nó cung cấp đủ thông tin để xác định nơi mà sự khớp tiếp theo có thể bắt đầu, qua đó bỏ qua việc kiểm tra lại các ký tự đã khớp trước đó.
 
-- **Time:** `O(|W| + |T|)` (much faster comparing to trivial `O(|W| * |T|)`)
-- **Space:** `O(|W|)`
+## Độ phức tạp
 
-## References
+- **Thời gian:** `O(|W| + |T|)` (nhanh hơn nhiều so với phương pháp trực tiếp `O(|W| * |T|)`)
+- **Không gian:** `O(|W|)`
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm)
 - [YouTube](https://www.youtube.com/watch?v=GTJr8OvyEVQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/levenshtein-distance/README.en-EN.md b/src/algorithms/string/levenshtein-distance/README.en-EN.md
new file mode 100644
index 0000000000..9b55de10a2
--- /dev/null
+++ b/src/algorithms/string/levenshtein-distance/README.en-EN.md
@@ -0,0 +1,118 @@
+# Levenshtein Distance
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Levenshtein distance is a string metric for measuring the
+difference between two sequences. Informally, the Levenshtein
+distance between two words is the minimum number of
+single-character edits (insertions, deletions or substitutions)
+required to change one word into the other.
+
+## Definition
+
+Mathematically, the Levenshtein distance between two strings
+`a` and `b` (of length `|a|` and `|b|` respectively) is given by
+![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/4cf357d8f2135035207088d2c7b890fb4b64e410)
+where
+
+![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/f0a48ecfc9852c042382fdc33c19e11a16948e85)
+
+where
+![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/52512ede08444b13838c570ba4a3fc71d54dbce9)
+is the indicator function equal to `0` when
+![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/231fda9ee578f0328c5ca28088d01928bb0aaaec)
+and equal to 1 otherwise, and
+![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/bdc0315678caad28648aafedb6ebafb16bd1655c)
+is the distance between the first `i` characters of `a` and the first
+`j` characters of `b`.
+
+Note that the first element in the minimum corresponds to
+deletion (from `a` to `b`), the second to insertion and
+the third to match or mismatch, depending on whether the
+respective symbols are the same.
+
+## Example
+
+For example, the Levenshtein distance between `kitten` and
+`sitting` is `3`, since the following three edits change one
+into the other, and there is no way to do it with fewer than
+three edits:
+
+1. **k**itten → **s**itten (substitution of "s" for "k")
+2. sitt**e**n → sitt**i**n (substitution of "i" for "e")
+3. sittin → sittin**g** (insertion of "g" at the end).
+
+## Applications
+
+This has a wide range of applications, for instance, spell checkers, correction
+systems for optical character recognition, fuzzy string searching, and software
+to assist natural language translation based on translation memory.
+
+## Dynamic Programming Approach Explanation
+
+Let’s take a simple example of finding minimum edit distance between
+strings `ME` and `MY`. Intuitively you already know that minimum edit distance
+here is `1` operation, which is replacing `E` with `Y`. But
+let’s try to formalize it in a form of the algorithm in order to be able to
+do more complex examples like transforming `Saturday` into `Sunday`.
+
+To apply the mathematical formula mentioned above to `ME → MY` transformation
+we need to know minimum edit distances of `ME → M`, `M → MY` and `M → M` transformations
+in prior. Then we will need to pick the minimum one and add _one_ operation to
+transform last letters `E → Y`. So minimum edit distance of `ME → MY` transformation
+is being calculated based on three previously possible transformations.
+
+To explain this further let’s draw the following matrix:
+
+![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*aTunSUoy0BJyYBVn4tWGrA.png)
+
+- Cell `(0:1)` contains red number 1. It means that we need 1 operation to
+  transform `M` to an empty string. And it is by deleting `M`. This is why this number is red.
+- Cell `(0:2)` contains red number 2. It means that we need 2 operations
+  to transform `ME` to an empty string. And it is by deleting `E` and `M`.
+- Cell `(1:0)` contains green number 1. It means that we need 1 operation
+  to transform an empty string to `M`. And it is by inserting `M`. This is why this number is green.
+- Cell `(2:0)` contains green number 2. It means that we need 2 operations
+  to transform an empty string to `MY`. And it is by inserting `Y` and `M`.
+- Cell `(1:1)` contains number 0. It means that it costs nothing
+  to transform `M` into `M`.
+- Cell `(1:2)` contains red number 1. It means that we need 1 operation
+  to transform `ME` to `M`. And it is by deleting `E`.
+- And so on...
+
+This looks easy for such small matrix as ours (it is only `3x3`). But here you
+may find basic concepts that may be applied to calculate all those numbers for
+bigger matrices (let’s say a `9x7` matrix for `Saturday → Sunday` transformation).
+
+According to the formula you only need three adjacent cells `(i-1:j)`, `(i-1:j-1)`, and `(i:j-1)` to
+calculate the number for current cell `(i:j)`. All we need to do is to find the
+minimum of those three cells and then add `1` in case if we have different
+letters in `i`'s row and `j`'s column.
+
+You may clearly see the recursive nature of the problem.
+
+![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*w8UB4DSvBnAK6mBXRGQDjw.png)
+
+Let's draw a decision graph for this problem.
+
+![Minimum Edit Distance Decision Graph](https://cdn-images-1.medium.com/max/1600/1*8jD0qvr5B9PwRFM_9z7q9A.png)
+
+You may see a number of overlapping sub-problems on the picture that are marked
+with red. Also there is no way to reduce the number of operations and make it
+less than a minimum of those three adjacent cells from the formula.
+
+Also you may notice that each cell number in the matrix is being calculated
+based on previous ones. Thus the tabulation technique (filling the cache in
+bottom-up direction) is being applied here.
+
+Applying this principle further we may solve more complicated cases like
+with `Saturday → Sunday` transformation.
+
+![Levenshtein distance](https://cdn-images-1.medium.com/max/2600/1*497gMaFErzJpCXG7kS_7dw.png)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Levenshtein_distance)
+- [YouTube](https://www.youtube.com/watch?v=We3YDTzNXEk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [ITNext](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe)
diff --git a/src/algorithms/string/levenshtein-distance/README.md b/src/algorithms/string/levenshtein-distance/README.md
index 8876d6791c..0e54bddf27 100644
--- a/src/algorithms/string/levenshtein-distance/README.md
+++ b/src/algorithms/string/levenshtein-distance/README.md
@@ -1,114 +1,82 @@
-# Levenshtein Distance
+# Khoảng cách Levenshtein
 
-The Levenshtein distance is a string metric for measuring the 
-difference between two sequences. Informally, the Levenshtein 
-distance between two words is the minimum number of 
-single-character edits (insertions, deletions or substitutions) 
-required to change one word into the other.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Definition
+Khoảng cách Levenshtein là một chỉ số chuỗi để đo sự khác biệt giữa hai chuỗi. Một cách không chính thức, khoảng cách Levenshtein giữa hai từ là số lượng tối thiểu các chỉnh sửa đơn vị (chèn, xóa hoặc thay thế một ký tự) cần thiết để biến đổi một từ thành từ kia.
 
-Mathematically, the Levenshtein distance between two strings
-`a` and `b` (of length `|a|` and `|b|` respectively) is given by
+## Định nghĩa
+
+Toán học, khoảng cách Levenshtein giữa hai chuỗi `a` và `b` (có độ dài `|a|` và `|b|` tương ứng) được cho bởi
 ![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/4cf357d8f2135035207088d2c7b890fb4b64e410)
-where
+trong đó
 
 ![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/f0a48ecfc9852c042382fdc33c19e11a16948e85)
 
-where 
+với
 ![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/52512ede08444b13838c570ba4a3fc71d54dbce9)
-is the indicator function equal to `0` when
+là hàm chỉ số bằng `0` khi
 ![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/231fda9ee578f0328c5ca28088d01928bb0aaaec)
-and equal to 1 otherwise, and
+và bằng 1 trong trường hợp ngược lại, và
 ![Levenshtein](https://wikimedia.org/api/rest_v1/media/math/render/svg/bdc0315678caad28648aafedb6ebafb16bd1655c)
-is the distance between the first `i` characters of `a` and the first 
-`j` characters of `b`.
-
-Note that the first element in the minimum corresponds to 
-deletion (from `a` to `b`), the second to insertion and 
-the third to match or mismatch, depending on whether the 
-respective symbols are the same.
-
-## Example
+là khoảng cách giữa `i` ký tự đầu tiên của `a` và `j` ký tự đầu tiên của `b`.
 
-For example, the Levenshtein distance between `kitten` and 
-`sitting` is `3`, since the following three edits change one 
-into the other, and there is no way to do it with fewer than 
-three edits:
+Lưu ý rằng phần tử đầu tiên trong giá trị tối thiểu tương ứng với việc xóa (từ `a` thành `b`), phần thứ hai là chèn và phần thứ ba là khớp hoặc không khớp, phụ thuộc vào việc các ký tự tương ứng có giống nhau không.
 
-1. **k**itten → **s**itten (substitution of "s" for "k")
-2. sitt**e**n → sitt**i**n (substitution of "i" for "e")
-3. sittin → sittin**g** (insertion of "g" at the end).
+## Ví dụ
 
-## Applications
+Ví dụ, khoảng cách Levenshtein giữa `kitten` và `sitting` là `3`, vì ba chỉnh sửa sau đây biến đổi một thành cái kia, và không có cách nào làm điều này ít hơn ba chỉnh sửa:
 
-This has a wide range of applications, for instance, spell checkers, correction 
-systems for optical character recognition, fuzzy string searching, and software 
-to assist natural language translation based on translation memory.
+1. **k**itten → **s**itten (thay thế "s" bằng "k")
+2. sitt**e**n → sitt**i**n (thay thế "i" bằng "e")
+3. sittin → sittin**g** (chèn "g" vào cuối).
 
-## Dynamic Programming Approach Explanation
+## Ứng dụng
 
-Let’s take a simple example of finding minimum edit distance between 
-strings `ME` and `MY`. Intuitively you already know that minimum edit distance 
-here is `1` operation, which is replacing `E` with `Y`. But 
-let’s try to formalize it in a form of the algorithm in order to be able to 
-do more complex examples like transforming `Saturday` into `Sunday`.
+Điều này có một loạt các ứng dụng, ví dụ như kiểm tra chính tả, hệ thống sửa lỗi cho nhận dạng ký tự quang học, tìm kiếm chuỗi mờ và phần mềm hỗ trợ dịch thuật ngôn ngữ tự nhiên dựa trên bộ nhớ dịch.
 
-To apply the mathematical formula mentioned above to `ME → MY` transformation 
-we need to know minimum edit distances of `ME → M`, `M → MY` and `M → M` transformations
-in prior. Then we will need to pick the minimum one and add _one_ operation to 
-transform last letters `E → Y`. So minimum edit distance of `ME → MY` transformation 
-is being calculated based on three previously possible transformations.
+## Giải thích phương pháp lập trình động
 
-To explain this further let’s draw the following matrix:
+Hãy xem một ví dụ đơn giản về việc tìm khoảng cách chỉnh sửa tối thiểu giữa các chuỗi `ME` và `MY`. Theo cách hiểu của bạn, bạn đã biết rằng khoảng cách chỉnh sửa tối thiểu ở đây là `1` thao tác, đó là thay thế `E` bằng `Y`. Nhưng hãy cố gắng hình thành nó dưới dạng thuật toán để có thể thực hiện các ví dụ phức tạp hơn như biến đổi `Saturday` thành `Sunday`.
 
-![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*aTunSUoy0BJyYBVn4tWGrA.png)
+Để áp dụng công thức toán học được đề cập ở trên vào biến đổi `ME → MY`, chúng ta cần biết khoảng cách chỉnh sửa tối thiểu của các biến đổi `ME → M`, `M → MY` và `M → M` trước. Sau đó, chúng ta sẽ cần chọn cái nhỏ nhất và thêm _một_ thao tác để biến đổi các ký tự cuối cùng `E → Y`. Vì vậy, khoảng cách chỉnh sửa tối thiểu của biến đổi `ME → MY` được tính dựa trên ba biến đổi có thể trước đó.
 
-- Cell `(0:1)` contains red number 1. It means that we need 1 operation to 
-transform `M` to an empty string. And it is by deleting `M`. This is why this number is red.
-- Cell `(0:2)` contains red number 2. It means that we need 2 operations 
-to transform `ME` to an empty string. And it is by deleting `E` and `M`.
-- Cell `(1:0)` contains green number 1. It means that we need 1 operation 
-to transform an empty string to `M`. And it is by inserting `M`. This is why this number is green.
-- Cell `(2:0)` contains green number 2. It means that we need 2 operations 
-to transform an empty string to `MY`. And it is by inserting `Y` and  `M`.
-- Cell `(1:1)` contains number 0. It means that it costs nothing 
-to transform `M` into `M`.
-- Cell `(1:2)` contains red number 1. It means that we need 1 operation 
-to transform `ME` to `M`. And it is by deleting `E`.
-- And so on...
+Để giải thích điều này cụ thể hơn, hãy vẽ ma trận sau:
 
-This looks easy for such small matrix as ours (it is only `3x3`). But here you
-may find basic concepts that may be applied to calculate all those numbers for
-bigger matrices (let’s say a `9x7` matrix for `Saturday → Sunday` transformation).
+![Ma trận Levenshtein](https://cdn-images-1.medium.com/max/1600/1*aTunSUoy0BJyYBVn4tWGrA.png)
 
-According to the formula you only need three adjacent cells `(i-1:j)`, `(i-1:j-1)`, and `(i:j-1)` to
-calculate the number for current cell `(i:j)`. All we need to do is to find the 
-minimum of those three cells and then add `1` in case if we have different 
-letters in `i`'s row and `j`'s column.
+- Ô `(0:1)` chứa số 1 màu đỏ. Nó có nghĩa là chúng ta cần 1 thao tác để biến đổi `M` thành một chuỗi trống. Và đó là bằng cách xóa `M`. Đây là lý do tại sao số này màu đỏ.
+- Ô `(0:2)` chứa số 2 màu đỏ. Nó có nghĩa là chúng ta cần 2 thao tác để biến đổi `ME` thành một chuỗi trống. Và đó là bằng cách xóa `E` và `M`.
+- Ô `(1:0)` chứa số 1 màu xanh. Nó có nghĩa là chúng ta cần 1 thao tác để biến đổi một chuỗi trống thành `M`. Và đó là bằng cách chèn `M`. Đây là lý do tại sao số này màu xanh.
+- Ô `(2:0)` chứa số 2 màu xanh. Nó có nghĩa là chúng ta cần 2 thao tác để biến đổi một chuỗi trống thành `MY`. Và đó là bằng cách chèn `Y` và `M`.
+- Ô `(1:1)` chứa số 0. Nó có nghĩa là không tốn gì
+  để biến đổi `M` thành `M`.
+- Ô `(1:2)` chứa số 1 màu đỏ. Nó có nghĩa là chúng ta cần 1 thao tác
+  để biến đổi `ME` thành `M`. Và đó là bằng cách xóa `E`.
+- Và tiếp tục...
 
-You may clearly see the recursive nature of the problem.
+Điều này trông dễ dàng cho ma trận nhỏ như của chúng ta (chỉ là `3x3`). Nhưng ở đây, bạn có thể tìm thấy các khái niệm cơ bản có thể được áp dụng để tính toán tất cả các số đó cho các ma trận lớn hơn (ví dụ, một ma trận `9x7` cho biến đổi `Saturday → Sunday`).
 
-![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*w8UB4DSvBnAK6mBXRGQDjw.png)
+Theo công thức, bạn chỉ cần ba ô liền kề `(i-1:j)`, `(i-1:j-1)`, và `(i:j-1)` để tính toán số cho ô hiện tại `(i:j)`. Tất cả những gì chúng ta cần làm là tìm số nhỏ nhất của ba ô đó, sau đó thêm `1` trong trường hợp nếu chúng ta có các chữ cái khác nhau trong hàng `i` và cột `j`.
 
-Let's draw a decision graph for this problem.
+Bạn có thể thấy rõ tính đệ quy của vấn đề.
 
-![Minimum Edit Distance Decision Graph](https://cdn-images-1.medium.com/max/1600/1*8jD0qvr5B9PwRFM_9z7q9A.png)
+Hãy vẽ một biểu đồ quyết định cho vấn đề này.
 
-You may see a number of overlapping sub-problems on the picture that are marked 
-with red. Also there is no way to reduce the number of operations and make it 
-less than a minimum of those three adjacent cells from the formula. 
+![Biểu đồ Quyết định Khoảng cách chỉnh sửa tối thiểu](https://cdn-images-1.medium.com/max/1600/1*8jD0qvr5B9PwRFM_9z7q9A.png)
 
-Also you may notice that each cell number in the matrix is being calculated 
-based on previous ones. Thus the tabulation technique (filling the cache in 
-bottom-up direction) is being applied here.
+Bạn có thể thấy một số vấn đề con chồng chéo trên hình ảnh được đánh dấu
+bằng màu đỏ. Ngoài ra, không có cách nào để giảm số lượng thao tác và làm
+nó ít hơn một tối thiểu của ba ô liền kề đó từ công thức.
 
-Applying this principle further we may solve more complicated cases like 
-with `Saturday → Sunday` transformation.
+Bạn cũng có thể nhận thấy rằng mỗi số ô trong ma trận đều được tính toán
+dựa trên các ô trước đó. Do đó, kỹ thuật bảng trên (điền vào bộ nhớ đệm theo
+hướng từ dưới lên) được áp dụng ở đây.
 
-![Levenshtein distance](https://cdn-images-1.medium.com/max/2600/1*497gMaFErzJpCXG7kS_7dw.png)
+Áp dụng nguyên tắc này tiếp tục, chúng ta có thể giải quyết các trường hợp
+phức tạp hơn như với biến đổi `Saturday → Sunday`.
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Levenshtein_distance)
 - [YouTube](https://www.youtube.com/watch?v=We3YDTzNXEk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/longest-common-substring/README.en-EN.md b/src/algorithms/string/longest-common-substring/README.en-EN.md
new file mode 100644
index 0000000000..e6c92e89bf
--- /dev/null
+++ b/src/algorithms/string/longest-common-substring/README.en-EN.md
@@ -0,0 +1,27 @@
+# Longest Common Substring Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The longest common substring problem is to find the longest string
+(or strings) that is a substring (or are substrings) of two or more
+strings.
+
+## Example
+
+The longest common substring of the strings `ABABC`, `BABCA` and
+`ABCBA` is string `ABC` of length 3. Other common substrings are
+`A`, `AB`, `B`, `BA`, `BC` and `C`.
+
+```
+ABABC
+  |||
+ BABCA
+  |||
+  ABCBA
+```
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_substring_problem)
+- [YouTube](https://www.youtube.com/watch?v=BysNXJHzCEs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/longest-common-substring/README.md b/src/algorithms/string/longest-common-substring/README.md
index 9e63294f04..ef6582fbac 100644
--- a/src/algorithms/string/longest-common-substring/README.md
+++ b/src/algorithms/string/longest-common-substring/README.md
@@ -1,14 +1,13 @@
-# Longest Common Substring Problem
+# Bài toán Chuỗi Con Chung Dài Nhất
 
-The longest common substring problem is to find the longest string 
-(or strings) that is a substring (or are substrings) of two or more 
-strings.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Example
+Bài toán chuỗi con chung dài nhất là tìm chuỗi dài nhất (hoặc các chuỗi) là một chuỗi con (hoặc là các chuỗi con) của hai hoặc nhiều chuỗi.
 
-The longest common substring of the strings `ABABC`, `BABCA` and 
-`ABCBA` is string `ABC` of length 3. Other common substrings are
-`A`, `AB`, `B`, `BA`, `BC` and `C`.
+## Ví dụ
+
+Chuỗi con chung dài nhất của các chuỗi `ABABC`, `BABCA` và `ABCBA` là chuỗi `ABC` có độ dài 3. Các chuỗi con chung khác là `A`, `AB`, `B`, `BA`, `BC` và `C`.
 
 ```
 ABABC
@@ -18,7 +17,7 @@ ABABC
   ABCBA
 ```
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_substring_problem)
 - [YouTube](https://www.youtube.com/watch?v=BysNXJHzCEs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/palindrome/README.en-EN.md b/src/algorithms/string/palindrome/README.en-EN.md
new file mode 100644
index 0000000000..9408b39e58
--- /dev/null
+++ b/src/algorithms/string/palindrome/README.en-EN.md
@@ -0,0 +1,32 @@
+# Palindrome Check
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A [Palindrome](https://en.wikipedia.org/wiki/Palindrome) is a string that reads the same forwards and backwards.
+This means that the second half of the string is the reverse of the
+first half.
+
+## Examples
+
+The following are palindromes (thus would return `TRUE`):
+
+```
+- "a"
+- "pop"     ->  p + o + p
+- "deed"    ->  de + ed
+- "kayak"   ->  ka + y + ak
+- "racecar" ->  rac + e + car
+```
+
+The following are NOT palindromes (thus would return `FALSE`):
+
+```
+- "rad"
+- "dodo"
+- "polo"
+```
+
+## References
+
+- [GeeksForGeeks - Check if a number is Palindrome](https://www.geeksforgeeks.org/check-if-a-number-is-palindrome/)
diff --git a/src/algorithms/string/palindrome/README.md b/src/algorithms/string/palindrome/README.md
index 0ce77d42b6..9f95ab489e 100644
--- a/src/algorithms/string/palindrome/README.md
+++ b/src/algorithms/string/palindrome/README.md
@@ -1,12 +1,13 @@
-# Palindrome Check
+# Kiểm Tra Chuỗi Palindrome
 
-A [Palindrome](https://en.wikipedia.org/wiki/Palindrome) is a string that reads the same forwards and backwards.
-This means that the second half of the string is the reverse of the
-first half.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-## Examples
+Một [Palindrome](https://en.wikipedia.org/wiki/Palindrome) là một chuỗi mà khi đọc từ trái sang phải hoặc từ phải sang trái đều giống nhau. Điều này có nghĩa là nửa sau của chuỗi là đảo ngược của nửa đầu.
 
-The following are palindromes (thus would return `TRUE`):
+## Ví dụ
+
+Dưới đây là các chuỗi Palindrome (do đó sẽ trả về `TRUE`):
 
 ```
 - "a"
@@ -16,7 +17,7 @@ The following are palindromes (thus would return `TRUE`):
 - "racecar" ->  rac + e + car
 ```
 
-The following are NOT palindromes (thus would return `FALSE`):
+Dưới đây là các chuỗi KHÔNG PHẢI Palindrome (do đó sẽ trả về `FALSE`):
 
 ```
 - "rad"
@@ -24,6 +25,6 @@ The following are NOT palindromes (thus would return `FALSE`):
 - "polo"
 ```
 
-## References
+## Tham khảo
 
-- [GeeksForGeeks - Check if a number is Palindrome](https://www.geeksforgeeks.org/check-if-a-number-is-palindrome/)
+- [GeeksForGeeks - Kiểm tra một số có phải là Palindrome không](https://www.geeksforgeeks.org/check-if-a-number-is-palindrome/)
diff --git a/src/algorithms/string/rabin-karp/README.en-EN.md b/src/algorithms/string/rabin-karp/README.en-EN.md
new file mode 100644
index 0000000000..ac094d5db2
--- /dev/null
+++ b/src/algorithms/string/rabin-karp/README.en-EN.md
@@ -0,0 +1,59 @@
+# Rabin Karp Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, the Rabin–Karp algorithm or Karp–Rabin algorithm
+is a string searching algorithm created by Richard M. Karp and
+Michael O. Rabin (1987) that uses hashing to find any one of a set
+of pattern strings in a text.
+
+## Algorithm
+
+The Rabin–Karp algorithm seeks to speed up the testing of equality of
+the pattern to the substrings in the text by using a hash function. A
+hash function is a function which converts every string into a numeric
+value, called its hash value; for example, we might
+have `hash('hello') = 5`. The algorithm exploits the fact
+that if two strings are equal, their hash values are also equal. Thus,
+string matching is reduced (almost) to computing the hash value of the
+search pattern and then looking for substrings of the input string with
+that hash value.
+
+However, there are two problems with this approach. First, because there
+are so many different strings and so few hash values, some differing
+strings will have the same hash value. If the hash values match, the
+pattern and the substring may not match; consequently, the potential
+match of search pattern and the substring must be confirmed by comparing
+them; that comparison can take a long time for long substrings.
+Luckily, a good hash function on reasonable strings usually does not
+have many collisions, so the expected search time will be acceptable.
+
+## Hash Function Used
+
+The key to the Rabin–Karp algorithm's performance is the efficient computation
+of hash values of the successive substrings of the text.
+The **Rabin fingerprint** is a popular and effective rolling hash function.
+
+The **polynomial hash function** described in this example is not a Rabin
+fingerprint, but it works equally well. It treats every substring as a
+number in some base, the base being usually a large prime.
+
+## Complexity
+
+For text of length `n` and `p` patterns of combined length `m`, its average
+and best case running time is `O(n + m)` in space `O(p)`, but its
+worst-case time is `O(n * m)`.
+
+## Application
+
+A practical application of the algorithm is detecting plagiarism.
+Given source material, the algorithm can rapidly search through a paper
+for instances of sentences from the source material, ignoring details
+such as case and punctuation. Because of the abundance of the sought
+strings, single-string searching algorithms are impractical.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm)
+- [YouTube](https://www.youtube.com/watch?v=H4VrKHVG5qI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/rabin-karp/README.md b/src/algorithms/string/rabin-karp/README.md
index c273b273db..df651c7e8c 100644
--- a/src/algorithms/string/rabin-karp/README.md
+++ b/src/algorithms/string/rabin-karp/README.md
@@ -1,56 +1,31 @@
-# Rabin Karp Algorithm
-
-In computer science, the Rabin–Karp algorithm or Karp–Rabin algorithm 
-is a string searching algorithm created by Richard M. Karp and 
-Michael O. Rabin (1987) that uses hashing to find any one of a set 
-of pattern strings in a text. 
-
-## Algorithm
-
-The Rabin–Karp algorithm seeks to speed up the testing of equality of 
-the pattern to the substrings in the text by using a hash function. A 
-hash function is a function which converts every string into a numeric 
-value, called its hash value; for example, we might 
-have `hash('hello') = 5`. The algorithm exploits the fact 
-that if two strings are equal, their hash values are also equal. Thus,
-string matching is reduced (almost) to computing the hash value of the
-search pattern and then looking for substrings of the input string with
-that hash value.
-
-However, there are two problems with this approach. First, because there
-are so many different strings and so few hash values, some differing
-strings will have the same hash value. If the hash values match, the
-pattern and the substring may not match; consequently, the potential
-match of search pattern and the substring must be confirmed by comparing
-them; that comparison can take a long time for long substrings.
-Luckily, a good hash function on reasonable strings usually does not
-have many collisions, so the expected search time will be acceptable.
-
-## Hash Function Used
-
-The key to the Rabin–Karp algorithm's performance is the efficient computation 
-of hash values of the successive substrings of the text.
-The **Rabin fingerprint** is a popular and effective rolling hash function.
-
-The **polynomial hash function** described in this example is not a Rabin 
-fingerprint, but it works equally well. It treats every substring as a 
-number in some base, the base being usually a large prime.
-
-## Complexity
-
-For text of length `n` and `p` patterns of combined length `m`, its average 
-and best case running time is `O(n + m)` in space `O(p)`, but its 
-worst-case time is `O(n * m)`. 
-
-## Application
-
-A practical application of the algorithm is detecting plagiarism. 
-Given source material, the algorithm can rapidly search through a paper 
-for instances of sentences from the source material, ignoring details 
-such as case and punctuation. Because of the abundance of the sought 
-strings, single-string searching algorithms are impractical.
-
-## References
+# Thuật toán Rabin-Karp
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, thuật toán Rabin–Karp hoặc thuật toán Karp–Rabin là một thuật toán tìm kiếm chuỗi được tạo ra bởi Richard M. Karp và Michael O. Rabin (năm 1987) sử dụng hàm băm để tìm bất kỳ một trong một tập hợp các chuỗi mẫu trong một văn bản.
+
+## Thuật toán
+
+Thuật toán Rabin–Karp cố gắng tăng tốc quá trình kiểm tra sự bằng nhau của mẫu với các chuỗi con trong văn bản bằng cách sử dụng một hàm băm. Một hàm băm là một hàm chuyển đổi mỗi chuỗi thành một giá trị số, gọi là giá trị băm của nó; ví dụ, chúng ta có thể có `hash('hello') = 5`. Thuật toán tận dụng việc nếu hai chuỗi bằng nhau, thì giá trị băm của chúng cũng bằng nhau. Do đó, việc khớp chuỗi được giảm bớt (gần như) thành việc tính giá trị băm của mẫu tìm kiếm và sau đó tìm chuỗi con của chuỗi đầu vào với giá trị băm đó.
+
+Tuy nhiên, có hai vấn đề với phương pháp này. Đầu tiên, vì có rất nhiều chuỗi khác nhau và rất ít giá trị băm, một số chuỗi khác biệt sẽ có cùng một giá trị băm. Nếu các giá trị băm khớp nhau, mẫu và chuỗi con có thể không khớp; do đó, sự khớp của tiềm năng của mẫu tìm kiếm và chuỗi con phải được xác nhận bằng cách so sánh chúng; việc so sánh đó có thể mất thời gian đối với các chuỗi con dài. May mắn thay, một hàm băm tốt trên các chuỗi hợp lý thường không có nhiều va chạm, vì vậy thời gian tìm kiếm kỳ vọng sẽ được chấp nhận.
+
+## Hàm Băm Sử Dụng
+
+Chìa khóa của hiệu suất của thuật toán Rabin–Karp là tính toán hiệu quả giá trị băm của các chuỗi con kế tiếp của văn bản. **Dấu vân tay Rabin** là một hàm băm trượt phổ biến và hiệu quả.
+
+**Hàm băm đa thức** mô tả trong ví dụ này không phải là một dấu vân tay Rabin, nhưng nó hoạt động cũng tốt. Nó xem mọi chuỗi con như một số trong một cơ số nào đó, cơ sở thường là một số nguyên tố lớn.
+
+## Phức Tạp
+
+Đối với văn bản có độ dài `n` và `p` mẫu với tổng độ dài `m`, thời gian chạy trung bình và tốt nhất là `O(n + m)` trong không gian `O(p)`, nhưng thời gian xấu nhất là `O(n * m)`.
+
+## Ứng Dụng
+
+Một ứng dụng thực tế của thuật toán là phát hiện sự sao chép. Dựa trên nguồn, thuật toán có thể tìm kiếm nhanh chóng qua một bài báo để tìm các câu từ nguồn, bỏ qua các chi tiết như chữ hoa và dấu câu. Vì sự phong phú của các chuỗi cần tìm, các thuật toán tìm kiếm chuỗi đơn lẻ không thực tế.
+
+## Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm)
 - [YouTube](https://www.youtube.com/watch?v=H4VrKHVG5qI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/algorithms/string/regular-expression-matching/README.en-EN.md b/src/algorithms/string/regular-expression-matching/README.en-EN.md
new file mode 100644
index 0000000000..145d969e8b
--- /dev/null
+++ b/src/algorithms/string/regular-expression-matching/README.en-EN.md
@@ -0,0 +1,78 @@
+# Regular Expression Matching
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Given an input string `s` and a pattern `p`, implement regular
+expression matching with support for `.` and `*`.
+
+- `.` Matches any single character.
+- `*` Matches zero or more of the preceding element.
+
+The matching should cover the **entire** input string (not partial).
+
+**Note**
+
+- `s` could be empty and contains only lowercase letters `a-z`.
+- `p` could be empty and contains only lowercase letters `a-z`, and characters like `.` or `*`.
+
+## Examples
+
+**Example #1**
+
+Input:
+
+```
+s = 'aa'
+p = 'a'
+```
+
+Output: `false`
+
+Explanation: `a` does not match the entire string `aa`.
+
+**Example #2**
+
+Input:
+
+```
+s = 'aa'
+p = 'a*'
+```
+
+Output: `true`
+
+Explanation: `*` means zero or more of the preceding element, `a`.
+Therefore, by repeating `a` once, it becomes `aa`.
+
+**Example #3**
+
+Input:
+
+```
+s = 'ab'
+p = '.*'
+```
+
+Output: `true`
+
+Explanation: `.*` means "zero or more (`*`) of any character (`.`)".
+
+**Example #4**
+
+Input:
+
+```
+s = 'aab'
+p = 'c*a*b'
+```
+
+Output: `true`
+
+Explanation: `c` can be repeated 0 times, `a` can be repeated
+1 time. Therefore it matches `aab`.
+
+## References
+
+- [YouTube](https://www.youtube.com/watch?v=l3hda49XcDE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=71&t=0s)
+- [LeetCode](https://leetcode.com/problems/regular-expression-matching/description/)
diff --git a/src/algorithms/string/regular-expression-matching/README.md b/src/algorithms/string/regular-expression-matching/README.md
index e04c071e40..a3d3a822ae 100644
--- a/src/algorithms/string/regular-expression-matching/README.md
+++ b/src/algorithms/string/regular-expression-matching/README.md
@@ -1,73 +1,77 @@
-# Regular Expression Matching
+# Khớp Biểu Thức Chính Quy
 
-Given an input string `s` and a pattern `p`, implement regular 
-expression matching with support for `.` and `*`.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-- `.` Matches any single character.
-- `*` Matches zero or more of the preceding element.
+Cho một chuỗi đầu vào `s` và một mẫu `p`, hãy thực hiện việc khớp biểu thức chính quy với hỗ trợ cho `.` và `*`.
 
-The matching should cover the **entire** input string (not partial).
+- `.` Khớp với bất kỳ ký tự nào.
+- `*` Khớp với không hoặc nhiều hơn một phần tử trước đó.
 
-**Note**
+Việc khớp này nên bao gồm **toàn bộ** chuỗi đầu vào (không phải là một phần).
 
-- `s` could be empty and contains only lowercase letters `a-z`.
-- `p` could be empty and contains only lowercase letters `a-z`, and characters like `.` or `*`.
+**Ghi Chú**
 
-## Examples
+- `s` có thể trống và chỉ chứa các chữ cái thường `a-z`.
+- `p` có thể trống và chỉ chứa các chữ cái thường `a-z`, và các ký tự như `.` hoặc `*`.
 
-**Example #1**
+## Ví dụ
+
+**Ví dụ #1**
+
+Đầu vào:
 
-Input:
 ```
 s = 'aa'
 p = 'a'
 ```
 
-Output: `false`
+Đầu ra: `false`
+
+Giải thích: `a` không khớp với toàn bộ chuỗi `aa`.
 
-Explanation: `a` does not match the entire string `aa`.
+**Ví dụ #2**
 
-**Example #2**
+Đầu vào:
 
-Input:
 ```
 s = 'aa'
 p = 'a*'
 ```
 
-Output: `true`
+Đầu ra: `true`
 
-Explanation: `*` means zero or more of the preceding element, `a`. 
-Therefore, by repeating `a` once, it becomes `aa`.
+Giải thích: `*` có nghĩa là không hoặc nhiều hơn một phần tử trước đó, `a`.
+Do đó, bằng cách lặp lại `a` một lần, nó trở thành `aa`.
 
-**Example #3**
+**Ví dụ #3**
 
-Input:
+Đầu vào:
 
 ```
 s = 'ab'
 p = '.*'
 ```
 
-Output: `true`
+Đầu ra: `true`
 
-Explanation: `.*` means "zero or more (`*`) of any character (`.`)".
+Giải thích: `.*` có nghĩa là "không hoặc nhiều hơn (`*`) bất kỳ ký tự nào (`.`)".
 
-**Example #4**
+**Ví dụ #4**
 
-Input:
+Đầu vào:
 
 ```
 s = 'aab'
 p = 'c*a*b'
 ```
 
-Output: `true`
+Đầu ra: `true`
 
-Explanation: `c` can be repeated 0 times, `a` can be repeated 
-1 time. Therefore it matches `aab`.
+Giải thích: `c` có thể được lặp lại 0 lần, `a` có thể được lặp lại
+1 lần. Do đó nó khớp với `aab`.
 
-## References
+## Tham Khảo
 
 - [YouTube](https://www.youtube.com/watch?v=l3hda49XcDE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=71&t=0s)
 - [LeetCode](https://leetcode.com/problems/regular-expression-matching/description/)
diff --git a/src/algorithms/string/z-algorithm/README.en-EN.md b/src/algorithms/string/z-algorithm/README.en-EN.md
new file mode 100644
index 0000000000..e22a88bb58
--- /dev/null
+++ b/src/algorithms/string/z-algorithm/README.en-EN.md
@@ -0,0 +1,65 @@
+# Z Algorithm
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Z-algorithm finds occurrences of a "word" `W`
+within a main "text string" `T` in linear time `O(|W| + |T|)`.
+
+Given a string `S` of length `n`, the algorithm produces
+an array, `Z` where `Z[i]` represents the longest substring
+starting from `S[i]` which is also a prefix of `S`. Finding
+`Z` for the string obtained by concatenating the word, `W`
+with a nonce character, say `$` followed by the text, `T`,
+helps with pattern matching, for if there is some index `i`
+such that `Z[i]` equals the pattern length, then the pattern
+must be present at that point.
+
+While the `Z` array can be computed with two nested loops in `O(|W| * |T|)` time, the
+following strategy shows how to obtain it in linear time, based
+on the idea that as we iterate over the letters in the string
+(index `i` from `1` to `n - 1`), we maintain an interval `[L, R]`
+which is the interval with maximum `R` such that `1 ≤ L ≤ i ≤ R`
+and `S[L...R]` is a prefix that is also a substring (if no such
+interval exists, just let `L = R =  - 1`). For `i = 1`, we can
+simply compute `L` and `R` by comparing `S[0...]` to `S[1...]`.
+
+**Example of Z array**
+
+```
+Index            0   1   2   3   4   5   6   7   8   9  10  11
+Text             a   a   b   c   a   a   b   x   a   a   a   z
+Z values         X   1   0   0   3   1   0   0   2   2   1   0
+```
+
+Other examples
+
+```
+str =  a a a a a a
+Z[] =  x 5 4 3 2 1
+```
+
+```
+str =  a a b a a c d
+Z[] =  x 1 0 2 1 0 0
+```
+
+```
+str =  a b a b a b a b
+Z[] =  x 0 6 0 4 0 2 0
+```
+
+**Example of Z box**
+
+![z-box](https://ivanyu.me/wp-content/uploads/2014/09/zalg1.png)
+
+## Complexity
+
+- **Time:** `O(|W| + |T|)`
+- **Space:** `O(|W|)`
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/)
+- [YouTube](https://www.youtube.com/watch?v=CpZh4eF8QBw&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=70)
+- [Z Algorithm by Ivan Yurchenko](https://ivanyu.me/blog/2013/10/15/z-algorithm/)
diff --git a/src/algorithms/string/z-algorithm/README.md b/src/algorithms/string/z-algorithm/README.md
index 0f12bc7333..4efbc39db5 100644
--- a/src/algorithms/string/z-algorithm/README.md
+++ b/src/algorithms/string/z-algorithm/README.md
@@ -1,62 +1,50 @@
-# Z Algorithm
+# Thuật Toán Z
 
-The Z-algorithm finds occurrences of a "word" `W` 
-within a main "text string" `T` in linear time `O(|W| + |T|)`.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Given a string `S` of length `n`, the algorithm produces 
-an array, `Z` where `Z[i]` represents the longest substring 
-starting from `S[i]` which is also a prefix of `S`. Finding
-`Z` for the string obtained by concatenating the word, `W` 
-with a nonce character, say `$` followed by the text, `T`,
-helps with pattern matching, for if there is some index `i`
-such that `Z[i]` equals the pattern length, then the pattern
-must be present at that point.
+Thuật toán Z tìm các xuất hiện của một "từ" `W` trong một "chuỗi văn bản" `T` với thời gian tuyến tính `O(|W| + |T|)`.
 
-While the `Z` array can be computed with two nested loops in `O(|W| * |T|)` time, the
-following strategy shows how to obtain it in linear time, based 
-on the idea that as we iterate over the letters in the string 
-(index `i` from `1` to `n - 1`), we maintain an interval `[L, R]`
-which is the interval with maximum `R` such that `1 ≤ L ≤ i ≤ R` 
-and `S[L...R]` is a prefix that is also a substring (if no such 
-interval exists, just let `L = R =  - 1`). For `i = 1`, we can 
-simply compute `L` and `R` by comparing `S[0...]` to `S[1...]`.
+Cho một chuỗi `S` có độ dài `n`, thuật toán tạo ra một mảng, `Z` trong đó `Z[i]` biểu thị chuỗi con dài nhất bắt đầu từ `S[i]` mà cũng là một tiền tố của `S`. Tìm `Z` cho chuỗi thu được bằng cách nối từ `W` với một ký tự nonce, ví dụ `$` sau đó là văn bản, `T`, giúp cho việc so khớp mẫu, vì nếu có một chỉ số `i` nào đó sao cho `Z[i]` bằng độ dài mẫu, thì mẫu phải có mặt tại điểm đó.
 
-**Example of Z array**
+Mặc dù mảng `Z` có thể được tính toán với hai vòng lặp lồng nhau trong thời gian `O(|W| * |T|)`, chiến lược sau đây cho thấy cách thu được nó trong thời gian tuyến tính, dựa trên ý tưởng rằng khi chúng ta lặp qua các ký tự trong chuỗi (chỉ số `i` từ `1` đến `n - 1`), chúng ta duy trì một khoảng `[L, R]` là khoảng với `R` tối đa sao cho `1 ≤ L ≤ i ≤ R` và `S[L...R]` là một tiền tố cũng là một chuỗi con (nếu không có khoảng nào tồn tại, chỉ cần đặt `L = R =  - 1`). Đối với `i = 1`, chúng ta có thể dễ dàng tính toán `L` và `R` bằng cách so sánh `S[0...]` với `S[1...]`.
+
+**Ví dụ về mảng Z**
 
 ```
-Index            0   1   2   3   4   5   6   7   8   9  10  11 
-Text             a   a   b   c   a   a   b   x   a   a   a   z
-Z values         X   1   0   0   3   1   0   0   2   2   1   0 
+Chỉ số           0   1   2   3   4   5   6   7   8   9  10  11
+Văn bản           a   a   b   c   a   a   b   x   a   a   a   z
+Giá trị Z        X   1   0   0   3   1   0   0   2   2   1   0
 ```
 
-Other examples
+Các ví dụ khác
 
 ```
-str =  a a a a a a
+chuỗi =  a a a a a a
 Z[] =  x 5 4 3 2 1
 ```
 
 ```
-str =  a a b a a c d
+chuỗi =  a a b a a c d
 Z[] =  x 1 0 2 1 0 0
 ```
 
 ```
-str =  a b a b a b a b
+chuỗi =  a b a b a b a b
 Z[] =  x 0 6 0 4 0 2 0
 ```
 
-**Example of Z box**
+**Ví dụ về hộp Z**
 
 ![z-box](https://ivanyu.me/wp-content/uploads/2014/09/zalg1.png)
 
-## Complexity
+## Phức Tạp
 
-- **Time:** `O(|W| + |T|)`
-- **Space:** `O(|W|)`
+- **Thời gian:** `O(|W| + |T|)`
+- **Không gian:** `O(|W|)`
 
-## References
+## Tham Khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/)
 - [YouTube](https://www.youtube.com/watch?v=CpZh4eF8QBw&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=70)
-- [Z Algorithm by Ivan Yurchenko](https://ivanyu.me/blog/2013/10/15/z-algorithm/)
+- [Thuật toán Z bởi Ivan Yurchenko](https://ivanyu.me/blog/2013/10/15/z-algorithm/)
diff --git a/src/algorithms/tree/breadth-first-search/README.en-EN.md b/src/algorithms/tree/breadth-first-search/README.en-EN.md
new file mode 100644
index 0000000000..d2af3e3fc2
--- /dev/null
+++ b/src/algorithms/tree/breadth-first-search/README.en-EN.md
@@ -0,0 +1,42 @@
+# Breadth-First Search (BFS)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Breadth-first search (BFS) is an algorithm for traversing
+or searching tree or graph data structures. It starts at
+the tree root (or some arbitrary node of a graph, sometimes
+referred to as a 'search key') and explores the neighbor
+nodes first, before moving to the next level neighbors.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)
+
+## Pseudocode
+
+```text
+BFS(root)
+  Pre: root is the node of the BST
+  Post: the nodes in the BST have been visited in breadth first order
+  q ← queue
+  while root = ø
+    yield root.value
+    if root.left = ø
+      q.enqueue(root.left)
+    end if
+    if root.right = ø
+      q.enqueue(root.right)
+    end if
+    if !q.isEmpty()
+      root ← q.dequeue()
+    else
+      root ← ø
+    end if
+  end while
+end BFS
+```
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)
+- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
diff --git a/src/algorithms/tree/breadth-first-search/README.md b/src/algorithms/tree/breadth-first-search/README.md
index fe31217ae5..4213411acc 100644
--- a/src/algorithms/tree/breadth-first-search/README.md
+++ b/src/algorithms/tree/breadth-first-search/README.md
@@ -1,38 +1,37 @@
-# Breadth-First Search (BFS)
+# Tìm Kiếm theo Chiều Rộng (BFS)
 
-Breadth-first search (BFS) is an algorithm for traversing 
-or searching tree or graph data structures. It starts at
-the tree root (or some arbitrary node of a graph, sometimes 
-referred to as a 'search key') and explores the neighbor
-nodes first, before moving to the next level neighbors.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Tìm kiếm theo chiều rộng (BFS) là một thuật toán để duyệt hoặc tìm kiếm các cấu trúc dữ liệu cây hoặc đồ thị. Nó bắt đầu từ gốc của cây (hoặc một nút tùy ý của một đồ thị, đôi khi được gọi là 'khóa tìm kiếm') và khám phá các nút lá trước, trước khi chuyển đến các nút lá cùng cấp tiếp theo.
 
 ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif)
 
-## Pseudocode
+## Mã giả
 
 ```text
-BFS(root)
-  Pre: root is the node of the BST
-  Post: the nodes in the BST have been visited in breadth first order
-  q ← queue
-  while root = ø
-    yield root.value
-    if root.left = ø
-      q.enqueue(root.left)
-    end if
-    if root.right = ø
-      q.enqueue(root.right)
-    end if
-    if !q.isEmpty()
-      root ← q.dequeue()
-    else
-      root ← ø
-    end if
-  end while
-end BFS
+BFS(gốc)
+  Tiền điều kiện: gốc là nút của BST
+  Sau điều kiện: các nút trong BST đã được thăm theo thứ tự chiều rộng
+  q ← hàng đợi
+  trong khi gốc ≠ ø
+    trả về giá trị của gốc
+    nếu gốc.trái = ø
+      q.enqueue(gốc.trái)
+    kết thúc nếu
+    nếu gốc.phải = ø
+      q.enqueue(gốc.phải)
+    kết thúc nếu
+    nếu !q.isEmpty()
+      gốc ← q.dequeue()
+    khác
+      gốc ← ø
+    kết thúc nếu
+  kết thúc vòng lặp
+kết thúc BFS
 ```
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search)
 - [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
diff --git a/src/algorithms/tree/depth-first-search/README.en-EN.md b/src/algorithms/tree/depth-first-search/README.en-EN.md
new file mode 100644
index 0000000000..cecc85327e
--- /dev/null
+++ b/src/algorithms/tree/depth-first-search/README.en-EN.md
@@ -0,0 +1,18 @@
+# Depth-First Search (DFS)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Depth-first search (DFS) is an algorithm for traversing or
+searching tree or graph data structures. One starts at
+the root (selecting some arbitrary node as the root in
+the case of a graph) and explores as far as possible
+along each branch before backtracking.
+
+![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)
+- [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
+- [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/)
diff --git a/src/algorithms/tree/depth-first-search/README.md b/src/algorithms/tree/depth-first-search/README.md
index 30f22ee7fd..afebca6caf 100644
--- a/src/algorithms/tree/depth-first-search/README.md
+++ b/src/algorithms/tree/depth-first-search/README.md
@@ -1,14 +1,13 @@
-# Depth-First Search (DFS)
+# Tìm Kiếm theo Chiều Sâu (DFS)
 
-Depth-first search (DFS) is an algorithm for traversing or 
-searching tree or graph data structures. One starts at 
-the root (selecting some arbitrary node as the root in 
-the case of a graph) and explores as far as possible 
-along each branch before backtracking.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Tìm kiếm theo chiều sâu (DFS) là một thuật toán để duyệt hoặc tìm kiếm các cấu trúc dữ liệu cây hoặc đồ thị. Người ta bắt đầu từ gốc (chọn một nút tùy ý làm gốc trong trường hợp của một đồ thị) và khám phá càng xa càng tốt dọc theo mỗi nhánh trước khi quay lại.
 
 ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif)
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search)
 - [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/)
diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.en-EN.md b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.en-EN.md
new file mode 100644
index 0000000000..88ef584838
--- /dev/null
+++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.en-EN.md
@@ -0,0 +1,110 @@
+# Best Time to Buy and Sell Stock
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## Task Description
+
+Say you have an array prices for which the `i`-th element is the price of a given stock on day `i`.
+
+Find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).
+
+> Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
+
+**Example #1**
+
+```
+Input: [7, 1, 5, 3, 6, 4]
+Output: 7
+```
+
+_Explanation:_ Buy on day `2` (`price = 1`) and sell on day `3` (`price = 5`), `profit = 5-1 = 4`. Then buy on day `4` (`price = 3`) and sell on day `5` (`price = 6`), `profit = 6-3 = 3`.
+
+**Example #2**
+
+```
+Input: [1, 2, 3, 4, 5]
+Output: 4
+```
+
+_Explanation:_ Buy on day `1` (`price = 1`) and sell on day `5` (`price = 5`), `profit = 5-1 = 4`. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
+
+**Example #3**
+
+```
+Input: [7, 6, 4, 3, 1]
+Output: 0
+```
+
+_Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`.
+
+## Possible Solutions
+
+### Divide and conquer approach `O(2^n)`
+
+We may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_.
+
+Let's say we have an array of prices `[7, 6, 4, 3, 1]` and we're on the _1st_ day of trading (at the very beginning of the array). At this point we may say that the overall maximum profit would be the _maximum_ of two following values:
+
+1. _Option 1: Keep the money_ → profit would equal to the profit from buying/selling the rest of the stocks → `keepProfit = profit([6, 4, 3, 1])`.
+2. _Option 2: Buy/sell at current price_ → profit in this case would equal to the profit from buying/selling the rest of the stocks plus (or minus, depending on whether we're selling or buying) the current stock price → `buySellProfit = -7 + profit([6, 4, 3, 1])`.
+
+The overall profit would be equal to → `overalProfit = Max(keepProfit, buySellProfit)`.
+
+As you can see the `profit([6, 4, 3, 1])` task is being solved in the same recursive manner.
+
+> See the full code example in [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js)
+
+#### Time Complexity
+
+As you may see, every recursive call will produce _2_ more recursive branches. The depth of the recursion will be `n` (size of prices array) and thus, the time complexity will equal to `O(2^n)`.
+
+As you may see, this is very inefficient. For example for just `20` prices the number of recursive calls will be somewhere close to `2M`!
+
+#### Additional Space Complexity
+
+If we avoid cloning the prices array between recursive function calls and will use the array pointer then additional space complexity will be proportional to the depth of the recursion: `O(n)`
+
+## Peak Valley Approach `O(n)`
+
+If we plot the prices array (i.e. `[7, 1, 5, 3, 6, 4]`) we may notice that the points of interest are the consecutive valleys and peaks
+
+![Peak Valley Approach](https://leetcode.com/media/original_images/122_maxprofit_1.PNG)
+
+_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
+
+So, if we will track the growing price and will sell the stocks immediately _before_ the price goes down we'll get the maximum profit (remember, we bought the stock in the valley at its low price).
+
+> See the full code example in [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js)
+
+#### Time Complexity
+
+Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.
+
+#### Additional Space Complexity
+
+Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.
+
+## Accumulator Approach `O(n)`
+
+There is even simpler approach exists. Let's say we have the prices array which looks like this `[1, 7, 2, 3, 6, 7, 6, 7]`:
+
+![Simple One Pass](https://leetcode.com/media/original_images/122_maxprofit_2.PNG)
+
+_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
+
+You may notice, that we don't even need to keep tracking of a constantly growing price. Instead, we may simply add the price difference for _all growing segments_ of the chart which eventually sums up to the highest possible profit,
+
+> See the full code example in [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js)
+
+#### Time Complexity
+
+Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.
+
+#### Additional Space Complexity
+
+Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.
+
+## References
+
+- [Best Time to Buy and Sell Stock on LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md
index 9446993e98..8f5e88ceb8 100644
--- a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md
+++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md
@@ -1,107 +1,110 @@
-# Best Time to Buy and Sell Stock
+# Thời điểm Tốt Nhất để Mua và Bán Cổ Phiếu
 
-## Task Description
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Say you have an array prices for which the `i`-th element is the price of a given stock on day `i`.
+## Mô tả Công Việc
 
-Find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).
+Cho một mảng giá cổ phiếu trong đó phần tử thứ `i` là giá của một cổ phiếu cụ thể vào ngày `i`.
 
-> Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
+Tìm lợi nhuận lớn nhất có thể. Bạn có thể thực hiện bất kỳ số giao dịch nào bạn muốn (tức là, mua và bán một cổ phiếu nhiều lần).
 
-**Example #1**
+> Lưu ý: Bạn không thể tham gia nhiều giao dịch cùng một lúc (tức là, bạn phải bán cổ phiếu trước khi mua lại).
+
+**Ví dụ #1**
 
 ```
 Input: [7, 1, 5, 3, 6, 4]
 Output: 7
 ```
 
-_Explanation:_ Buy on day `2` (`price = 1`) and sell on day `3` (`price = 5`), `profit = 5-1 = 4`. Then buy on day `4` (`price = 3`) and sell on day `5` (`price = 6`), `profit = 6-3 = 3`.
+_Giải thích:_ Mua vào ngày `2` (`giá = 1`) và bán vào ngày `3` (`giá = 5`), `lợi nhuận = 5-1 = 4`. Sau đó mua vào ngày `4` (`giá = 3`) và bán vào ngày `5` (`giá = 6`), `lợi nhuận = 6-3 = 3`.
 
-**Example #2**
+**Ví dụ #2**
 
 ```
 Input: [1, 2, 3, 4, 5]
 Output: 4
 ```
 
-_Explanation:_ Buy on day `1` (`price = 1`) and sell on day `5` (`price = 5`), `profit = 5-1 = 4`. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
+_Giải thích:_ Mua vào ngày `1` (`giá = 1`) và bán vào ngày `5` (`giá = 5`), `lợi nhuận = 5-1 = 4`. Lưu ý rằng bạn không thể mua vào ngày 1, mua vào ngày 2 và sau đó bán chúng sau này, vì bạn đang tham gia nhiều giao dịch cùng một lúc. Bạn phải bán trước khi mua lại.
 
-**Example #3**
+**Ví dụ #3**
 
 ```
 Input: [7, 6, 4, 3, 1]
 Output: 0
 ```
 
-_Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`.
+_Giải thích:_ Trong trường hợp này, không có giao dịch nào được thực hiện, tức là lợi nhuận tối đa `lợi nhuận = 0`.
 
-## Possible Solutions
+## Các Giải Pháp Có Thể
 
-### Divide and conquer approach `O(2^n)`
+### Tiếp Cận Chia và Trị `O(2^n)`
 
-We may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_.
+Chúng ta có thể thử **tất cả** các kết hợp mua và bán và tìm ra kết quả có lợi nhuận lớn nhất bằng cách áp dụng _tiếp cận chia và trị_.
 
-Let's say we have an array of prices `[7, 6, 4, 3, 1]` and we're on the _1st_ day of trading (at the very beginning of the array). At this point we may say that the overall maximum profit would be the _maximum_ of two following values:
+Hãy giả sử chúng ta có một mảng giá `[7, 6, 4, 3, 1]` và chúng ta đang ở _ngày thứ nhất_ của giao dịch (tại điểm bắt đầu của mảng). Tại thời điểm này, chúng ta có thể nói rằng tổng lợi nhuận toàn bộ sẽ là _lớn nhất_ của hai giá trị sau:
 
-1. _Option 1: Keep the money_ → profit would equal to the profit from buying/selling the rest of the stocks → `keepProfit = profit([6, 4, 3, 1])`.
-2. _Option 2: Buy/sell at current price_ → profit in this case would equal to the profit from buying/selling the rest of the stocks plus (or minus, depending on whether we're selling or buying) the current stock price → `buySellProfit = -7 + profit([6, 4, 3, 1])`.
+1. _Tùy chọn 1: Giữ lại tiền_ → lợi nhuận sẽ bằng lợi nhuận từ việc mua/bán cổ phiếu còn lại → `keepProfit = profit([6, 4, 3, 1])`.
+2. _Tùy chọn 2: Mua/bán tại giá hiện tại_ → lợi nhuận trong trường hợp này sẽ bằng lợi nhuận từ việc mua/bán cổ phiếu còn lại cộng (hoặc trừ, phụ thuộc vào việc chúng ta bán hay mua) giá cổ phiếu hiện tại → `buySellProfit = -7 + profit([6, 4, 3, 1])`.
 
-The overall profit would be equal to → `overalProfit = Max(keepProfit, buySellProfit)`.
+Tổng lợi nhuận sẽ bằng → `overalProfit = Max(keepProfit, buySellProfit)`.
 
-As you can see the `profit([6, 4, 3, 1])` task is being solved in the same recursive manner.
+Như bạn có thể thấy nhiệm vụ `profit([6, 4, 3, 1])` được giải quyết theo cùng một cách đệ quy.
 
-> See the full code example in [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js)
+> Xem ví dụ mã đầy đủ tại [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js)
 
-#### Time Complexity
+#### Độ Phức Tạp Thời Gian
 
-As you may see, every recursive call will produce _2_ more recursive branches. The depth of the recursion will be `n` (size of prices array) and thus, the time complexity will equal to `O(2^n)`.
+Như bạn có thể thấy, mỗi lời gọi đệ quy sẽ tạo ra _2_ nhánh đệ quy nữa. Độ sâu của đệ quy sẽ là `n` (kích thước của mảng giá) và do đó, độ phức tạp thời gian sẽ bằng `O(2^n)`.
 
-As you may see, this is very inefficient. For example for just `20` prices the number of recursive calls will be somewhere close to `2M`!
+Như bạn có thể thấy, điều này rất không hiệu quả. Ví dụ, chỉ cần `20` giá trị thì số lời gọi đệ quy sẽ gần bằng `2M`!
 
-#### Additional Space Complexity
+#### Độ Phức Tạp Không Gian Bổ Sung
 
-If we avoid cloning the prices array between recursive function calls and will use the array pointer then additional space complexity will be proportional to the depth of the recursion: `O(n)`
+Nếu chúng ta tránh việc sao chép mảng giá giữa các lời gọi hàm đệ quy và sử dụng con trỏ mảng thì độ phức tạp không gian bổ sung sẽ tỉ lệ với độ sâu của đệ quy: `O(n)`.
 
-## Peak Valley Approach `O(n)`
+## Tiếp Cận Đỉnh Thung Lũng `O(n)`
 
-If we plot the prices array (i.e. `[7, 1, 5, 3, 6, 4]`) we may notice that the points of interest are the consecutive valleys and peaks
+Nếu chúng ta vẽ biểu đồ của mảng giá (ví dụ: `[7, 1, 5, 3, 6, 4]`) thì chúng ta có thể nhận thấy các điểm quan trọng là các thung lũng và đỉnh liên tiếp
 
-![Peak Valley Approach](https://leetcode.com/media/original_images/122_maxprofit_1.PNG)
+![Tiếp Cận Đỉnh Thung Lũng](https://leetcode.com/media/original_images/122_maxprofit_1.PNG)
 
-_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
+_Nguồn hình ảnh: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
 
-So, if we will track the growing price and will sell the stocks immediately _before_ the price goes down we'll get the maximum profit (remember, we bought the stock in the valley at its low price).
+Vì vậy, nếu chúng ta theo dõi giá tăng và bán cổ phiếu ngay _trước khi_ giá giảm xuống, chúng ta sẽ nhận được lợi nhuận tối đa (hãy nhớ, chúng ta mua cổ phiếu ở thung lũng với giá thấp của nó).
 
-> See the full code example in [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js)
+> Xem ví dụ mã đầy đủ tại [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js)
 
-#### Time Complexity
+#### Độ Phức Tạp Thời Gian
 
-Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.
+Vì thuật toán chỉ yêu cầu một lần duyệt qua mảng giá, do đó độ phức tạp thời gian sẽ bằng `O(n)`.
 
-#### Additional Space Complexity
+#### Độ Phức Tạp Không Gian Bổ Sung
 
-Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.
+Ngoài mảng giá chính nó, thuật toán chỉ tiêu thụ một lượng bộ nhớ cố định. Do đó, độ phức tạp không gian bổ sung là `O(1)`.
 
-## Accumulator Approach `O(n)`
+## Tiếp Cận Tích Lũy `O(n)`
 
-There is even simpler approach exists. Let's say we have the prices array which looks like this `[1, 7, 2, 3, 6, 7, 6, 7]`:
+Còn một cách tiếp cận đơn giản hơn tồn tại. Hãy giả sử chúng ta có mảng giá như sau `[1, 7, 2, 3, 6, 7, 6, 7]`:
 
-![Simple One Pass](https://leetcode.com/media/original_images/122_maxprofit_2.PNG)
+![Duyệt Một Lần](https://leetcode.com/media/original_images/122_maxprofit_2.PNG)
 
-_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
+_Nguồn hình ảnh: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_
 
-You may notice, that we don't even need to keep tracking of a constantly growing price. Instead, we may simply add the price difference for _all growing segments_ of the chart which eventually sums up to the highest possible profit,
+Bạn có thể nhận thấy, chúng ta thậm chí không cần theo dõi một giá cả liên tục tăng. Thay vào đó, chúng ta có thể đơn giản là thêm số chênh lệch giá cho _tất cả các đoạn liên tiếp_ của biểu đồ mà tăng giá, điều này cuối cùng sẽ cộng lại thành lợi nhuận cao nhất có thể,
 
-> See the full code example in [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js)
+> Xem ví dụ mã đầy đủ tại [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js)
 
-#### Time Complexity
+#### Độ Phức Tạp Thời Gian
 
-Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`.
+Vì thuật toán chỉ yêu cầu một lần duyệt qua mảng giá, do đó độ phức tạp thời gian sẽ bằng `O(n)`.
 
-#### Additional Space Complexity
+#### Độ Phức Tạp Không Gian Bổ Sung
 
-Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`.
+Ngoài mảng giá chính nó, thuật toán chỉ tiêu thụ một lượng bộ nhớ cố định. Do đó, độ phức tạp không gian bổ sung là `O(1)`.
 
-## References
+## Tham Khảo
 
-- [Best Time to Buy and Sell Stock on LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
+- [Thời Điểm Tốt Nhất để Mua và Bán Cổ Phiếu trên LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
diff --git a/src/algorithms/uncategorized/hanoi-tower/README.en-EN.md b/src/algorithms/uncategorized/hanoi-tower/README.en-EN.md
new file mode 100644
index 0000000000..43a7f27ab4
--- /dev/null
+++ b/src/algorithms/uncategorized/hanoi-tower/README.en-EN.md
@@ -0,0 +1,32 @@
+# Tower of Hanoi
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The Tower of Hanoi (also called the Tower of Brahma or Lucas'
+Tower and sometimes pluralized) is a mathematical game or puzzle.
+It consists of three rods and a number of disks of different sizes,
+which can slide onto any rod. The puzzle starts with the disks in
+a neat stack in ascending order of size on one rod, the smallest
+at the top, thus making a conical shape.
+
+The objective of the puzzle is to move the entire stack to another
+rod, obeying the following simple rules:
+
+- Only one disk can be moved at a time.
+- Each move consists of taking the upper disk from one of the
+  stacks and placing it on top of another stack or on an empty rod.
+- No disk may be placed on top of a smaller disk.
+
+![Hanoi Tower](https://upload.wikimedia.org/wikipedia/commons/8/8d/Iterative_algorithm_solving_a_6_disks_Tower_of_Hanoi.gif)
+
+Animation of an iterative algorithm solving 6-disk problem
+
+With `3` disks, the puzzle can be solved in `7` moves. The minimal
+number of moves required to solve a Tower of Hanoi puzzle
+is `2^n − 1`, where `n` is the number of disks.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Tower_of_Hanoi)
+- [HackerEarth](https://www.hackerearth.com/blog/algorithms/tower-hanoi-recursion-game-algorithm-explained/)
diff --git a/src/algorithms/uncategorized/hanoi-tower/README.md b/src/algorithms/uncategorized/hanoi-tower/README.md
index 816df8d3d6..04a3c1cde0 100644
--- a/src/algorithms/uncategorized/hanoi-tower/README.md
+++ b/src/algorithms/uncategorized/hanoi-tower/README.md
@@ -1,29 +1,27 @@
-# Tower of Hanoi
+# Tháp Hà Nội
 
-The Tower of Hanoi (also called the Tower of Brahma or Lucas'
-Tower and sometimes pluralized) is a mathematical game or puzzle. 
-It consists of three rods and a number of disks of different sizes,
-which can slide onto any rod. The puzzle starts with the disks in 
-a neat stack in ascending order of size on one rod, the smallest 
-at the top, thus making a conical shape.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The objective of the puzzle is to move the entire stack to another 
-rod, obeying the following simple rules:
+Tháp Hà Nội (cũng được gọi là Tháp Brahma hoặc Tháp Lucas và đôi khi được sử dụng số ít) là một trò chơi hoặc bài toán toán học.
+Nó bao gồm ba thanh và một số đĩa có kích thước khác nhau,
+có thể trượt lên bất kỳ thanh nào. Bài toán bắt đầu với các đĩa được xếp gọn theo thứ tự tăng dần về kích thước trên một thanh, với đĩa nhỏ nhất ở trên cùng, tạo thành một hình nón.
 
-- Only one disk can be moved at a time.
-- Each move consists of taking the upper disk from one of the 
-stacks and placing it on top of another stack or on an empty rod.
-- No disk may be placed on top of a smaller disk.
+Mục tiêu của bài toán là di chuyển toàn bộ các đĩa sang một thanh khác,
+tuân theo các quy tắc đơn giản sau đây:
 
-![Hanoi Tower](https://upload.wikimedia.org/wikipedia/commons/8/8d/Iterative_algorithm_solving_a_6_disks_Tower_of_Hanoi.gif)
+- Chỉ có thể di chuyển một đĩa mỗi lần.
+- Mỗi lần di chuyển bao gồm việc lấy đĩa trên cùng từ một trong các thanh và đặt nó lên trên đỉnh của một thanh khác hoặc trên một thanh trống.
+- Không có đĩa nào được đặt lên trên đĩa nhỏ hơn.
 
-Animation of an iterative algorithm solving 6-disk problem
+![Tháp Hà Nội](https://upload.wikimedia.org/wikipedia/commons/8/8d/Iterative_algorithm_solving_a_6_disks_Tower_of_Hanoi.gif)
 
-With `3` disks, the puzzle can be solved in `7` moves. The minimal 
-number of moves required to solve a Tower of Hanoi puzzle 
-is `2^n − 1`, where `n` is the number of disks.
+Phim hoạt hình của một thuật toán lặp giải quyết bài toán với 6 đĩa
 
-## References
+Với `3` đĩa, bài toán có thể giải quyết trong `7` bước. Số lần di chuyển tối thiểu cần thiết để giải quyết bài toán Tháp Hà Nội
+là `2^n - 1`, trong đó `n` là số đĩa.
+
+## Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Tower_of_Hanoi)
 - [HackerEarth](https://www.hackerearth.com/blog/algorithms/tower-hanoi-recursion-game-algorithm-explained/)
diff --git a/src/algorithms/uncategorized/jump-game/README.en-EN.md b/src/algorithms/uncategorized/jump-game/README.en-EN.md
new file mode 100644
index 0000000000..aafa8efb90
--- /dev/null
+++ b/src/algorithms/uncategorized/jump-game/README.en-EN.md
@@ -0,0 +1,131 @@
+# Jump Game
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## The Problem
+
+Given an array of non-negative integers, you are initially positioned at
+the first index of the array. Each element in the array represents your maximum
+jump length at that position.
+
+Determine if you are able to reach the last index.
+
+**Example #1**
+
+```
+Input: [2,3,1,1,4]
+Output: true
+Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
+```
+
+**Example #2**
+
+```
+Input: [3,2,1,0,4]
+Output: false
+Explanation: You will always arrive at index 3 no matter what. Its maximum
+             jump length is 0, which makes it impossible to reach the last index.
+```
+
+## Naming
+
+We call a position in the array a **"good index"** if starting at that position,
+we can reach the last index. Otherwise, that index is called a **"bad index"**.
+The problem then reduces to whether or not index 0 is a "good index".
+
+## Solutions
+
+### Approach 1: Backtracking
+
+This is the inefficient solution where we try every single jump pattern that
+takes us from the first position to the last. We start from the first position
+and jump to every index that is reachable. We repeat the process until last
+index is reached. When stuck, backtrack.
+
+> See [backtrackingJumpGame.js](backtrackingJumpGame.js) file
+
+**Time complexity:**: `O(2^n)`.
+There are 2<sup>n</sup> (upper bound) ways of jumping from
+the first position to the last, where `n` is the length of
+array `nums`.
+
+**Auxiliary Space Complexity**: `O(n)`.
+Recursion requires additional memory for the stack frames.
+
+### Approach 2: Dynamic Programming Top-down
+
+Top-down Dynamic Programming can be thought of as optimized
+backtracking. It relies on the observation that once we determine
+that a certain index is good / bad, this result will never change.
+This means that we can store the result and not need to recompute
+it every time.
+
+Therefore, for each position in the array, we remember whether the
+index is good or bad. Let's call this array memo and let its values
+be either one of: GOOD, BAD, UNKNOWN. This technique is
+called memoization.
+
+> See [dpTopDownJumpGame.js](dpTopDownJumpGame.js) file
+
+**Time complexity:**: `O(n^2)`.
+For every element in the array, say `i`, we are looking at the
+next `nums[i]` elements to its right aiming to find a GOOD
+index. `nums[i]` can be at most `n`, where `n` is the length
+of array `nums`.
+
+**Auxiliary Space Complexity**: `O(2 * n) = O(n)`.
+First `n` originates from recursion. Second `n` comes from the
+usage of the memo table.
+
+### Approach 3: Dynamic Programming Bottom-up
+
+Top-down to bottom-up conversion is done by eliminating recursion.
+In practice, this achieves better performance as we no longer have the
+method stack overhead and might even benefit from some caching. More
+importantly, this step opens up possibilities for future optimization.
+The recursion is usually eliminated by trying to reverse the order of
+the steps from the top-down approach.
+
+The observation to make here is that we only ever jump to the right.
+This means that if we start from the right of the array, every time
+we will query a position to our right, that position has already be
+determined as being GOOD or BAD. This means we don't need to recurse
+anymore, as we will always hit the memo table.
+
+> See [dpBottomUpJumpGame.js](dpBottomUpJumpGame.js) file
+
+**Time complexity:**: `O(n^2)`.
+For every element in the array, say `i`, we are looking at the
+next `nums[i]` elements to its right aiming to find a GOOD
+index. `nums[i]` can be at most `n`, where `n` is the length
+of array `nums`.
+
+**Auxiliary Space Complexity**: `O(n)`.
+This comes from the usage of the memo table.
+
+### Approach 4: Greedy
+
+Once we have our code in the bottom-up state, we can make one final,
+important observation. From a given position, when we try to see if
+we can jump to a GOOD position, we only ever use one - the first one.
+In other words, the left-most one. If we keep track of this left-most
+GOOD position as a separate variable, we can avoid searching for it in
+the array. Not only that, but we can stop using the array altogether.
+
+> See [greedyJumpGame.js](greedyJumpGame.js) file
+
+**Time complexity:**: `O(n)`.
+We are doing a single pass through the `nums` array, hence `n` steps,
+where `n` is the length of array `nums`.
+
+**Auxiliary Space Complexity**: `O(1)`.
+We are not using any extra memory.
+
+## References
+
+- [Jump Game Fully Explained on LeetCode](https://leetcode.com/articles/jump-game/)
+- [Dynamic Programming vs Divide and Conquer](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe)
+- [Dynamic Programming](https://en.wikipedia.org/wiki/Dynamic_programming)
+- [Memoization on Wikipedia](https://en.wikipedia.org/wiki/Memoization)
+- [Top-Down and Bottom-Up Design on Wikipedia](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design)
diff --git a/src/algorithms/uncategorized/jump-game/README.md b/src/algorithms/uncategorized/jump-game/README.md
index fc8c713e3e..fcecda5646 100644
--- a/src/algorithms/uncategorized/jump-game/README.md
+++ b/src/algorithms/uncategorized/jump-game/README.md
@@ -1,128 +1,107 @@
-# Jump Game
+# Bước Nhảy
 
-## The Problem
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Given an array of non-negative integers, you are initially positioned at 
-the first index of the array. Each element in the array represents your maximum 
-jump length at that position.
+## Bài Toán
 
-Determine if you are able to reach the last index.
+Cho một mảng các số nguyên không âm, ban đầu bạn đứng ở
+chỉ mục đầu tiên của mảng. Mỗi phần tử trong mảng đại diện cho
+độ dài bước nhảy tối đa của bạn tại vị trí đó.
 
-**Example #1**
+Xác định xem bạn có thể đạt được chỉ mục cuối cùng không.
+
+**Ví dụ #1**
 
 ```
 Input: [2,3,1,1,4]
 Output: true
-Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
+Giải thích: Nhảy 1 bước từ chỉ mục 0 đến 1, sau đó 3 bước đến chỉ mục cuối cùng.
 ```
 
-**Example #2**
+**Ví dụ #2**
 
 ```
 Input: [3,2,1,0,4]
 Output: false
-Explanation: You will always arrive at index 3 no matter what. Its maximum
-             jump length is 0, which makes it impossible to reach the last index.
+Giải thích: Bạn luôn đến chỉ mục 3 dù cho điều gì. Độ dài bước nhảy tối đa là 0, điều này khiến cho việc đạt được chỉ mục cuối cùng là không thể.
 ```
 
-## Naming
+## Đặt Tên
+
+Chúng tôi gọi một vị trí trong mảng là **"chỉ mục tốt"** nếu bắt đầu từ vị trí đó,
+chúng ta có thể đạt được chỉ mục cuối cùng. Ngược lại, chỉ mục đó được gọi là **"chỉ mục xấu"**.
+Vấn đề sau đó thu gọn lại là xem chỉ mục 0 có phải là "chỉ mục tốt" không.
 
-We call a position in the array a **"good index"** if starting at that position,
-we can reach the last index. Otherwise, that index is called a **"bad index"**.
-The problem then reduces to whether or not index 0 is a "good index".
+## Các Giải Pháp
 
-## Solutions
+### Phương Pháp 1: Quay Lại (Backtracking)
 
-### Approach 1: Backtracking
+Đây là phương pháp không hiệu quả nơi chúng ta thử mọi cách nhảy từ
+vị trí đầu tiên đến cuối cùng. Chúng ta bắt đầu từ vị trí đầu tiên
+và nhảy đến mỗi chỉ mục có thể đạt được. Chúng ta lặp lại quá trình cho đến khi cuối
+chỉ mục cuối cùng được đạt. Khi bị kẹt, quay lại.
 
-This is the inefficient solution where we try every single jump pattern that 
-takes us from the first position to the last. We start from the first position 
-and jump to every index that is reachable. We repeat the process until last 
-index is reached. When stuck, backtrack.
+> Xem tập tin [backtrackingJumpGame.js](backtrackingJumpGame.js)
 
-> See [backtrackingJumpGame.js](backtrackingJumpGame.js) file
+**Độ phức tạp thời gian:** `O(2^n)`.
+Có 2<sup>n</sup> (giới hạn trên) cách nhảy từ vị trí đầu tiên đến
+cuối cùng, nơi `n` là độ dài của mảng `nums`.
 
-**Time complexity:**: `O(2^n)`.
-There are 2<sup>n</sup> (upper bound) ways of jumping from 
-the first position to the last, where `n` is the length of 
-array `nums`.
+**Độ phức tạp không gian phụ**: `O(n)`.
+Đệ quy yêu cầu bộ nhớ bổ sung cho các khung ngăn xếp.
 
-**Auxiliary Space Complexity**: `O(n)`.
-Recursion requires additional memory for the stack frames.
+### Phương Pháp 2: Quy Hoạch Động Trên Xuống (Dynamic Programming Top-down)
 
-### Approach 2: Dynamic Programming Top-down
+Quy hoạch động trên xuống có thể được coi là quay lại tối ưu hóa.
+Nó dựa trên quan sát rằng một khi chúng ta xác định
+rằng một chỉ mục nhất định là tốt / xấu, kết quả này sẽ không bao giờ thay đổi.
+Điều này có nghĩa là chúng ta có thể lưu kết quả và không cần phải tính toán lại
+nó mỗi lần.
 
-Top-down Dynamic Programming can be thought of as optimized 
-backtracking. It relies on the observation that once we determine 
-that a certain index is good / bad, this result will never change.
-This means that we can store the result and not need to recompute
-it every time.
+Do đó, đối với mỗi vị trí trong mảng, chúng ta nhớ xem chỉ mục đó có tốt hay xấu không. Hãy gọi mảng này là bảng nhớ và để giá trị của nó là một trong các giá trị sau: GOOD, BAD, UNKNOWN. Kỹ thuật này được gọi là memoization (ghi nhớ).
 
-Therefore, for each position in the array, we remember whether the 
-index is good or bad. Let's call this array memo and let its values
-be either one of: GOOD, BAD, UNKNOWN. This technique is 
-called memoization.
+> Xem tập tin [dpTopDownJumpGame.js](dpTopDownJumpGame.js)
 
-> See [dpTopDownJumpGame.js](dpTopDownJumpGame.js) file
+**Độ phức tạp thời gian:** `O(n^2)`.
+Đối với mỗi phần tử trong mảng, nói `i`, chúng ta đang xem xét
+các phần tử `nums[i]` tiếp theo ở bên phải mục tiêu là tìm chỉ mục tốt. `nums[i]` có thể là tối đa `n`, nơi `n` là độ dài của mảng `nums`.
 
-**Time complexity:**: `O(n^2)`.
-For every element in the array, say `i`, we are looking at the 
-next `nums[i]` elements to its right aiming to find a GOOD
-index. `nums[i]` can be at most `n`, where `n` is the length 
-of array `nums`.
+**Độ phức tạp không gian phụ**: `O(2 * n) = O(n)`.
+Đầu tiên `n` xuất phát từ đệ quy. Thứ hai `n` xuất phát từ việc sử dụng bảng memo.
 
-**Auxiliary Space Complexity**: `O(2 * n) = O(n)`.
-First `n` originates from recursion. Second `n` comes from the 
-usage of the memo table.
+### Phương Pháp 3: Quy Hoạch Động Dưới Lên (Dynamic Programming Bottom-up)
 
-### Approach 3: Dynamic Programming Bottom-up
+Chuyển từ trên xuống sang dưới được thực hiện bằng cách loại bỏ đệ quy. Trong thực tế, điều này đạt được hiệu suất tốt hơn vì chúng ta không còn bị ảnh hưởng bởi overhead ngăn xếp phương thức và thậm chí còn có thể tận dụng một số bộ nhớ cache. Quan trọng hơn, bước này mở ra các cơ hội tối ưu hóa trong tương lai. Đệ quy thường được loại bỏ bằng cách cố gắng đảo ngược thứ tự các bước từ phương pháp trên xuống.
 
-Top-down to bottom-up conversion is done by eliminating recursion. 
-In practice, this achieves better performance as we no longer have the 
-method stack overhead and might even benefit from some caching. More 
-importantly, this step opens up possibilities for future optimization.
-The recursion is usually eliminated by trying to reverse the order of 
-the steps from the top-down approach.
+Quan sát phải là chúng ta chỉ nhảy sang phải. Điều này có nghĩa là nếu chúng ta bắt đầu từ phải của mảng, mỗi khi chúng ta truy vấn một vị trí sang phải của chúng ta, vị trí đó đã được xác định là tốt hoặc xấu. Điều này có nghĩa là chúng ta không cần phải đệ quy nữa, vì chúng ta luôn sẽ đạt được bảng nhớ.
 
-The observation to make here is that we only ever jump to the right.
-This means that if we start from the right of the array, every time 
-we will query a position to our right, that position has already be
-determined as being GOOD or BAD. This means we don't need to recurse
-anymore, as we will always hit the memo table.
+> Xem tập tin [dpBottomUpJumpGame.js](dpBottomUpJumpGame.js)
 
-> See [dpBottomUpJumpGame.js](dpBottomUpJumpGame.js) file
+**Độ phức tạp thời gian:** `O(n^2)`.
+Đối với mỗi phần tử trong mảng, nói `i`, chúng ta đang xem xét
+các phần tử `nums[i]` tiếp theo ở bên phải mục tiêu là tìm chỉ mục tốt. `nums[i]` có thể là tối đa `n`, nơi `n` là độ dài của mảng `nums`.
 
-**Time complexity:**: `O(n^2)`.
-For every element in the array, say `i`, we are looking at the 
-next `nums[i]` elements to its right aiming to find a GOOD
-index. `nums[i]` can be at most `n`, where `n` is the length 
-of array `nums`.
+**Độ phức tạp không gian phụ**: `O(n)`.
+Điều này đến từ việc sử dụng bảng memo.
 
-**Auxiliary Space Complexity**: `O(n)`.
-This comes from the usage of the memo table.
- 
-### Approach 4: Greedy
+### Phương Pháp 4: Tham Lam (Greedy)
 
-Once we have our code in the bottom-up state, we can make one final,
-important observation. From a given position, when we try to see if
-we can jump to a GOOD position, we only ever use one - the first one.
-In other words, the left-most one. If we keep track of this left-most
-GOOD position as a separate variable, we can avoid searching for it in
-the array. Not only that, but we can stop using the array altogether.
+Khi chúng ta có mã của mình ở trạng thái từ dưới lên, chúng ta có thể thực hiện một quan sát cuối cùng, quan trọng. Từ một vị trí đã cho, khi chúng ta cố gắng xem liệu chúng ta có thể nhảy đến một vị trí TỐT, chúng ta chỉ sử dụng một vị trí - vị trí đầu tiên. Nói cách khác, vị trí cách xa bên trái. Nếu chúng ta tiếp tục theo dõi vị trí TỐT cách xa bên trái như một biến riêng biệt, chúng ta có thể tránh việc tìm kiếm nó trong mảng. Không chỉ vậy, nhưng chúng ta có thể dừng việc sử dụng mảng hoàn toàn.
 
-> See [greedyJumpGame.js](greedyJumpGame.js) file
+> Xem tập tin [greedyJumpGame.js](greedyJumpGame.js)
 
-**Time complexity:**: `O(n)`.
-We are doing a single pass through the `nums` array, hence `n` steps,
-where `n` is the length of array `nums`.
+**Độ phức tạp thời gian:** `O(n)`.
+Chúng tôi thực hiện một lượt qua mảng `nums`, do đó có `n` bước,
+nơi `n` là độ dài của mảng `nums`.
 
-**Auxiliary Space Complexity**: `O(1)`.
-We are not using any extra memory.
+**Độ phức tạp không gian phụ**: `O(1)`.
+Chúng tôi không sử dụng bất kỳ bộ nhớ phụ nào.
 
-## References
+## Tham Khảo
 
-- [Jump Game Fully Explained on LeetCode](https://leetcode.com/articles/jump-game/)
+- [Jump Game Fully Explained trên LeetCode](https://leetcode.com/articles/jump-game/)
 - [Dynamic Programming vs Divide and Conquer](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe)
-- [Dynamic Programming](https://en.wikipedia.org/wiki/Dynamic_programming)
-- [Memoization on Wikipedia](https://en.wikipedia.org/wiki/Memoization)
-- [Top-Down and Bottom-Up Design on Wikipedia](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design)
+- [Quy Hoạch Động](https://en.wikipedia.org/wiki/Dynamic_programming)
+- [Memoization trên Wikipedia](https://en.wikipedia.org/wiki/Memoization)
+- [Thiết Kế Từ Trên Xuống và Từ Dưới Lên trên Wikipedia](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design)
diff --git a/src/algorithms/uncategorized/knight-tour/README.en-EN.md b/src/algorithms/uncategorized/knight-tour/README.en-EN.md
new file mode 100644
index 0000000000..d72e5e0bcf
--- /dev/null
+++ b/src/algorithms/uncategorized/knight-tour/README.en-EN.md
@@ -0,0 +1,36 @@
+# Knight's Tour
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **knight's tour** is a sequence of moves of a knight on a chessboard
+such that the knight visits every square only once. If the knight
+ends on a square that is one knight's move from the beginning
+square (so that it could tour the board again immediately,
+following the same path), the tour is **closed**, otherwise it
+is **open**.
+
+The **knight's tour problem** is the mathematical problem of
+finding a knight's tour. Creating a program to find a knight's
+tour is a common problem given to computer science students.
+Variations of the knight's tour problem involve chessboards of
+different sizes than the usual `8×8`, as well as irregular
+(non-rectangular) boards.
+
+The knight's tour problem is an instance of the more
+general **Hamiltonian path problem** in graph theory. The problem of finding
+a closed knight's tour is similarly an instance of the Hamiltonian
+cycle problem.
+
+![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/d/da/Knight%27s_tour_anim_2.gif)
+
+An open knight's tour of a chessboard.
+
+![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/c/ca/Knights-Tour-Animation.gif)
+
+An animation of an open knight's tour on a 5 by 5 board.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Knight%27s_tour)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-1-the-knights-tour-problem/)
diff --git a/src/algorithms/uncategorized/knight-tour/README.md b/src/algorithms/uncategorized/knight-tour/README.md
index 6696b307fb..cc2db539ad 100644
--- a/src/algorithms/uncategorized/knight-tour/README.md
+++ b/src/algorithms/uncategorized/knight-tour/README.md
@@ -1,33 +1,23 @@
-# Knight's Tour
+# Hành trình của quân mã
 
-A **knight's tour** is a sequence of moves of a knight on a chessboard 
-such that the knight visits every square only once. If the knight 
-ends on a square that is one knight's move from the beginning 
-square (so that it could tour the board again immediately, 
-following the same path), the tour is **closed**, otherwise it 
-is **open**.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The **knight's tour problem** is the mathematical problem of 
-finding a knight's tour. Creating a program to find a knight's 
-tour is a common problem given to computer science students.
-Variations of the knight's tour problem involve chessboards of 
-different sizes than the usual `8×8`, as well as irregular 
-(non-rectangular) boards.
+Một **hành trình của quân mã** là một chuỗi các nước đi của một quân mã trên bàn cờ cờ vua sao cho quân mã ghé qua mỗi ô chỉ một lần. Nếu quân mã kết thúc trên một ô mà chỉ cách ô ban đầu một nước đi của quân mã (vì vậy nó có thể thăm bàn cờ lại ngay lập tức, theo cùng một con đường), thì hành trình đó là **đóng**, nếu không thì nó là **mở**.
 
-The knight's tour problem is an instance of the more 
-general **Hamiltonian path problem** in graph theory. The problem of finding 
-a closed knight's tour is similarly an instance of the Hamiltonian 
-cycle problem.
+**Vấn đề hành trình của quân mã** là vấn đề toán học của việc tìm một hành trình của quân mã. Việc tạo ra một chương trình để tìm một hành trình của quân mã là một vấn đề phổ biến được giao cho sinh viên khoa học máy tính. Các biến thể của vấn đề hành trình của quân mã liên quan đến các bàn cờ vua có kích thước khác so với kích thước thông thường là `8×8`, cũng như các bảng không đều (không hình chữ nhật).
 
-![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/d/da/Knight%27s_tour_anim_2.gif)
+Vấn đề hành trình của quân mã là một trường hợp của vấn đề **đường đi Hamiltonian** trong lý thuyết đồ thị. Vấn đề tìm một hành trình đóng của quân mã cũng tương tự như vấn đề chu trình Hamiltonian.
 
-An open knight's tour of a chessboard.
+![Hành trình của quân mã](https://upload.wikimedia.org/wikipedia/commons/d/da/Knight%27s_tour_anim_2.gif)
 
-![Knight's Tour](https://upload.wikimedia.org/wikipedia/commons/c/ca/Knights-Tour-Animation.gif)
+Một hành trình mở của quân mã trên bàn cờ vua.
 
-An animation of an open knight's tour on a 5 by 5 board.
+![Hành trình của quân mã](https://upload.wikimedia.org/wikipedia/commons/c/ca/Knights-Tour-Animation.gif)
 
-## References
+Một đoạn animation của một hành trình mở của quân mã trên bàn cờ kích thước `5×5`.
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Knight%27s_tour)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-1-the-knights-tour-problem/)
diff --git a/src/algorithms/uncategorized/n-queens/README.en-EN.md b/src/algorithms/uncategorized/n-queens/README.en-EN.md
new file mode 100644
index 0000000000..8dd03e1833
--- /dev/null
+++ b/src/algorithms/uncategorized/n-queens/README.en-EN.md
@@ -0,0 +1,120 @@
+# N-Queens Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+The **eight queens puzzle** is the problem of placing eight chess queens
+on an `8×8` chessboard so that no two queens threaten each other.
+Thus, a solution requires that no two queens share the same row,
+column, or diagonal. The eight queens puzzle is an example of the
+more general _n queens problem_ of placing n non-attacking queens
+on an `n×n` chessboard, for which solutions exist for all natural
+numbers `n` with the exception of `n=2` and `n=3`.
+
+For example, following is a solution for 4 Queen problem.
+
+![N Queens](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/N_Queen_Problem.jpg)
+
+The expected output is a binary matrix which has 1s for the blocks
+where queens are placed. For example following is the output matrix
+for above 4 queen solution.
+
+```
+{ 0,  1,  0,  0}
+{ 0,  0,  0,  1}
+{ 1,  0,  0,  0}
+{ 0,  0,  1,  0}
+```
+
+## Naive Algorithm
+
+Generate all possible configurations of queens on board and print a
+configuration that satisfies the given constraints.
+
+```
+while there are untried configurations
+{
+   generate the next configuration
+   if queens don't attack in this configuration then
+   {
+      print this configuration;
+   }
+}
+```
+
+## Backtracking Algorithm
+
+The idea is to place queens one by one in different columns,
+starting from the leftmost column. When we place a queen in a
+column, we check for clashes with already placed queens. In
+the current column, if we find a row for which there is no
+clash, we mark this row and column as part of the solution.
+If we do not find such a row due to clashes then we backtrack
+and return false.
+
+```
+1) Start in the leftmost column
+2) If all queens are placed
+    return true
+3) Try all rows in the current column.  Do following for every tried row.
+    a) If the queen can be placed safely in this row then mark this [row,
+        column] as part of the solution and recursively check if placing
+        queen here leads to a solution.
+    b) If placing queen in [row, column] leads to a solution then return
+        true.
+    c) If placing queen doesn't lead to a solution then umark this [row,
+        column] (Backtrack) and go to step (a) to try other rows.
+3) If all rows have been tried and nothing worked, return false to trigger
+    backtracking.
+```
+
+## Bitwise Solution
+
+Bitwise algorithm basically approaches the problem like this:
+
+- Queens can attack diagonally, vertically, or horizontally. As a result, there
+  can only be one queen in each row, one in each column, and at most one on each
+  diagonal.
+- Since we know there can only one queen per row, we will start at the first row,
+  place a queen, then move to the second row, place a second queen, and so on until
+  either a) we reach a valid solution or b) we reach a dead end (ie. we can't place
+  a queen such that it is "safe" from the other queens).
+- Since we are only placing one queen per row, we don't need to worry about
+  horizontal attacks, since no queen will ever be on the same row as another queen.
+- That means we only need to check three things before placing a queen on a
+  certain square: 1) The square's column doesn't have any other queens on it, 2)
+  the square's left diagonal doesn't have any other queens on it, and 3) the
+  square's right diagonal doesn't have any other queens on it.
+- If we ever reach a point where there is nowhere safe to place a queen, we can
+  give up on our current attempt and immediately test out the next possibility.
+
+First let's talk about the recursive function. You'll notice that it accepts
+3 parameters: `leftDiagonal`, `column`, and `rightDiagonal`. Each of these is
+technically an integer, but the algorithm takes advantage of the fact that an
+integer is represented by a sequence of bits. So, think of each of these
+parameters as a sequence of `N` bits.
+
+Each bit in each of the parameters represents whether the corresponding location
+on the current row is "available".
+
+For example:
+
+- For `N=4`, column having a value of `0010` would mean that the 3rd column is
+  already occupied by a queen.
+- For `N=8`, ld having a value of `00011000` at row 5 would mean that the
+  top-left-to-bottom-right diagonals that pass through columns 4 and 5 of that
+  row are already occupied by queens.
+
+Below is a visual aid for `leftDiagonal`, `column`, and `rightDiagonal`.
+
+![](http://gregtrowbridge.com/content/images/2014/Jul/Screenshot-from-2014-06-17-19-46-20.png)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-3-n-queen-problem/)
+- [On YouTube by Abdul Bari](https://www.youtube.com/watch?v=xFv_Hl4B83A&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=xouin83ebxE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- Bitwise Solution
+  - [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
+  - [Solution by Greg Trowbridge](http://gregtrowbridge.com/a-bitwise-solution-to-the-n-queens-problem-in-javascript/)
diff --git a/src/algorithms/uncategorized/n-queens/README.md b/src/algorithms/uncategorized/n-queens/README.md
index 077e26d73d..6bfdaad154 100644
--- a/src/algorithms/uncategorized/n-queens/README.md
+++ b/src/algorithms/uncategorized/n-queens/README.md
@@ -1,20 +1,15 @@
-# N-Queens Problem
+# Vấn đề N Hậu
 
-The **eight queens puzzle** is the problem of placing eight chess queens 
-on an `8×8` chessboard so that no two queens threaten each other. 
-Thus, a solution requires that no two queens share the same row, 
-column, or diagonal. The eight queens puzzle is an example of the 
-more general *n queens problem* of placing n non-attacking queens 
-on an `n×n` chessboard, for which solutions exist for all natural 
-numbers `n` with the exception of `n=2` and `n=3`.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-For example, following is a solution for 4 Queen problem.
+**Bài toán bát quân hậu** là bài toán về việc đặt tám quân hậu trên một bàn cờ vua `8×8` sao cho không có hai quân hậu nào đe dọa nhau. Do đó, một giải pháp yêu cầu không có hai quân hậu nào chia sẻ cùng một hàng, cột hoặc đường chéo. Bài toán bát quân hậu là một ví dụ của **bài toán n quân hậu** tổng quát hơn, trong đó đặt n quân hậu không đe dọa lẫn nhau trên một bàn cờ vua `n×n`, và giải pháp tồn tại cho tất cả các số tự nhiên `n` ngoại trừ `n=2` và `n=3`.
+
+Ví dụ, dưới đây là một giải pháp cho bài toán 4 Quân hậu.
 
 ![N Queens](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/N_Queen_Problem.jpg)
 
-The expected output is a binary matrix which has 1s for the blocks 
-where queens are placed. For example following is the output matrix 
-for above 4 queen solution.
+Kết quả mong đợi là một ma trận nhị phân có giá trị 1 cho các ô mà quân hậu được đặt. Ví dụ sau đây là ma trận kết quả cho giải pháp 4 quân hậu ở trên.
 
 ```
 { 0,  1,  0,  0}
@@ -23,95 +18,65 @@ for above 4 queen solution.
 { 0,  0,  1,  0}
 ```
 
-## Naive Algorithm
+## Thuật toán Ngu Naïve
 
-Generate all possible configurations of queens on board and print a 
-configuration that satisfies the given constraints.
+Tạo tất cả các cấu hình có thể của quân hậu trên bàn cờ và in ra một cấu hình thỏa mãn các ràng buộc đã cho.
 
 ```
-while there are untried configurations
+khi còn các cấu hình chưa thử
 {
-   generate the next configuration
-   if queens don't attack in this configuration then
+   tạo cấu hình tiếp theo
+   nếu các quân hậu không đe dọa trong cấu hình này thì
    {
-      print this configuration;
+      in ra cấu hình này;
    }
 }
 ```
 
-## Backtracking Algorithm
+## Thuật toán Backtracking
 
-The idea is to place queens one by one in different columns, 
-starting from the leftmost column. When we place a queen in a 
-column, we check for clashes with already placed queens. In 
-the current column, if we find a row for which there is no 
-clash, we mark this row and column as part of the solution. 
-If we do not find such a row due to clashes then we backtrack 
-and return false.
+Ý tưởng là đặt các quân hậu một cách tuần tự trong các cột khác nhau, bắt đầu từ cột trái nhất. Khi chúng ta đặt một quân hậu trong một cột, chúng ta kiểm tra xem có xung đột với các quân hậu đã đặt trước đó không. Trong cột hiện tại, nếu chúng ta tìm thấy một hàng mà không có xung đột, chúng ta đánh dấu hàng và cột này là một phần của giải pháp. Nếu chúng ta không tìm thấy hàng đó do xung đột, chúng ta quay lại và trả về giá trị sai.
 
 ```
-1) Start in the leftmost column
-2) If all queens are placed
-    return true
-3) Try all rows in the current column.  Do following for every tried row.
-    a) If the queen can be placed safely in this row then mark this [row, 
-        column] as part of the solution and recursively check if placing  
-        queen here leads to a solution.
-    b) If placing queen in [row, column] leads to a solution then return 
-        true.
-    c) If placing queen doesn't lead to a solution then umark this [row, 
-        column] (Backtrack) and go to step (a) to try other rows.
-3) If all rows have been tried and nothing worked, return false to trigger 
-    backtracking.
+1) Bắt đầu từ cột trái nhất
+2) Nếu tất cả quân hậu đã được đặt trả về true
+3) Thử tất cả các hàng trong cột hiện tại. Làm theo mỗi hàng đã thử.
+    a) Nếu quân hậu có thể được đặt an toàn trong hàng này thì đánh dấu [hàng, cột] này là một phần của giải pháp và kiểm tra đệ quy xem việc đặt quân hậu ở đây dẫn đến một giải pháp hay không.
+    b) Nếu việc đặt quân hậu ở [hàng, cột] dẫn đến một giải pháp thì trả về true.
+    c) Nếu việc đặt quân hậu không dẫn đến một giải pháp thì hủy đánh dấu [hàng, cột] này (Backtrack) và đi đến bước (a) để thử các hàng khác.
+3) Nếu tất cả các hàng đã được thử và không có gì hoạt động, trả về false để kích
+    hoạt quay lại.
 ```
 
-## Bitwise Solution
-
-Bitwise algorithm basically approaches the problem like this:
-
-- Queens can attack diagonally, vertically, or horizontally. As a result, there 
-can only be one queen in each row, one in each column, and at most one on each 
-diagonal.
-- Since we know there can only one queen per row, we will start at the first row,
-place a queen, then move to the second row, place a second queen, and so on until
-either a) we reach a valid solution or b) we reach a dead end (ie. we can't place
-a queen such that it is "safe" from the other queens).
-- Since we are only placing one queen per row, we don't need to worry about
-horizontal attacks, since no queen will ever be on the same row as another queen.
-- That means we only need to check three things before placing a queen on a
-certain square: 1) The square's column doesn't have any other queens on it, 2)
-the square's left diagonal doesn't have any other queens on it, and 3) the
-square's right diagonal doesn't have any other queens on it.
-- If we ever reach a point where there is nowhere safe to place a queen, we can
-give up on our current attempt and immediately test out the next possibility.
-
-First let's talk about the recursive function. You'll notice that it accepts 
-3 parameters: `leftDiagonal`, `column`, and `rightDiagonal`. Each of these is 
-technically an integer, but the algorithm takes advantage of the fact that an 
-integer is represented by a sequence of bits. So, think of each of these 
-parameters as a sequence of `N` bits.
-
-Each bit in each of the parameters represents whether the corresponding location
-on the current row is "available".
-
-For example:
-- For `N=4`, column having a value of `0010` would mean that the 3rd column is 
-already occupied by a queen.
-- For `N=8`, ld having a value of `00011000` at row 5 would mean that the 
-top-left-to-bottom-right diagonals that pass through columns 4 and 5 of that 
-row are already occupied by queens.
-
-Below is a visual aid for `leftDiagonal`, `column`, and `rightDiagonal`.
+## Giải Pháp Bitwise
+
+Thuật toán bitwise cơ bản tiếp cận vấn đề như sau:
+
+- Quân hậu có thể đe dọa theo đường chéo, dọc hoặc ngang. Do đó, chỉ có thể có một quân hậu trong mỗi hàng, một trong mỗi cột và tối đa một trong mỗi đường chéo.
+- Vì chúng ta biết chỉ có một quân hậu trên mỗi hàng, chúng ta sẽ bắt đầu ở hàng đầu tiên, đặt một quân hậu, sau đó di chuyển đến hàng thứ hai, đặt quân hậu thứ hai và tiếp tục cho đến khi a) chúng ta đạt được một giải pháp hợp lệ hoặc b) chúng ta đạt đến một thứ tự "tử thua" (tức là chúng ta không thể đặt một quân hậu sao cho nó "an toàn" từ các quân hậu khác).
+- Vì chúng ta chỉ đặt một quân hậu trên mỗi hàng, nên chúng ta không cần phải lo lắng về các cuộc tấn công ngang, vì không có quân hậu nào sẽ bao giờ ở trên cùng một hàng với quân hậu khác.
+- Điều đó có nghĩa là chúng ta chỉ cần kiểm tra ba điều trước khi đặt một quân hậu vào một ô nhất định: 1) Cột của ô đó không có bất kỳ quân hậu nào khác, 2) đường chéo trái của ô đó không có quân hậu nào khác, và 3) đường chéo phải của ô đó không có quân hậu nào khác.
+- Nếu chúng ta bao giờ đạt đến một điểm nơi không có nơi an toàn nào để đặt một quân hậu, chúng ta có thể từ bỏ nỗ lực hiện tại của mình và ngay lập tức thử nghiệm các khả năng tiếp theo.
+
+Trước hết hãy nói về hàm đệ quy. Bạn sẽ nhận thấy rằng nó chấp nhận 3 tham số: `leftDiagonal`, `column`, và `rightDiagonal`. Mỗi tham số này kỹ thuật là một số nguyên, nhưng thuật toán tận dụng việc rằng một số nguyên được biểu diễn bằng một chuỗi bit. Vì vậy, hãy nghĩ về mỗi tham số này như một chuỗi gồm `N` bit.
+
+Mỗi bit trong mỗi tham số này đại diện cho việc ô tương ứng trên hàng hiện tại "có sẵn" hay không.
+
+Ví dụ:
+
+- Với `N=4`, cột có giá trị `0010` sẽ có nghĩa là cột thứ 3 đã bị chiếm bởi một quân hậu.
+- Với `N=8`, ld có giá trị `00011000` tại hàng 5 sẽ có nghĩa là các đường chéo từ trên xuống dưới qua cột 4 và 5 của hàng đó đã bị chiếm bởi quân hậu.
+
+Dưới đây là một hình minh họa cho `leftDiagonal`, `column`, và `rightDiagonal`.
 
 ![](http://gregtrowbridge.com/content/images/2014/Jul/Screenshot-from-2014-06-17-19-46-20.png)
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/backtracking-set-3-n-queen-problem/)
-- [On YouTube by Abdul Bari](https://www.youtube.com/watch?v=xFv_Hl4B83A&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=xouin83ebxE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- Bitwise Solution
+- [Trên YouTube bởi Abdul Bari](https://www.youtube.com/watch?v=xFv_Hl4B83A&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Trên YouTube bởi Tushar Roy](https://www.youtube.com/watch?v=xouin83ebxE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- Giải Pháp Bitwise
   - [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
-  - [Solution by Greg Trowbridge](http://gregtrowbridge.com/a-bitwise-solution-to-the-n-queens-problem-in-javascript/)
-  
+  - [Giải pháp của Greg Trowbridge](http://gregtrowbridge.com/a-bitwise-solution-to-the-n-queens-problem-in-javascript/)
diff --git a/src/algorithms/uncategorized/rain-terraces/README.en-EN.md b/src/algorithms/uncategorized/rain-terraces/README.en-EN.md
new file mode 100644
index 0000000000..ef628ee736
--- /dev/null
+++ b/src/algorithms/uncategorized/rain-terraces/README.en-EN.md
@@ -0,0 +1,125 @@
+# Rain Terraces (Trapping Rain Water) Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+Given an array of non-negative integers representing terraces in an elevation map
+where the width of each bar is `1`, compute how much water it is able to trap
+after raining.
+
+![Rain Terraces](https://www.geeksforgeeks.org/wp-content/uploads/watertrap.png)
+
+## Examples
+
+**Example #1**
+
+```
+Input: arr[] = [2, 0, 2]
+Output: 2
+Structure is like below:
+
+| |
+|_|
+
+We can trap 2 units of water in the middle gap.
+```
+
+**Example #2**
+
+```
+Input: arr[] = [3, 0, 0, 2, 0, 4]
+Output: 10
+Structure is like below:
+
+     |
+|    |
+|  | |
+|__|_|
+
+We can trap "3*2 units" of water between 3 an 2,
+"1 unit" on top of bar 2 and "3 units" between 2
+and 4. See below diagram also.
+```
+
+**Example #3**
+
+```
+Input: arr[] = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
+Output: 6
+Structure is like below:
+
+       |
+   |   || |
+_|_||_||||||
+
+Trap "1 unit" between first 1 and 2, "4 units" between
+first 2 and 3 and "1 unit" between second last 1 and last 2.
+```
+
+## The Algorithm
+
+An element of array can store water if there are higher bars on left and right.
+We can find amount of water to be stored in every element by finding the heights
+of bars on left and right sides. The idea is to compute amount of water that can
+be stored in every element of array. For example, consider the array
+`[3, 0, 0, 2, 0, 4]`, We can trap "3\*2 units" of water between 3 an 2, "1 unit"
+on top of bar 2 and "3 units" between 2 and 4. See below diagram also.
+
+### Approach 1: Brute force
+
+**Intuition**
+
+For each element in the array, we find the maximum level of water it can trap
+after the rain, which is equal to the minimum of maximum height of bars on both
+the sides minus its own height.
+
+**Steps**
+
+- Initialize `answer = 0`
+- Iterate the array from left to right:
+  - Initialize `max_left = 0` and `max_right = 0`
+  - Iterate from the current element to the beginning of array updating: `max_left = max(max_left, height[j])`
+  - Iterate from the current element to the end of array updating: `max_right = max(max_right, height[j])`
+  - Add `min(max_left, max_right) − height[i]` to `answer`
+
+**Complexity Analysis**
+
+Time complexity: `O(n^2)`. For each element of array, we iterate the left and right parts.
+
+Auxiliary space complexity: `O(1)` extra space.
+
+### Approach 2: Dynamic Programming
+
+**Intuition**
+
+In brute force, we iterate over the left and right parts again and again just to
+find the highest bar size up to that index. But, this could be stored. Voila,
+dynamic programming.
+
+So we may pre-compute highest bar on left and right of every bar in `O(n)` time.
+Then use these pre-computed values to find the amount of water in every array element.
+
+The concept is illustrated as shown:
+
+![DP Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/Figures/42/trapping_rain_water.png)
+
+**Steps**
+
+- Find maximum height of bar from the left end up to an index `i` in the array `left_max`.
+- Find maximum height of bar from the right end up to an index `i` in the array `right_max`.
+- Iterate over the `height` array and update `answer`:
+  - Add `min(max_left[i], max_right[i]) − height[i]` to `answer`.
+
+**Complexity Analysis**
+
+Time complexity: `O(n)`. We store the maximum heights upto a point using 2
+iterations of `O(n)` each. We finally update `answer` using the stored
+values in `O(n)`.
+
+Auxiliary space complexity: `O(n)` extra space. Additional space
+for `left_max` and `right_max` arrays than in Approach 1.
+
+## References
+
+- [GeeksForGeeks](https://www.geeksforgeeks.org/trapping-rain-water/)
+- [LeetCode](https://leetcode.com/problems/trapping-rain-water/solution/)
diff --git a/src/algorithms/uncategorized/rain-terraces/README.md b/src/algorithms/uncategorized/rain-terraces/README.md
index cb59346b30..9a58a31629 100644
--- a/src/algorithms/uncategorized/rain-terraces/README.md
+++ b/src/algorithms/uncategorized/rain-terraces/README.md
@@ -1,122 +1,110 @@
-# Rain Terraces (Trapping Rain Water) Problem
+# Bài toán Tận Dụng Nước Mưa (Tính Nước Mưa)
 
-Given an array of non-negative integers representing terraces in an elevation map 
-where the width of each bar is `1`, compute how much water it is able to trap 
-after raining.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Cho một mảng các số nguyên không âm biểu diễn các sân thượng trong một bản đồ độ cao với chiều rộng của mỗi thanh là `1`, tính toán xem sau cơn mưa có thể lấy được bao nhiêu nước.
 
 ![Rain Terraces](https://www.geeksforgeeks.org/wp-content/uploads/watertrap.png)
 
-## Examples
+## Ví dụ
 
-**Example #1**
+**Ví dụ #1**
 
 ```
 Input: arr[] = [2, 0, 2]
 Output: 2
-Structure is like below:
+Cấu trúc như sau:
 
 | |
 |_|
 
-We can trap 2 units of water in the middle gap.
+Chúng ta có thể lấy được 2 đơn vị nước ở khoảng trống giữa.
 ```
 
-**Example #2**
+**Ví dụ #2**
 
 ```
 Input: arr[] = [3, 0, 0, 2, 0, 4]
 Output: 10
-Structure is like below:
+Cấu trúc như sau:
 
      |
 |    |
 |  | |
-|__|_| 
+|__|_|
 
-We can trap "3*2 units" of water between 3 an 2,
-"1 unit" on top of bar 2 and "3 units" between 2 
-and 4. See below diagram also.
+Chúng ta có thể lấy được "3*2 đơn vị" nước giữa 3 và 2,
+"1 đơn vị" trên đỉnh của thanh 2 và "3 đơn vị" giữa 2
+và 4. Xem biểu đồ bên dưới để biết thêm.
 ```
 
-**Example #3**
+**Ví dụ #3**
 
 ```
 Input: arr[] = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
 Output: 6
-Structure is like below:
+Cấu trúc như sau:
 
-       | 
+       |
    |   || |
 _|_||_||||||
 
-Trap "1 unit" between first 1 and 2, "4 units" between
-first 2 and 3 and "1 unit" between second last 1 and last 2.
+Lấy "1 đơn vị" nước giữa số 1 đầu tiên và 2, "4 đơn vị" giữa
+số 2 đầu tiên và 3 và "1 đơn vị" giữa số 1 cuối cùng và số 2 cuối cùng.
 ```
 
-## The Algorithm
+## Thuật Toán
 
-An element of array can store water if there are higher bars on left and right. 
-We can find amount of water to be stored in every element by finding the heights 
-of bars on left and right sides. The idea is to compute amount of water that can
-be stored in every element of array. For example, consider the array
-`[3, 0, 0, 2, 0, 4]`, We can trap "3*2 units" of water between 3 an 2, "1 unit" 
-on top of bar 2 and "3 units" between 2 and 4. See below diagram also.
+Một phần tử của mảng có thể chứa nước nếu có thanh cao hơn ở bên trái và bên phải. Chúng ta có thể tính được lượng nước có thể được lưu trữ trong mỗi phần tử bằng cách tìm chiều cao của thanh ở cả hai bên trái và phải. Ý tưởng là tính toán lượng nước có thể được lưu trữ trong mỗi phần tử của mảng. Ví dụ, xem xét mảng `[3, 0, 0, 2, 0, 4]`, Chúng ta có thể lấy được "3\*2 đơn vị" nước giữa 3 và 2, "1 đơn vị" trên đỉnh của thanh 2 và "3 đơn vị" giữa 2 và 4. Xem biểu đồ dưới đây để biết thêm.
 
-### Approach 1: Brute force
+### Phương pháp 1: Lực Brute
 
-**Intuition**
+**Ý tưởng**
 
-For each element in the array, we find the maximum level of water it can trap 
-after the rain, which is equal to the minimum of maximum height of bars on both 
-the sides minus its own height.
+Đối với mỗi phần tử trong mảng, chúng ta tìm mức nước cao nhất nó có thể lưu trữ sau cơn mưa, tức là bằng cách tính toán giá trị tối thiểu của chiều cao tối đa của thanh ở cả hai bên trái và phải trừ chiều cao của chính nó.
 
-**Steps**
+**Bước thực hiện**
 
-- Initialize `answer = 0`
-- Iterate the array from left to right:
-  - Initialize `max_left = 0`  and `max_right = 0`
-  - Iterate from the current element to the beginning of array updating: `max_left = max(max_left, height[j])`
-  - Iterate from the current element to the end of array updating: `max_right = max(max_right, height[j])`
-  - Add `min(max_left, max_right) − height[i]` to `answer`
+- Khởi tạo `answer = 0`
+- Lặp qua mảng từ trái sang phải:
+  - Khởi tạo `max_left = 0` và `max_right = 0`
+  - Lặp từ phần tử hiện tại đến đầu mảng cập nhật: `max_left = max(max_left, height[j])`
+  - Lặp từ phần tử hiện tại đến cuối mảng cập nhật: `max_right = max(max_right, height[j])`
+  - Thêm `min(max_left, max_right) − height[i]` vào `answer`
 
-**Complexity Analysis**
+**Phân Tích Độ Phức Tạp**
 
-Time complexity: `O(n^2)`. For each element of array, we iterate the left and right parts.
+Độ phức tạp thời gian: `O(n^2)`. Đối với mỗi phần tử của mảng, chúng ta lặp qua các phần bên trái và bên phải.
 
-Auxiliary space complexity: `O(1)` extra space.
+Độ phức tạp không gian phụ: `O(1)` không gian phụ.
 
-### Approach 2: Dynamic Programming
+### Phương pháp 2: Lập Trình Động
 
-**Intuition**
+**Ý tưởng**
 
-In brute force, we iterate over the left and right parts again and again just to 
-find the highest bar size up to that index. But, this could be stored. Voila, 
-dynamic programming.
+Trong lực brute, chúng ta lặp lại phần bên trái và phải một lần nữa chỉ để tìm kích thước thanh cao nhất cho đến vị trí đó. Nhưng điều này có thể được lưu trữ. Đúng vậy, lập trình động.
 
-So we may pre-compute highest bar on left and right of every bar in `O(n)` time.
-Then use these pre-computed values to find the amount of water in every array element.
+Vì vậy, chúng ta có thể tính trước chiều cao cao nhất từ bên trái và phải của mỗi thanh trong `O(n)` thời gian. Sau đó sử dụng các giá trị được tính trước này để tìm lượng nước trong mỗi phần tử mảng.
 
-The concept is illustrated as shown:
+Khái niệm được minh họa như dưới đây:
 
-![DP Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/Figures/42/trapping_rain_water.png)
+![Lập Trình Động Tính Nước Mưa](https://leetcode.com/problems/trapping-rain-water/Figures/42/trapping_rain_water.png)
 
-**Steps**
+**Bước thực hiện**
 
-- Find maximum height of bar from the left end up to an index `i` in the array `left_max`.
-- Find maximum height of bar from the right end up to an index `i` in the array `right_max`.
-- Iterate over the `height` array and update `answer`:
-  - Add `min(max_left[i], max_right[i]) − height[i]` to `answer`.
+- Tìm chiều cao cao nhất của thanh từ đầu bên trái đến một chỉ số `i` trong mảng `left_max`.
+- Tìm chiều cao cao nhất của thanh từ cuối bên phải đến một chỉ số `i` trong mảng `right_max`.
+- Lặp qua mảng `height` và cập nhật `answer`:
+  - Thêm `min(max_left[i], max_right[i]) − height[i]` vào `answer`.
 
-**Complexity Analysis**
+**Phân Tích Độ Phức Tạp**
 
-Time complexity: `O(n)`. We store the maximum heights upto a point using 2 
-iterations of `O(n)` each. We finally update `answer` using the stored 
-values in `O(n)`.
+Độ phức tạp thời gian: `O(n)`. Chúng ta lưu trữ các chiều cao tối đa cho đến một điểm bằng cách sử dụng 2 lặp `O(n)` mỗi lần. Cuối cùng, chúng ta cập nhật `answer` bằng cách sử dụng các giá trị đã lưu trữ trong `O(n)`.
 
-Auxiliary space complexity: `O(n)` extra space. Additional space 
-for `left_max` and `right_max` arrays than in Approach 1.
+Độ phức tạp không gian phụ: `O(n)` không gian phụ. Dùng thêm không gian cho các mảng `left_max` và `right_max` so với Phương pháp 1.
 
-## References
+## Tham Khảo
 
 - [GeeksForGeeks](https://www.geeksforgeeks.org/trapping-rain-water/)
 - [LeetCode](https://leetcode.com/problems/trapping-rain-water/solution/)
diff --git a/src/algorithms/uncategorized/recursive-staircase/README.en-EN.md b/src/algorithms/uncategorized/recursive-staircase/README.en-EN.md
new file mode 100644
index 0000000000..9d34a77d88
--- /dev/null
+++ b/src/algorithms/uncategorized/recursive-staircase/README.en-EN.md
@@ -0,0 +1,24 @@
+# Recursive Staircase Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## The Problem
+
+There are `n` stairs, a person standing at the bottom wants to reach the top. The person can climb either `1` or `2` stairs at a time. _Count the number of ways, the person can reach the top._
+
+![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png)
+
+## The Solution
+
+This is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms.
+
+- [Brute Force Recursive Solution](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)`
+- [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)`
+- [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)`
+- [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)`
+
+## References
+
+- [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/)
diff --git a/src/algorithms/uncategorized/recursive-staircase/README.md b/src/algorithms/uncategorized/recursive-staircase/README.md
index d7e6f81464..0cd17438cb 100644
--- a/src/algorithms/uncategorized/recursive-staircase/README.md
+++ b/src/algorithms/uncategorized/recursive-staircase/README.md
@@ -1,21 +1,24 @@
-# Recursive Staircase Problem
+# Bài toán Cầu Thang Đệ Quy
 
-## The Problem
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-There are `n` stairs, a person standing at the bottom wants to reach the top. The person can climb either `1` or `2` stairs at a time. _Count the number of ways, the person can reach the top._
+## Vấn đề
+
+Có `n` bậc cầu thang, một người đứng ở dưới muốn đến đỉnh. Người đó có thể leo `1` hoặc `2` bậc cầu thang mỗi lần. _Đếm số cách mà người đó có thể đến được đỉnh._
 
 ![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png)
 
-## The Solution
+## Giải Pháp
 
-This is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms.
+Đây là một vấn đề thú vị vì có nhiều cách để giải quyết mà minh họa các phương pháp lập trình khác nhau.
 
-- [Brute Force Recursive Solution](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)`
-- [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)`
-- [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)`
-- [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)` 
+- [Giải Pháp Đệ Quy Brute Force](./recursiveStaircaseBF.js) - Thời gian: `O(2^n)`; Không gian: `O(1)`
+- [Giải Pháp Đệ Quy Với Ghi Nhớ](./recursiveStaircaseMEM.js) - Thời gian: `O(n)`; Không gian: `O(n)`
+- [Giải Pháp Lập Trình Động](./recursiveStaircaseDP.js) - Thời gian: `O(n)`; Không gian: `O(n)`
+- [Giải Pháp Lặp](./recursiveStaircaseIT.js) - Thời gian: `O(n)`; Không gian: `O(1)`
 
-## References
+## Tham Khảo
 
-- [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)
+- [Trên YouTube bởi Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/)
diff --git a/src/algorithms/uncategorized/square-matrix-rotation/README.en-EN.md b/src/algorithms/uncategorized/square-matrix-rotation/README.en-EN.md
new file mode 100644
index 0000000000..938498c07b
--- /dev/null
+++ b/src/algorithms/uncategorized/square-matrix-rotation/README.en-EN.md
@@ -0,0 +1,113 @@
+# Square Matrix In-Place Rotation
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+## The Problem
+
+You are given an `n x n` 2D matrix (representing an image).
+Rotate the matrix by `90` degrees (clockwise).
+
+**Note**
+
+You have to rotate the image **in-place**, which means you
+have to modify the input 2D matrix directly. **DO NOT** allocate
+another 2D matrix and do the rotation.
+
+## Examples
+
+**Example #1**
+
+Given input matrix:
+
+```
+[
+  [1, 2, 3],
+  [4, 5, 6],
+  [7, 8, 9],
+]
+```
+
+Rotate the input matrix in-place such that it becomes:
+
+```
+[
+  [7, 4, 1],
+  [8, 5, 2],
+  [9, 6, 3],
+]
+```
+
+**Example #2**
+
+Given input matrix:
+
+```
+[
+  [5, 1, 9, 11],
+  [2, 4, 8, 10],
+  [13, 3, 6, 7],
+  [15, 14, 12, 16],
+]
+```
+
+Rotate the input matrix in-place such that it becomes:
+
+```
+[
+  [15, 13, 2, 5],
+  [14, 3, 4, 1],
+  [12, 6, 8, 9],
+  [16, 7, 10, 11],
+]
+```
+
+## Algorithm
+
+We would need to do two reflections of the matrix:
+
+- reflect vertically
+- reflect diagonally from bottom-left to top-right
+
+Or we also could Furthermore, you can reflect diagonally
+top-left/bottom-right and reflect horizontally.
+
+A common question is how do you even figure out what kind
+of reflections to do? Simply rip a square piece of paper,
+write a random word on it so you know its rotation. Then,
+flip the square piece of paper around until you figure out
+how to come to the solution.
+
+Here is an example of how first line may be rotated using
+diagonal top-right/bottom-left rotation along with horizontal
+rotation.
+
+```
+Let's say we have a string at the top of the matrix:
+
+A B C
+• • •
+• • •
+
+Let's do top-right/bottom-left diagonal reflection:
+
+A B C
+/ / •
+/ • •
+
+And now let's do horizontal reflection:
+
+A → →
+B → →
+C → →
+
+The string has been rotated to 90 degree:
+
+• • A
+• • B
+• • C
+```
+
+## References
+
+- [LeetCode](https://leetcode.com/problems/rotate-image/description/)
diff --git a/src/algorithms/uncategorized/square-matrix-rotation/README.md b/src/algorithms/uncategorized/square-matrix-rotation/README.md
index 34ef47f15d..6c5e47d25b 100644
--- a/src/algorithms/uncategorized/square-matrix-rotation/README.md
+++ b/src/algorithms/uncategorized/square-matrix-rotation/README.md
@@ -1,21 +1,24 @@
-# Square Matrix In-Place Rotation
+# Xoay ma trận vuông tại chỗ
 
-## The Problem
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-You are given an `n x n` 2D matrix (representing an image). 
-Rotate the matrix by `90` degrees (clockwise).
+## Vấn đề
 
-**Note**
+Bạn được cho một ma trận 2D `n x n` (đại diện cho một hình ảnh).
+Xoay ma trận theo góc `90` độ (theo chiều kim đồng hồ).
 
-You have to rotate the image **in-place**, which means you 
-have to modify the input 2D matrix directly. **DO NOT** allocate
-another 2D matrix and do the rotation.
+**Lưu Ý**
 
-## Examples
+Bạn phải xoay hình ảnh **tại chỗ**, điều này có nghĩa là bạn
+phải sửa đổi trực tiếp ma trận 2D đầu vào. **KHÔNG** phải cấp
+phát một ma trận 2D khác và thực hiện xoay.
 
-**Example #1**
+## Ví dụ
 
-Given input matrix:
+**Ví dụ #1**
+
+Ma trận đầu vào được cho:
 
 ```
 [
@@ -25,7 +28,7 @@ Given input matrix:
 ]
 ```
 
-Rotate the input matrix in-place such that it becomes:
+Xoay ma trận đầu vào tại chỗ sao cho nó trở thành:
 
 ```
 [
@@ -35,9 +38,9 @@ Rotate the input matrix in-place such that it becomes:
 ]
 ```
 
-**Example #2**
+**Ví dụ #2**
 
-Given input matrix:
+Ma trận đầu vào được cho:
 
 ```
 [
@@ -48,7 +51,7 @@ Given input matrix:
 ]
 ```
 
-Rotate the input matrix in-place such that it becomes:
+Xoay ma trận đầu vào tại chỗ sao cho nó trở thành:
 
 ```
 [
@@ -59,52 +62,45 @@ Rotate the input matrix in-place such that it becomes:
 ]
 ```
 
-## Algorithm
+## Thuật Toán
+
+Chúng ta cần thực hiện hai phản chiếu của ma trận:
 
-We would need to do two reflections of the matrix: 
+- phản chiếu theo chiều dọc
+- phản chiếu theo đường chéo từ dưới lên trên từ góc dưới bên trái đến góc trên bên phải
 
-- reflect vertically
-- reflect diagonally from bottom-left to top-right
+Hoặc bạn cũng có thể phản chiếu theo đường chéo từ trên xuống dưới và phản chiếu theo chiều ngang.
 
-Or we also could Furthermore, you can reflect diagonally 
-top-left/bottom-right and reflect horizontally.
+Một câu hỏi phổ biến là làm sao bạn có thể tìm ra loại phản chiếu nào để thực hiện? Đơn giản là lấy một tờ giấy vuông, viết một từ ngẫu nhiên trên đó để bạn biết nó đã được xoay. Sau đó, quay tờ giấy vuông cho đến khi bạn tìm ra cách để đến được giải pháp.
 
-A common question is how do you even figure out what kind 
-of reflections to do? Simply rip a square piece of paper,
-write a random word on it so you know its rotation. Then,
-flip the square piece of paper around until you figure out
-how to come to the solution.
- 
-Here is an example of how first line may be rotated using
-diagonal top-right/bottom-left rotation along with horizontal
-rotation.
+Dưới đây là một ví dụ về cách dòng đầu tiên có thể được xoay bằng cách sử dụng phản chiếu đường chéo từ trên xuống dưới và phản chiếu theo chiều ngang.
 
 ```
-Let's say we have a string at the top of the matrix:
+Hãy nói chúng ta có một chuỗi ở đầu của ma trận:
 
 A B C
 • • •
 • • •
 
-Let's do top-right/bottom-left diagonal reflection:
+Hãy thực hiện phản chiếu đường chéo từ trên xuống dưới:
 
 A B C
 / / •
-/ • •  
+/ • •
 
-And now let's do horizontal reflection:
+Và bây giờ hãy thực hiện phản chiếu theo chiều ngang:
 
 A → →
 B → →
 C → →
 
-The string has been rotated to 90 degree:
+Chuỗi đã được xoay 90 độ:
 
 • • A
 • • B
 • • C
 ```
 
-## References
+## Tham Khảo
 
 - [LeetCode](https://leetcode.com/problems/rotate-image/description/)
diff --git a/src/algorithms/uncategorized/unique-paths/README.en-EN.md b/src/algorithms/uncategorized/unique-paths/README.en-EN.md
new file mode 100644
index 0000000000..440dfe4af3
--- /dev/null
+++ b/src/algorithms/uncategorized/unique-paths/README.en-EN.md
@@ -0,0 +1,109 @@
+# Unique Paths Problem
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A robot is located at the top-left corner of a `m x n` grid
+(marked 'Start' in the diagram below).
+
+The robot can only move either down or right at any point in
+time. The robot is trying to reach the bottom-right corner
+of the grid (marked 'Finish' in the diagram below).
+
+How many possible unique paths are there?
+
+![Unique Paths](https://leetcode.com/static/images/problemset/robot_maze.png)
+
+## Examples
+
+**Example #1**
+
+```
+Input: m = 3, n = 2
+Output: 3
+Explanation:
+From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
+1. Right -> Right -> Down
+2. Right -> Down -> Right
+3. Down -> Right -> Right
+```
+
+**Example #2**
+
+```
+Input: m = 7, n = 3
+Output: 28
+```
+
+## Algorithms
+
+### Backtracking
+
+First thought that might came to mind is that we need to build a decision tree
+where `D` means moving down and `R` means moving right. For example in case
+of boars `width = 3` and `height = 2` we will have the following decision tree:
+
+```
+                START
+                /   \
+               D     R
+             /     /   \
+           R      D      R
+         /      /         \
+        R      R            D
+
+       END    END          END
+```
+
+We can see three unique branches here that is the answer to our problem.
+
+**Time Complexity**: `O(2 ^ n)` - roughly in worst case with square board
+of size `n`.
+
+**Auxiliary Space Complexity**: `O(m + n)` - since we need to store current path with
+positions.
+
+### Dynamic Programming
+
+Let's treat `BOARD[i][j]` as our sub-problem.
+
+Since we have restriction of moving only to the right
+and down we might say that number of unique paths to the current
+cell is a sum of numbers of unique paths to the cell above the
+current one and to the cell to the left of current one.
+
+```
+BOARD[i][j] = BOARD[i - 1][j] + BOARD[i][j - 1]; // since we can only move down or right.
+```
+
+Base cases are:
+
+```
+BOARD[0][any] = 1; // only one way to reach any top slot.
+BOARD[any][0] = 1; // only one way to reach any slot in the leftmost column.
+```
+
+For the board `3 x 2` our dynamic programming matrix will look like:
+
+|       |  0  |  1  |  1  |
+| :---: | :-: | :-: | :-: |
+| **0** |  0  |  1  |  1  |
+| **1** |  1  |  2  |  3  |
+
+Each cell contains the number of unique paths to it. We need
+the bottom right one with number `3`.
+
+**Time Complexity**: `O(m * n)` - since we're going through each cell of the DP matrix.
+
+**Auxiliary Space Complexity**: `O(m * n)` - since we need to have DP matrix.
+
+### Pascal's Triangle Based
+
+This question is actually another form of Pascal Triangle.
+
+The corner of this rectangle is at `m + n - 2` line, and
+at `min(m, n) - 1` position of the Pascal's Triangle.
+
+## References
+
+- [LeetCode](https://leetcode.com/problems/unique-paths/description/)
diff --git a/src/algorithms/uncategorized/unique-paths/README.md b/src/algorithms/uncategorized/unique-paths/README.md
index 924c97ba1f..5df2437fcc 100644
--- a/src/algorithms/uncategorized/unique-paths/README.md
+++ b/src/algorithms/uncategorized/unique-paths/README.md
@@ -1,47 +1,51 @@
-# Unique Paths Problem
+# Bài toán Đường đi duy nhất
 
-A robot is located at the top-left corner of a `m x n` grid 
-(marked 'Start' in the diagram below).
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-The robot can only move either down or right at any point in 
-time. The robot is trying to reach the bottom-right corner 
-of the grid (marked 'Finish' in the diagram below).
+Một con robot đang được đặt ở góc trên cùng bên trái của một lưới `m x n`
+(mô tả là 'Bắt đầu' trong hình dưới đây).
 
-How many possible unique paths are there?
+Robot chỉ có thể di chuyển xuống hoặc sang phải tại bất kỳ thời điểm nào.
+Robot đang cố gắng đến góc dưới cùng bên phải của lưới (được đánh dấu là 'Kết thúc'
+trong hình dưới đây).
 
-![Unique Paths](https://leetcode.com/static/images/problemset/robot_maze.png)
+Có bao nhiêu đường đi duy nhất có thể có?
 
-## Examples
+![Đường đi duy nhất](https://leetcode.com/static/images/problemset/robot_maze.png)
 
-**Example #1**
+## Ví dụ
+
+**Ví dụ #1**
 
 ```
-Input: m = 3, n = 2
-Output: 3
-Explanation:
-From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
-1. Right -> Right -> Down
-2. Right -> Down -> Right
-3. Down -> Right -> Right
+Đầu vào: m = 3, n = 2
+Đầu ra: 3
+Giải thích:
+Từ góc trên cùng bên trái, có tổng cộng 3 cách để đến góc dưới cùng bên phải:
+1. Sang phải -> Sang phải -> Xuống
+2. Sang phải -> Xuống -> Sang phải
+3. Xuống -> Sang phải -> Sang phải
 ```
 
-**Example #2**
+**Ví dụ #2**
 
 ```
-Input: m = 7, n = 3
-Output: 28
+Đầu vào: m = 7, n = 3
+Đầu ra: 28
 ```
 
-## Algorithms
+## Thuật toán
 
-### Backtracking
+### Quay lui
 
-First thought that might came to mind is that we need to build a decision tree 
-where `D` means moving down and `R` means moving right. For example in case
-of boars `width = 3` and `height = 2` we will have the following decision tree:
+Ý tưởng đầu tiên mà có thể nghĩ đến là chúng ta cần xây dựng một cây quyết định
+trong đó `D` có nghĩa là di chuyển xuống và `R` có nghĩa là di chuyển sang phải.
+Ví dụ trong trường hợp bảng `chiều rộng = 3` và `chiều cao = 2` chúng ta sẽ có cây
+quyết định như sau:
 
 ```
-                START
+                BẮT ĐẦU
                 /   \
                D     R
              /     /   \
@@ -49,58 +53,58 @@ of boars `width = 3` and `height = 2` we will have the following decision tree:
          /      /         \
         R      R            D
 
-       END    END          END
+       KẾT THÚC KẾT THÚC KẾT THÚC
 ```
 
-We can see three unique branches here that is the answer to our problem.
+Chúng ta có thể thấy ba nhánh duy nhất ở đây đó là câu trả lời cho vấn đề của chúng ta.
 
-**Time Complexity**: `O(2 ^ n)` - roughly in worst case with square board
-of size `n`.
+**Độ phức tạp thời gian**: `O(2 ^ n)` - khoảng cách xấp xỉ trong trường hợp xấu nhất
+với bảng vuông có kích thước `n`.
 
-**Auxiliary Space Complexity**: `O(m + n)` - since we need to store current path with
-positions.
+**Độ phức tạp không gian phụ**: `O(m + n)` - vì chúng ta cần lưu trữ đường đi hiện tại với
+các vị trí.
 
-### Dynamic Programming
+### Lập trình động
 
-Let's treat `BOARD[i][j]` as our sub-problem.
+Hãy xem `BẢNG[i][j]` như là bài toán phụ của chúng ta.
 
-Since we have restriction of moving only to the right
-and down we might say that number of unique paths to the current
-cell is a sum of numbers of unique paths to the cell above the
-current one and to the cell to the left of current one.
+Khi chúng ta có hạn chế chỉ được di chuyển sang phải
+và xuống, chúng ta có thể nói rằng số lượng đường đi duy nhất đến ô hiện
+tại là tổng của số lượng đường đi duy nhất đến ô phía trên ô hiện tại
+và ô bên trái của ô hiện tại.
 
 ```
-BOARD[i][j] = BOARD[i - 1][j] + BOARD[i][j - 1]; // since we can only move down or right.
+BẢNG[i][j] = BẢNG[i - 1][j] + BẢNG[i][j - 1]; // vì chúng ta chỉ có thể di chuyển xuống hoặc sang phải.
 ```
 
-Base cases are:
+Các trường hợp cơ sở là:
 
 ```
-BOARD[0][any] = 1; // only one way to reach any top slot.
-BOARD[any][0] = 1; // only one way to reach any slot in the leftmost column.
+BẢNG[0][bất kỳ] = 1; // chỉ có một cách để đến bất kỳ ô trên cùng nào.
+BẢNG[bất kỳ][0] = 1; // chỉ có một cách để đến bất kỳ ô nào trong cột bên trái.
 ```
 
-For the board `3 x 2` our dynamic programming matrix will look like:
+Đối với bảng `3 x 2` của chúng ta, ma trận lập trình động sẽ trông như sau:
 
-|     | 0   | 1   | 1   |
-|:---:|:---:|:---:|:---:|
-|**0**| 0   | 1   | 1   |
-|**1**| 1   | 2   | 3   |
+|       |  0  |  1  |  1  |
+| :---: | :-: | :-: | :-: |
+| **0** |  0  |  1  |  1  |
+| **1** |  1  |  2  |  3  |
 
-Each cell contains the number of unique paths to it. We need 
-the bottom right one with number `3`.
+Mỗi ô chứa số lượng đường đi duy nhất đến nó. Chúng ta cần
+ô phía dưới bên phải với số `3`.
 
-**Time Complexity**: `O(m * n)` - since we're going through each cell of the DP matrix.
+**Độ phức tạp thời gian**: `O(m * n)` - vì chúng ta đi qua mỗi ô của ma trận lập trình động.
 
-**Auxiliary Space Complexity**: `O(m * n)` - since we need to have DP matrix.
+**Độ phức tạp không gian phụ**: `O(m * n)` - vì chúng ta cần có ma trận lập trình động.
 
-### Pascal's Triangle Based
+### Dựa trên Tam giác Pascal
 
-This question is actually another form of Pascal Triangle.
+Câu hỏi này thực sự là một dạng khác của Tam giác Pascal.
 
-The corner of this rectangle is at `m + n - 2` line, and 
-at `min(m, n) - 1` position of the Pascal's Triangle.
+Góc của hình chữ nhật này ở dòng `m + n - 2`, và
+ở vị trí `min(m, n) - 1` của Tam giác Pascal.
 
-## References
+## Tham khảo
 
 - [LeetCode](https://leetcode.com/problems/unique-paths/description/)
diff --git a/src/data-structures/bloom-filter/README.en-EN.md b/src/data-structures/bloom-filter/README.en-EN.md
new file mode 100644
index 0000000000..695aa88366
--- /dev/null
+++ b/src/data-structures/bloom-filter/README.en-EN.md
@@ -0,0 +1,131 @@
+# Bloom Filter
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **bloom filter** is a space-efficient probabilistic
+data structure designed to test whether an element
+is present in a set. It is designed to be blazingly
+fast and use minimal memory at the cost of potential
+false positives. False positive matches are possible,
+but false negatives are not – in other words, a query
+returns either "possibly in set" or "definitely not in set".
+
+Bloom proposed the technique for applications where the
+amount of source data would require an impractically large
+amount of memory if "conventional" error-free hashing
+techniques were applied.
+
+## Algorithm description
+
+An empty Bloom filter is a bit array of `m` bits, all
+set to `0`. There must also be `k` different hash functions
+defined, each of which maps or hashes some set element to
+one of the `m` array positions, generating a uniform random
+distribution. Typically, `k` is a constant, much smaller
+than `m`, which is proportional to the number of elements
+to be added; the precise choice of `k` and the constant of
+proportionality of `m` are determined by the intended
+false positive rate of the filter.
+
+Here is an example of a Bloom filter, representing the
+set `{x, y, z}`. The colored arrows show the positions
+in the bit array that each set element is mapped to. The
+element `w` is not in the set `{x, y, z}`, because it
+hashes to one bit-array position containing `0`. For
+this figure, `m = 18` and `k = 3`.
+
+![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
+
+## Operations
+
+There are two main operations a bloom filter can
+perform: _insertion_ and _search_. Search may result in
+false positives. Deletion is not possible.
+
+In other words, the filter can take in items. When
+we go to check if an item has previously been
+inserted, it can tell us either "no" or "maybe".
+
+Both insertion and search are `O(1)` operations.
+
+## Making the filter
+
+A bloom filter is created by allotting a certain size.
+In our example, we use `100` as a default length. All
+locations are initialized to `false`.
+
+### Insertion
+
+During insertion, a number of hash functions,
+in our case `3` hash functions, are used to create
+hashes of the input. These hash functions output
+indexes. At every index received, we simply change
+the value in our bloom filter to `true`.
+
+### Search
+
+During a search, the same hash functions are called
+and used to hash the input. We then check if the
+indexes received _all_ have a value of `true` inside
+our bloom filter. If they _all_ have a value of
+`true`, we know that the bloom filter may have had
+the value previously inserted.
+
+However, it's not certain, because it's possible
+that other values previously inserted flipped the
+values to `true`. The values aren't necessarily
+`true` due to the item currently being searched for.
+Absolute certainty is impossible unless only a single
+item has previously been inserted.
+
+While checking the bloom filter for the indexes
+returned by our hash functions, if even one of them
+has a value of `false`, we definitively know that the
+item was not previously inserted.
+
+## False Positives
+
+The probability of false positives is determined by
+three factors: the size of the bloom filter, the
+number of hash functions we use, and the number
+of items that have been inserted into the filter.
+
+The formula to calculate probablity of a false positive is:
+
+( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>
+
+`k` = number of hash functions
+
+`m` = filter size
+
+`n` = number of items inserted
+
+These variables, `k`, `m`, and `n`, should be picked based
+on how acceptable false positives are. If the values
+are picked and the resulting probability is too high,
+the values should be tweaked and the probability
+re-calculated.
+
+## Applications
+
+A bloom filter can be used on a blogging website. If
+the goal is to show readers only articles that they
+have never seen before, a bloom filter is perfect.
+It can store hashed values based on the articles. After
+a user reads a few articles, they can be inserted into
+the filter. The next time the user visits the site,
+those articles can be filtered out of the results.
+
+Some articles will inevitably be filtered out by mistake,
+but the cost is acceptable. It's ok if a user never sees
+a few articles as long as they have other, brand new ones
+to see every time they visit the site.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)
+- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)
+- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)
+- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)
+- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)
diff --git a/src/data-structures/bloom-filter/README.md b/src/data-structures/bloom-filter/README.md
index e156310cb4..4d30c89897 100644
--- a/src/data-structures/bloom-filter/README.md
+++ b/src/data-structures/bloom-filter/README.md
@@ -1,133 +1,70 @@
-# Bloom Filter
-
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md),
-[_Português_](README.pt-BR.md),
-[_Українська_](README.uk-UA.md)
-
-A **bloom filter** is a space-efficient probabilistic
-data structure designed to test whether an element
-is present in a set. It is designed to be blazingly
-fast and use minimal memory at the cost of potential
-false positives. False positive matches are possible,
-but false negatives are not – in other words, a query
-returns either "possibly in set" or "definitely not in set".
-
-Bloom proposed the technique for applications where the
-amount of source data would require an impractically large
-amount of memory if "conventional" error-free hashing
-techniques were applied.
-
-## Algorithm description
-
-An empty Bloom filter is a bit array of `m` bits, all
-set to `0`. There must also be `k` different hash functions
-defined, each of which maps or hashes some set element to
-one of the `m` array positions, generating a uniform random
-distribution. Typically, `k` is a constant, much smaller
-than `m`, which is proportional to the number of elements
-to be added; the precise choice of `k` and the constant of
-proportionality of `m` are determined by the intended
-false positive rate of the filter.
-
-Here is an example of a Bloom filter, representing the
-set `{x, y, z}`. The colored arrows show the positions
-in the bit array that each set element is mapped to. The
-element `w` is not in the set `{x, y, z}`, because it
-hashes to one bit-array position containing `0`. For
-this figure, `m = 18` and `k = 3`.
-
-![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
-
-## Operations
-
-There are two main operations a bloom filter can
-perform: _insertion_ and _search_. Search may result in
-false positives. Deletion is not possible.
-
-In other words, the filter can take in items. When
-we go to check if an item has previously been
-inserted, it can tell us either "no" or "maybe".
-
-Both insertion and search are `O(1)` operations.
-
-## Making the filter
-
-A bloom filter is created by allotting a certain size.
-In our example, we use `100` as a default length. All
-locations are initialized to `false`.
-
-### Insertion
-
-During insertion, a number of hash functions,
-in our case `3` hash functions, are used to create
-hashes of the input. These hash functions output
-indexes. At every index received, we simply change
-the value in our bloom filter to `true`.
-
-### Search
-
-During a search, the same hash functions are called
-and used to hash the input. We then check if the
-indexes received _all_ have a value of `true` inside
-our bloom filter. If they _all_ have a value of
-`true`, we know that the bloom filter may have had
-the value previously inserted.
-
-However, it's not certain, because it's possible
-that other values previously inserted flipped the
-values to `true`. The values aren't necessarily
-`true` due to the item currently being searched for.
-Absolute certainty is impossible unless only a single
-item has previously been inserted.
-
-While checking the bloom filter for the indexes
-returned by our hash functions, if even one of them
-has a value of `false`, we definitively know that the
-item was not previously inserted.
-
-## False Positives
-
-The probability of false positives is determined by
-three factors: the size of the bloom filter, the
-number of hash functions we use, and the number
-of items that have been inserted into the filter.
-
-The formula to calculate probablity of a false positive is:
+# Bloom Filter - Bộ lọc Bloom
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+**Bộ lọc Bloom** là một cấu trúc dữ liệu xác suất hiệu quả về không gian, được thiết kế để kiểm tra xem một phần tử có tồn tại trong một tập hợp hay không. Nó được thiết kế để hoạt động với tốc độ nhanh chóng và sử dụng bộ nhớ tối thiểu với chi phí có thể là các dương tính giả. Các dương tính giả có thể xảy ra, nhưng các âm tính giả không thể - nói cách khác, một truy vấn sẽ trả về một trong hai kết quả "có thể có trong tập hợp" hoặc "chắc chắn không trong tập hợp".
+
+Bloom đề xuất phương pháp này cho các ứng dụng mà lượng dữ liệu nguồn sẽ đòi hỏi một lượng bộ nhớ không thể áp dụng được nếu các kỹ thuật băm không lỗi được áp dụng.
+
+## Mô tả thuật toán
+
+Một bộ lọc Bloom trống là một mảng bit có `m` bit, tất cả đều được đặt thành `0`. Cũng cần phải xác định `k` hàm băm khác nhau, mỗi hàm băm sẽ ánh xạ hoặc băm một phần tử của tập hợp sang một trong `m` vị trí mảng, tạo ra một phân phối ngẫu nhiên đồng đều. Thông thường, `k` là một hằng số, nhỏ hơn rất nhiều so với `m`, tỷ lệ này tương tự với số phần tử được thêm vào; việc chọn chính xác của `k` và hằng số tỷ lệ của `m` được xác định bởi tỷ lệ dương tính giả mong muốn của bộ lọc.
+
+Dưới đây là một ví dụ về bộ lọc Bloom, đại diện cho tập hợp `{x, y, z}`. Các mũi tên màu chỉ ra các vị trí trong mảng bit mà mỗi phần tử của tập hợp được ánh xạ đến. Phần tử `w` không thuộc tập hợp `{x, y, z}`, vì nó băm tới một vị trí mảng bit chứa `0`. Đối với hình này, `m = 18` và `k = 3`.
+
+![Bộ lọc Bloom](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
+
+## Các hoạt động
+
+Có hai hoạt động chính mà một bộ lọc Bloom có thể thực hiện: _chèn_ và _tìm kiếm_. Tìm kiếm có thể dẫn đến các dương tính giả. Không thể xóa.
+
+Nói cách khác, bộ lọc có thể nhận vào các mục. Khi chúng ta kiểm tra xem một mục đã được chèn trước đó hay chưa, nó có thể cho chúng ta biết "không" hoặc "có thể".
+
+Cả hai hoạt động chèn và tìm kiếm đều là các hoạt động `O(1)`.
+
+## Tạo bộ lọc
+
+Một bộ lọc Bloom được tạo bằng cách phân bổ một kích thước nhất định. Trong ví dụ của chúng tôi, chúng tôi sử dụng `100` làm chiều dài mặc định. Tất cả các vị trí được khởi tạo thành `false`.
+
+### Chèn
+
+Trong quá trình chèn, một số lượng hàm băm, trong trường hợp của chúng tôi là `3` hàm băm, được sử dụng để tạo các băm của đầu vào. Các hàm băm này xuất các chỉ mục. Tại mỗi chỉ mục nhận được, chúng ta đơn giản thay đổi giá trị trong bộ lọc Bloom của chúng ta thành `true`.
+
+### Tìm kiếm
+
+Trong một tìm kiếm, các hàm băm giống nhau được gọi và được sử dụng để băm đầu vào. Sau đó, chúng ta kiểm tra xem các chỉ mục nhận được _tất cả_ có một giá trị `true` bên trong bộ lọc Bloom của chúng ta không. Nếu _tất cả_ đều có giá trị `true`, chúng ta biết rằng bộ lọc Bloom có thể đã có giá trị được chèn trước đó.
+
+Tuy nhiên, không chắc chắn, vì có thể các giá trị khác được chèn trước đó đã làm cho các giá trị thành `true`. Các giá trị không nhất thiết là `true` do mục đang được tìm kiếm. Sự chắc chắn tuyệt đối là không thể trừ khi chỉ một mục đã được chèn trước đó.
+
+Trong khi kiểm tra bộ lọc Bloom cho các chỉ mục được trả về bởi các hàm băm của chúng ta, nếu ngay cả một trong số chúng có giá trị `false`, chúng ta chắc chắn biết rằng mục đó không được chèn trước đó.
+
+## Dương tính giả
+
+Xác suất của các dương tính giả được xác định bởi ba yếu tố: kích thước của bộ lọc Bloom, số lượng hàm băm mà chúng ta sử dụng và số lượng các mục đã được chèn vào bộ lọc.
+
+Công thức để tính xác suất của dương tính giả là:
 
 ( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>
 
-`k` = number of hash functions
+`k` = số lượng hàm băm
 
-`m` = filter size
+`m` = kích thước của bộ lọc
 
-`n` = number of items inserted
+`n` = số lượng các mục đã chèn
 
-These variables, `k`, `m`, and `n`, should be picked based
-on how acceptable false positives are. If the values
-are picked and the resulting probability is too high,
-the values should be tweaked and the probability
-re-calculated.
+Các biến này, `k`, `m`, và `n`, nên được chọn dựa trên mức độ chấp nhận của dương tính giả. Nếu các giá trị được chọn và xác suất kết quả quá cao, các giá trị nên được điều chỉnh và xác suất được tính toán lại.
 
-## Applications
+## Ứng dụng
 
-A bloom filter can be used on a blogging website. If
-the goal is to show readers only articles that they
-have never seen before, a bloom filter is perfect.
-It can store hashed values based on the articles. After
-a user reads a few articles, they can be inserted into
-the filter. The next time the user visits the site,
-those articles can be filtered out of the results.
+Một bộ lọc Bloom có thể được sử dụng trên một trang web blog. Nếu mục tiêu là chỉ hiển thị bài viết cho người đọc mà họ chưa bao giờ thấy trước đó, một bộ lọc Bloom là lựa chọn hoàn hảo. Nó có thể lưu trữ các giá trị băm dựa trên các bài viết. Sau khi một người dùng đọc một vài bài viết, chúng có thể được chèn vào bộ lọc. Lần sau khi người dùng truy cập trang web, những bài viết đó có thể được lọc ra khỏi kết quả.
 
-Some articles will inevitably be filtered out by mistake,
-but the cost is acceptable. It's ok if a user never sees
-a few articles as long as they have other, brand new ones
-to see every time they visit the site.
+Một số bài viết sẽ tất nhiên bị lọc ra một cách nhầm lẫn, nhưng chi phí là chấp nhận được. Không sao nếu một người dùng không bao giờ xem một số bài viết miễn là họ có những bài viết mới hoàn toàn khác mỗi lần họ truy cập trang web.
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)
-- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)
-- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)
-- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)
-- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)
+- [Bộ Lọc Bloom qua Ví Dụ](http://llimllib.github.io/bloomfilter-tutorial/)
+- [Tính Xác Suất Dương Tính Giả](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)
+- [Bộ Lọc Bloom trên Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)
+- [Bộ Lọc Bloom trên YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)
diff --git a/src/data-structures/bloom-filter/README.pt-BR.md b/src/data-structures/bloom-filter/README.pt-BR.md
deleted file mode 100644
index 0c8522b958..0000000000
--- a/src/data-structures/bloom-filter/README.pt-BR.md
+++ /dev/null
@@ -1,129 +0,0 @@
-# Filtro Bloom (Bloom Filter)
-
-O **bloom filter** é uma estrutura de dados probabilística
-espaço-eficiente designada para testar se um elemento está
-ou não presente em um conjunto de dados. Foi projetado para ser
-incrivelmente rápida e utilizar o mínimo de memória ao 
-potencial custo de um falso-positivo. Correspondências 
-_falsas positivas_ são possíveis, contudo _falsos negativos_ 
-não são - em outras palavras, a consulta retorna 
-"possivelmente no conjunto" ou "definitivamente não no conjunto".
-
-Bloom propôs a técnica para aplicações onde a quantidade 
-de entrada de dados exigiria uma alocação de memória
-impraticavelmente grande se as "convencionais" técnicas
-error-free hashing fossem aplicadas.
-
-## Descrição do algoritmo
-
-Um filtro Bloom vazio é um _bit array_ de `m` bits, todos
-definidos como `0`. Também deverá haver diferentes funções
-de hash `k` definidas, cada um dos quais mapeia e produz hash
-para um dos elementos definidos em uma das posições `m` da
- _array_, gerando uma distribuição aleatória e uniforme.
-Normalmente, `k` é uma constante, muito menor do que `m`,
-pelo qual é proporcional ao número de elements a ser adicionado;
-a escolha precisa de `k` e a constante de proporcionalidade de `m`
-são determinadas pela taxa de falsos positivos planejado do filtro.
-
-Aqui está um exemplo de um filtro Bloom, representando o
-conjunto `{x, y, z}`. As flechas coloridas demonstram as
-posições no _bit array_ em que cada elemento é mapeado.
-O elemento `w` não está definido dentro de `{x, y, z}`,
-porque este produz hash para uma posição de array de bits
-contendo `0`. Para esta imagem: `m = 18` e `k = 3`.
-
-![Bloom Filter](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
-
-## Operações
-
-Existem duas operações principais que o filtro Bloom pode operar:
-_inserção_ e _pesquisa_. A pesquisa pode resultar em falsos
-positivos. Remoção não é possível.
-
-Em outras palavras, o filtro pode receber itens. Quando
-vamos verificar se um item já foi anteriormente
-inserido, ele poderá nos dizer "não" ou "talvez".
-
-Ambas as inserções e pesquisas são operações `O(1)`.
-
-## Criando o filtro
-
-Um filtro Bloom é criado ao alocar um certo tamanho.
-No nosso exemplo, nós utilizamos `100` como tamanho padrão.
-Todas as posições são initializadas como `false`.
-
-### Inserção
-
-Durante a inserção, um número de função hash, no nosso caso `3`
-funções de hash, são utilizadas para criar hashes de uma entrada.
-Estas funções de hash emitem saída de índices. A cada índice
-recebido, nós simplismente trocamos o valor de nosso filtro
-Bloom para `true`.
-
-### Pesquisa
-
-Durante a pesquisa, a mesma função de hash é chamada
-e usada para emitir hash da entrada. Depois nós checamos
-se _todos_ os indices recebidos possuem o valor `true`
-dentro de nosso filtro Bloom. Caso _todos_ possuam o valor
-`true`, nós sabemos que o filtro Bloom pode ter tido
-o valor inserido anteriormente.
-
-Contudo, isto não é certeza, porque é possível que outros
-valores anteriormente inseridos trocaram o valor para `true`.
-Os valores não são necessariamente `true` devido ao ítem
-atualmente sendo pesquisado. A certeza absoluta é impossível,
-a não ser que apenas um item foi inserido anteriormente.
-
-Durante a checagem do filtro Bloom para índices retornados
-pela nossa função de hash, mesmo que apenas um deles possua
-valor como `false`, nós definitivamente sabemos que o ítem
-não foi anteriormente inserido.
-
-## Falso Positivos
-
-A probabilidade de falso positivos é determinado por
-três fatores: o tamanho do filtro de Bloom, o número de 
-funções de hash que utilizados, e o número de itens que
-foram inseridos dentro do filtro.
-
-A formula para calcular a probabilidade de um falso positivo é:
-
-( 1 - e <sup>-kn/m</sup> ) <sup>k</sup>
-
-`k` = número de funções de hash
-
-`m` = tamanho do filtro
-
-`n` = número de itens inserido
-
-Estas variáveis, `k`, `m` e `n`, devem ser escolhidas baseado
-em quanto aceitável são os falsos positivos. Se os valores
-escolhidos resultam em uma probabilidade muito alta, então
-os valores devem ser ajustados e a probabilidade recalculada.
-
-## Aplicações
-
-Um filtro Bloom pode ser utilizado em uma página de Blog.
-Se o objetivo é mostrar aos leitores somente os artigos
-em que eles nunca viram, então o filtro Bloom é perfeito 
-para isso. Ele pode armazenar hashes baseados nos artigos.
-Depois que um usuário lê alguns artigos, eles podem ser
-inseridos dentro do filtro. Na próxima vez que o usuário
-visitar o Blog, aqueles artigos poderão ser filtrados (eliminados) 
-do resultado.
-
-Alguns artigos serão inevitavelmente filtrados (eliminados) 
-por engano, mas o custo é aceitável. Tudo bem se um usuário nunca
-ver alguns poucos artigos, desde que tenham outros novos
-para ver toda vez que eles visitam o site. 
-
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter)
-- [Bloom Filters by Example](http://llimllib.github.io/bloomfilter-tutorial/)
-- [Calculating False Positive Probability](https://hur.st/bloomfilter/?n=4&p=&m=18&k=3)
-- [Bloom Filters on Medium](https://blog.medium.com/what-are-bloom-filters-1ec2a50c68ff)
-- [Bloom Filters on YouTube](https://www.youtube.com/watch?v=bEmBh1HtYrw)
diff --git a/src/data-structures/bloom-filter/README.ru-RU.md b/src/data-structures/bloom-filter/README.ru-RU.md
deleted file mode 100644
index b5c19c06c8..0000000000
--- a/src/data-structures/bloom-filter/README.ru-RU.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# Фильтр Блума
-
-**Фильтр Блума** - это пространственно-эффективная вероятностная структура данных, созданная для проверки наличия элемента
-в множестве. Он спроектирован невероятно быстрым при минимальном использовании памяти ценой потенциальных ложных срабатываний.
-Существует возможность получить ложноположительное срабатывание (элемента в множестве нет, но структура данных сообщает,
-что он есть), но не ложноотрицательное. Другими словами, очередь возвращает или "возможно в наборе", или "определённо не
-в наборе". Фильтр Блума может использовать любой объём памяти, однако чем он больше, тем меньше вероятность ложного
-срабатывания. 
-
-Блум предложил эту технику для применения в областях, где количество исходных данных потребовало бы непрактично много 
-памяти, в случае применения условно безошибочных техник хеширования.
-
-## Описание алгоритма
-
-Пустой фильтр Блума представлен битовым массивом из `m` битов, все биты которого обнулены. Должно быть определено `k`
-независимых хеш-функций, отображающих каждый элемент множества в одну из `m` позиций в массиве, генерируя единообразное
-случайное распределение. Обычно `k` задана константой, которая много меньше `m` и пропорциональна
-количеству добавляемых элементов; точный выбор `k` и постоянной пропорциональности `m` определяются уровнем ложных
-срабатываний фильтра.
-
-Вот пример Блум фильтра, представляющего набор `{x, y, z}`. Цветные стрелки показывают позиции в битовом массиве,
-которым привязан каждый элемент набора. Элемент `w` не в наборе `{x, y, z}`, потому что он привязан к позиции в битовом
-массиве, равной `0`. Для этой формы , `m = 18`, а `k = 3`.
-
-Фильтр Блума представляет собой битовый массив из `m` бит. Изначально, когда структура данных хранит пустое множество, все
-`m` бит обнулены. Пользователь должен определить `k` независимых хеш-функций `h1`, …, `hk`,
-отображающих каждый элемент в одну из `m` позиций битового массива достаточно равномерным образом.
-
-Для добавления элемента e необходимо записать единицы на каждую из позиций `h1(e)`, …, `hk(e)`
-битового массива.
-
-Для проверки принадлежности элемента `e` к множеству хранимых элементов, необходимо проверить состояние битов
-`h1(e)`, …, `hk(e)`. Если хотя бы один из них равен нулю, элемент не может принадлежать множеству
-(иначе бы при его добавлении все эти биты были установлены). Если все они равны единице, то структура данных сообщает,
-что `е` принадлежит множеству. При этом может возникнуть две ситуации: либо элемент действительно принадлежит множеству,
-либо все эти биты оказались установлены по случайности при добавлении других элементов, что и является источником ложных
-срабатываний в этой структуре данных.
-
-![Фильтр Блума](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
-
-## Применения
-
-Фильтр Блума может быть использован для блогов. Если цель состоит в том, чтобы показать читателям только те статьи,
-которые они ещё не видели, фильтр блума идеален. Он может содержать хешированные значения, соответствующие статье. После
-того, как пользователь прочитал несколько статей, они могут быть помещены в фильтр. В следующий раз, когда пользователь
-посетит сайт, эти статьи могут быть убраны из результатов с помощью фильтра.
-
-Некоторые статьи неизбежно будут отфильтрованы по ошибке, но цена приемлема. То, что пользователь не увидит несколько
-статей в полне приемлемо, принимая во внимание тот факт, что ему всегда показываются другие новые статьи при каждом
-новом посещении.
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80_%D0%91%D0%BB%D1%83%D0%BC%D0%B0)
-- [Фильтр Блума на Хабре](https://habr.com/ru/post/112069/)
diff --git a/src/data-structures/bloom-filter/README.uk-UA.md b/src/data-structures/bloom-filter/README.uk-UA.md
deleted file mode 100644
index aa9075a094..0000000000
--- a/src/data-structures/bloom-filter/README.uk-UA.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Фільтр Блума
-
-**Фільтр Блума** - це просторово-ефективна ймовірна структура даних, створена для перевірки наявності елемента
-у множині. Він спроектований неймовірно швидким за мінімального використання пам'яті ціною потенційних помилкових спрацьовувань.
-Існує можливість отримати хибнопозитивне спрацьовування (елемента в безлічі немає, але структура даних повідомляє,
-що він є), але не хибнонегативне. Іншими словами, черга повертає або "можливо в наборі", або "певно не
-у наборі". Фільтр Блума може використовувати будь-який обсяг пам'яті, проте чим він більший, тим менша вірогідність помилкового
-спрацьовування.
-
-Блум запропонував цю техніку для застосування в областях, де кількість вихідних даних потребувала б непрактично багато
-пам'яті, у разі застосування умовно безпомилкових технік хешування.
-
-## Опис алгоритму
-
-Порожній фільтр Блума представлений бітовим масивом з `m` бітів, всі біти якого обнулені. Має бути визначено `k`
-незалежних хеш-функцій, що відображають кожен елемент множини в одну з `m` позицій у масиві, генеруючи однакове
-випадковий розподіл. Зазвичай `k` задана константою, яка набагато менше `m` і пропорційна
-кількості елементів, що додаються; точний вибір `k` та постійної пропорційності `m` визначаються рівнем хибних
-спрацьовувань фільтра.
-
-Ось приклад Блум фільтра, що представляє набір `{x, y, z}`. Кольорові стрілки показують позиції в бітовому масиві,
-яким прив'язаний кожен елемент набору. Елемент `w` не в наборі `{x, y, z}`, тому що він прив'язаний до позиції в бітовому
-масиві, що дорівнює `0`. Для цієї форми, `m = 18`, а `k = 3`.
-
-Фільтр Блума є бітовий масив з `m` біт. Спочатку, коли структура даних зберігає порожню множину, всі
-m біт обнулені. Користувач повинен визначити `k` незалежних хеш-функцій `h1`, …, `hk`,
-що відображають кожен елемент в одну з m позицій бітового масиву досить рівномірним чином.
-
-Для додавання елемента e необхідно записати одиниці на кожну з позицій `h1(e)`, …, `hk(e)`
-бітового масиву.
-
-Для перевірки приналежності елемента `e` до безлічі елементів, що зберігаються, необхідно перевірити стан бітів
-`h1(e)`, …, `hk(e)`. Якщо хоча б один з них дорівнює нулю, елемент не може належати множині
-(інакше при його додаванні всі ці біти були встановлені). Якщо вони рівні одиниці, то структура даних повідомляє,
-що `е` належить безлічі. При цьому може виникнути дві ситуації: або елемент дійсно належить множині,
-або всі ці біти виявилися встановлені випадково при додаванні інших елементів, що і є джерелом помилкових
-спрацьовувань у цій структурі даних.
-
-![Фільтр Блума](https://upload.wikimedia.org/wikipedia/commons/a/ac/Bloom_filter.svg)
-
-## Застосування
-
-Фільтр Блума може бути використаний для блогів. Якщо мета полягає в тому, щоб показати читачам лише ті статті,
-які вони ще не бачили, фільтр блуму ідеальний. Він може містити значення, що хешуються, відповідні статті. Після
-того, як користувач прочитав кілька статей, вони можуть бути поміщені у фільтр. Наступного разу, коли користувач
-відвідає сайт, ці статті можуть бути вилучені з результатів за допомогою фільтра.
-
-Деякі статті неминуче будуть відфільтровані помилково, але ціна прийнятна. Те, що користувач не побачить дещо
-статей цілком прийнятно, беручи до уваги той факт, що йому завжди показуються інші нові статті при кожному
-новому відвідуванні.
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A4%D1%96%D0%BB%D1%8C%D1%82%D1%80_%D0%91%D0%BB%D1%83%D0%BC%D0%B0)
diff --git a/src/data-structures/disjoint-set/README.en-EN.md b/src/data-structures/disjoint-set/README.en-EN.md
new file mode 100644
index 0000000000..8ca8a3b9a3
--- /dev/null
+++ b/src/data-structures/disjoint-set/README.en-EN.md
@@ -0,0 +1,28 @@
+# Disjoint Set
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+**Disjoint-set** data structure (also called a union–find data structure or merge–find set) is a data
+structure that tracks a set of elements partitioned into a number of disjoint (non-overlapping) subsets.
+It provides near-constant-time operations (bounded by the inverse Ackermann function) to _add new sets_,
+to _merge existing sets_, and to _determine whether elements are in the same set_.
+In addition to many other uses (see the Applications section), disjoint-sets play a key role in Kruskal's algorithm for finding the minimum spanning tree of a graph.
+
+![disjoint set](https://upload.wikimedia.org/wikipedia/commons/6/67/Dsu_disjoint_sets_init.svg)
+
+_MakeSet_ creates 8 singletons.
+
+![disjoint set](https://upload.wikimedia.org/wikipedia/commons/a/ac/Dsu_disjoint_sets_final.svg)
+
+After some operations of _Union_, some sets are grouped together.
+
+## Implementation
+
+- [DisjointSet.js](./DisjointSet.js)
+- [DisjointSetAdhoc.js](./DisjointSetAdhoc.js) - The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
+- [By Abdul Bari on YouTube](https://www.youtube.com/watch?v=wU6udHRIkcc&index=14&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/disjoint-set/README.md b/src/data-structures/disjoint-set/README.md
index 772f68191b..8d01b3e9be 100644
--- a/src/data-structures/disjoint-set/README.md
+++ b/src/data-structures/disjoint-set/README.md
@@ -1,30 +1,25 @@
-# Disjoint Set
+# Disjoint Set - Cấu Trúc Dữ Liệu Tách Biệt
 
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md),
-[_Português_](README.pt-BR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-**Disjoint-set** data structure (also called a union–find data structure or merge–find set) is a data
-structure that tracks a set of elements partitioned into a number of disjoint (non-overlapping) subsets.
-It provides near-constant-time operations (bounded by the inverse Ackermann function) to _add new sets_,
-to _merge existing sets_, and to _determine whether elements are in the same set_.
-In addition to many other uses (see the Applications section), disjoint-sets play a key role in Kruskal's algorithm for finding the minimum spanning tree of a graph.
+**Disjoint-set** (cũng được gọi là cấu trúc dữ liệu hợp nhất-tìm hoặc cấu trúc dữ liệu hợp nhất-tìm-ghép) là một cấu trúc dữ liệu theo dõi một tập hợp các phần tử được phân chia thành một số tập hợp tách biệt (không giao nhau). Nó cung cấp các hoạt động gần như độ phức tạp hằng số (bị chặn bởi hàm Ackermann nghịch đảo) để _thêm các tập hợp mới_, _gộp các tập hợp hiện có_, và _xác định xem các phần tử có trong cùng một tập hợp không_.
+Ngoài việc được sử dụng trong nhiều mục đích khác nhau (xem phần Ứng dụng), các tập hợp không giao nhau còn đóng vai trò quan trọng trong thuật toán Kruskal để tìm cây khung tối thiểu của một đồ thị.
 
 ![disjoint set](https://upload.wikimedia.org/wikipedia/commons/6/67/Dsu_disjoint_sets_init.svg)
 
-_MakeSet_ creates 8 singletons.
+_MakeSet_ tạo ra 8 tập hợp đơn lẻ.
 
 ![disjoint set](https://upload.wikimedia.org/wikipedia/commons/a/ac/Dsu_disjoint_sets_final.svg)
 
-After some operations of _Union_, some sets are grouped together.
+Sau một số hoạt động _Union_, một số tập hợp được nhóm lại.
 
-## Implementation
+## Thực hiện
 
 - [DisjointSet.js](./DisjointSet.js)
-- [DisjointSetAdhoc.js](./DisjointSetAdhoc.js) - The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
+- [DisjointSetAdhoc.js](./DisjointSetAdhoc.js) - Phiên bản tối thiểu (tạm thời) của cấu trúc dữ liệu DisjointSet (hoặc UnionFind) không có các phụ thuộc bên ngoài và dễ dàng sao chép-và-dán và sử dụng trong cuộc phỏng vấn lập trình nếu được phép bởi người phỏng vấn (vì nhiều cấu trúc dữ liệu trong JS thiếu).
 
-## References
+## Tài liệu tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
 - [By Abdul Bari on YouTube](https://www.youtube.com/watch?v=wU6udHRIkcc&index=14&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/disjoint-set/README.pt-BR.md b/src/data-structures/disjoint-set/README.pt-BR.md
deleted file mode 100644
index a7d827a8a2..0000000000
--- a/src/data-structures/disjoint-set/README.pt-BR.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Conjunto Disjunto (Disjoint Set)
-
-**Conjunto Disjunto**
-
-**Conjunto Disjunto** é uma estrutura de dados (também chamado de
-estrutura de dados de union–find ou merge–find) é uma estrutura de dados
-que rastreia um conjunto de elementos particionados em um número de
-subconjuntos separados (sem sobreposição).
-Ele fornece operações de tempo quase constante (limitadas pela função
-inversa de Ackermann) para *adicionar novos conjuntos*, para 
-*mesclar/fundir conjuntos existentes* e para *determinar se os elementos
-estão no mesmo conjunto*.
-Além de muitos outros usos (veja a seção Applications), conjuntos disjuntos
-desempenham um papel fundamental no algoritmo de Kruskal para encontrar a
-árvore geradora mínima de um grafo (graph).
-
-![disjoint set](https://upload.wikimedia.org/wikipedia/commons/6/67/Dsu_disjoint_sets_init.svg)
-
-*MakeSet* cria 8 singletons.
-
-![disjoint set](https://upload.wikimedia.org/wikipedia/commons/a/ac/Dsu_disjoint_sets_final.svg)
-
-Depois de algumas operações de *Uniões*, alguns conjuntos são agrupados juntos.
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
-- [By Abdul Bari on YouTube](https://www.youtube.com/watch?v=wU6udHRIkcc&index=14&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/disjoint-set/README.ru-RU.md b/src/data-structures/disjoint-set/README.ru-RU.md
deleted file mode 100644
index a9c234bf9c..0000000000
--- a/src/data-structures/disjoint-set/README.ru-RU.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Система непересекающихся множеств
-
-**Система непересекающихся множеств** это структура данных (также называемая структурой данной поиска пересечения или
-множеством поиска слияния), которая управляет множеством элементов, разбитых на несколько непересекающихся подмножеств.
-Она предоставляет около-константное время выполнения операций (ограниченное обратной функцией Акерманна) по *добавлению
-новых множеств*, *слиянию существующих множеств* и *опеределению, относятся ли элементы к одному и тому же множеству*.
-
-Применяется для хранения компонент связности в графах, в частности, алгоритму Краскала необходима подобная структура
-данных для эффективной реализации.
-
-Основные операции:
-
-- *MakeSet(x)* - создаёт одноэлементное множество {x},
-- *Find(x)* - возвращает идентификатор множества, содержащего элемент x,
-- *Union(x,y)* - объединение множеств, содержащих x и y.
-
-После некоторых операций *объединения*, некоторые множества собраны вместе
-
-## Ссылки
-- [СНМ на Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B5%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D0%BA%D0%B0%D1%8E%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2)
-- [СНМ на YouTube](https://www.youtube.com/watch?v=bXBHYqNeBLo)
diff --git a/src/data-structures/disjoint-set/README.uk-UA.md b/src/data-structures/disjoint-set/README.uk-UA.md
deleted file mode 100644
index c721b66420..0000000000
--- a/src/data-structures/disjoint-set/README.uk-UA.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Система неперетинних множин
-
-**Система неперетинних множин** це структура даних (також звана структурою даної пошуку перетину або
-безліччю пошуку злиття), яка управляє безліччю елементів, розбитих на кілька підмножин, що не перетинаються.
-Вона надає близько-константний час виконання операцій (обмежений зворотною функцією Акерманна) за додаванням
-нових множин, *злиття існуючих множин і *випередження, чи відносяться елементи до одного і того ж безлічі.
-
-Застосовується для зберігання компонентів зв'язності в графах, зокрема, алгоритму Фарбала необхідна подібна структура
-даних для ефективної реалізації.
-
-Основні операції:
-
-- _MakeSet(x)_ - створює одноелементне безліч {x},
-- _Find(x)_ - повертає ідентифікатор множини, що містить елемент x,
-- _Union(x,y)_ - об'єднання множин, що містять x та y.
-
-Після деяких операцій _об'єднання_, деякі множини зібрані разом.
-
-## Посилання
-
-- [СНМ на Wikipedia](https://uk.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B5%D0%BF%D0%B5%D1%80%D0%B5%D1%82%D0%B8%D0%BD%D0%BD%D0%B8%D1%85_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B8%D0%BD)
-- [СНМ на YouTube](https://www.youtube.com/watch?v=5XwRPwLnK6I)
diff --git a/src/data-structures/doubly-linked-list/README.en-EN.md b/src/data-structures/doubly-linked-list/README.en-EN.md
new file mode 100644
index 0000000000..5d044a729b
--- /dev/null
+++ b/src/data-structures/doubly-linked-list/README.en-EN.md
@@ -0,0 +1,113 @@
+# Doubly Linked List
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **doubly linked list** is a linked data structure that
+consists of a set of sequentially linked records called nodes. Each node contains
+two fields, called links, that are references to the previous and to the next
+node in the sequence of nodes. The beginning and ending nodes' previous and next
+links, respectively, point to some kind of terminator, typically a sentinel
+node or null, to facilitate the traversal of the list. If there is only one
+sentinel node, then the list is circularly linked via the sentinel node. It can
+be conceptualized as two singly linked lists formed from the same data items,
+but in opposite sequential orders.
+
+![Doubly Linked List](./images/doubly-linked-list.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+The two node links allow traversal of the list in either direction. While adding
+or removing a node in a doubly linked list requires changing more links than the
+same operations on a singly linked list, the operations are simpler and
+potentially more efficient (for nodes other than first nodes) because there
+is no need to keep track of the previous node during traversal or no need
+to traverse the list to find the previous node, so that its link can be modified.
+
+## Pseudocode for Basic Operations
+
+### Insert
+
+```text
+Add(value)
+  Pre: value is the value to add to the list
+  Post: value has been placed at the tail of the list
+  n ← node(value)
+  if head = ø
+    head ← n
+    tail ← n
+  else
+    n.previous ← tail
+    tail.next ← n
+    tail ← n
+  end if
+end Add
+```
+
+### Delete
+
+```text
+Remove(head, value)
+  Pre: head is the head node in the list
+       value is the value to remove from the list
+  Post: value is removed from the list, true; otherwise false
+  if head = ø
+    return false
+  end if
+  if value = head.value
+    if head = tail
+      head ← ø
+      tail ← ø
+    else
+      head ← head.next
+      head.previous ← ø
+    end if
+    return true
+  end if
+  n ← head.next
+  while n != ø and value !== n.value
+    n ← n.next
+  end while
+  if n = tail
+    tail ← tail.previous
+    tail.next ← ø
+    return true
+  else if n != ø
+    n.previous.next ← n.next
+    n.next.previous ← n.previous
+    return true
+  end if
+  return false
+end Remove
+```
+
+### Reverse Traversal
+
+```text
+ReverseTraversal(tail)
+  Pre: tail is the node of the list to traverse
+  Post: the list has been traversed in reverse order
+  n ← tail
+  while n != ø
+    yield n.value
+    n ← n.previous
+  end while
+end Reverse Traversal
+```
+
+## Complexities
+
+## Time Complexity
+
+| Access | Search | Insertion | Deletion |
+| :----: | :----: | :-------: | :------: |
+|  O(n)  |  O(n)  |   O(1)    |   O(n)   |
+
+### Space Complexity
+
+O(n)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
+- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.es-ES.md b/src/data-structures/doubly-linked-list/README.es-ES.md
deleted file mode 100644
index 490466d74b..0000000000
--- a/src/data-structures/doubly-linked-list/README.es-ES.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# Lista doblemente enlazada
-
-_Lea esto en otros idiomas:_
-[_Русский_](README.ru-RU.md),
-[_简体中文_](README.zh-CN.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md)
-[_한국어_](README.ko-KR.md)
-
-En informática, una **lista doblemente enlazada** es una estructura de datos relacionados que consta de un conjunto de registros conectados secuencialmente llamados nodos. Cada nodo contiene dos campos, llamados enlaces, que son referencias al nodo anterior y al siguiente en la secuencia de nodos. Los enlaces anterior y siguiente de los nodos inicial y final, apuntan respectivamente a algún tipo de terminador (normalmente un nodo centinela o nulo), facilitando así el recorrido de la lista. Si solo hay un nodo nulo, la lista se enlaza circularmente a través este. Puede conceptualizarse como dos listas enlazadas individualmente formadas a partir de los mismos elementos de datos, pero en órdenes secuenciales opuestos.
-
-![Lista doblemente enlazada](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Los dos enlaces de un nodo permiten recorrer la lista en cualquier dirección. Si bien agregar o eliminar un nodo en una lista doblemente enlazada requiere cambiar más enlaces que las mismas operaciones en una lista enlazada individualmente, las operaciones son más simples y potencialmente más eficientes (para nodos que no sean los primeros) porque no hay necesidad de realizar un seguimiento del nodo anterior durante el recorrido o no es necesario recorrer la lista para encontrar el nodo anterior, de modo que se pueda modificar su enlace.
-
-## Pseudocódigo para operaciones básicas
-
-### Insertar
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### Eliminar
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true; otherwise false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n != ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n != ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Recorrido Inverso
-
-```text
-ReverseTraversal(tail)
-  Pre: tail is the node of the list to traverse
-  Post: the list has been traversed in reverse order
-  n ← tail
-  while n != ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## Complejidades
-
-## Complejidad del Tiempo
-
-| Acceso | Búsqueda | Inserción | Eliminación |
-| :----: | :------: | :-------: | :---------: |
-|  O(n)  |   O(n)   |   O(1)    |    O(n)     |
-
-### Complejidad del Espacio
-
-O(n)
-
-## Referencias
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
-- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.ja-JP.md b/src/data-structures/doubly-linked-list/README.ja-JP.md
deleted file mode 100644
index 0ff96628c9..0000000000
--- a/src/data-structures/doubly-linked-list/README.ja-JP.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# 双方向リスト
-
-コンピュータサイエンスにおいて、**双方向リスト**はノードと呼ばれる一連のリンクレコードからなる連結データ構造です。各ノードはリンクと呼ばれる2つのフィールドを持っていて、これらは一連のノード内における前のノードと次のノードを参照しています。最初のノードの前のリンクと最後のノードの次のリンクはある種の終端を示していて、一般的にはダミーノードやnullが格納され、リストのトラバースを容易に行えるようにしています。もしダミーノードが1つしかない場合、リストはその1つのノードを介して循環的にリンクされます。これは、それぞれ逆の順番の単方向のリンクリストが2つあるものとして考えることができます。
-
-![Doubly Linked List](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-2つのリンクにより、リストをどちらの方向にもトラバースすることができます。双方向リストはノードの追加や削除の際に、片方向リンクリストと比べてより多くのリンクを変更する必要があります。しかし、その操作は簡単で、より効率的な(最初のノード以外の場合)可能性があります。前のノードのリンクを更新する際に前のノードを保持したり、前のノードを見つけるためにリストをトラバースする必要がありません。
-
-## 基本操作の擬似コード
-
-### 挿入
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### 削除
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true; otherwise false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n = ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n = ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### 逆トラバース
-
-```text
-ReverseTraversal(tail)
-  Pre: tail is the node of the list to traverse
-  Post: the list has been traversed in reverse order
-  n ← tail
-  while n = ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## 計算量
-
-## 時間計算量
-
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-### 空間計算量
-
-O(n)
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
-- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.ko-KR.md b/src/data-structures/doubly-linked-list/README.ko-KR.md
deleted file mode 100644
index 9f60e54f32..0000000000
--- a/src/data-structures/doubly-linked-list/README.ko-KR.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Doubly Linked List
-
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md),
-[_简体中文_](README.zh-CN.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md)
-
-컴퓨터공학에서 **이중 연결 리스트**는 순차적으로 링크된 노드라는 레코드 세트로 구성된 링크된 데이터 구조입니다.
-각 노드에는 링크라고 하는 두 개의 필드가 있으며, 노드 순서에서 이전 노드와 다음 노드에 대한 참조를 가집니다.
-시작 및 종료 노드의 이전 및 다음 링크는 각각 리스트의 순회를 용이하게 하기 위해서 일종의 종결자 (일반적으로 센티넬노드 또는 null)를 나타냅니다.
-센티넬 노드가 하나만 있으면, 목록이 센티넬 노드를 통해서 원형으로 연결됩니다.
-동일한 데이터 항목으로 구성되어 있지만, 반대 순서로 두 개의 단일 연결 리스트로 개념화 할 수 있습니다.
-
-![이중 연결 리스트](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-두 개의 노드 링크를 사용하면 어느 방향으로든 리스트를 순회할 수 있습니다.
-이중 연결 리스트에서 노드를 추가하거나 제거하려면, 단일 연결 리스트에서 동일한 작업보다 더 많은 링크를 변경해야 하지만, 첫 번째 노드 이외의 노드인 경우 작업을 추적할 필요가 없으므로 작업이 더 단순해져 잠재적으로 더 효율적입니다.
-리스트 순회 중 이전 노드 또는 링크를 수정할 수 있도록 이전 노드를 찾기 위해 리스트를 순회할 필요가 없습니다.
-
-## 기본 동작을 위한 Pseudocode
-
-### 삽입
-
-```text
-Add(value)
-  Pre: value는 리스트에 추가하고자 하는 값
-  Post: value는 목록의 끝에 배치됨
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### 삭제
-
-```text
-Remove(head, value)
-  Pre: head는 리스트의 앞단에 위치
-       value는 리스트에서 제거하고자 하는 값
-  Post: value가 리스트에서 제거되면 true; 아니라면 false;
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n = ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n = ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### 역순회
-
-```text
-ReverseTraversal(tail)
-  Pre: tail은 리스트에서 순회하고자 하는 노드
-  Post: 리스트가 역순으로 순회됨
-  n ← tail
-  while n = ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## 복잡도
-
-## 시간 복잡도
-
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-### 공간 복잡도
-
-O(n)
-
-## 참고
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
-- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.md b/src/data-structures/doubly-linked-list/README.md
index 1610d1e497..dfff0986af 100644
--- a/src/data-structures/doubly-linked-list/README.md
+++ b/src/data-structures/doubly-linked-list/README.md
@@ -1,119 +1,100 @@
-# Doubly Linked List
-
-_Read this in other languages:_
-[_Русский_](README.ru-RU.md),
-[_简体中文_](README.zh-CN.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Español_](README.es-ES.md),
-[_Українська_](README.uk-UA.md)
-
-In computer science, a **doubly linked list** is a linked data structure that
-consists of a set of sequentially linked records called nodes. Each node contains
-two fields, called links, that are references to the previous and to the next
-node in the sequence of nodes. The beginning and ending nodes' previous and next
-links, respectively, point to some kind of terminator, typically a sentinel
-node or null, to facilitate the traversal of the list. If there is only one
-sentinel node, then the list is circularly linked via the sentinel node. It can
-be conceptualized as two singly linked lists formed from the same data items,
-but in opposite sequential orders.
-
-![Doubly Linked List](./images/doubly-linked-list.jpeg)
-
-_Made with [okso.app](https://okso.app)_
-
-The two node links allow traversal of the list in either direction. While adding
-or removing a node in a doubly linked list requires changing more links than the
-same operations on a singly linked list, the operations are simpler and
-potentially more efficient (for nodes other than first nodes) because there
-is no need to keep track of the previous node during traversal or no need
-to traverse the list to find the previous node, so that its link can be modified.
-
-## Pseudocode for Basic Operations
-
-### Insert
+# Doubly Linked List - Danh Sách Liên Kết Hai Chiều
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, **doubly linked list** là một cấu trúc dữ liệu liên kết bao gồm một tập hợp các bản ghi liên kết tuần tự gọi là các nút. Mỗi nút chứa hai trường, được gọi là liên kết, đó là các tham chiếu đến nút trước đó và nút tiếp theo trong chuỗi các nút. Các liên kết trước đó và tiếp theo của các nút đầu và cuối, tương ứng, trỏ đến một loại kết thúc, thường là một nút báo hiệu hoặc null, để dễ dàng đi qua danh sách. Nếu chỉ có một nút báo hiệu, thì danh sách được liên kết vòng qua nút báo hiệu. Nó có thể được tưởng tượng như là hai danh sách liên kết đơn được hình thành từ các mục dữ liệu giống nhau, nhưng theo thứ tự tuần tự ngược lại.
+
+![Danh Sách Liên Kết Hai Chiều](./images/doubly-linked-list.jpeg)
+
+_Tạo với [okso.app](https://okso.app)_
+
+Hai liên kết nút cho phép đi qua danh sách theo cả hai hướng. Trong khi thêm hoặc xóa một nút trong danh sách liên kết hai chiều đòi hỏi thay đổi nhiều liên kết hơn so với các hoạt động tương tự trên danh sách liên kết đơn, các hoạt động này lại đơn giản hơn và tiềm năng hiệu quả hơn (đối với các nút không phải là nút đầu) vì không cần theo dõi nút trước đó trong quá trình đi qua hoặc không cần phải đi qua danh sách để tìm nút trước đó, để liên kết của nó có thể được sửa đổi.
+
+## Mã Giả cho Các Hoạt Động Cơ Bản
+
+### Thêm
 
 ```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
+Thêm(giá_trị)
+  Tiền: giá_trị là giá trị để thêm vào danh sách
+  Sau: giá_trị đã được đặt ở cuối danh sách
+  n ← nút(giá_trị)
+  nếu đầu = ø
+    đầu ← n
+    cuối ← n
+  ngược lại
+    n.trước ← cuối
+    cuối.sau ← n
+    cuối ← n
+  kết thúc nếu
+end Thêm
 ```
 
-### Delete
+### Xóa
 
 ```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true; otherwise false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n != ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n != ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
+Xóa(đầu, giá_trị)
+  Tiền: đầu là nút đầu trong danh sách
+        giá_trị là giá trị để xóa khỏi danh sách
+  Sau: giá_trị được xóa khỏi danh sách, true; nếu không, là false
+  nếu đầu = ø
+    trả về false
+  kết thúc nếu
+  nếu giá_trị = giá_trị_đầu
+    nếu đầu = cuối
+      đầu ← ø
+      cuối ← ø
+    ngược lại
+      đầu ← đầu.sau
+      đầu.trước ← ø
+    kết thúc nếu
+    trả về true
+  kết thúc nếu
+  n ← đầu.sau
+  trong khi n != ø và giá_trị !== giá_trị của n
+    n ← n.sau
+  kết thúc trong khi
+  nếu n = cuối
+    cuối ← cuối.trước
+    cuối.sau ← ø
+    trả về true
+  ngược lại nếu n != ø
+    n.trước.sau ← n.sau
+    n.sau.trước ← n.trước
+    trả về true
+  kết thúc nếu
+  trả về false
+end Xóa
 ```
 
-### Reverse Traversal
+### Điều Hướng Ngược
 
 ```text
-ReverseTraversal(tail)
-  Pre: tail is the node of the list to traverse
-  Post: the list has been traversed in reverse order
-  n ← tail
-  while n != ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
+ĐiềuHướngNgược(cuối)
+  Tiền: cuối là nút của danh sách cần đi qua
+  Sau: danh sách đã được đi qua theo thứ tự ngược lại
+  n ← cuối
+  trong khi n != ø
+    cho nút giá_trị
+    n ← n.trước
+  kết thúc trong khi
+end Điều Hướng Ngược
 ```
 
-## Complexities
+## Độ Phức Tạp
 
-## Time Complexity
+## Độ Phức Tạp Thời Gian
 
-| Access | Search | Insertion | Deletion |
-| :----: | :----: | :-------: | :------: |
-|  O(n)  |  O(n)  |   O(1)    |   O(n)   |
+| Truy Cập | Tìm Kiếm | Thêm | Xóa  |
+| :------: | :------: | :--: | :--: |
+|   O(n)   |   O(n)   | O(1) | O(n) |
 
-### Space Complexity
+### Độ Phức Tạp Không Gian
 
 O(n)
 
-## References
+## Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
 - [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.pt-BR.md b/src/data-structures/doubly-linked-list/README.pt-BR.md
deleted file mode 100644
index c4294decf4..0000000000
--- a/src/data-structures/doubly-linked-list/README.pt-BR.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# Lista Duplamente Ligada (Doubly Linked List)
-
-Na ciência da computação, uma **lista duplamente conectada** é uma estrutura
-de dados vinculada que se consistem em um conjunto de registros
-sequencialmente vinculados chamados de nós (nodes). Em cada nó contém dois
-campos, chamados de ligações, que são referenciados ao nó anterior e posterior
-de uma sequência de nós. O começo e o fim dos nós anteriormente e posteriormente
-ligados, respectiviamente, apontam para algum tipo de terminação, normalmente
-um nó sentinela ou nulo, para facilitar a travessia da lista. Se existe
-somente um nó sentinela, então a lista é ligada circularmente através do nó
-sentinela. Ela pode ser conceitualizada como duas listas individualmente ligadas
-e formadas a partir dos mesmos itens, mas em ordem sequencial opostas.
-
-![Doubly Linked List](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Os dois nós ligados permitem a travessia da lista em qualquer direção.
-Enquanto adicionar ou remover um nó de uma lista duplamente vinculada requer
-alterar mais ligações (conexões) do que em uma lista encadeada individualmente
-(singly linked list), as operações são mais simples e potencialmente mais
-eficientes (para nós que não sejam nós iniciais) porque não há necessidade
-de manter um rastreamento do nó anterior durante a travessia ou não há
-necessidade de percorrer a lista para encontrar o nó anterior, para que
-então sua ligação/conexão possa ser modificada.
-
-## Pseudocódigo para Operações Básicas
-
-### Inserir
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### Remoção
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true; otherwise false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n = ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n = ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Travessia reversa
-
-```text
-ReverseTraversal(tail)
-  Pre: tail is the node of the list to traverse
-  Post: the list has been traversed in reverse order
-  n ← tail
-  while n = ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## Complexidades
-
-## Complexidade de Tempo
-
-| Acesso    | Pesquisa    | Inserção | Remoção  |
-| :-------: | :---------: | :------: | :------: |
-| O(n)      | O(n)        | O(1)     | O(n)     |
-
-### Complexidade de Espaço
-
-O(n)
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
-- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/doubly-linked-list/README.ru-RU.md b/src/data-structures/doubly-linked-list/README.ru-RU.md
deleted file mode 100644
index b69d0da393..0000000000
--- a/src/data-structures/doubly-linked-list/README.ru-RU.md
+++ /dev/null
@@ -1,110 +0,0 @@
-# Двусвязный список
-
-**Двусвязный список** — связная структура данных в информатике, состоящая из набора
-последовательно связанных записей, называемых узлами. Каждый узел содержит два поля,
-называемых ссылками, которые указывают на предыдущий и последующий элементы в
-последовательности узлов. Ссылка на предыдущий элемент корневого узла и ссылка на
-последующий элемент последнего узла указывают на некого рода прерыватель, обычно
-сторожевой узел или null, для облегчения обхода списка. Если в списке только один
-сторожевой узел, тогда список циклически связан через него.
-Двусвязный список можно представить, как два связных списка, которые образованы из
-одних и тех же данных, но расположенных в противоположном порядке.
-
-![Двусвязный список](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Две ссылки позволяют обходить список в обоих направлениях. Добавление и
-удаление узла в двусвязном списке требует изменения большего количества ссылок,
-чем аналогичные операции в связном списке. Однако данные операции проще и потенциально
-более эффективны (для некорневых узлов) - при обходе не нужно следить за предыдущим
-узлом или повторно обходить список в поиске предыдущего узла, плюс его ссылка
-может быть изменена.
-
-## Псевдокод основных операций
-
-### Вставка
-
-```text
-Add(value)
-  Pre: value - добавляемое значение
-  Post: value помещено в конец списка
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### Удаление
-
-```text
-Remove(head, value)
-  Pre: head - первый узел в списке
-       value - значение, которое следует удалить
-  Post: true - value удалено из списка, иначе false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n = ø and value = n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n = ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Обратный обход
-
-```text
-ReverseTraversal(tail)
-  Pre: tail - конечный элемент обходимого списка
-  Post: элементы списка пройдены в обратном порядке
-  n ← tail
-  while n = ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## Сложность
-
-## Временная сложность
-
-| Чтение    | Поиск     | Вставка   | Удаление  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-### Пространственная сложность
-
-O(n)
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA#%D0%94%D0%B2%D1%83%D1%81%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_(%D0%B4%D0%B2%D1%83%D0%BD%D0%B0%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D1%81%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA))
-- [YouTube](https://www.youtube.com/watch?v=lQ-lPjbb9Ew)
diff --git a/src/data-structures/doubly-linked-list/README.uk-UA.md b/src/data-structures/doubly-linked-list/README.uk-UA.md
deleted file mode 100644
index a52a8015e0..0000000000
--- a/src/data-structures/doubly-linked-list/README.uk-UA.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Двобічно зв'язаний список
-
-**Двобічно зв'язаний список** — зв'язкова структура даних в інформатиці, що складається з набору
-послідовно пов'язаних записів, званих вузлами. Кожен вузол містить два поля,
-званих посиланнями, які вказують на попередній і наступний елементи
-послідовність вузлів. Посилання на попередній елемент кореневого вузла та посилання на
-Наступний елемент останнього вузла вказують на деякого роду переривник, зазвичай
-сторожовий вузол або null для полегшення обходу списку. Якщо у списку лише один
-сторожовий вузол, тоді перелік циклічно пов'язаний через нього.
-Двобічно зв'язаний список можна уявити, як два зв'язкові списки, які утворені з
-одних і тих самих даних, але розташованих у протилежному порядку.
-
-![Двобічно зв'язаний список](./images/doubly-linked-list.jpeg)
-
-_Made with [okso.app](https://okso.app)_
-
-Два посилання дозволяють обходити список в обох напрямках. Додавання та
-видалення вузла у двозв'язному списку вимагає зміни більшої кількості посилань,
-ніж аналогічні операції у зв'язковому списку. Однак дані операції простіше та потенційно
-більш ефективні (для некореневих вузлів) – при обході не потрібно стежити за попереднім
-вузлом або повторно обходити список у пошуку попереднього вузла, плюс його посилання
-може бути змінено.
-
-## Псевдокод основних операцій
-
-### Вставка
-
-```text
-Add(value)
-  Pre: value - значення, що додається
-  Post: value поміщено в кінець списку
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### Видалення
-
-```text
-Remove(head, value)
-  Pre: head - перший вузол у списку
-       value - значення, яке слід видалити
-  Post: true - value видалено зі списку, інакше false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n = ø and value = n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n = ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Зворотний обхід
-
-```text
-ReverseTraversal(tail)
-  Pre: tail - кінцевий елемент обхідного списку
-  Post: елементи списку пройдено у зворотному порядку
-  n ← tail
-  while n = ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## Складність
-
-## Часова складність
-
-| Читання | Пошук | Вставка | Видалення |
-| :-----: | :---: | :-----: | :-------: |
-|  O(n)   | O(n)  |  O(1)   |   O(n)    |
-
-### Просторова складність
-
-O(n)
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B1%D1%96%D1%87%D0%BD%D0%BE_%D0%B7%D0%B2%27%D1%8F%D0%B7%D0%B0%D0%BD%D0%B8%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA#:~:text=%D0%94%D0%B2%D0%BE%D0%B1%D1%96%D1%87%D0%BD%D0%BE%20%D0%B7%D0%B2'%D1%8F%D0%B7%D0%B0%D0%BD%D0%B8%D0%B9%20%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20%E2%80%94%20%D0%B2%D0%B8%D0%B4,%D0%BD%D0%B0%20%D0%BF%D0%BE%D0%B4%D0%B0%D0%BB%D1%8C%D1%88%D0%B8%D0%B9%20%D0%B2%D1%83%D0%B7%D0%BE%D0%BB%20%D1%83%20%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D1%83.)
diff --git a/src/data-structures/doubly-linked-list/README.zh-CN.md b/src/data-structures/doubly-linked-list/README.zh-CN.md
deleted file mode 100644
index 3e669f4c45..0000000000
--- a/src/data-structures/doubly-linked-list/README.zh-CN.md
+++ /dev/null
@@ -1,101 +0,0 @@
-# 双向链表
-
-在计算机科学中, 一个 **双向链表(doubly linked list)** 是由一组称为节点的顺序链接记录组成的链接数据结构。每个节点包含两个字段，称为链接，它们是对节点序列中上一个节点和下一个节点的引用。开始节点和结束节点的上一个链接和下一个链接分别指向某种终止节点，通常是前哨节点或null，以方便遍历列表。如果只有一个前哨节点，则列表通过前哨节点循环链接。它可以被概念化为两个由相同数据项组成的单链表，但顺序相反。
-
-![Doubly Linked List](./images/doubly-linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-两个节点链接允许在任一方向上遍历列表。
-
-在双向链表中进行添加或者删除节点时,需做的链接更改要比单向链表复杂得多。这种操作在单向链表中更简单高效,因为不需要关注一个节点（除第一个和最后一个节点以外的节点）的两个链接,而只需要关注一个链接即可。
-
-
-
-## 基础操作的伪代码
-
-### 插入
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head != ø
-    head ← n
-    tail ← n
-  else
-    n.previous ← tail
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-### 删除
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true; otherwise false
-  if head = ø
-    return false
-  end if
-  if value = head.value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-      head.previous ← ø
-    end if
-    return true
-  end if
-  n ← head.next
-  while n != ø and value !== n.value
-    n ← n.next
-  end while
-  if n = tail
-    tail ← tail.previous
-    tail.next ← ø
-    return true
-  else if n != ø
-    n.previous.next ← n.next
-    n.next.previous ← n.previous
-    return true
-  end if
-  return false
-end Remove
-```
-
-### 反向遍历
-
-```text
-ReverseTraversal(tail)
-  Pre: tail is the node of the list to traverse
-  Post: the list has been traversed in reverse order
-  n ← tail
-  while n != ø
-    yield n.value
-    n ← n.previous
-  end while
-end Reverse Traversal
-```
-
-## 复杂度
-
-## 时间复杂度
-
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(1)      |
-
-### 空间复杂度
-
-O(n)
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
-- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/graph/README.en-EN.md b/src/data-structures/graph/README.en-EN.md
new file mode 100644
index 0000000000..7895f944ce
--- /dev/null
+++ b/src/data-structures/graph/README.en-EN.md
@@ -0,0 +1,30 @@
+# Graph
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **graph** is an abstract data type
+that is meant to implement the undirected graph and
+directed graph concepts from mathematics, specifically
+the field of graph theory
+
+A graph data structure consists of a finite (and possibly
+mutable) set of vertices or nodes or points, together
+with a set of unordered pairs of these vertices for an
+undirected graph or a set of ordered pairs for a
+directed graph. These pairs are known as edges, arcs,
+or lines for an undirected graph and as arrows,
+directed edges, directed arcs, or directed lines
+for a directed graph. The vertices may be part of
+the graph structure, or may be external entities
+represented by integer indices or references.
+
+![Graph](./images/graph.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Graph_(abstract_data_type)>)
+- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/graph/README.fr-FR.md b/src/data-structures/graph/README.fr-FR.md
deleted file mode 100644
index c6a6c90892..0000000000
--- a/src/data-structures/graph/README.fr-FR.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Graph
-
-En informatique, un **graphe** est une structure de
-données abstraite qui implémente les concepts de
-graphe orienté et de graphe non-orienté venant
-des mathématiques, plus précisément du domaine de
-la théorie des graphes.
-
-La structure de données abstraite de graphe consiste
-en un ensemble fini, éventuellement mutable de sommets
-ou nœuds ou points, avec un ensemble de paires ordonnées
-ou non de tels éléments. Ces paires sont des arêtes, arcs
-non orientés, ou lignes pour un graphe non orienté, et
-flèches, arêtes orientées , arcs, ou lignes orientées
-dans le cas orienté. Les sommets peuvent faire partie
-de la structure, ou être des entités extérieures,
-représentées par des entiers ou des références.
-
-![Graph](./images/graph.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## References
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Graphe_(type_abstrait))
diff --git a/src/data-structures/graph/README.md b/src/data-structures/graph/README.md
index 790602b536..a7876ccc39 100644
--- a/src/data-structures/graph/README.md
+++ b/src/data-structures/graph/README.md
@@ -1,35 +1,18 @@
-# Graph
+# Đồ Thị
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
+Trong khoa học máy tính, **đồ thị** là một loại dữ liệu trừu tượng được thiết kế để thực hiện các khái niệm về đồ thị vô hướng và đồ thị có hướng từ toán học, cụ thể là lĩnh vực lý thuyết đồ thị.
 
-In computer science, a **graph** is an abstract data type
-that is meant to implement the undirected graph and
-directed graph concepts from mathematics, specifically
-the field of graph theory
+Một cấu trúc dữ liệu đồ thị bao gồm một tập hợp hữu hạn (và có thể thay đổi) các đỉnh hoặc nút hoặc điểm, cùng với một tập hợp các cặp không thứ tự của các đỉnh này cho một đồ thị vô hướng hoặc một tập hợp các cặp có thứ tự cho một đồ thị có hướng. Các cặp này được gọi là cạnh, cung, hoặc đường cho một đồ thị vô hướng và là mũi tên, cạnh có hướng, cung có hướng, hoặc đường có hướng cho một đồ thị có hướng. Các đỉnh có thể là phần của cấu trúc đồ thị, hoặc có thể là các thực thể bên ngoài được biểu diễn bằng các chỉ số số nguyên hoặc tham chiếu.
 
-A graph data structure consists of a finite (and possibly
-mutable) set of vertices or nodes or points, together
-with a set of unordered pairs of these vertices for an
-undirected graph or a set of ordered pairs for a
-directed graph. These pairs are known as edges, arcs,
-or lines for an undirected graph and as arrows,
-directed edges, directed arcs, or directed lines
-for a directed graph. The vertices may be part of
-the graph structure, or may be external entities
-represented by integer indices or references.
+![Đồ Thị](./images/graph.jpeg)
 
-![Graph](./images/graph.jpeg)
+_Tạo với [okso.app](https://okso.app)_
 
-*Made with [okso.app](https://okso.app)*
+## Tham Khảo
 
-## References
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))
-- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Wikipedia](<https://en.wikipedia.org/wiki/Graph_(abstract_data_type)>)
+- [Giới Thiệu về Đồ Thị trên YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [Biểu Diễn Đồ Thị trên YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/graph/README.pt-BR.md b/src/data-structures/graph/README.pt-BR.md
deleted file mode 100644
index de7947cba8..0000000000
--- a/src/data-structures/graph/README.pt-BR.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Grafo (Graph)
-
-Na ciência da computação, um **grafo** é uma abstração de estrutura
-de dados que se destina a implementar os conceitos da matemática de
-grafos direcionados e não direcionados, especificamente o campo da
-teoria dos grafos.
-
-Uma estrutura de dados grafos consiste em um finito (e possivelmente
-mutável) conjunto de vértices, nós ou pontos, juntos com um
-conjunto de pares não ordenados desses vértices para um grafo não
-direcionado ou para um conjunto de pares ordenados para um grafo
-direcionado. Esses pares são conhecidos como arestas, arcos
-ou linhas diretas para um grafo não direcionado e como setas,
-arestas direcionadas, arcos direcionados ou linhas direcionadas
-para um grafo direcionado.
-
-Os vértices podem fazer parte a estrutura do grafo, ou podem
-ser entidades externas representadas por índices inteiros ou referências.
-
-![Graph](./images/graph.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))
-- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/graph/README.ru-RU.md b/src/data-structures/graph/README.ru-RU.md
deleted file mode 100644
index 950198451b..0000000000
--- a/src/data-structures/graph/README.ru-RU.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Граф
-
-**Граф** в информатике - абстрактный тип данных, который должен реализовывать концепции направленного и ненаправленного
-графа в математике, особенно в области теории графов.
-
-Структура данных графа состоит из конечного (и возможно изменяющегося) набора вершин или узлов, или точек, совместно с
-набором ненаправленных пар этих вершин для ненаправленного графа или с набором направленных пар для направленного графа.
-Эти пары известны как рёбра, арки или линии для ненаправленного графа и как стрелки, направленные рёбра, направленные
-арки или направленные линии для направленного графа. Эти вершины могут быть частью структуры графа, или внешними
-сущностями, представленными целочисленными индексами или ссылками.
-
-Для разных областей применения виды графов могут различаться направленностью, ограничениями на количество связей и
-дополнительными данными о вершинах или рёбрах. Многие структуры, представляющие практический интерес в математике и
-информатике, могут быть представлены графами. Например, строение Википедии можно смоделировать при помощи
-ориентированного графа, в котором вершины — это статьи, а дуги (ориентированные рёбра) — гиперссылки.
-
-![Граф](./images/graph.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Ссылки
-
-- [Граф в математике на Wikipedia](https://ru.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D1%84_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0))
-- [Графы на YouTube. Часть 1(~10 мин)](https://www.youtube.com/watch?v=GOUuhJPLG3s)
-- [Графы на YouTube. Часть 2(~10 мин)](https://www.youtube.com/watch?v=N-kCJJkTk7g)
-- [Графы на YouTube. Часть 3(~10 мин)](https://www.youtube.com/watch?v=2o3TINew0b8)
diff --git a/src/data-structures/graph/README.uk-UA.md b/src/data-structures/graph/README.uk-UA.md
deleted file mode 100644
index 9886cd904c..0000000000
--- a/src/data-structures/graph/README.uk-UA.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Граф
-
-**Граф** в інформатиці - абстрактний тип даних, який має реалізовувати концепції спрямованого та неспрямованого
-графа у математиці, особливо у галузі теорії графів.
-
-Структура даних графа складається з кінцевого (і можливо, що змінюється) набору вершин або вузлів, або точок, спільно з
-набором ненаправлених пар цих вершин для ненаправленого графа або набором спрямованих пар для спрямованого графа.
-Ці пари відомі як ребра, арки або лінії для ненаправленого графа та як стрілки, спрямовані ребра, спрямовані
-арки чи спрямовані лінії для спрямованого графа. Ці вершини можуть бути частиною структури графа, або зовнішніми
-сутностями, представленими цілими індексами або посиланнями.
-
-Для різних областей застосування види графів можуть відрізнятися спрямованістю, обмеженнями на кількість зв'язків та
-додатковими даними про вершини або ребра. Багато структур, що становлять практичний інтерес у математиці та
-інформатики можуть бути представлені графами. Наприклад, будову Вікіпедії можна змоделювати за допомогою
-орієнтованого графа, в якому вершини – це статті, а дуги (орієнтовані ребра) – гіперпосилання.
-
-![Граф](./images/graph.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Посилання
-
-- [Граф у математиці на Wikipedia](https://uk.wikipedia.org/wiki/%D0%93%D1%80%D0%B0%D1%84_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0))
-- [Структура даних Graph / Граф](https://www.youtube.com/watch?v=D0U8aFEhgKQ)
diff --git a/src/data-structures/graph/README.zh-CN.md b/src/data-structures/graph/README.zh-CN.md
deleted file mode 100644
index 1f885a43b9..0000000000
--- a/src/data-structures/graph/README.zh-CN.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# 图
-
-在计算机科学中, **图(graph)** 是一种抽象数据类型,
-旨在实现数学中的无向图和有向图概念，特别是图论领域。
-
-一个图数据结构是一个(由有限个或者可变数量的)顶点/节点/点和边构成的有限集。
-
-如果顶点对之间是无序的,称为无序图,否则称为有序图;
-
-如果顶点对之间的边是没有方向的,称为无向图,否则称为有向图;
-
-如果顶点对之间的边是有权重的,该图可称为加权图。
-
-![Graph](./images/graph.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))
-- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.en-EN.md b/src/data-structures/hash-table/README.en-EN.md
new file mode 100644
index 0000000000..486dd7875d
--- /dev/null
+++ b/src/data-structures/hash-table/README.en-EN.md
@@ -0,0 +1,31 @@
+# Hash Table
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computing, a **hash table** (hash map) is a data
+structure which implements an _associative array_
+abstract data type, a structure that can _map keys
+to values_. A hash table uses a _hash function_ to
+compute an index into an array of buckets or slots,
+from which the desired value can be found
+
+Ideally, the hash function will assign each key to a
+unique bucket, but most hash table designs employ an
+imperfect hash function, which might cause hash
+collisions where the hash function generates the same
+index for more than one key. Such collisions must be
+accommodated in some way.
+
+![Hash Table](./images/hash-table.jpeg)
+
+Hash collision resolved by separate chaining.
+
+![Hash Collision](./images/collision-resolution.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
+- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.fr-FR.md b/src/data-structures/hash-table/README.fr-FR.md
deleted file mode 100644
index 2fd41c8838..0000000000
--- a/src/data-structures/hash-table/README.fr-FR.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Table de hachage
-
-En informatique, une **table de hachage** (carte de
-hachage) est une structure de données qui implémente
-un type de données abstrait *tableau nassociatif*,
-une structure qui permet de *mapper des clés sur des
-valeurs*. Une table de hachage utilise une *fonction
-de hachage* pour calculer un index dans un tableau
-d'alvéoles (en anglais, buckets ou slots), à partir
-duquel la valeur souhaitée peut être trouvée.
-
-Idéalement, la fonction de hachage affectera chaque clé
-à une alvéole unique, mais la plupart des tables de
-hachage conçues emploient une fonction de hachage
-imparfaite, ce qui peut provoquer des collisions de
-hachage où la fonction de hachage génère le même index
-pour plusieurs clés. De telles collisions doivent être
-accommodées d'une manière ou d'une autre.
-
-![Hash Table](./images/hash-table.jpeg)
-
-Collision de hachage résolue par chaînage séparé.
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Table_de_hachage)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.ja-JP.md b/src/data-structures/hash-table/README.ja-JP.md
deleted file mode 100644
index d71cb273b9..0000000000
--- a/src/data-structures/hash-table/README.ja-JP.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# ハッシュテーブル
-
-コンピュータサイエンスにおいて、**ハッシュテーブル**（ハッシュマップ)は*キーを値にマッピング*できる*連想配列*の機能を持ったデータ構造です。ハッシュテーブルは*ハッシュ関数*を使ってバケットやスロットの配列へのインデックスを計算し、そこから目的の値を見つけることができます。
-
-理想的には、ハッシュ関数は各キーを一意のバケットに割り当てますが、ほとんどのハッシュテーブルは不完全なハッシュ関数を採用しているため、複数のキーに対して同じインデックスを生成した時にハッシュの衝突が起こります。このような衝突は何らかの方法で対処する必要があります。
-
-![Hash Table](./images/hash-table.jpeg)
-
-チェイン法によるハッシュの衝突の解決例
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.ko-KR.md b/src/data-structures/hash-table/README.ko-KR.md
deleted file mode 100644
index b3a8c94066..0000000000
--- a/src/data-structures/hash-table/README.ko-KR.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Hash Table
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md)
-
-컴퓨팅에서, **해시 테이블**(해시 맵)은 키를 값에 매핑할 수 있는 구조인 *연관 배열*을 구현하는 자료 구조입니다. 해시 테이블은 *해시 함수*를 사용해 원하는 값을 담을 수 있는 버킷 또는 슬롯 배열의 인덱스를 계산합니다.
-
-이상적으로, 해시 함수는 각 키들을 고유 버킷에 할당하지만 대부분의 해시 테이블은 불완전한 해시 함수를 사용하기 때문에 해시 함수를 통해 두 개 이상의 키에 대해 동일한 인덱스를 생성하는 해시 충돌이 발생할 수 있습니다. 이러한 해시 충돌은 어떠한 방법으로든 해결되어야 합니다.
-
-![Hash Table](./images/hash-table.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-다음은 분리 연결법을 통해 해시 충돌을 해결한 예시입니다.
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 참고
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.md b/src/data-structures/hash-table/README.md
index f0d0c9932d..ed0ab56534 100644
--- a/src/data-structures/hash-table/README.md
+++ b/src/data-structures/hash-table/README.md
@@ -1,37 +1,21 @@
-# Hash Table
+# Bảng Băm
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computing, a **hash table** (hash map) is a data
-structure which implements an _associative array_
-abstract data type, a structure that can _map keys
-to values_. A hash table uses a _hash function_ to
-compute an index into an array of buckets or slots,
-from which the desired value can be found
+Trong lĩnh vực máy tính, **bảng băm** (hash map) là một cấu trúc dữ liệu mà triển khai một loại dữ liệu trừu tượng gọi là _mảng kết hợp_, một cấu trúc có thể _ánh xạ các khóa sang các giá trị_. Một bảng băm sử dụng một _hàm băm_ để tính toán một chỉ số vào một mảng các ô hoặc khe, từ đó giá trị mong muốn có thể được tìm thấy.
 
-Ideally, the hash function will assign each key to a
-unique bucket, but most hash table designs employ an
-imperfect hash function, which might cause hash
-collisions where the hash function generates the same
-index for more than one key. Such collisions must be
-accommodated in some way.
+Lý tưởng, hàm băm sẽ gán mỗi khóa vào một khe duy nhất, nhưng hầu hết các thiết kế bảng băm sử dụng một hàm băm không hoàn hảo, có thể gây ra _xung đột băm_ khi hàm băm tạo ra cùng một chỉ số cho nhiều hơn một khóa. Những xung đột như vậy phải được xử lý một cách nào đó.
 
-![Hash Table](./images/hash-table.jpeg)
+![Bảng Băm](./images/hash-table.jpeg)
 
-Hash collision resolved by separate chaining.
+Xung đột băm được giải quyết bằng phương pháp chuỗi riêng.
 
-![Hash Collision](./images/collision-resolution.jpeg)
+![Xung Đột Băm](./images/collision-resolution.jpeg)
 
-_Made with [okso.app](https://okso.app)_
+_Tạo với [okso.app](https://okso.app)_
 
-## References
+## Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
 - [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.pt-BR.md b/src/data-structures/hash-table/README.pt-BR.md
deleted file mode 100644
index c89faf6ca1..0000000000
--- a/src/data-structures/hash-table/README.pt-BR.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Tabela de Hash (Hash Table)
-
-Na ciência da computação, uma **tabela de hash** (hash table) é uma
-estrutura de dados pela qual implementa um tipo de dado abstrado de
-*array associativo*, uma estrutura que pode *mapear chaves para valores*.
-Uma tabela de hash utiliza uma *função de hash* para calcular um índice
-em um _array_ de buckets ou slots, a partir do qual o valor desejado
-pode ser encontrado.
-
-Idealmente, a função de hash irá atribuir a cada chave a um bucket único,
-mas a maioria dos designs de tabela de hash emprega uma função de hash
-imperfeita, pela qual poderá causar colisões de hashes onde a função de hash
-gera o mesmo índice para mais de uma chave. Tais colisões devem ser
-acomodados de alguma forma.
-
-![Hash Table](./images/hash-table.jpeg)
-
-Colisão de hash resolvida por encadeamento separado.
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/hash-table/README.ru-RU.md b/src/data-structures/hash-table/README.ru-RU.md
deleted file mode 100644
index e1e21129da..0000000000
--- a/src/data-structures/hash-table/README.ru-RU.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Хэш таблица
-
-**Хеш-таблица** - структура данных, реализующая абстрактный тип данных *ассоциативный массив*, т.е. структура, которая
-*связывает ключи со значениями*. Хеш-таблица использует *хеш-функцию* для вычисления индекса в массиве, в котором может
-быть найдено желаемое значение. Ниже представлена хеш-таблица, в которой ключом выступает имя человека, а значениями
-являются телефонные номера. Хеш-функция преобразует ключ-имя в индекс массива с телефонными номерами.
-
-![Hash Table](./images/hash-table.jpeg)
-
-В идеале хеш-функция будет присваивать элементу массива уникальный ключ. Однако большинство реальных хеш-таблиц
-используют несовершенные хеш-функции. Это может привести к ситуациям, когда хеш-функция генерирует одинаковый индекс для
-нескольких ключей. Данные ситуации называются коллизиями и должны быть как-то разрешены.
-
-Существует два варианта решения коллизий - хеш-таблица с цепочками и с открытой адресацией.
-
-Метод цепочек подразумевает хранение значений, соответствующих одному и тому же индексу в виде связного списка(цепочки).
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Метод открытой адресации помещает значение, для которого получен дублирующий индекс, в первую свободную ячейку.
-
-![Хеш открытая адресация](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Hash_table_5_0_1_1_1_1_0_SP.svg/380px-Hash_table_5_0_1_1_1_1_0_SP.svg.png)
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A5%D0%B5%D1%88-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0)
-- [YouTube](https://www.youtube.com/watch?v=rVr1y32fDI0)
diff --git a/src/data-structures/hash-table/README.uk-UA.md b/src/data-structures/hash-table/README.uk-UA.md
deleted file mode 100644
index 2ab3183599..0000000000
--- a/src/data-structures/hash-table/README.uk-UA.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Геш таблиця
-
-**Геш таблиця** - структура даних, що реалізує абстрактний тип даних асоціативний масив, тобто. структура, яка
-_зв'язує ключі зі значеннями_. Геш-таблиця використовує _геш-функцію_ для обчислення індексу в масиві, в якому може
-бути знайдено бажане значення. Нижче представлена геш-таблиця, у якій ключем виступає ім'я людини, а значеннями
-телефонні номери. Геш-функція перетворює ключ-ім'я на індекс масиву з телефонними номерами.
-
-![Hash Table](./images/hash-table.jpeg)
-
-В ідеалі геш-функція присвоюватиме елементу масиву унікальний ключ. Проте більшість реальних геш-таблиць
-використовують недосконалі геш-функції. Це може призвести до ситуацій, коли геш-функція генерує однаковий індекс для
-кількох ключів. Ці ситуації називаються колізіями і мають бути якось вирішені.
-
-Існує два варіанти вирішення колізій - геш-таблиця з ланцюжками та з відкритою адресацією.
-
-Метод ланцюжків передбачає зберігання значень, відповідних одному й тому індексу як зв'язкового списку(ланцюжка).
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-_Made with [okso.app](https://okso.app)_
-
-Метод відкритої адресації поміщає значення, для якого отримано дублюючий індекс, в першу вільну комірку.
-
-![Геш відкрита адресація](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Hash_table_5_0_1_1_1_1_0_SP.svg/380px-Hash_table_5_0_1_1_1_1_0_SP.svg.png)
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%93%D0%B5%D1%88-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8F)
-- [YouTube](https://www.youtube.com/watch?v=WTYaboK-NMk)
diff --git a/src/data-structures/hash-table/README.zh-CN.md b/src/data-structures/hash-table/README.zh-CN.md
deleted file mode 100644
index c53214aa88..0000000000
--- a/src/data-structures/hash-table/README.zh-CN.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# 哈希表
-
-在计算中, 一个  **哈希表(hash table 或hash map)**  是一种实现 *关联数组(associative array)*
-的抽象数据类型, 该结构可以将 *键映射到值*。
-
-哈希表使用 *哈希函数/散列函数* 来计算一个值在数组或桶(buckets)中或槽(slots)中对应的索引,可使用该索引找到所需的值。
-
-理想情况下,散列函数将为每个键分配给一个唯一的桶(bucket),但是大多数哈希表设计采用不完美的散列函数,这可能会导致"哈希冲突(hash collisions)",也就是散列函数为多个键(key)生成了相同的索引,这种碰撞必须
-以某种方式进行处理。
-
-
-![Hash Table](./images/hash-table.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-通过单独的链接解决哈希冲突
-
-![Hash Collision](./images/collision-resolution.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
-- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.en-EN.md b/src/data-structures/heap/README.en-EN.md
new file mode 100644
index 0000000000..fdcb76b69c
--- /dev/null
+++ b/src/data-structures/heap/README.en-EN.md
@@ -0,0 +1,62 @@
+# Heap (data-structure)
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **heap** is a specialized tree-based
+data structure that satisfies the heap property described
+below.
+
+In a _min heap_, if `P` is a parent node of `C`, then the
+key (the value) of `P` is less than or equal to the
+key of `C`.
+
+![MinHeap](./images/min-heap.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+In a _max heap_, the key of `P` is greater than or equal
+to the key of `C`
+
+![MaxHeap](./images/max-heap.jpeg)
+
+![Array Representation](./images/array-representation.jpeg)
+
+The node at the "top" of the heap with no parents is
+called the root node.
+
+## Time Complexities
+
+Here are time complexities of various heap data structures. Function names assume a max-heap.
+
+| Operation                                                                                          | find-max   | delete-max | insert     | increase-key | meld       |
+| -------------------------------------------------------------------------------------------------- | ---------- | ---------- | ---------- | ------------ | ---------- |
+| [Binary](https://en.wikipedia.org/wiki/Binary_heap)                                                | `Θ(1)`     | `Θ(log n)` | `O(log n)` | `O(log n)`   | `Θ(n)`     |
+| [Leftist](https://en.wikipedia.org/wiki/Leftist_tree)                                              | `Θ(1)`     | `Θ(log n)` | `Θ(log n)` | `O(log n)`   | `Θ(log n)` |
+| [Binomial](https://en.wikipedia.org/wiki/Binomial_heap)                                            | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `O(log n)`   | `O(log n)` |
+| [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap)                                          | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`       | `Θ(1)`     |
+| [Pairing](https://en.wikipedia.org/wiki/Pairing_heap)                                              | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `o(log n)`   | `Θ(1)`     |
+| [Brodal](https://en.wikipedia.org/wiki/Brodal_queue)                                               | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`       | `Θ(1)`     |
+| [Rank-pairing](https://en.wikipedia.org/w/index.php?title=Rank-pairing_heap&action=edit&redlink=1) | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`       | `Θ(1)`     |
+| [Strict Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap)                                   | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`       | `Θ(1)`     |
+| [2-3 heap](https://en.wikipedia.org/wiki/2%E2%80%933_heap)                                         | `O(log n)` | `O(log n)` | `O(log n)` | `Θ(1)`       | `?`        |
+
+Where:
+
+- **find-max (or find-min):** find a maximum item of a max-heap, or a minimum item of a min-heap, respectively (a.k.a. _peek_)
+- **delete-max (or delete-min):** removing the root node of a max heap (or min heap), respectively
+- **insert:** adding a new key to the heap (a.k.a., _push_)
+- **increase-key or decrease-key:** updating a key within a max- or min-heap, respectively
+- **meld:** joining two heaps to form a valid new heap containing all the elements of both, destroying the original heaps.
+
+> In this repository, the [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) are examples of the **Binary** heap.
+
+## Implementation
+
+- [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js)
+- [MaxHeapAdhoc.js](./MaxHeapAdhoc.js) and [MinHeapAdhoc.js](./MinHeapAdhoc.js) - The minimalistic (ad hoc) version of a MinHeap/MaxHeap data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Heap_(data_structure)>)
+- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.fr-FR.md b/src/data-structures/heap/README.fr-FR.md
deleted file mode 100644
index 56f184b593..0000000000
--- a/src/data-structures/heap/README.fr-FR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Tas (structure de données)
-
-En informatique, un **tas** est une structure de données arborescente spécialisée qui satisfait la propriété de tas décrite ci-dessous.
-
-Dans un *tas minimal* (en anglais *min heap*), si `P` est un nœud parent de `C`, alors la clé (la valeur) de `P` est inférieure ou égale à la clé de `C`.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Dans un *tas maximal* (en anglais *max heap*), la clé de `P` est supérieure ou égale à la clé de `C`.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-Le nœud au «sommet» du tas sans parents est appelé le nœud racine.
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Tas_(informatique))
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.ja-JP.md b/src/data-structures/heap/README.ja-JP.md
deleted file mode 100644
index 13d3e36338..0000000000
--- a/src/data-structures/heap/README.ja-JP.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# ヒープ (データ構造)
-
-コンピュータサイエンスにおいて、*ヒープ*は特殊な木構造のデータ構造で、後述するヒープの特性を持っています。
-
-*最小ヒープ*では、もし`P`が`C`の親ノードの場合、`P`のキー(値)は`C`のキーより小さい、または等しくなります。
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-*最大ヒープ*では、`P`のキーは`C`のキーより大きい、もしくは等しくなります。
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-ヒープの「トップ」のノードには親ノードが存在せず、ルートノードと呼ばれます。
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.ko-KR.md b/src/data-structures/heap/README.ko-KR.md
deleted file mode 100644
index 136a87b420..0000000000
--- a/src/data-structures/heap/README.ko-KR.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# 힙 (자료구조)
-
-컴퓨터 과학에서의 **힙**은 아래에 설명된 힙 속성을 만족하는 전문화된 트리 기반 데이터구조입니다.
-
-*최소 힙*에서 `P`가 `C`의 상위 노드라면 `P`의 키(값)는 `C`의 키보다 작거나 같습니다.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-*최대 힙*에서 `P`의 키는 `C`의 키보다 크거나 같습니다.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-상위 노드가 없는 힙의 "상단"에 있는 노드를 루트 노드라고 합니다.
-
-## 참조
-
-- [Wikipedia](<https://en.wikipedia.org/wiki/Heap_(data_structure)>)
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-
diff --git a/src/data-structures/heap/README.md b/src/data-structures/heap/README.md
index 392c5c96bc..3c40d9fb25 100644
--- a/src/data-structures/heap/README.md
+++ b/src/data-structures/heap/README.md
@@ -1,69 +1,54 @@
-# Heap (data-structure)
+# Cây Heap (Cấu trúc dữ liệu)
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_Türkçe_](README.tr-TR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
+_Bạn có thể đọc bản dịch bằng các ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
+Trong khoa học máy tính, một **cây heap** là một cấu trúc dữ liệu dựa trên cây đặc biệt được thiết kế để thỏa mãn thuộc tính cây heap mô tả dưới đây.
 
-In computer science, a **heap** is a specialized tree-based
-data structure that satisfies the heap property described
-below.
-
-In a *min heap*, if `P` is a parent node of `C`, then the
-key (the value) of `P` is less than or equal to the
-key of `C`.
+Trong một _heap tối thiểu_, nếu `P` là một nút cha của `C`, thì khóa (giá trị) của `P` phải nhỏ hơn hoặc bằng khóa của `C`.
 
 ![MinHeap](./images/min-heap.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo với [okso.app](https://okso.app)_
 
-In a *max heap*, the key of `P` is greater than or equal
-to the key of `C`
+Trong một _heap tối đa_, khóa của `P` phải lớn hơn hoặc bằng khóa của `C`.
 
 ![MaxHeap](./images/max-heap.jpeg)
 
-![Array Representation](./images/array-representation.jpeg)
+Nút ở "đỉnh" của heap mà không có nút cha được gọi là nút gốc.
 
-The node at the "top" of the heap with no parents is
-called the root node.
+## Phức Tạp Thời Gian
 
-## Time Complexities
+Dưới đây là phức tạp thời gian của các cấu trúc dữ liệu heap khác nhau. Tên hàm giả sử một heap tối đa.
 
-Here are time complexities of various heap data structures. Function names assume a max-heap.
+| Hoạt Động                                                                                              | tìm-max    | xóa-max    | chèn       | tăng-khóa  | hợp        |
+| ------------------------------------------------------------------------------------------------------ | ---------- | ---------- | ---------- | ---------- | ---------- |
+| [Nhị Phân](https://en.wikipedia.org/wiki/Binary_heap)                                                  | `Θ(1)`     | `Θ(log n)` | `O(log n)` | `O(log n)` | `Θ(n)`     |
+| [Leftist](https://en.wikipedia.org/wiki/Leftist_tree)                                                  | `Θ(1)`     | `Θ(log n)` | `Θ(log n)` | `O(log n)` | `Θ(log n)` |
+| [Hình thái nhị phân](https://en.wikipedia.org/wiki/Binomial_heap)                                      | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `O(log n)` | `O(log n)` |
+| [Hình thái Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap)                                    | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`     | `Θ(1)`     |
+| [Hình thái Pairing](https://en.wikipedia.org/wiki/Pairing_heap)                                        | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `o(log n)` | `Θ(1)`     |
+| [Brodal](https://en.wikipedia.org/wiki/Brodal_queue)                                                   | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`     | `Θ(1)`     |
+| [Xếp hạng-Pairing](https://en.wikipedia.org/w/index.php?title=Rank-pairing_heap&action=edit&redlink=1) | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`     | `Θ(1)`     |
+| [Fibonacci nghiêm ngặt](https://en.wikipedia.org/wiki/Fibonacci_heap)                                  | `Θ(1)`     | `Θ(log n)` | `Θ(1)`     | `Θ(1)`     | `Θ(1)`     |
+| [2-3 heap](https://en.wikipedia.org/wiki/2%E2%80%933_heap)                                             | `O(log n)` | `O(log n)` | `O(log n)` | `Θ(1)`     | `?`        |
 
-| Operation | find-max | delete-max | insert| increase-key| meld |
-| --------- | -------- | ---------- | ----- | ----------- | ---- |
-| [Binary](https://en.wikipedia.org/wiki/Binary_heap) | `Θ(1)` | `Θ(log n)` | `O(log n)` | `O(log n)` | `Θ(n)` |
-| [Leftist](https://en.wikipedia.org/wiki/Leftist_tree) | `Θ(1)` | `Θ(log n)` | `Θ(log n)` | `O(log n)` | `Θ(log n)` |
-| [Binomial](https://en.wikipedia.org/wiki/Binomial_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `O(log n)` | `O(log n)` |
-| [Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |
-| [Pairing](https://en.wikipedia.org/wiki/Pairing_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `o(log n)` | `Θ(1)` |
-| [Brodal](https://en.wikipedia.org/wiki/Brodal_queue) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |
-| [Rank-pairing](https://en.wikipedia.org/w/index.php?title=Rank-pairing_heap&action=edit&redlink=1) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |
-| [Strict Fibonacci](https://en.wikipedia.org/wiki/Fibonacci_heap) | `Θ(1)` | `Θ(log n)` | `Θ(1)` | `Θ(1)` | `Θ(1)` |
-| [2-3 heap](https://en.wikipedia.org/wiki/2%E2%80%933_heap) | `O(log n)` | `O(log n)` | `O(log n)` | `Θ(1)` | `?` |
+Trong đó:
 
-Where:
-- **find-max (or find-min):** find a maximum item of a max-heap, or a minimum item of a min-heap, respectively (a.k.a. *peek*)
-- **delete-max (or delete-min):** removing the root node of a max heap (or min heap), respectively
-- **insert:** adding a new key to the heap (a.k.a., *push*)
-- **increase-key or decrease-key:** updating a key within a max- or min-heap, respectively
-- **meld:** joining two heaps to form a valid new heap containing all the elements of both, destroying the original heaps.
+- **tìm-max (hoặc tìm-min):** tìm một phần tử tối đa của heap tối đa hoặc một phần tử tối thiểu của heap tối thiểu, tương ứng (còn được gọi là _đỉnh_)
+- **xóa-max (hoặc xóa-min):** loại bỏ nút gốc của heap tối đa (hoặc heap tối thiểu), tương ứng
+- **chèn:** thêm một khóa mới vào heap (còn được gọi là _đẩy_)
+- **tăng-khóa hoặc giảm-khóa:** cập nhật một khóa trong heap tối đa hoặc tối thiểu, tương ứng
+- **hợp:** kết hợp hai heap để tạo ra một heap mới hợp lệ chứa tất cả các phần tử của cả hai, phá hủy các heap gốc.
 
-> In this repository, the [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) are examples of the **Binary** heap.
+> Trong kho lưu trữ này, [MaxHeap.js](./MaxHeap.js) và [MinHeap.js](./MinHeap.js) là các ví dụ về heap **Nhị phân**.
 
-## Implementation
+## Cài Đặt
 
-- [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js)
-- [MaxHeapAdhoc.js](./MaxHeapAdhoc.js) and [MinHeapAdhoc.js](./MinHeapAdhoc.js) - The minimalistic (ad hoc) version of a MinHeap/MaxHeap data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
+- [MaxHeap.js](./MaxHeap.js) và [MinHeap.js](./MinHeap.js)
+- [MaxHeapAdhoc.js](./MaxHeapAdhoc.js) và [MinHeapAdhoc.js](./MinHeapAdhoc.js) - Phiên bản tối giản (tùy ý) của cấu trúc dữ liệu MinHeap/MaxHeap không có các phụ thuộc bên ngoài và dễ dàng sao chép và sử dụng trong quá trình phỏng vấn lập trình nếu được phép bởi người phỏng vấn (vì nhiều cấu trúc dữ liệu trong JS thiếu).
 
-## References
+## Tham Khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
+- [Wikipedia](<https://en.wikipedia.org/wiki/Heap_(data_structure)>)
 - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.pt-BR.md b/src/data-structures/heap/README.pt-BR.md
deleted file mode 100644
index f229048d3a..0000000000
--- a/src/data-structures/heap/README.pt-BR.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Heap (estrutura de dados)
-
-Na ciência da computação, um **heap** é uma estrutura de dados
-baseada em uma árvore especializada que satisfaz a propriedade _heap_ descrita abaixo.
-
-Em um *heap mínimo* (min heap), caso `P` é um nó pai de `C`, então a chave
-(o valor) de `P` é menor ou igual a chave de `C`.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Em uma *heap máximo* (max heap), a chave de `P` é maior ou igual
-a chave de `C`.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-O nó no "topo" do _heap_, cujo não possui pais, é chamado de nó raiz.
-
-## References
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.ru-RU.md b/src/data-structures/heap/README.ru-RU.md
deleted file mode 100644
index 4c074d1f7c..0000000000
--- a/src/data-structures/heap/README.ru-RU.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Куча (структура данных)
-
-В компьютерных науках куча — это специализированная структура данных типа дерево, которая удовлетворяет свойству кучи:
-если B является узлом-потомком узла A, то ключ(A) ≥ ключ(B). Из этого следует, что элемент с наибольшим ключом всегда
-является корневым узлом кучи, поэтому иногда такие кучи называют max-кучами.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-Если сравнение перевернуть, то наименьший элемент будет всегда корневым узлом, такие кучи называют min-кучами.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Не существует никаких ограничений относительно того, сколько узлов-потомков имеет каждый узел кучи. На практике их
-число обычно не более двух. Куча является максимально эффективной реализацией абстрактного типа данных, который
-называется очередью с приоритетом.
-
-Узел на вершине кучи, у которого нет родителей, называется корневым узлом.
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/Куча_(структура_данных))
-- [YouTube](https://www.youtube.com/watch?v=noQ4SUoqrQA)
diff --git a/src/data-structures/heap/README.tr-TR.md b/src/data-structures/heap/README.tr-TR.md
deleted file mode 100644
index 05906391e8..0000000000
--- a/src/data-structures/heap/README.tr-TR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Heap (data-structure)
-
-Bilgisayar biliminde, **yığın (heap)** aşağıda açıklanan özellikleri karşılayan ağaç tabanlı(tree-based) özel bir veri yapısıdır.
-
-*min heap*, Eğer `P`, `C`'nin üst düğümü ise, `P`'nin anahtarı (değeri)  `C`'nin anahtarından (değerinden) küçük veya ona eşittir.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-*max heap*, `P`'nin anahtarı `C`'nin anahtarından büyük veya eşittir.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-Yığının (Heap) "en üstündeki" ebeveyni olmayan düğüme kök düğüm (root node) denir.
-
-## Referanslar
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/heap/README.uk-UA.md b/src/data-structures/heap/README.uk-UA.md
deleted file mode 100644
index f35995d8ae..0000000000
--- a/src/data-structures/heap/README.uk-UA.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Купа (структура даних)
-
-У комп'ютерних науках купа - це спеціалізована структура даних на кшталт дерева, яка задовольняє властивості купи:
-якщо B є вузлом-нащадком вузла A, то ключ (A) ≥ ключ (B). З цього випливає, що елемент із найбільшим ключем завжди
-є кореневим вузлом купи, тому іноді такі купи називають max-купами.
-
-![MaxHeap](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-Якщо порівняння перевернути, то найменший елемент завжди буде кореневим вузлом, такі купи називають min-купами.
-
-![MinHeap](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-Не існує жодних обмежень щодо того, скільки вузлів-нащадків має кожен вузол купи. На практиці їх
-число зазвичай трохи більше двох. Купа є максимально ефективною реалізацією абстрактного типу даних, який
-називається чергою із пріоритетом.
-
-Вузол на вершині купи, який не має батьків, називається кореневим вузлом.
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%9A%D1%83%D0%BF%D0%B0_(%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85))
diff --git a/src/data-structures/heap/README.zh-CN.md b/src/data-structures/heap/README.zh-CN.md
deleted file mode 100644
index 8ba42dfb05..0000000000
--- a/src/data-structures/heap/README.zh-CN.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# 堆 (数据结构)
-
-在计算机科学中, 一个 **堆(heap)** 是一种特殊的基于树的数据结构，它满足下面描述的堆属性。
-
-在一个 *最小堆(min heap)* 中, 如果 `P` 是 `C` 的一个父级节点, 那么 `P`  的key(或value)应小于或等于 `C` 的对应值.
-
-![M最小堆](./images/min-heap.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-在一个  *最大堆(max heap)* 中,  `P` 的key(或value)大于 `C` 的对应值。
-
-![堆](./images/max-heap.jpeg)
-
-![Array Representation](./images/array-representation.jpeg)
-
-
-在堆“顶部”的没有父级节点的节点,被称之为根节点。
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.zh-CN.md b/src/data-structures/linked-list/README.en-EN.md
similarity index 62%
rename from src/data-structures/linked-list/README.zh-CN.md
rename to src/data-structures/linked-list/README.en-EN.md
index f0b75121e7..823411ec5d 100644
--- a/src/data-structures/linked-list/README.zh-CN.md
+++ b/src/data-structures/linked-list/README.en-EN.md
@@ -1,20 +1,32 @@
-# 链表
-
-在计算机科学中, 一个 **链表** 是数据元素的线性集合, 元素的线性顺序不是由它们在内存中的物理位置给出的。 相反, 每个元素指向下一个元素。它是由一组节点组成的数据结构,这些节点一起,表示序列。
-
-在最简单的形式下，每个节点由数据和到序列中下一个节点的引用(换句话说，链接)组成。这种结构允许在迭代期间有效地从序列中的任何位置插入或删除元素。
-
-更复杂的变体添加额外的链接，允许有效地插入或删除任意元素引用。链表的一个缺点是访问时间是线性的(而且难以管道化)。
-
-更快的访问，如随机访问，是不可行的。与链表相比，数组具有更好的缓存位置。
+# Linked List
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **linked list** is a linear collection
+of data elements, in which linear order is not given by
+their physical placement in memory. Instead, each
+element points to the next. It is a data structure
+consisting of a group of nodes which together represent
+a sequence. Under the simplest form, each node is
+composed of data and a reference (in other words,
+a link) to the next node in the sequence. This structure
+allows for efficient insertion or removal of elements
+from any position in the sequence during iteration.
+More complex variants add additional links, allowing
+efficient insertion or removal from arbitrary element
+references. A drawback of linked lists is that access
+time is linear (and difficult to pipeline). Faster
+access, such as random access, is not feasible. Arrays
+have better cache locality as compared to linked lists.
 
 ![Linked List](./images/linked-list.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Made with [okso.app](https://okso.app)_
 
-## 基本操作的伪代码
+## Pseudocode for Basic Operations
 
-### 插入
+### Insert
 
 ```text
 Add(value)
@@ -31,7 +43,7 @@ Add(value)
 end Add
 ```
 
-```
+```text
 Prepend(value)
  Pre: value is the value to add to the list
  Post: value has been placed at the head of the list
@@ -44,7 +56,7 @@ Prepend(value)
 end Prepend
 ```
 
-### 搜索
+### Search
 
 ```text
 Contains(head, value)
@@ -62,7 +74,7 @@ Contains(head, value)
 end Contains
 ```
 
-### 删除
+### Delete
 
 ```text
 Remove(head, value)
@@ -88,15 +100,17 @@ Remove(head, value)
   if n.next != ø
     if n.next = tail
       tail ← n
+      tail.next = null
+    else
+      n.next ← n.next.next
     end if
-    n.next ← n.next.next
     return true
   end if
   return false
 end Remove
 ```
 
-### 遍历
+### Traverse
 
 ```text
 Traverse(head)
@@ -110,7 +124,7 @@ Traverse(head)
 end Traverse
 ```
 
-### 反向遍历
+### Traverse in Reverse
 
 ```text
 ReverseTraversal(head, tail)
@@ -131,19 +145,19 @@ ReverseTraversal(head, tail)
 end ReverseTraversal
 ```
 
-## 复杂度
+## Complexities
 
-### 时间复杂度
+### Time Complexity
 
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(1)      |
+| Access | Search | Insertion | Deletion |
+| :----: | :----: | :-------: | :------: |
+|  O(n)  |  O(n)  |   O(1)    |   O(n)   |
 
-### 空间复杂度
+### Space Complexity
 
 O(n)
 
-## 参考
+## References
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
 - [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.es-ES.md b/src/data-structures/linked-list/README.es-ES.md
deleted file mode 100644
index c21c48cded..0000000000
--- a/src/data-structures/linked-list/README.es-ES.md
+++ /dev/null
@@ -1,165 +0,0 @@
-# Lista Enlazada (Linked List)
-
-_Lee este artículo en otros idiomas:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md)
-[_English_](README.md)
-
-En ciencias de la computaciòn una **lista enlazada** es una  coleccion linear
-de elementos de datos, en los cuales el orden linear no es dado por
-su posciòn fisica en memoria. En cambio, cada
-elemento señala al siguiente. Es una estructura de datos
-que consiste en un grupo de nodos los cuales juntos representan
-una secuencia. En su forma más sencilla, cada nodo está
-compuesto de datos y una referencia (en otras palabras,
-un enlace) al siguiente nodo en la secuencia. Esta estructura
-permite la inserción o eliminación de elementos
-desde cualquier posición en la secuencia durante la iteración.
-Las variantes más complejas agregan enlaces adicionales, permitiendo
-una eficiente inserción o eliminación desde referencias arbitrarias
-del elemento. Una desventaja de las listas lazadas es que el tiempo de
-acceso es lineal (y difícil de canalizar). Un acceso
-más rápido, como un acceso aleatorio, no es factible. Los arreglos
-tienen una mejor locazion en caché comparados con las listas lazadas.
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Pseudocódigo para operaciones básicas
-
-### Insertar
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value is the value to add to the list
- Post: value has been placed at the head of the list
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### Buscar
-
-```text
-Contains(head, value)
-  Pre: head is the head node in the list
-       value is the value to search for
-  Post: the item is either in the linked list, true; otherwise false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Borrar
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true, otherwise false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Atrevesar
-
-```text
-Traverse(head)
-  Pre: head is the head node in the list
-  Post: the items in the list have been traversed
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### Atravesar en Reversa
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head and tail belong to the same list
-  Post: the items in the list have been traversed in reverse order
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## Complejidades
-
-### Complejidad de Tiempo
-
-| Acceso | Búsqueda | Inserción | Eliminación |
-| :----: | :------: | :-------: | :---------: |
-|  O(n)  |   O(n)   |   O(1)    |    O(n)     |
-
-### Complejidad Espacial
-
-O(n)
-
-## Referencias
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.ja-JP.md b/src/data-structures/linked-list/README.ja-JP.md
deleted file mode 100644
index c78997042b..0000000000
--- a/src/data-structures/linked-list/README.ja-JP.md
+++ /dev/null
@@ -1,143 +0,0 @@
-# リンクリスト
-
-コンピュータサイエンスにおいて、**リンクリスト**はデータ要素の線形コレクションです。要素の順番はメモリ内の物理的な配置によっては決まりません。代わりに、各要素が次の要素を指しています。リンクリストはノードのグループからなるデータ構造です。最も単純な形式では、各ノードはデータとシーケンス内における次のノードへの参照(つまり、リンク)で構成されています。この構造はイテレーションにおいて任意の位置へ要素を効率的に挿入、削除することを可能にしています。より複雑なリンクリストではリンクをさらに追加することで、任意の要素の参照から要素を効率的に挿入、削除することを可能にしています。リンクリストの欠点はアクセスタイムが線形である(そして、パイプライン処理が難しい)ことです。ランダムアクセスのような高速なアクセスは実現不可能です。配列の方がリンクリストと比較して参照の局所性が優れています。
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 基本操作の擬似コード
-
-### 挿入
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value is the value to add to the list
- Post: value has been placed at the head of the list
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### 検索
-
-```text
-Contains(head, value)
-  Pre: head is the head node in the list
-       value is the value to search for
-  Post: the item is either in the linked list, true; otherwise false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### 削除
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true, otherwise false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### トラバース
-
-```text
-Traverse(head)
-  Pre: head is the head node in the list
-  Post: the items in the list have been traversed
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### 逆トラバース
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head and tail belong to the same list
-  Post: the items in the list have been traversed in reverse order
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## 計算量
-
-### 時間計算量
-
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-### 空間計算量
-
-O(n)
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.ko-KR.md b/src/data-structures/linked-list/README.ko-KR.md
deleted file mode 100644
index f68d8a464d..0000000000
--- a/src/data-structures/linked-list/README.ko-KR.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# 링크드 리스트
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md)
-
-컴퓨터과학에서, **링크드 리스트**는 데이터 요소의 선형 집합이며, 이 집합에서 논리적 저장 순서는 메모리의 물리적 저장 순서와 일치하지 않습니다. 그 대신, 각각의 원소들은 자기 자신 다음의 원소를 가리킵니다. **링크드 리스트**는 순서를 표현하는 노드들의 집합으로 이루어져 있습니다. 간단하게, 각각의 노드들은 데이터와 다음 순서의 노드를 가리키는 레퍼런스로 이루어져 있습니다. (링크라고 부릅니다.) 이 자료구조는 순회하는 동안 순서에 상관없이 효율적인 삽입이나 삭제가 가능합니다. 더 복잡한 변형은 추가적인 링크를 더해, 임의의 원소 참조로부터 효율적인 삽입과 삭제를 가능하게 합니다. 링크드 리스트의 단점은 접근 시간이 선형이라는 것이고, 병렬처리도 하지 못합니다. 임의 접근처럼 빠른 접근은 불가능합니다. 링크드 리스트에 비해 배열이 더 나은 캐시 지역성을 가지고 있습니다.
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 기본 연산에 대한 수도코드
-
-### 삽입
-
-```text
-Add(value)
-  Pre: 리스트에 추가할 값
-  Post: 리스트의 맨 마지막에 있는 값
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: 리스트에 추가할 값
- Post: 리스트의 맨 앞에 있는 값
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### 탐색
-
-```text
-Contains(head, value)
-  Pre: head는 리스트에서 맨 앞 노드
-       value는 찾고자 하는 값
-  Post: 항목이 링크드 리스트에 있으면 true;
-        없으면 false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### 삭제
-
-```text
-Remove(head, value)
-  Pre: head는 리스트에서 맨 앞 노드
-       value는 삭제하고자 하는 값
-  Post: 항목이 링크드 리스트에서 삭제되면 true;
-        없으면 false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### 순회
-
-```text
-Traverse(head)
-  Pre: head는 리스트에서 맨 앞 노드
-  Post: 순회된 항목들
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### 역순회
-
-```text
-ReverseTraversal(head, tail)
-  Pre: 같은 리스트에 들어 있는 맨 앞, 맨 뒤 노드
-  Post: 역순회된 항목들
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## 복잡도
-
-### 시간 복잡도
-
-|  접근   |  탐색   |  삽입   |  삭제   |
-| :---: | :---: | :---: | :---: |
-| O(n)  | O(n)  | O(1)  | O(n)  |
-
-### 공간 복잡도
-
-O(n)
-
-## 참조
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.md b/src/data-structures/linked-list/README.md
index 825a0272f4..1683506190 100644
--- a/src/data-structures/linked-list/README.md
+++ b/src/data-structures/linked-list/README.md
@@ -1,170 +1,148 @@
-# Linked List
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Español_](README.es-ES.md),
-[_Türkçe_](README.tr-TR.md),
-[_Українська_](README.uk-UA.md)
-
-In computer science, a **linked list** is a linear collection
-of data elements, in which linear order is not given by
-their physical placement in memory. Instead, each
-element points to the next. It is a data structure
-consisting of a group of nodes which together represent
-a sequence. Under the simplest form, each node is
-composed of data and a reference (in other words,
-a link) to the next node in the sequence. This structure
-allows for efficient insertion or removal of elements
-from any position in the sequence during iteration.
-More complex variants add additional links, allowing
-efficient insertion or removal from arbitrary element
-references. A drawback of linked lists is that access
-time is linear (and difficult to pipeline). Faster
-access, such as random access, is not feasible. Arrays
-have better cache locality as compared to linked lists.
+# Danh Sách Liên Kết
+
+_Tìm hiểu bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, một **danh sách liên kết** là một tập hợp tuyến tính các phần tử dữ liệu, trong đó thứ tự tuyến tính không được xác định bởi vị trí vật lý trong bộ nhớ. Thay vào đó, mỗi phần tử trỏ đến phần tử tiếp theo. Đó là một cấu trúc dữ liệu bao gồm một nhóm các nút cùng đại diện cho một chuỗi. Dưới dạng đơn giản nhất, mỗi nút bao gồm dữ liệu và một tham chiếu (nói cách khác, một liên kết) đến nút tiếp theo trong chuỗi. Cấu trúc này cho phép việc chèn hoặc xóa hiệu quả các phần tử từ bất kỳ vị trí nào trong chuỗi trong quá trình lặp. Các biến thể phức tạp hơn thêm các liên kết bổ sung, cho phép việc chèn hoặc xóa hiệu quả từ các tham chiếu phần tử tùy ý. Một hạn chế của danh sách liên kết là thời gian truy cập tuyến tính (và khó xử lý). Truy cập nhanh, như truy cập ngẫu nhiên, không khả thi. Mảng có sự tương đồng bộ hơn so với danh sách liên kết.
 
 ![Linked List](./images/linked-list.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo với [okso.app](https://okso.app)_
 
-## Pseudocode for Basic Operations
+## Mã Giả Cho Các Hoạt Động Cơ Bản
 
-### Insert
+### Chèn
 
 ```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
+Thêm(giá_trị)
+  Tiền: giá_trị là giá trị để thêm vào danh sách
+  Sau: giá_trị đã được đặt ở cuối danh sách
+  n ← nút(giá_trị)
+  nếu đầu = ø
+    đầu ← n
+    cuối ← n
+  nếu không
+    cuối.kế_tiếp ← n
+    cuối ← n
+  kết thúc nếu
+end Thêm
 ```
 
 ```text
-Prepend(value)
- Pre: value is the value to add to the list
- Post: value has been placed at the head of the list
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
+ChènTrước(giá_trị)
+ Tiền: giá_trị là giá trị để thêm vào danh sách
+ Sau: giá_trị đã được đặt ở đầu danh sách
+ n ← nút(giá_trị)
+ n.kế_tiếp ← đầu
+ đầu ← n
+ nếu cuối = ø
+   cuối ← n
+ kết thúc
+end ChènTrước
 ```
 
-### Search
+### Tìm Kiếm
 
 ```text
-Contains(head, value)
-  Pre: head is the head node in the list
-       value is the value to search for
-  Post: the item is either in the linked list, true; otherwise false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
+Chứa(đầu, giá_trị)
+  Tiền: đầu là nút đầu trong danh sách
+       giá_trị là giá trị để tìm kiếm
+  Sau: phần tử có thể có trong danh sách liên kết, true; nếu không, là false
+  n ← đầu
+  khi n != ø và n.giá_trị != giá_trị
+    n ← n.kế_tiếp
+  kết thúc khi
+  nếu n = ø
+    trả về false
+  kết thúc nếu
+  trả về true
+end Chứa
 ```
 
-### Delete
+### Xóa
 
 ```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true, otherwise false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-      tail.next = null
-    else
-      n.next ← n.next.next
-    end if
-    return true
-  end if
-  return false
-end Remove
+Xóa(đầu, giá_trị)
+  Tiền: đầu là nút đầu trong danh sách
+       giá_trị là giá trị để loại bỏ khỏi danh sách
+  Sau: giá_trị được loại bỏ khỏi danh sách, true; nếu không, là false
+  nếu đầu = ø
+    trả về false
+  kết thúc nếu
+  n ← đầu
+  nếu n.giá_trị = giá_trị
+    nếu đầu = cuối
+      đầu ← ø
+      cuối ← ø
+    nếu không
+      đầu ← đầu.kế_tiếp
+    kết thúc nếu
+    trả về true
+  kết thúc nếu
+  khi n.kế_tiếp != ø và n.kế_tiếp.giá_trị != giá_trị
+    n ← n.kế_tiếp
+  kết thúc khi
+  nếu n.kế_tiếp != ø
+    nếu n.kế_tiếp = cuối
+      cuối ← n
+      cuối.kế_tiếp = null
+    nếu không
+      n.kế_tiếp ← n.kế_tiếp.kế_tiếp
+    kết thúc nếu
+    trả về true
+  kết thúc nếu
+  trả về false
+end Xóa
 ```
 
-### Traverse
+### Duyệt
 
 ```text
-Traverse(head)
-  Pre: head is the head node in the list
-  Post: the items in the list have been traversed
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
+Duyệt(đầu)
+  Tiền: đầu là nút đầu trong danh sách
+  Sau: các mục trong danh sách đã được duyệt
+  n ← đầu
+  khi n != ø
+    xuất n.giá_trị
+    n ← n.kế_tiếp
+  kết thúc khi
+end Duyệt
 ```
 
-### Traverse in Reverse
+### Duyệt Ngược
 
 ```text
-ReverseTraversal(head, tail)
-  Pre: head and tail belong to the same list
-  Post: the items in the list have been traversed in reverse order
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
+DuyệtNgược(đầu, cuối)
+  Tiền: đầu và cuối thuộc cùng một danh sách
+  Sau: các mục trong danh sách đã được duyệt theo thứ tự ngược lại
+  nếu cuối != ø
+    hiện_tại ← cuối
+    khi hiện_tại != đầu
+      trước ← đầu
+      khi trước.kế_tiếp != hiện_tại
+        trước ← trước.kế_tiếp
+      kết thúc khi
+      xuất hiện_tại.giá_trị
+      hiện_tại ← trước
+    kết thúc khi
+   xuất hiện_tại.giá_trị
+  kết thúc nếu
+end DuyệtNgược
 ```
 
-## Complexities
+## Phức Tạp
 
-### Time Complexity
+### Phức Tạp Thời Gian
 
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
+| Truy Cập | Tìm Kiếm | Chèn | Xóa  |
+| :------: | :------: | :--: | :--: |
+|   O(n)   |   O(n)   | O(1) | O(n) |
 
-### Space Complexity
+### Phức Tạp Không Gian
 
 O(n)
 
-## References
+## Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
 - [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.pt-BR.md b/src/data-structures/linked-list/README.pt-BR.md
deleted file mode 100644
index 579a4fce8c..0000000000
--- a/src/data-structures/linked-list/README.pt-BR.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# Lista Encadeada (Linked List)
-
-Na ciência da computação, uma **lista encadeada** é uma coleção linear de
-elementos de dados, em que a ordem linear não é dada por sua locação
-física na memória. Em vez disso, cada elemento aponta para o próximo.
-É uma estrutura de dados consistindo em um grupo de nós
-que juntos representam uma sequência. Sob a forma mais simples,
-cada nó é composto de dados e uma referência (em outras palavras,
-uma ligação/conexão) para o próximo nó na sequência. Esta estrutura
-permite inserção ou remoção eficiente de elementos de qualquer
-posição na sequência durante a iteração.
-
-Variantes mais complexas adicionam ligações adicionais, permitindo
-uma inserção ou remoção mais eficiente a partir de referências
-de elementos arbitrárias. Uma desvantagem das listas encadeadas
-é que o tempo de acesso é linear (e difícil de inserir em uma
-pipeline). Acesso mais rápido, como acesso aleatório, não é viável.
-Arrays possuem uma melhor localização de cache em comparação
-com listas encadeadas (linked lists).
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Pseudo código para Operações Básicas
-
-### Inserção
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value is the value to add to the list
- Post: value has been placed at the head of the list
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### Pesquisa
-
-```text
-Contains(head, value)
-  Pre: head is the head node in the list
-       value is the value to search for
-  Post: the item is either in the linked list, true; otherwise false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Remoção
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true, otherwise false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Travessia
-
-```text
-Traverse(head)
-  Pre: head is the head node in the list
-  Post: the items in the list have been traversed
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### Travessia Reversa
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head and tail belong to the same list
-  Post: the items in the list have been traversed in reverse order
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## Complexidades
-
-### Complexidade de Tempo
-
-| Acesso | Pesquisa | Inserção | Remoção |
-| :----: | :------: | :------: | :-----: |
-|  O(n)  |  O(n)    |  O(1)    |  O(n)   |
-
-### Complexidade de Espaçø
-
-O(n)
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.ru-RU.md b/src/data-structures/linked-list/README.ru-RU.md
deleted file mode 100644
index 98ad6c4727..0000000000
--- a/src/data-structures/linked-list/README.ru-RU.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# Связный список
-
-Связный список — базовая динамическая структура данных в информатике, состоящая из узлов, каждый из которых содержит как собственно данные,так ссылку («связку») на следующий узел списка. Данная структура позволяет эффективно добавлять и удалять элементы на произвольной позиции в последовательности в процессе итерации. Более сложные варианты включают дополнительные ссылки, позволяющие эффективно добавлять и удалять произвольные элементы.
-
-Принципиальным преимуществом перед массивом является структурная гибкость: порядок элементов связного списка может не совпадать с порядком расположения элементов данных в памяти компьютера, а порядок обхода списка всегда явно задаётся его внутренними связями. Суть преимущества состоит в том, что во многих языках создание массива требует указать его размер заранее. Связный список позволяет обойти это ограничение.
-
-Недостатком связных списков является то, что время доступа линейно (и затруднительно для реализации конвейеров). Быстрый доступ(случайный) невозможен.
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Псевдокод основных операций
-
-### Вставка
-
-```text
-Add(value)
-  Pre: value - добавляемое значение
-  Post: value помещено в конец списка
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value - добавляемое значение
- Post: value помещено в начало списка
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### Поиск
-
-```text
-Contains(head, value)
-  Pre: head - первый узел в списке
-         value - значение, которое следует найти
-  Post: true - value найдено в списке, иначе false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Удаление
-
-```text
-Remove(head, value)
-  Pre: head - первый узел в списке
-       value - значение, которое следует удалить
-  Post: true - value удалено из списка, иначе false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Обход
-
-```text
-Traverse(head)
-  Pre: head - первый узел в списке
-  Post: элементы списка пройдены
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### Обратный обход
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head и tail относятся к одному списку
-  Post: элементы списка пройдены в обратном порядке
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## Сложность
-
-### Временная сложность
-
-| Чтение    | Поиск     | Вставка   | Удаление  |
-| :--------: | :-------: | :--------: | :-------: |
-| O(n)       | O(n)      | O(1)       | O(n)      |
-
-### Пространственная сложность
-
-O(n)
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA)
-- [YouTube](https://www.youtube.com/watch?v=KTpOalDwBjg)
diff --git a/src/data-structures/linked-list/README.tr-TR.md b/src/data-structures/linked-list/README.tr-TR.md
deleted file mode 100644
index e5ed05623d..0000000000
--- a/src/data-structures/linked-list/README.tr-TR.md
+++ /dev/null
@@ -1,161 +0,0 @@
-# Bağlantılı Liste
-
-_Bunu diğer dillerde okuyun:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Español_](README.es-ES.md),
-
-Bilgisayar bilimlerinde, **Bağlantılı liste**, her biri hem gerçek verileri
-hem de listedeki bir sonraki düğümün bir bağlantısını içeren dinamik bir
-veri yapısıdır. Bu yapı, yineleme sırasında rastgele bir konumda
-öğeleri verimli bir şekilde eklemenize ve kaldırmanıza olanak tanır.
-Daha karmaşık seçenekler için, isteğe bağlı öğeleri verimli bir şekilde
-eklemek ve kaldırmak için ek bağlantılar içerir.
-
-Bağlantılı listelerin bir dezavantajı, erişim süresinin doğrusal olmasıdır
-(ve ardışık düzene geçirilmesi zordur). Rastgele erişim gibi daha hızlı erişim
-mümkün değildir. Diziler, bağlantılı listelere kıyasla daha iyi önbellek konumuna sahiptir.
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Temel İşlemler için Sözde Kod
-
-### Ekleme
-
-```text
-Add(value)
-  Pre: value is the value to add to the list
-  Post: value has been placed at the tail of the list
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value is the value to add to the list
- Post: value has been placed at the head of the list
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### Arama
-
-```text
-Contains(head, value)
-  Pre: head is the head node in the list
-       value is the value to search for
-  Post: the item is either in the linked list, true; otherwise false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Silme
-
-```text
-Remove(head, value)
-  Pre: head is the head node in the list
-       value is the value to remove from the list
-  Post: value is removed from the list, true, otherwise false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-      tail.next = null
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Geçiş
-
-```text
-Traverse(head)
-  Pre: head is the head node in the list
-  Post: the items in the list have been traversed
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### Ters Geçiş
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head and tail belong to the same list
-  Post: the items in the list have been traversed in reverse order
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## Karmaşıklıklar
-
-### Zaman Karmaşıklığı
-
-| Erişim    | Arama     | Ekleme    | Silme     |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-### Uzay Karmaşıklığı
-
-O(n)
-
-## Referanslar
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/linked-list/README.uk-UA.md b/src/data-structures/linked-list/README.uk-UA.md
deleted file mode 100644
index 5424c58db4..0000000000
--- a/src/data-structures/linked-list/README.uk-UA.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# Зв'язаний список
-
-Зв'язаний список — базова динамічна структура даних в інформатиці, що складається з вузлів, кожен з яких містить як дані, так посилання («зв'язку») на наступний вузол списку. Дана структура дозволяє ефективно додавати та видаляти елементи на довільній позиції у послідовності у процесі ітерації. Більш складні варіанти включають додаткові посилання, що дозволяють ефективно додавати та видаляти довільні елементи.
-
-Принциповою перевагою перед масивом є структурна гнучкість: порядок елементів зв'язкового списку може збігатися з порядком розташування елементів даних у пам'яті комп'ютера, а порядок обходу списку завжди явно задається його внутрішніми зв'язками. Суть переваги у тому, що у багатьох мовах створення масиву вимагає вказати його заздалегідь. Зв'язковий список дозволяє обійти це обмеження.
-
-Недоліком зв'язкових списків є те, що час доступу є лінійним (і важко для реалізації конвеєрів). Неможливий швидкий доступ (випадковий).
-
-![Linked List](./images/linked-list.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Псевдокод основних операцій
-
-### Вставка
-
-```text
-Add(value)
-  Pre: value - значення, що додається
-  Post: value поміщено в кінець списку
-  n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end Add
-```
-
-```text
-Prepend(value)
- Pre: value - значення, що додається
- Post: value поміщено на початок списку
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end Prepend
-```
-
-### Поиск
-
-```text
-Contains(head, value)
-  Pre: head - перший вузол у списку
-         value - значення, яке слід знайти
-  Post: true - value знайдено у списку, інакше false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Вилучення
-
-```text
-Remove(head, value)
-  Pre: head - перший вузол у списку
-       value - значення, яке слід видалити
-  Post: true - value видалено зі списку, інакше false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-    end if
-    n.next ← n.next.next
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Обход
-
-```text
-Traverse(head)
-  Pre: head - перший вузол у списку
-  Post: елементи списку пройдені
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-```
-
-### Зворотний обхід
-
-```text
-ReverseTraversal(head, tail)
-  Pre: head и tail відносяться до одного списку
-  Post: елементи списку пройдено у зворотному порядку
-  if tail != ø
-    curr ← tail
-    while curr != head
-      prev ← head
-      while prev.next != curr
-        prev ← prev.next
-      end while
-      yield curr.value
-      curr ← prev
-    end while
-   yield curr.value
-  end if
-end ReverseTraversal
-```
-
-## Складність
-
-### Тимчасова складність
-
-| Читання    | Пошук     | Вставка    | Вилучення |
-| :--------: | :-------: | :--------: | :-------: |
-| O(n)       | O(n)      | O(1)       | O(n)      |
-
-### Просторова складність
-
-O(n)
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%97%D0%B2%27%D1%8F%D0%B7%D0%B0%D0%BD%D0%B8%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA)
-- [YouTube](https://www.youtube.com/watch?v=6snsMa4E1Os)
diff --git a/src/data-structures/linked-list/README.vi-VN.md b/src/data-structures/linked-list/README.vi-VN.md
deleted file mode 100644
index 005838c6c1..0000000000
--- a/src/data-structures/linked-list/README.vi-VN.md
+++ /dev/null
@@ -1,155 +0,0 @@
-# Danh sách liên kết (Linked List)
-
-_Đọc bằng ngôn ngữ khác:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Español_](README.es-ES.md),
-[_Türkçe_](README.tr-TR.md),
-[_Українська_](README.uk-UA.md)
-
-
-Trong khoa học máy tính, một danh sách liên kết là một bộ sưu tập tuyến tính
-các phần tử dữ liệu, trong đó thứ tự tuyến tính không được xác định bởi
-vị trí vật lý của chúng trong bộ nhớ. Thay vào đó, mỗi
-phần tử trỏ đến phần tử tiếp theo. Đây là một cấu trúc dữ liệu
-bao gồm một nhóm các nút cùng đại diện cho
-một chuỗi. Dưới dạng đơn giản nhất, mỗi nút
-bao gồm dữ liệu và một tham chiếu (nói cách khác,
-một liên kết) đến nút tiếp theo trong chuỗi. Cấu trúc này
-cho phép việc chèn hoặc loại bỏ các phần tử một cách hiệu quả
-từ bất kỳ vị trí nào trong chuỗi trong quá trình lặp.
-Các biến thể phức tạp hơn thêm các liên kết bổ sung, cho phép
-việc chèn hoặc loại bỏ một cách hiệu quả từ bất kỳ phần tử nào
-trong chuỗi dựa trên tham chiếu. Một nhược điểm của danh sách liên kết
-là thời gian truy cập tuyến tính (và khó điều chỉnh). Truy cập nhanh hơn,
-như truy cập ngẫu nhiên, là không khả thi. Mảng
-có độ tương phản cache tốt hơn so với danh sách liên kết.
-
-![Linked List](./images/linked-list.jpeg)
-*Được làm từ [okso.app](https://okso.app)*
-
-## Mã giải (Pseudocode) cho Các Hoạt Động Cơ Bản
-  *head = đầu,
-  *tail = đuôi,
-  *next = kế tiếp,
-  *node = nút,
-  *value = giá trị
-
-### Chèn (Insert)
-
-```
-ThêmGiáTrị(giá trị) (Add(value))
-  Trước(Pre): giá trị là giá trị muốn thêm vào danh sách
-  Sau(Post): giá trị đã được đặt ở cuối danh sách
-
- n ← node(value)
-  if head = ø
-    head ← n
-    tail ← n
-  else
-    tail.next ← n
-    tail ← n
-  end if
-end ThêmGiáTrị(Add)
-```
-
-```
-ChènVàoĐầu(giá trị)
-  Trước(Pre): giá trị là giá trị muốn thêm vào danh sách
-  Sau(Post): giá trị đã được đặt ở đầu danh sách
-
- n ← node(value)
- n.next ← head
- head ← n
- if tail = ø
-   tail ← n
- end
-end ChènVàoĐầu
-```
-
-### Tìm Kiếm (Search)
-```
-Chứa(đầu, giá trị)
-  Trước: đầu là nút đầu trong danh sách
-       giá trị là giá trị cần tìm kiếm
-  Sau: mục đó có thể ở trong danh sách liên kết, true; nếu không, là false
-  n ← head
-  while n != ø and n.value != value
-    n ← n.next
-  end while
-  if n = ø
-    return false
-  end if
-  return true
-end Contains
-```
-
-### Xóa (Delete)
-```
-Xóa(đầu, giá trị)
-  Trước: đầu là nút đầu trong danh sách
-       giá trị là giá trị cần xóa khỏi danh sách
-  Sau: giá trị đã được xóa khỏi danh sách, true; nếu không, là false
-  if head = ø
-    return false
-  end if
-  n ← head
-  if n.value = value
-    if head = tail
-      head ← ø
-      tail ← ø
-    else
-      head ← head.next
-    end if
-    return true
-  end if
-  while n.next != ø and n.next.value != value
-    n ← n.next
-  end while
-  if n.next != ø
-    if n.next = tail
-      tail ← n
-      tail.next = null
-    else
-      n.next ← n.next.next
-    end if
-    return true
-  end if
-  return false
-end Remove
-```
-
-### Duyệt(raverse)
-Duyệt(đầu)
-  Trước: đầu là nút đầu trong danh sách
-  Sau: các mục trong danh sách đã được duyệt
-  n ← head
-  while n != ø
-    yield n.value
-    n ← n.next
-  end while
-end Traverse
-
-### Duyệt Ngược (Traverse in Reverse)
-DuyệtNgược(đầu, đuôi)
-  Trước: đầu và đuôi thuộc cùng một danh sách
-  Sau: các mục trong danh sách đã được duyệt theo thứ tự ngược lại
-
-## Độ Phức Tạp
-
-### Độ Phức Tạp Thời Gian (Time Complexity)
-
-| Access    | Search    | Insertion | Deletion  |
-| :-------: | :-------: | :-------: | :-------: |
-| O(n)      | O(n)      | O(1)      | O(n)      |
-
-## Độ Phức Tạp Không Gian (Space Complexity)
-O(n)
-
-## Tham Khảo
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/lru-cache/README.en-EN.md b/src/data-structures/lru-cache/README.en-EN.md
new file mode 100644
index 0000000000..da3dba5b99
--- /dev/null
+++ b/src/data-structures/lru-cache/README.en-EN.md
@@ -0,0 +1,54 @@
+# Least Recently Used (LRU) Cache
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **Least Recently Used (LRU) Cache** organizes items in order of use, allowing you to quickly identify which item hasn't been used for the longest amount of time.
+
+Picture a clothes rack, where clothes are always hung up on one side. To find the least-recently used item, look at the item on the other end of the rack.
+
+## The problem statement
+
+Implement the LRUCache class:
+
+- `LRUCache(int capacity)` Initialize the LRU cache with **positive** size `capacity`.
+- `int get(int key)` Return the value of the `key` if the `key` exists, otherwise return `undefined`.
+- `void set(int key, int value)` Update the value of the `key` if the `key` exists. Otherwise, add the `key-value` pair to the cache. If the number of keys exceeds the `capacity` from this operation, **evict** the least recently used key.
+
+The functions `get()` and `set()` must each run in `O(1)` average time complexity.
+
+## Implementation
+
+### Version 1: Doubly Linked List + Hash Map
+
+See the `LRUCache` implementation example in [LRUCache.js](./LRUCache.js). The solution uses a `HashMap` for fast `O(1)` (in average) cache items access, and a `DoublyLinkedList` for fast `O(1)` (in average) cache items promotions and eviction (to keep the maximum allowed cache capacity).
+
+![Linked List](./images/lru-cache.jpg)
+
+_Made with [okso.app](https://okso.app)_
+
+You may also find more test-case examples of how the LRU Cache works in [LRUCache.test.js](./__test__/LRUCache.test.js) file.
+
+### Version 2: Ordered Map
+
+The first implementation that uses doubly linked list is good for learning purposes and for better understanding of how the average `O(1)` time complexity is achievable while doing `set()` and `get()`.
+
+However, the simpler approach might be to use a JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object. The `Map` object holds key-value pairs and **remembers the original insertion order** of the keys. We can use this fact in order to keep the recently-used items in the "end" of the map by removing and re-adding items. The item at the beginning of the `Map` is the first one to be evicted if cache capacity overflows. The order of the items may checked by using the `IterableIterator` like `map.keys()`.
+
+See the `LRUCacheOnMap` implementation example in [LRUCacheOnMap.js](./LRUCacheOnMap.js).
+
+You may also find more test-case examples of how the LRU Cache works in [LRUCacheOnMap.test.js](./__test__/LRUCacheOnMap.test.js) file.
+
+## Complexities
+
+|          | Average |
+| -------- | ------- |
+| Space    | `O(n)`  |
+| Get item | `O(1)`  |
+| Set item | `O(1)`  |
+
+## References
+
+- [LRU Cache on LeetCode](https://leetcode.com/problems/lru-cache/solutions/244744/lru-cache/)
+- [LRU Cache on InterviewCake](https://www.interviewcake.com/concept/java/lru-cache)
+- [LRU Cache on Wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies)
diff --git a/src/data-structures/lru-cache/README.md b/src/data-structures/lru-cache/README.md
index 05bcc0a0f7..a4ad53f8da 100644
--- a/src/data-structures/lru-cache/README.md
+++ b/src/data-structures/lru-cache/README.md
@@ -1,51 +1,54 @@
-# Least Recently Used (LRU) Cache
+# Bộ nhớ cache Least Recently Used (LRU)
 
-A **Least Recently Used (LRU) Cache** organizes items in order of use, allowing you to quickly identify which item hasn't been used for the longest amount of time.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-Picture a clothes rack, where clothes are always hung up on one side. To find the least-recently used item, look at the item on the other end of the rack.
+Bộ nhớ cache Least Recently Used (LRU) sắp xếp các mục theo thứ tự sử dụng, cho phép bạn nhanh chóng xác định mục nào chưa được sử dụng trong thời gian dài nhất.
 
-## The problem statement
+Hãy tưởng tượng một cái gác áo, nơi quần áo luôn được treo ở một bên. Để tìm mục ít được sử dụng nhất, hãy nhìn vào mục ở đầu kia của gác áo.
 
-Implement the LRUCache class:
+## Tuyên bố vấn đề
 
-- `LRUCache(int capacity)` Initialize the LRU cache with **positive** size `capacity`.
-- `int get(int key)` Return the value of the `key` if the `key` exists, otherwise return `undefined`.
-- `void set(int key, int value)` Update the value of the `key` if the `key` exists. Otherwise, add the `key-value` pair to the cache. If the number of keys exceeds the `capacity` from this operation, **evict** the least recently used key.
+Thực hiện lớp LRUCache:
 
-The functions `get()` and `set()` must each run in `O(1)` average time complexity.
+- `LRUCache(int capacity)` Khởi tạo bộ nhớ cache LRU với kích thước dương `capacity`.
+- `int get(int key)` Trả về giá trị của `key` nếu `key` tồn tại, nếu không trả về `undefined`.
+- `void set(int key, int value)` Cập nhật giá trị của `key` nếu `key` tồn tại. Nếu không, thêm cặp `key-value` vào bộ nhớ cache. Nếu số lượng key vượt quá `capacity` từ hoạt động này, **loại bỏ** key ít được sử dụng nhất.
 
-## Implementation
+Các hàm `get()` và `set()` phải chạy trong thời gian trung bình `O(1)`.
 
-### Version 1: Doubly Linked List + Hash Map
+## Thực hiện
 
-See the `LRUCache` implementation example in [LRUCache.js](./LRUCache.js). The solution uses a `HashMap` for fast `O(1)` (in average) cache items access, and a `DoublyLinkedList` for fast `O(1)` (in average) cache items promotions and eviction (to keep the maximum allowed cache capacity).
+### Phiên bản 1: Danh sách liên kết hai chiều + Bản đồ băm
 
-![Linked List](./images/lru-cache.jpg)
+Xem ví dụ cài đặt `LRUCache` trong tệp [LRUCache.js](./LRUCache.js). Giải pháp sử dụng `HashMap` để truy cập nhanh chóng các mục cache với `O(1)` (trong trường hợp trung bình), và `DoublyLinkedList` để thúc đẩy và loại bỏ mục cache nhanh chóng với `O(1)` (trong trường hợp trung bình) (để giữ cho dung lượng bộ nhớ cache tối đa được phép).
 
-*Made with [okso.app](https://okso.app)*
+![Danh sách liên kết](./images/lru-cache.jpg)
 
-You may also find more test-case examples of how the LRU Cache works in [LRUCache.test.js](./__test__/LRUCache.test.js) file.
+_Tạo với [okso.app](https://okso.app)_
 
-### Version 2: Ordered Map
+Bạn cũng có thể tìm thấy nhiều ví dụ về trường hợp thử nghiệm về cách bộ nhớ cache LRU hoạt động trong tệp [LRUCache.test.js](./__test__/LRUCache.test.js).
 
-The first implementation that uses doubly linked list is good for learning purposes and for better understanding of how the average `O(1)` time complexity is achievable while doing `set()` and `get()`.
+### Phiên bản 2: Bản đồ có thứ tự
 
-However, the simpler approach might be to use a JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object. The `Map` object holds key-value pairs and **remembers the original insertion order** of the keys. We can use this fact in order to keep the recently-used items in the "end" of the map by removing and re-adding items. The item at the beginning of the `Map` is the first one to be evicted if cache capacity overflows. The order of the items may checked by using the `IterableIterator` like `map.keys()`.
+Cài đặt đầu tiên sử dụng danh sách liên kết hai chiều là tốt cho mục đích học và để hiểu rõ hơn về cách độ phức tạp thời gian trung bình `O(1)` có thể đạt được trong khi thực hiện `set()` và `get()`.
 
-See the `LRUCacheOnMap` implementation example in [LRUCacheOnMap.js](./LRUCacheOnMap.js).
+Tuy nhiên, phương pháp đơn giản hơn có thể là sử dụng một đối tượng [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) JavaScript. Đối tượng `Map` giữ các cặp khóa-giá trị và **nhớ thứ tự chèn ban đầu** của các khóa. Chúng ta có thể sử dụng sự thật này để giữ các mục đã sử dụng gần đây ở "cuối" của bản đồ bằng cách loại bỏ và thêm lại các mục. Mục ở đầu của `Map` sẽ là mục đầu tiên bị loại bỏ nếu dung lượng bộ nhớ cache vượt quá. Thứ tự của các mục có thể được kiểm tra bằng cách sử dụng `IterableIterator` như `map.keys()`.
 
-You may also find more test-case examples of how the LRU Cache works in [LRUCacheOnMap.test.js](./__test__/LRUCacheOnMap.test.js) file.
+Xem ví dụ cài đặt `LRUCacheOnMap` trong tệp [LRUCacheOnMap.js](./LRUCacheOnMap.js).
 
-## Complexities
+Bạn cũng có thể tìm thấy nhiều ví dụ về trường hợp thử nghiệm về cách bộ nhớ cache LRU hoạt động trong tệp [LRUCacheOnMap.test.js](./__test__/LRUCacheOnMap.test.js).
 
-|   | Average |
-|---|---|
-| Space |`O(n)`|
-| Get item | `O(1)` |
-| Set item | `O(1)` |
+## Độ phức tạp
 
-## References
+|            | Trung bình |
+| ---------- | ---------- |
+| Dung lượng | `O(n)`     |
+| Lấy mục    | `O(1)`     |
+| Đặt mục    | `O(1)`     |
 
-- [LRU Cache on LeetCode](https://leetcode.com/problems/lru-cache/solutions/244744/lru-cache/)
-- [LRU Cache on InterviewCake](https://www.interviewcake.com/concept/java/lru-cache)
-- [LRU Cache on Wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies)
+## Tham khảo
+
+- [Bộ nhớ cache LRU trên LeetCode](https://leetcode.com/problems/lru-cache/solutions/244744/lru-cache/)
+- [Bộ nhớ cache LRU trên InterviewCake](https://www.interviewcake.com/concept/java/lru-cache)
+- [Bộ nhớ cache LRU trên Wiki](https://en.wikipedia.org/wiki/Cache_replacement_policies)
diff --git a/src/data-structures/priority-queue/README.en-EN.md b/src/data-structures/priority-queue/README.en-EN.md
new file mode 100644
index 0000000000..8a7a20e121
--- /dev/null
+++ b/src/data-structures/priority-queue/README.en-EN.md
@@ -0,0 +1,23 @@
+# Priority Queue
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **priority queue** is an abstract data type
+which is like a regular queue or stack data structure, but where
+additionally each element has a "priority" associated with it.
+In a priority queue, an element with high priority is served before
+an element with low priority. If two elements have the same
+priority, they are served according to their order in the queue.
+
+While priority queues are often implemented with heaps, they are
+conceptually distinct from heaps. A priority queue is an abstract
+concept like "a list" or "a map"; just as a list can be implemented
+with a linked list or an array, a priority queue can be implemented
+with a heap or a variety of other methods such as an unordered
+array.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
+- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.fr-FR.md b/src/data-structures/priority-queue/README.fr-FR.md
deleted file mode 100644
index 76a5f895dd..0000000000
--- a/src/data-structures/priority-queue/README.fr-FR.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# File de priorité
-
-En informatique, une **file de priorité** est un type
-de données abstrait qui s'apparente à une file d'attente normale
-ou une structure de données empilées, mais où chaque élément est
-en plus associé à une "priorité".
-Dans une file de priorité, un élément avec une priorité élevée
-est servi avant un élément à faible priorité. Si deux éléments ont
-la même priorité, ils sont servis selon leur ordre dans la file
-d'attente.
-
-Alors que les files de priorité sont souvent implémentées avec des tas,
-elles sont conceptuellement distinctes des tas. Une file de priorité
-est un concept abstrait comme "une liste" ou "une carte"; tout comme
-une liste peut être implémentée avec une liste chaînée ou un tableau,
-une file de priorité peut être implémentée avec un tas ou une variété
-d'autres méthodes telles qu'un tableau non ordonné.
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/File_de_priorit%C3%A9)
-- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.ja-JP.md b/src/data-structures/priority-queue/README.ja-JP.md
deleted file mode 100644
index 0154034871..0000000000
--- a/src/data-structures/priority-queue/README.ja-JP.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# 優先度付きキュー
-
-コンピュータサイエンスにおいて、**優先度付きキュー**は通常のキューやスタックのデータ構造と似た抽象データ型ですが、各要素に「優先度」が関連づけられています。優先度付きキューでは優先度の高い要素が優先度の低い要素よりも先に処理されます。もし2つの要素が同じ優先度だった場合、それらはキュー内の順序に従って処理されます。
-
-優先度付きキューは多くの場合ヒープによって実装されていますが、概念的にはヒープとは異なります。優先度付きキューは「リスト」や「マップ」のような抽象的な概念です。リストがリンクリストや配列で実装できるのと同様に、優先度付きキューはヒープや未ソート配列のような様々な方法で実装することができます。
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
-- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.ko-KR.md b/src/data-structures/priority-queue/README.ko-KR.md
deleted file mode 100644
index 50a064d05a..0000000000
--- a/src/data-structures/priority-queue/README.ko-KR.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# 우선 순위 큐 
-
-컴퓨터 과학에서 **우선 순위 큐**는 일반 큐 또는 스택 데이터 구조와 같은 추상 데이터 유형이지만, 여기서 각 요소에는 "우선 순위"가 연결됩니다. 
-우선 순위 큐에서는 우선 순위가 높은 요소가 낮은 요소 앞에 제공됩니다. 두 요소가 동일한 우선 순위를 가질 경우 큐의 순서에 따라 제공됩니다.
-
-우선 순위 큐는 종종 힙을 사용하여 구현되지만 개념적으로는 힙과 구별됩니다. 우선 순위 대기열은 "리스트(list)" 또는 "맵(map)"과 같은 추상적인 개념입니다; 
-리스트가 링크드 리스트나 배열로 구현될 수 있는 것처럼 우선 순위 큐는 힙이나 정렬되지 않은 배열과 같은 다양한 다른 방법으로 구현될 수 있습니다.
-
-## 참조
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
-- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.md b/src/data-structures/priority-queue/README.md
index 6d0901960d..32ae2e39b9 100644
--- a/src/data-structures/priority-queue/README.md
+++ b/src/data-structures/priority-queue/README.md
@@ -1,29 +1,13 @@
-# Priority Queue
+# Hàng đợi Ưu tiên
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, a **priority queue** is an abstract data type
-which is like a regular queue or stack data structure, but where
-additionally each element has a "priority" associated with it.
-In a priority queue, an element with high priority is served before
-an element with low priority. If two elements have the same
-priority, they are served according to their order in the queue.
+Trong khoa học máy tính, một **hàng đợi ưu tiên** là một loại dữ liệu trừu tượng giống như một cấu trúc dữ liệu hàng đợi hoặc ngăn xếp thông thường, nhưng nơi mỗi phần tử cũng có một "ưu tiên" đi kèm. Trong một hàng đợi ưu tiên, một phần tử có ưu tiên cao được phục vụ trước một phần tử có ưu tiên thấp. Nếu hai phần tử có cùng ưu tiên, chúng được phục vụ dựa trên thứ tự của chúng trong hàng đợi.
 
-While priority queues are often implemented with heaps, they are
-conceptually distinct from heaps. A priority queue is an abstract
-concept like "a list" or "a map"; just as a list can be implemented
-with a linked list or an array, a priority queue can be implemented
-with a heap or a variety of other methods such as an unordered
-array.
+Mặc dù hàng đợi ưu tiên thường được triển khai với các heap, chúng khác biệt về mặt khái niệm so với heap. Một hàng đợi ưu tiên là một khái niệm trừu tượng như "một danh sách" hoặc "một bản đồ"; giống như một danh sách có thể được triển khai với một danh sách liên kết hoặc một mảng, một hàng đợi ưu tiên có thể được triển khai với một heap hoặc một loạt các phương pháp khác như một mảng không tuần tự.
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
 - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.pt-BR.md b/src/data-structures/priority-queue/README.pt-BR.md
deleted file mode 100644
index e6d84e263a..0000000000
--- a/src/data-structures/priority-queue/README.pt-BR.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Fila de Prioridade (Priority Queue)
-
-Na ciência da computação, uma **fila de prioridade** é um tipo de estrutura de
-dados abastrata que é como uma fila regular (regular queue) ou estrutura de
-dados de pilha (stack), mas adicionalmente cada elemento possui uma
-"prioridade" associada.
-
-Em uma fila de prioridade, um elemento com uma prioridade alta é servido
-antes de um elemento com baixa prioridade. Caso dois elementos posusam a
-mesma prioridade, eles serão servidos de acordo com sua ordem na fila.
-
-Enquanto as filas de prioridade são frequentemente implementadas com
-pilhas (stacks), elas são conceitualmente distintas das pilhas (stacks).
-A fila de prioridade é um conceito abstrato como uma "lista" (list) ou
-um "mapa" (map); assim como uma lista pode ser implementada com uma
-lista encadeada (liked list) ou um array, a fila de prioridade pode ser
-implementada com uma pilha (stack) ou com uma variedade de outros métodos,
-como um array não ordenado (unordered array).
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
-- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/priority-queue/README.ru-RU.md b/src/data-structures/priority-queue/README.ru-RU.md
deleted file mode 100644
index 7ce0c1f496..0000000000
--- a/src/data-structures/priority-queue/README.ru-RU.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Очередь с приоритетом
-
-Очередь с приоритетом (англ. priority queue) — абстрактный тип данных в информатике,
-для каждого элемента которого можно вычислить его приоритет.
-
-В очереди с приоритетами элемент с высоким приоритетом обслуживается раньше
-элемента с низким приоритетом. Если два элемента имеют одинаковый приоритет, они
-обслуживаются в соответствии с их порядком в очереди.
-
-Очередь с приоритетом поддерживает две обязательные операции — добавить элемент и
-извлечь максимум(минимум).
-
-Хотя приоритетные очереди часто реализуются в виде куч(heaps), они
-концептуально отличаются от куч. Очередь приоритетов является абстрактной
-концепцией вроде «списка» или «карты»; так же, как список может быть реализован
-в виде связного списка или массива, так и очередь с приоритетом может быть реализована
-в виде кучи или множеством других методов, например в виде неупорядоченного массива.
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C_%D1%81_%D0%BF%D1%80%D0%B8%D0%BE%D1%80%D0%B8%D1%82%D0%B5%D1%82%D0%BE%D0%BC_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5))
-- [YouTube](https://www.youtube.com/watch?v=y_2toG5-j_M)
diff --git a/src/data-structures/priority-queue/README.uk-UA.md b/src/data-structures/priority-queue/README.uk-UA.md
deleted file mode 100644
index 2f0454479e..0000000000
--- a/src/data-structures/priority-queue/README.uk-UA.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Черга з пріоритетом
-
-Черга з пріоритетом (англ. priority queue) - абстрактний тип даних в інформатиці,
-для кожного елемента якого можна визначити його пріоритет.
-
-У черзі з пріоритетами елемент із високим пріоритетом обслуговується раніше
-елемент з низьким пріоритетом. Якщо два елементи мають однаковий пріоритет, вони
-обслуговуються відповідно до їх порядку в черзі.
-
-Черга з пріоритетом підтримує дві обов'язкові операції – додати елемент та
-витягти максимум (мінімум).
-
-Хоча пріоритетні черги часто реалізуються у вигляді куп (heaps), вони
-концептуально відрізняються від куп. Черга пріоритетів є абстрактною
-концепцією на кшталт «списку» чи «карти»; так само, як список може бути реалізований
-у вигляді зв'язкового списку або масиву, так і черга з пріоритетом може бути реалізована
-у вигляді купи або безліччю інших методів, наприклад, у вигляді невпорядкованого масиву.
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A7%D0%B5%D1%80%D0%B3%D0%B0_%D0%B7_%D0%BF%D1%80%D1%96%D0%BE%D1%80%D0%B8%D1%82%D0%B5%D1%82%D0%BE%D0%BC)
diff --git a/src/data-structures/priority-queue/README.zh-CN.md b/src/data-structures/priority-queue/README.zh-CN.md
deleted file mode 100644
index caffcd7136..0000000000
--- a/src/data-structures/priority-queue/README.zh-CN.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# 优先队列
-
-在计算机科学中,  **优先级队列(priority queue)** 是一种抽象数据类型, 它类似于常规的队列或栈, 但每个元素都有与之关联的“优先级”。
-
-在优先队列中, 低优先级的元素之前前面应该是高优先级的元素。 如果两个元素具有相同的优先级, 则根据它们在队列中的顺序是它们的出现顺序即可。
-
-优先队列虽通常用堆来实现,但它在概念上与堆不同。优先队列是一个抽象概念，就像“列表”或“图”这样的抽象概念一样; 
-
-正如列表可以用链表或数组实现一样，优先队列可以用堆或各种其他方法实现,例如无序数组。
-
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
-- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)
diff --git a/src/data-structures/queue/README.en-EN.md b/src/data-structures/queue/README.en-EN.md
new file mode 100644
index 0000000000..57247f0542
--- /dev/null
+++ b/src/data-structures/queue/README.en-EN.md
@@ -0,0 +1,31 @@
+# Queue
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **queue** is a particular kind of abstract data
+type or collection in which the entities in the collection are
+kept in order and the principle (or only) operations on the
+collection are the addition of entities to the rear terminal
+position, known as enqueue, and removal of entities from the
+front terminal position, known as dequeue. This makes the queue
+a First-In-First-Out (FIFO) data structure. In a FIFO data
+structure, the first element added to the queue will be the
+first one to be removed. This is equivalent to the requirement
+that once a new element is added, all elements that were added
+before have to be removed before the new element can be removed.
+Often a peek or front operation is also entered, returning the
+value of the front element without dequeuing it. A queue is an
+example of a linear data structure, or more abstractly a
+sequential collection.
+
+Representation of a FIFO (first in, first out) queue
+
+![Queue](./images/queue.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Queue_(abstract_data_type)>)
+- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.fr-FR.md b/src/data-structures/queue/README.fr-FR.md
deleted file mode 100644
index 33d327744f..0000000000
--- a/src/data-structures/queue/README.fr-FR.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# File
-
-En informatique, une **file**, aussi appelée file d'attente, est
-sorte particulière de structure de données abstraite dans lequel
-les entités de la collection sont conservées dans l'ordre et les
-opérations principales sur la collection sont le résultat de l'ajout
-d'entités à la position terminale arrière, connue sous le nom de mise
-en file d'attente ("enqueue"), et de la suppression des entités de la
-position terminale avant, appelée retrait de la file d'attente ("dequeu").
-
-Cela fait de la file d'attente une structure de données PEPS (premier entré,
-premier sorti), en anglais FIFO (first in, first out). Dans une structure de données
-PEPS, le premier élément ajouté à la file d'attente sera le premier à être
-supprimé. Cela équivaut à l'exigence qu'une fois qu'un nouvel élément est
-ajouté, tous les éléments qui ont été ajoutés auparavant doivent être supprimés
-avant que le nouvel élément ne puisse être supprimé. Souvent, une opération d'aperçu
-ou de front est également intégrée, renvoyant la valeur de l'élément avant
-sans le retirer de la file d'attente. Une file d'attente est un exemple de
-structure de données linéaire, ou, plus abstraitement, une collection séquentielle.
-
-Représentation d'une file PEPS (premier entré, premier sorti)
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/File_(structure_de_donn%C3%A9es))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.ja-JP.md b/src/data-structures/queue/README.ja-JP.md
deleted file mode 100644
index 1ffa9c1a68..0000000000
--- a/src/data-structures/queue/README.ja-JP.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# キュー
-
-コンピュータサイエンスにおいて、**キュー**は特定の種類の抽象データ型またはコレクションです。コレクションの中のエンティティは順番に並べられており、コレクションに対する基本的な（または唯一の)操作は末尾にエンティティを追加するエンキューと、先頭からエンティティを削除するデキューがあります。これにより、キューは先入れ先出し(FIFO)のデータ構造となります。FIFOのデータ構造では、キューに追加された最初の要素が最初に削除されます。これは、新しい要素が追加されたら、その要素を削除するにはそれまでに追加された全ての要素が削除されなければならないという要件と同じです。多くの場合、ピークのような先頭の要素を検査する操作も備えていて、これはデキューせずに先頭の要素の値を返します。キューは線形のデータ構造や、より抽象的なシーケンシャルなコレクションの一例です。
-
-FIFO(先入れ先出し)のキュー
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.ko-KR.md b/src/data-structures/queue/README.ko-KR.md
deleted file mode 100644
index 606c8ff35e..0000000000
--- a/src/data-structures/queue/README.ko-KR.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Queue
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md)
-
-컴퓨터 공학에서 **큐**는 일종의 추상 데이터 타입이자 컬렉션입니다. 큐 내부의 엔터티들은 순서를 유지하며 컬렉션의 가장 뒷 부분에 엔터티를 추가하는 인큐(enqueue), 컬렉션의 가장 앞에 위치한 엔터티를 제거하는 디큐(dequeue) 작업을 수행합니다. 이것은 큐를 선입선출 자료 구조로 만듭니다. 선입선출 자료 구조에서는, 추가된 첫 번째 요소가 가장 먼저 제거되는 요소가 됩니다. 이는 새로운 요소가 추가되면 이전에 추가되었던 모든 요소들을 제거해야 새로운 요소를 제거할 수 있다는것과 같은 의미입니다. 또한 큐의 가장 앞에 위치한 요소를 반환하기 위한 작업이 입력되면 디큐 작업 없이 해당 요소를 반환합니다.
-
-큐는 선형 자료 구조의 예시이며, 더 추상적으로는 순차적인 컬렉션입니다.
-
-선입선출 자료 구조인 큐를 나타내면 다음과 같습니다.
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 참고
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.md b/src/data-structures/queue/README.md
index d8e0288b42..3143e1f5e6 100644
--- a/src/data-structures/queue/README.md
+++ b/src/data-structures/queue/README.md
@@ -1,37 +1,17 @@
-# Queue
+# Hàng Đợi
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, a **queue** is a particular kind of abstract data
-type or collection in which the entities in the collection are
-kept in order and the principle (or only) operations on the
-collection are the addition of entities to the rear terminal
-position, known as enqueue, and removal of entities from the
-front terminal position, known as dequeue. This makes the queue
-a First-In-First-Out (FIFO) data structure. In a FIFO data
-structure, the first element added to the queue will be the
-first one to be removed. This is equivalent to the requirement
-that once a new element is added, all elements that were added
-before have to be removed before the new element can be removed.
-Often a peek or front operation is also entered, returning the
-value of the front element without dequeuing it. A queue is an
-example of a linear data structure, or more abstractly a
-sequential collection.
+Trong khoa học máy tính, một **hàng đợi** là một loại cụ thể của kiểu dữ liệu trừu tượng hoặc bộ sưu tập trong đó các thực thể trong bộ sưu tập được giữ theo thứ tự và nguyên tắc (hoặc chỉ) các hoạt động trên bộ sưu tập là việc thêm các thực thể vào vị trí cuối cùng phía sau, được biết đến như là "enqueue", và loại bỏ các thực thể từ vị trí cuối cùng phía trước, được biết đến như là "dequeue". Điều này khiến cho hàng đợi trở thành một cấu trúc dữ liệu First-In-First-Out (FIFO). Trong một cấu trúc dữ liệu FIFO, phần tử đầu tiên được thêm vào hàng đợi sẽ là phần tử đầu tiên được loại bỏ. Điều này tương đương với yêu cầu rằng sau khi một phần tử mới được thêm vào, tất cả các phần tử đã được thêm trước phải được loại bỏ trước khi phần tử mới có thể được loại bỏ. Thường thì một hoặc phương thức xem trước hoặc front cũng được nhập vào, trả về giá trị của phần tử ở phía trước mà không loại bỏ nó. Một hàng đợi là một ví dụ về một cấu trúc dữ liệu tuyến tính, hoặc trừu tượng hơn là một bộ sưu tập tuần tự.
 
-Representation of a FIFO (first in, first out) queue
+Biểu diễn của một hàng đợi FIFO (first in, first out)
 
-![Queue](./images/queue.jpeg)
+![Hàng đợi](./images/queue.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo bởi [okso.app](https://okso.app)_
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
+- [Wikipedia](<https://en.wikipedia.org/wiki/Queue_(abstract_data_type)>)
 - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.pt-BR.md b/src/data-structures/queue/README.pt-BR.md
deleted file mode 100644
index 9464864120..0000000000
--- a/src/data-structures/queue/README.pt-BR.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Fila (Queue)
-
-Na ciência da computação, uma **fila** é um tipo particular de abstração
-de tipo de dado ou coleção em que as entidades na coleção são mantidas em
-ordem e a causa primária (ou única) de operações na coleção são a
-adição de entidades à posição final da coleção, conhecido como enfileiramento
-(enqueue) e a remoção de entidades do posição inicial, conhecida como desenfileirar
-(dequeue).Isto torna a fila uma estrutura de dados tipo First-In-First-Out (FIFO).
-
-Em uma estrutura de dados FIFO, o primeiro elemento adicionado a fila
-será o primeiro a ser removido. Isso é equivalente ao requisito em que uma vez
-que um novo elemento é adicionado, todos os elementos que foram adicionados
-anteriormente devem ser removidos antes que o novo elemento possa ser removido.
-
-Muitas vezes uma espiada (peek) ou uma operação de frente é iniciada,
-retornando o valor do elemento da frente, sem desenfileira-lo. Uma lista é
-um exemplo de uma estrutura de dados linear, ou mais abstratamente uma
-coleção seqüencial.
-
-
-Representação de uma file FIFO (first in, first out)
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## References
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.ru-RU.md b/src/data-structures/queue/README.ru-RU.md
deleted file mode 100644
index 1f9e5ff6f1..0000000000
--- a/src/data-structures/queue/README.ru-RU.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Очередь
-
-Очередь (англ. queue) - структура данных в информатике, в которой элементы
-хранятся в порядке их добавления. Добавление новых элементов(enqueue)
-осуществляется в конец списка. А удаление элементов (dequeue)
-осуществляется с начала. Таким образом очередь реализует принцип
-"первым вошёл - первым вышел" (FIFO). Часто реализуется операция чтения
-головного элемента (peek), которая возвращает первый в очереди элемент,
-при этом не удаляя его. Очередь является примером линейной структуры
-данных или последовательной коллекции.
-
-Иллюстрация работы с очередью.
-
-![Очередь](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## References
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5))
-- [YouTube](https://www.youtube.com/watch?v=GRsVMTlBIoE)
diff --git a/src/data-structures/queue/README.uk-UA.md b/src/data-structures/queue/README.uk-UA.md
deleted file mode 100644
index 7934c7571a..0000000000
--- a/src/data-structures/queue/README.uk-UA.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Черга
-
-Черга (англ. queue) – структура даних в інформатиці, в якій елементи
-зберігаються у порядку їх додавання. Додавання нових елементів(enqueue)
-здійснюється на кінець списку. А видалення елементів (dequeue)
-здійснюється із початку. Таким чином черга реалізує принцип
-"першим увійшов – першим вийшов" (FIFO). Часто реалізується операція читання
-головного елемента (peek), яка повертає перший у черзі елемент,
-при цьому не видаляючи його. Черга є прикладом лінійної структури
-даних чи послідовної колекції.
-
-Ілюстрація роботи з чергою.
-
-![Черга](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Список літератури
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A7%D0%B5%D1%80%D0%B3%D0%B0_(%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85))
-- [YouTube](https://www.youtube.com/watch?v=ll4QLNSPn60)
diff --git a/src/data-structures/queue/README.vi-VN.md b/src/data-structures/queue/README.vi-VN.md
deleted file mode 100644
index 84b3bdbfa6..0000000000
--- a/src/data-structures/queue/README.vi-VN.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Hàng đợi (Queue)
-
-_Đọc bằng ngôn ngữ khác:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
-
-Trong khoa học máy tính, một **hàng đợi** là một loại cụ thể của kiểu dữ liệu trừu tượng hoặc bộ sưu tập trong đó các phần tử trong bộ sưu tập được giữ theo thứ tự và nguyên tắc (hoặc chỉ) các hoạt động trên bộ sưu tập là thêm các phần tử vào vị trí cuối cùng, được gọi là đưa vào hàng đợi (enqueue), và loại bỏ các phần tử từ vị trí đầu tiên, được gọi là đưa ra khỏi hàng đợi (dequeue). Điều này khiến cho hàng đợi trở thành một cấu trúc dữ liệu First-In-First-Out (FIFO). Trong cấu trúc dữ liệu FIFO, phần tử đầu tiên được thêm vào hàng đợi sẽ là phần tử đầu tiên được loại bỏ. Điều này tương đương với yêu cầu rằng sau khi một phần tử mới được thêm vào, tất cả các phần tử đã được thêm vào trước đó phải được loại bỏ trước khi có thể loại bỏ phần tử mới. Thường thì cũng có thêm một hoạt động nhìn hay lấy phần đầu, trả về giá trị của phần tử đầu tiên mà không loại bỏ nó. Hàng đợi là một ví dụ về cấu trúc dữ liệu tuyến tính, hoặc trừu tượng hơn là một bộ sưu tập tuần tự.
-
-Hàng đợi FIFO (First-In-First-Out) có thể được biểu diễn như sau:
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Tham Khảo
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/queue/README.zh-CN.md b/src/data-structures/queue/README.zh-CN.md
deleted file mode 100644
index af608107d3..0000000000
--- a/src/data-structures/queue/README.zh-CN.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# 队列
-
-在计算机科学中, 一个 **队列(queue)** 是一种特殊类型的抽象数据类型或集合。集合中的实体按顺序保存。
-
-队列基本操作有两种：入队和出队。从队列的后端位置添加实体，称为入队；从队列的前端位置移除实体，称为出队。
-
-
-队列中元素先进先出 FIFO (first in, first out)的示意
-
-![Queue](./images/queue.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.en-EN.md b/src/data-structures/stack/README.en-EN.md
new file mode 100644
index 0000000000..192aca55c8
--- /dev/null
+++ b/src/data-structures/stack/README.en-EN.md
@@ -0,0 +1,30 @@
+# Stack
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **stack** is an abstract data type that serves
+as a collection of elements, with two principal operations:
+
+- **push**, which adds an element to the collection, and
+- **pop**, which removes the most recently added element that was not yet removed.
+
+The order in which elements come off a stack gives rise to its
+alternative name, LIFO (last in, first out). Additionally, a
+peek operation may give access to the top without modifying
+the stack. The name "stack" for this type of structure comes
+from the analogy to a set of physical items stacked on top of
+each other, which makes it easy to take an item off the top
+of the stack, while getting to an item deeper in the stack
+may require taking off multiple other items first.
+
+Simple representation of a stack runtime with push and pop operations.
+
+![Stack](./images/stack.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>)
+- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.fr-FR.md b/src/data-structures/stack/README.fr-FR.md
deleted file mode 100644
index 0d6c388640..0000000000
--- a/src/data-structures/stack/README.fr-FR.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Pile
-
-En informatique, une **pile** est un type de données abstrait
-qui sert de collection d'éléments, avec deux opérations principales:
-
-* **empiler** (en anglais *push*), qui ajoute un élément à la collection, et
-* **dépiler** (en anglais *pop*), qui supprime l'élément le plus récemment
-ajouté qui n'a pas encore été supprimé.
-
-L'ordre dans lequel les éléments sortent d'une pile donne
-lieu à son nom alternatif, LIFO ("last in, first out",
-littéralement "dernier arrivé, premier sorti"). En outre,
-une opération d'aperçu peut donner accès au sommet sans
-modifier la pile. Le nom "pile" pour ce type de structure
-vient de l'analogie avec un ensemble d'éléments physiques empilés
-les uns sur les autres, ce qui permet de retirer facilement un
-élément du haut de la pile, tout comme accéder à un élément plus
-profond dans le la pile peut nécessiter de retirer plusieurs
-autres articles en premier.
-
-Représentation simple de l'éxecution d'une pile avec des opérations empiler (push) et dépiler (pop).
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Références
-
-- [Wikipedia](https://fr.wikipedia.org/wiki/Pile_(informatique))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.ja-JP.md b/src/data-structures/stack/README.ja-JP.md
deleted file mode 100644
index 55ca25206c..0000000000
--- a/src/data-structures/stack/README.ja-JP.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# スタック
-
-コンピュータサイエンスにおいて、**スタック**は抽象データ型で、2つの主要な操作ができる要素のコレクションです。
-
-* **プッシュ**はコレクションに要素を追加します。
-* **ポップ**は最近追加された要素でまだ削除されていないものを削除します。
-
-要素がスタックから外れる順番から、LIFO(後入れ先出し)とも呼ばれます。スタックに変更を加えることなく、先頭の要素を検査するピーク操作を備えることもあります。「スタック」という名前は、物理的な物を上に積み重ねていく様子との類似性に由来しています。一番上の物を取ることは簡単ですが、スタックの下の方にあるものを取るときは先に上にある複数の物を取り除く必要があります。
-
-プッシュとポップの例
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.ko-KR.md b/src/data-structures/stack/README.ko-KR.md
deleted file mode 100644
index c36a472e66..0000000000
--- a/src/data-structures/stack/README.ko-KR.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# 스택
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md)
-
-컴퓨터 과학에서, **스택**은 아래의 두가지 연산을 가진 요소들의 집합인 추상 자료형입니다.
-
-* **push**는 집합에 요소를 추가하는 것이며,
-* **pop**은 아직 제거되지 않은 가장 최근에 추가된 요소를 제거하는 연산입니다.
-
-요소가 스택에서 나오는 과정은 LIFO (last in, first out)라는 이름으로 확인할 수 있습니다. 추가적으로, peek 연산은 스택을 수정하지 않고 최상단의 요소에 접근할 수 있게 해줍니다. 이런 자료구조의 "스택"이라는 이름은 실제 물건들이 다른 물건들의 위에 쌓이게 되는 것에서 유추되었습니다. 스택의 최상단의 물건은 빼내기 쉽지만 깊이 있는 물건을 빼내려면 다른 물건들을 먼저 빼내야 하는게 필요합니다.
-
-다음은 push와 pop 연산을 실행하는 간단한 스택의 실행입니다.
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 참조
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.md b/src/data-structures/stack/README.md
index 612f926736..12316ff18a 100644
--- a/src/data-structures/stack/README.md
+++ b/src/data-structures/stack/README.md
@@ -1,36 +1,22 @@
-# Stack
+# Ngăn Xếp
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Français_](README.fr-FR.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Українська_](README.uk-UA.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, a **stack** is an abstract data type that serves
-as a collection of elements, with two principal operations:
+Trong khoa học máy tính, một **ngăn xếp** là một loại dữ liệu trừu tượng dùng như một bộ sưu tập các phần tử, với hai thao tác chính:
 
-* **push**, which adds an element to the collection, and
-* **pop**, which removes the most recently added element that was not yet removed.
+- **đẩy (push)**, thêm một phần tử vào bộ sưu tập, và
+- **lấy ra (pop)**, loại bỏ phần tử được thêm vào gần đây nhất mà chưa bị loại bỏ.
 
-The order in which elements come off a stack gives rise to its
-alternative name, LIFO (last in, first out). Additionally, a
-peek operation may give access to the top without modifying
-the stack. The name "stack" for this type of structure comes
-from the analogy to a set of physical items stacked on top of
-each other, which makes it easy to take an item off the top
-of the stack, while getting to an item deeper in the stack
-may require taking off multiple other items first.
+Thứ tự mà các phần tử được lấy ra từ một ngăn xếp tạo ra tên gọi thay thế, LIFO (last in, first out - sau vào, trước ra). Ngoài ra, một thao tác nhìn trước (peek) có thể cho phép truy cập vào phần đỉnh mà không làm thay đổi ngăn xếp. Tên "ngăn xếp" cho loại cấu trúc này được lấy từ sự tương đồng với một tập hợp các vật phẩm vật lý được xếp lên nhau, điều này khiến việc lấy một mục ra khỏi đỉnh của ngăn xếp dễ dàng, trong khi việc đạt được một mục sâu hơn trong ngăn xếp có thể yêu cầu loại bỏ nhiều mục khác trước đó.
 
-Simple representation of a stack runtime with push and pop operations.
+Biểu diễn đơn giản của một ngăn xếp thời gian chạy với các hoạt động đẩy và lấy ra.
 
-![Stack](./images/stack.jpeg)
+![Ngăn xếp](./images/stack.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo bởi [okso.app](https://okso.app)_
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
+- [Wikipedia](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>)
 - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.pt-BR.md b/src/data-structures/stack/README.pt-BR.md
deleted file mode 100644
index ee862fe43a..0000000000
--- a/src/data-structures/stack/README.pt-BR.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Pilha (Stack)
-
-Na ciência da computação, uma **pilha** é uma estrutura de dados abstrata
-que serve como uma coleção de elementos com duas operações principais:
-
-* **push**, pela qual adiciona um elemento à coleção, e
-* **pop**, pela qual remove o último elemento adicionado.
-
-A ordem em que os elementos saem de um _stack_ dá origem ao seu
-nome alternativo, LIFO (last in, first out). Adicionalmente, uma operação
-de espiada (peek) pode dar acesso ao topo sem modificar o _stack_.
-O nome "stack" para este tipo de estrutura vem da analogia de
-um conjunto de itens físicos empilhados uns sobre os outros,
-o que facilita retirar um item do topo da pilha, enquanto para chegar a
-um item mais profundo na pilha pode exigir a retirada de
-vários outros itens primeiro.
-
-Representação simples de um tempo de execução de pilha com operações
-_push_ e _pop_.
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/stack/README.ru-RU.md b/src/data-structures/stack/README.ru-RU.md
deleted file mode 100644
index 3e33c87119..0000000000
--- a/src/data-structures/stack/README.ru-RU.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Стек
-
-Стек (англ. stack — стопка) — абстрактный тип данных, представляющий собой
-список элементов, организованных по принципу LIFO (последним пришёл — первым вышел).
-
-Стек имеет две ключевые операции:
-* **добавление (push)** элемента в конец стека, и
-* **удаление (pop)**, последнего добавленного элемента.
-
-Дополнительная операция чтения головного элемента (peek) даёт доступ
-к последнему элементу стека без изменения самого стека.
-
-Чаще всего принцип работы стека сравнивают со стопкой тарелок: чтобы взять вторую
-сверху, нужно снять верхнюю.
-
-Иллюстрация работы со стеком.
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA)
-- [YouTube](https://www.youtube.com/watch?v=tH8qi7lej5U)
diff --git a/src/data-structures/stack/README.uk-UA.md b/src/data-structures/stack/README.uk-UA.md
deleted file mode 100644
index 9941114f5b..0000000000
--- a/src/data-structures/stack/README.uk-UA.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Стек
-
-Стек (англ. stack - стопка) - абстрактний тип даних, що представляє собою
-список елементів, організованих за принципом LIFO (останнім прийшов – першим вийшов).
-
-Стек має дві ключові операції:
-* **додавання (push)** елемента в кінець стеку, та
-* **видалення (pop)**, останнього доданого елемента.
-
-Додаткова операція для читання головного елемента (peek) дає доступ
-до останнього елементу стека без зміни самого стека.
-
-Найчастіше принцип роботи стека порівнюють зі чаркою тарілок: щоб узяти другу
-зверху потрібно зняти верхню.
-
-Ілюстрація роботи зі стеком.
-
-![Стек](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA)
-- [YouTube](https://www.youtube.com/watch?v=4jh1e1YCbYc)
diff --git a/src/data-structures/stack/README.vi-VN.md b/src/data-structures/stack/README.vi-VN.md
deleted file mode 100644
index f051f3201f..0000000000
--- a/src/data-structures/stack/README.vi-VN.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Ngăn xếp (stack)
-
-_Đọc bằng ngôn ngữ khác:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_日本語_](README.ja-JP.md),
-[_Português_](README.pt-BR.md),
-[_한국어_](README.ko-KR.md),
-[_Español_](README.es-ES.md),
-[_Українська_](README.uk-UA.md)
-
-Trong khoa học máy tính, một ngăn xếp (stack) là một kiểu dữ liệu trừu tượng phục vụ như một bộ sưu tập các phần tử, với hai hoạt động chính:
-
-đẩy (push), thêm một phần tử vào bộ sưu tập, và
-lấy (pop), loại bỏ phần tử được thêm gần nhất mà chưa được loại bỏ.
-Thứ tự mà các phần tử được lấy ra khỏi ngăn xếp dẫn đến tên gọi thay thế của nó, là LIFO (last in, first out). Ngoài ra, một hoạt động nhìn có thể cung cấp quyền truy cập vào phần trên mà không làm thay đổi ngăn xếp. Tên "ngăn xếp" cho loại cấu trúc này đến từ sự tương tự với một bộ sưu tập các vật phẩm vật lý được xếp chồng lên nhau, điều này làm cho việc lấy một vật phẩm ra khỏi đỉnh của ngăn xếp dễ dàng, trong khi để đến được một vật phẩm sâu hơn trong ngăn xếp có thể đòi hỏi việc lấy ra nhiều vật phẩm khác trước đó.
-
-Biểu diễn đơn giản về thời gian chạy của một ngăn xếp với các hoạt động đẩy và lấy.
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Tham Khảo
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
-- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/stack/README.zh-CN.md b/src/data-structures/stack/README.zh-CN.md
deleted file mode 100644
index f00e3eab00..0000000000
--- a/src/data-structures/stack/README.zh-CN.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# 栈
-
-在计算机科学中, 一个 **栈(stack)** 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作:
-
-* **push**, 添加元素到栈的顶端(末尾);
-* **pop**, 移除栈最顶端(末尾)的元素.
-
-以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。
-
-此外,应有一个 `peek` 操作用于访问栈当前顶端(末尾)的元素。
-
-"栈"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。
-
-栈的 push 和 pop 操作的示意
-
-![Stack](./images/stack.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
-- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
diff --git a/src/data-structures/tree/README.en-EN.md b/src/data-structures/tree/README.en-EN.md
new file mode 100644
index 0000000000..6720332fc5
--- /dev/null
+++ b/src/data-structures/tree/README.en-EN.md
@@ -0,0 +1,36 @@
+# Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+- [Binary Search Tree](binary-search-tree)
+- [AVL Tree](avl-tree)
+- [Red-Black Tree](red-black-tree)
+- [Segment Tree](segment-tree) - with min/max/sum range queries examples
+- [Fenwick Tree](fenwick-tree) (Binary Indexed Tree)
+
+In computer science, a **tree** is a widely used abstract data
+type (ADT) — or data structure implementing this ADT—that
+simulates a hierarchical tree structure, with a root value
+and subtrees of children with a parent node, represented as
+a set of linked nodes.
+
+A tree data structure can be defined recursively (locally)
+as a collection of nodes (starting at a root node), where
+each node is a data structure consisting of a value,
+together with a list of references to nodes (the "children"),
+with the constraints that no reference is duplicated, and none
+points to the root.
+
+A simple unordered tree; in this diagram, the node labeled 3 has
+two children, labeled 2 and 6, and one parent, labeled 2. The
+root node, at the top, has no parent.
+
+![Tree](./images/tree.jpeg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](<https://en.wikipedia.org/wiki/Tree_(data_structure)>)
+- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)
diff --git a/src/data-structures/tree/README.md b/src/data-structures/tree/README.md
index e492257d33..3f54cfff42 100644
--- a/src/data-structures/tree/README.md
+++ b/src/data-structures/tree/README.md
@@ -1,37 +1,25 @@
-# Tree
+# Cây
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-* [Binary Search Tree](binary-search-tree)
-* [AVL Tree](avl-tree)
-* [Red-Black Tree](red-black-tree)
-* [Segment Tree](segment-tree) - with min/max/sum range queries examples
-* [Fenwick Tree](fenwick-tree) (Binary Indexed Tree)
+- [Cây Tìm Kiếm Nhị Phân](binary-search-tree)
+- [Cây AVL](avl-tree)
+- [Cây Đỏ-Đen](red-black-tree)
+- [Cây Đoạn](segment-tree) - với các ví dụ về truy vấn phạm vi min/max/sum
+- [Cây Fenwick](fenwick-tree) (Cây Chỉ Mục Nhị Phân)
 
-In computer science, a **tree** is a widely used abstract data
-type (ADT) — or data structure implementing this ADT—that
-simulates a hierarchical tree structure, with a root value
-and subtrees of children with a parent node, represented as
-a set of linked nodes.
+Trong khoa học máy tính, một **cây** là một loại cấu trúc dữ liệu trừu tượng (ADT) phổ biến — hoặc cấu trúc dữ liệu thực thi ADT này — mô phỏng một cấu trúc cây phân cấp, với một giá trị gốc và các cây con có một nút cha, được đại diện dưới dạng một tập hợp các nút liên kết.
 
-A tree data structure can be defined recursively (locally)
-as a collection of nodes (starting at a root node), where
-each node is a data structure consisting of a value,
-together with a list of references to nodes (the "children"),
-with the constraints that no reference is duplicated, and none
-points to the root.
+Một cấu trúc dữ liệu cây có thể được định nghĩa đệ quy (cục bộ) như một tập hợp các nút (bắt đầu từ một nút gốc), trong đó mỗi nút là một cấu trúc dữ liệu bao gồm một giá trị, cùng với một danh sách các tham chiếu đến các nút (các "con"), với ràng buộc là không có tham chiếu nào bị trùng lặp và không có tham chiếu nào chỉ vào gốc.
 
-A simple unordered tree; in this diagram, the node labeled 3 has
-two children, labeled 2 and 6, and one parent, labeled 2. The
-root node, at the top, has no parent.
+Một cây không thứ tự đơn giản; trong biểu đồ này, nút được gán nhãn 3 có hai nút con, được gán nhãn 2 và 6, và một nút cha, được gán nhãn 2. Nút gốc, ở trên cùng, không có nút cha.
 
-![Tree](./images/tree.jpeg)
+![Cây](./images/tree.jpeg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo bởi [okso.app](https://okso.app)_
 
-## References
+## Tham khảo
 
-- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))
+- [Wikipedia](<https://en.wikipedia.org/wiki/Tree_(data_structure)>)
 - [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)
diff --git a/src/data-structures/tree/README.pt-BR.md b/src/data-structures/tree/README.pt-BR.md
deleted file mode 100644
index 7aade88caa..0000000000
--- a/src/data-structures/tree/README.pt-BR.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Árvore (Tree)
-
-* [Árvore de Pesquisa Binária (Binary Search Tree)](binary-search-tree/README.pt-BR.md)
-* [Árvore AVL (AVL Tree)](avl-tree/README.pt-BR.md)
-* [Árvore Vermelha-Preta (Red-Black Tree)](red-black-tree/README.pt-BR.md)
-* [Árvore de Segmento (Segment Tree)](segment-tree/README.pt-BR.md) - com exemplos de consulta de intervalores min/max/sum
-* [Árvorem Fenwick (Fenwick Tree)](fenwick-tree/README.pt-BR.md) (Árvore Binária Indexada / Binary Indexed Tree)
-
-Na ciência da computação, uma **árvore** é uma estrutura de dados
-abstrada (ADT) amplamente utilizada - ou uma estrutura de dados
-implementando este ADT que simula uma estrutura hierárquica de árvore,
-com valor raíz e sub-árvores de filhos com um nó pai, representado
-como um conjunto de nós conectados.
-
-Uma estrutura de dados em árvore pode ser definida recursivamente como
-(localmente) uma coleção de nós (começando no nó raíz), aonde cada nó
-é uma estrutura de dados consistindo de um valor, junto com uma lista
-de referências aos nós (os "filhos"), com as restrições de que nenhuma
-referência é duplicada e nenhuma aponta para a raiz.
-
-Uma árvore não ordenada simples; neste diagrama, o nó rotulado como `7`
-possui dois filhos, rotulados como `2` e `6`, e um pai, rotulado como `2`.
-O nó raíz, no topo, não possui nenhum pai.
-
-![Tree](./images/tree.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)
diff --git a/src/data-structures/tree/README.zh-CN.md b/src/data-structures/tree/README.zh-CN.md
deleted file mode 100644
index 2f4df983d4..0000000000
--- a/src/data-structures/tree/README.zh-CN.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# 树
-
-* [二叉搜索树](binary-search-tree)
-* [AVL树](avl-tree)
-* [红黑树](red-black-tree)
-* [线段树](segment-tree) - with min/max/sum range queries examples
-* [芬威克树/Fenwick Tree](fenwick-tree) (Binary Indexed Tree)
-
-在计算机科学中, **树(tree)** 是一种广泛使用的抽象数据类型(ADT)— 或实现此ADT的数据结构 — 模拟分层树结构, 具有根节点和有父节点的子树,表示为一组链接节点。
-
-树可以被(本地地)递归定义为一个(始于一个根节点的)节点集, 每个节点都是一个包含了值的数据结构, 除了值,还有该节点的节点引用列表(子节点)一起。
-树的节点之间没有引用重复的约束。
-
-一棵简单的无序树; 在下图中:
-
-标记为7的节点具有两个子节点, 标记为2和6;
-一个父节点,标记为2,作为根节点, 在顶部,没有父节点。
-
-![Tree](./images/tree.jpeg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))
-- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)
diff --git a/src/data-structures/tree/avl-tree/README.en-EN.md b/src/data-structures/tree/avl-tree/README.en-EN.md
new file mode 100644
index 0000000000..e535b5fb55
--- /dev/null
+++ b/src/data-structures/tree/avl-tree/README.en-EN.md
@@ -0,0 +1,51 @@
+# AVL Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, an **AVL tree** (named after inventors
+Adelson-Velsky and Landis) is a self-balancing binary search
+tree. It was the first such data structure to be invented.
+In an AVL tree, the heights of the two child subtrees of any
+node differ by at most one; if at any time they differ by
+more than one, rebalancing is done to restore this property.
+Lookup, insertion, and deletion all take `O(log n)` time in
+both the average and worst cases, where n is the number of
+nodes in the tree prior to the operation. Insertions and
+deletions may require the tree to be rebalanced by one or
+more tree rotations.
+
+Animation showing the insertion of several elements into an AVL
+tree. It includes left, right, left-right and right-left rotations.
+
+![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)
+
+AVL tree with balance factors (green)
+
+![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)
+
+### AVL Tree Rotations
+
+**Left-Left Rotation**
+
+![Left-Left Rotation](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)
+
+**Right-Right Rotation**
+
+![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)
+
+**Left-Right Rotation**
+
+![Left-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)
+
+**Right-Left Rotation**
+
+![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)
+- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)
+- [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)
+- [AVL Tree Insertion on YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)
+- [AVL Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)
diff --git a/src/data-structures/tree/avl-tree/README.md b/src/data-structures/tree/avl-tree/README.md
index c70fca7bcd..2d1ebb74f1 100644
--- a/src/data-structures/tree/avl-tree/README.md
+++ b/src/data-structures/tree/avl-tree/README.md
@@ -1,51 +1,40 @@
-# AVL Tree
+# Cây AVL
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, an **AVL tree** (named after inventors 
-Adelson-Velsky and Landis) is a self-balancing binary search 
-tree. It was the first such data structure to be invented. 
-In an AVL tree, the heights of the two child subtrees of any
-node differ by at most one; if at any time they differ by 
-more than one, rebalancing is done to restore this property.
-Lookup, insertion, and deletion all take `O(log n)` time in 
-both the average and worst cases, where n is the number of 
-nodes in the tree prior to the operation. Insertions and 
-deletions may require the tree to be rebalanced by one or 
-more tree rotations.
+Trong khoa học máy tính, một **cây AVL** (được đặt theo tên của các nhà phát minh Adelson-Velsky và Landis) là một cây tìm kiếm nhị phân tự cân bằng. Đây là cấu trúc dữ liệu đầu tiên được phát minh trong số đó. Trong một cây AVL, độ cao của hai cây con của bất kỳ nút nào cũng chỉ khác nhau tối đa một; nếu vào bất kỳ thời điểm nào chúng khác nhau hơn một, sẽ được thực hiện cân bằng lại để khôi phục tính chất này. Tìm kiếm, chèn và xóa đều mất `O(log n)` thời gian trong cả trường hợp trung bình và trường hợp xấu nhất, trong đó n là số nút trong cây trước khi thực hiện thao tác. Việc chèn và xóa có thể yêu cầu cây phải được cân bằng lại bằng một hoặc nhiều phép xoay cây.
 
-Animation showing the insertion of several elements into an AVL 
-tree. It includes left, right, left-right and right-left rotations.
+Hình ảnh động hiển thị việc chèn một số phần tử vào một cây AVL. Nó bao gồm các phép quay trái, phải, trái-phải và phải-trái.
 
-![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)
+![Cây AVL](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)
 
-AVL tree with balance factors (green)
+Cây AVL với các yếu tố cân bằng (màu xanh lá cây)
 
-![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)
+![Cây AVL](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)
 
-### AVL Tree Rotations
+### Phép Xoay Cây AVL
 
-**Left-Left Rotation**
+**Xoay Trái-Trái**
 
-![Left-Left Rotation](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)
+![Xoay Trái-Trái](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)
 
-**Right-Right Rotation**
+**Xoay Phải-Phải**
 
-![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)
+![Xoay Phải-Phải](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)
 
-**Left-Right Rotation**
+**Xoay Trái-Phải**
 
-![Left-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)
+![Xoay Trái-Phải](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)
 
-**Right-Left Rotation**
+**Xoay Phải-Trái**
 
-![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)
+![Xoay Phải-Phải](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)
 
-## References
+## Tham khảo
 
-* [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)
-* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)
-* [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)
-* [AVL Tree Insertion on YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)
-* [AVL Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)
+- [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)
+- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)
+- [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)
+- [Chèn Cây AVL trên YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)
+- [Các Trực Quan Hóa Tương Tác của Cây AVL](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)
diff --git a/src/data-structures/tree/avl-tree/README.pt-BR.md b/src/data-structures/tree/avl-tree/README.pt-BR.md
deleted file mode 100644
index 9b9e9ffb93..0000000000
--- a/src/data-structures/tree/avl-tree/README.pt-BR.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Árvore AVL (AVL Tree)
-
-Na ciência da computação, uma **árvore AVL** (em homenagem aos
-inventores Adelson-Velsky e Landis) é uma árvore de pesquisa
-binária auto balanceada. Foi a primeira estrutura de dados a
-ser inventada.
-Em uma árvore AVL, as alturas de duas sub-árvores filhas
-de qualquer nó diferem no máximo em um; se a qualquer momento
-diferirem por em mais de um, um rebalanceamento é feito para
-restaurar esta propriedade.
-Pesquisa, inserção e exclusão possuem tempo `O(log n)` tanto na
-média quanto nos piores casos, onde `n` é o número de nós na
-árvore antes da operação. Inserções e exclusões podem exigir
-que a árvore seja reequilibrada por uma ou mais rotações.
-
-
-Animação mostrando a inserção de vários elementos em uma árvore AVL.
-Inclui as rotações de esquerda, direita, esquerda-direita e direita-esquerda.
-
-![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/f/fd/AVL_Tree_Example.gif)
-
-Árvore AVL com fatores de equilíbrio (verde)
-
-![AVL Tree](https://upload.wikimedia.org/wikipedia/commons/a/ad/AVL-tree-wBalance_K.svg)
-
-### Rotações de Árvores AVL
-
-**Rotação Esquerda-Esquerda**
-
-![Left-Left Rotation](http://btechsmartclass.com/data_structures/ds_images/LL%20Rotation.png)
-
-**Rotação direita-direita**
-
-![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RR%20Rotation.png)
-
-**Rotação Esquerda-Direita**
-
-![Left-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/LR%20Rotation.png)
-
-**Rotação Direita-Esquerda**
-
-![Right-Right Rotation](http://btechsmartclass.com/data_structures/ds_images/RL%20Rotation.png)
-
-## Referências
-
-* [Wikipedia](https://en.wikipedia.org/wiki/AVL_tree)
-* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm)
-* [BTech](http://btechsmartclass.com/data_structures/avl-trees.html)
-* [AVL Tree Insertion on YouTube](https://www.youtube.com/watch?v=rbg7Qf8GkQ4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=12&)
-* [AVL Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/AVLtree.html)
diff --git a/src/data-structures/tree/binary-search-tree/README.pt-BR.md b/src/data-structures/tree/binary-search-tree/README.en-EN.md
similarity index 69%
rename from src/data-structures/tree/binary-search-tree/README.pt-BR.md
rename to src/data-structures/tree/binary-search-tree/README.en-EN.md
index 1e71714104..e5f9fd90dd 100644
--- a/src/data-structures/tree/binary-search-tree/README.pt-BR.md
+++ b/src/data-structures/tree/binary-search-tree/README.en-EN.md
@@ -1,38 +1,40 @@
-# Árvore de Pesquisa Binária (Binary Search Tree)
-
-Na ciência da computação **binary search trees** (BST), algumas vezes
-chamadas de árvores binárias ordenadas (_ordered or sorted binary trees_),
-é um tipo particular de container: estruturas de dados que armazenam
-"itens" (como números, nomes, etc.) na memória. Permite pesquisa rápida,
-adição e remoção de itens além de poder ser utilizado para implementar
-tanto conjuntos dinâmicos de itens ou, consultar tabelas que permitem
-encontrar um item por seu valor chave. E.g. encontrar o número de
-telefone de uma pessoa pelo seu nome.
-
-Árvore de Pesquisa Binária mantem seus valores chaves ordenados, para
-que uma pesquisa e outras operações possam usar o princípio da pesquisa
-binária: quando pesquisando por um valor chave na árvore (ou um lugar
-para inserir uma nova chave), eles atravessam a árvore da raiz para a folha,
-fazendo comparações com chaves armazenadas nos nós da árvore e decidindo então,
-com base nas comparações, continuar pesquisando nas sub-árvores a direita ou
-a esquerda. Em média isto significa que cara comparação permite as operações
-pular metade da árvore, para que então, cada pesquisa, inserção ou remoção
-consuma tempo proporcional ao logaritmo do número de itens armazenados na
-árvore. Isto é muito melhor do que um tempo linear necessário para encontrar
-itens por seu valor chave em um array (desorndenado - _unsorted_), mas muito
-mais lento do que operações similares em tableas de hash (_hash tables_).
-
-Uma pesquisa de árvore binária de tamanho 9 e profundidade 3, com valor 8
-na raíz.
-As folhas não foram desenhadas.
+# Binary Search Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, **binary search trees** (BST), sometimes called
+ordered or sorted binary trees, are a particular type of container:
+data structures that store "items" (such as numbers, names etc.)
+in memory. They allow fast lookup, addition and removal of
+items, and can be used to implement either dynamic sets of
+items, or lookup tables that allow finding an item by its key
+(e.g., finding the phone number of a person by name).
+
+Binary search trees keep their keys in sorted order, so that lookup
+and other operations can use the principle of binary search:
+when looking for a key in a tree (or a place to insert a new key),
+they traverse the tree from root to leaf, making comparisons to
+keys stored in the nodes of the tree and deciding, on the basis
+of the comparison, to continue searching in the left or right
+subtrees. On average, this means that each comparison allows
+the operations to skip about half of the tree, so that each
+lookup, insertion or deletion takes time proportional to the
+logarithm of the number of items stored in the tree. This is
+much better than the linear time required to find items by key
+in an (unsorted) array, but slower than the corresponding
+operations on hash tables.
+
+A binary search tree of size 9 and depth 3, with 8 at the root.
+The leaves are not drawn.
 
 ![Trie](./images/binary-search-tree.jpg)
 
-*Made with [okso.app](https://okso.app)*
+_Made with [okso.app](https://okso.app)_
 
-## Pseudocódigo para Operações Básicas
+## Pseudocode for Basic Operations
 
-### Inserção
+### Insertion
 
 ```text
 insert(value)
@@ -66,7 +68,7 @@ insertNode(current, value)
 end insertNode
 ```
 
-### Pesquisa
+### Searching
 
 ```text
 contains(root, value)
@@ -85,8 +87,7 @@ contains(root, value)
 end contains
 ```
 
-
-### Remoção
+### Deletion
 
 ```text
 remove(value)
@@ -137,7 +138,7 @@ remove(value)
 end remove
 ```
 
-### Encontrar o Nó Pai
+### Find Parent of Node
 
 ```text
 findParent(value, root)
@@ -167,7 +168,7 @@ findParent(value, root)
 end findParent
 ```
 
-### Encontrar um Nó
+### Find Node
 
 ```text
 findNode(root, value)
@@ -187,7 +188,7 @@ findNode(root, value)
 end findNode
 ```
 
-### Encontrar Mínimo
+### Find Minimum
 
 ```text
 findMin(root)
@@ -201,7 +202,7 @@ findMin(root)
 end findMin
 ```
 
-### Encontrar Máximo
+### Find Maximum
 
 ```text
 findMax(root)
@@ -217,13 +218,13 @@ end findMax
 
 ### Traversal
 
-#### Na Ordem Traversal (InOrder Traversal)
+#### InOrder Traversal
 
 ```text
 inorder(root)
   Pre: root is the root node of the BST
   Post: the nodes in the BST have been visited in inorder
-  if root = ø
+  if root != ø
     inorder(root.left)
     yield root.value
     inorder(root.right)
@@ -231,13 +232,13 @@ inorder(root)
 end inorder
 ```
 
-#### Pré Ordem Traversal (PreOrder Traversal)
+#### PreOrder Traversal
 
 ```text
 preorder(root)
   Pre: root is the root node of the BST
   Post: the nodes in the BST have been visited in preorder
-  if root = ø
+  if root != ø
     yield root.value
     preorder(root.left)
     preorder(root.right)
@@ -245,13 +246,13 @@ preorder(root)
 end preorder
 ```
 
-#### Pós Ordem Traversal (PostOrder Traversal)
+#### PostOrder Traversal
 
 ```text
 postorder(root)
   Pre: root is the root node of the BST
   Post: the nodes in the BST have been visited in postorder
-  if root = ø
+  if root != ø
     postorder(root.left)
     postorder(root.right)
     yield root.value
@@ -259,19 +260,19 @@ postorder(root)
 end postorder
 ```
 
-## Complexidades
+## Complexities
 
-### Complexidade de Tempo
+### Time Complexity
 
-| Access    | Search    | Insertion | Deletion  |
+|  Access   |  Search   | Insertion | Deletion  |
 | :-------: | :-------: | :-------: | :-------: |
 | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) |
 
-### Complexidade de Espaço
+### Space Complexity
 
 O(n)
 
-## Referências
+## References
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree)
 - [Inserting to BST on YouTube](https://www.youtube.com/watch?v=wcIRPqTR3Kc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=9&t=0s)
diff --git a/src/data-structures/tree/binary-search-tree/README.md b/src/data-structures/tree/binary-search-tree/README.md
index d05a891545..7363ba40d4 100644
--- a/src/data-structures/tree/binary-search-tree/README.md
+++ b/src/data-structures/tree/binary-search-tree/README.md
@@ -1,40 +1,21 @@
-# Binary Search Tree
-
-_Read this in other languages:_
-[_Português_](README.pt-BR.md)
-
-In computer science, **binary search trees** (BST), sometimes called
-ordered or sorted binary trees, are a particular type of container:
-data structures that store "items" (such as numbers, names etc.)
-in memory. They allow fast lookup, addition and removal of
-items, and can be used to implement either dynamic sets of
-items, or lookup tables that allow finding an item by its key
-(e.g., finding the phone number of a person by name).
-
-Binary search trees keep their keys in sorted order, so that lookup
-and other operations can use the principle of binary search:
-when looking for a key in a tree (or a place to insert a new key),
-they traverse the tree from root to leaf, making comparisons to
-keys stored in the nodes of the tree and deciding, on the basis
-of the comparison, to continue searching in the left or right
-subtrees. On average, this means that each comparison allows
-the operations to skip about half of the tree, so that each
-lookup, insertion or deletion takes time proportional to the
-logarithm of the number of items stored in the tree. This is
-much better than the linear time required to find items by key
-in an (unsorted) array, but slower than the corresponding
-operations on hash tables.
-
-A binary search tree of size 9 and depth 3, with 8 at the root.
-The leaves are not drawn.
+# Cây Tìm Kiếm Nhị Phân
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, **cây tìm kiếm nhị phân** (BST), đôi khi được gọi là cây nhị phân được sắp xếp, là một loại đặc biệt của bộ chứa: các cấu trúc dữ liệu lưu trữ "mục" (như số, tên, v.v.) trong bộ nhớ. Chúng cho phép tìm kiếm, thêm và xóa mục một cách nhanh chóng, và có thể được sử dụng để triển khai cả tập hợp động của các mục hoặc bảng tra cứu cho phép tìm một mục bằng khóa của nó (ví dụ, tìm số điện thoại của một người bằng tên).
+
+Cây tìm kiếm nhị phân giữ các khóa của chúng theo thứ tự sắp xếp, để tìm kiếm và các thao tác khác có thể sử dụng nguyên lý của tìm kiếm nhị phân: khi tìm kiếm một khóa trong một cây (hoặc một vị trí để chèn một khóa mới), chúng đi qua cây từ gốc đến lá, so sánh với các khóa được lưu trữ trong các nút của cây và quyết định, dựa trên sự so sánh, để tiếp tục tìm kiếm trong cây con bên trái hoặc bên phải. Trong trung bình, điều này có nghĩa là mỗi sự so sánh cho phép các thao tác bỏ qua khoảng một nửa cây, sao cho mỗi tìm kiếm, chèn hoặc xóa mất thời gian tỷ lệ với logarit của số lượng mục được lưu trữ trong cây. Điều này tốt hơn nhiều so với thời gian tuyến tính cần thiết để tìm các mục theo khóa trong một mảng (chưa được sắp xếp), nhưng chậm hơn so với các thao tác tương ứng trên bảng băm.
+
+Một cây tìm kiếm nhị phân có kích thước 9 và độ sâu 3, với 8 ở gốc. Những lá không được vẽ.
 
 ![Trie](./images/binary-search-tree.jpg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo bởi [okso.app](https://okso.app)_
 
-## Pseudocode for Basic Operations
+## Mã Giả cho Các Thao Tác Cơ Bản
 
-### Insertion
+### Chèn
 
 ```text
 insert(value)
@@ -68,7 +49,7 @@ insertNode(current, value)
 end insertNode
 ```
 
-### Searching
+### Tìm Kiếm
 
 ```text
 contains(root, value)
@@ -87,8 +68,7 @@ contains(root, value)
 end contains
 ```
 
-
-### Deletion
+### Xóa
 
 ```text
 remove(value)
@@ -139,7 +119,7 @@ remove(value)
 end remove
 ```
 
-### Find Parent of Node
+### Tìm Cha của Nút
 
 ```text
 findParent(value, root)
@@ -169,7 +149,7 @@ findParent(value, root)
 end findParent
 ```
 
-### Find Node
+### Tìm Nút
 
 ```text
 findNode(root, value)
@@ -189,7 +169,7 @@ findNode(root, value)
 end findNode
 ```
 
-### Find Minimum
+### Tìm Giá Trị Nhỏ Nhất
 
 ```text
 findMin(root)
@@ -203,7 +183,7 @@ findMin(root)
 end findMin
 ```
 
-### Find Maximum
+### Tìm Giá Trị Lớn Nhất
 
 ```text
 findMax(root)
@@ -217,9 +197,9 @@ findMax(root)
 end findMax
 ```
 
-### Traversal
+### Duyệt
 
-#### InOrder Traversal
+#### Duyệt theo Trình Tự Trung Tự
 
 ```text
 inorder(root)
@@ -233,7 +213,7 @@ inorder(root)
 end inorder
 ```
 
-#### PreOrder Traversal
+#### Duyệt theo Trình Tự Trước
 
 ```text
 preorder(root)
@@ -247,7 +227,7 @@ preorder(root)
 end preorder
 ```
 
-#### PostOrder Traversal
+#### Duyệt theo Trình Tự Sau
 
 ```text
 postorder(root)
@@ -261,20 +241,20 @@ postorder(root)
 end postorder
 ```
 
-## Complexities
+## Độ Phức Tạp
 
-### Time Complexity
+### Độ Phức Tạp Thời Gian
 
-| Access    | Search    | Insertion | Deletion  |
+| Truy Cập  | Tìm Kiếm  |   Chèn    |    Xóa    |
 | :-------: | :-------: | :-------: | :-------: |
 | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) |
 
-### Space Complexity
+### Độ Phức Tạp Không Gian
 
 O(n)
 
-## References
+## Tài Liệu Tham Khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_tree)
-- [Inserting to BST on YouTube](https://www.youtube.com/watch?v=wcIRPqTR3Kc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=9&t=0s)
-- [BST Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/BST.html)
+- [Chèn vào BST trên YouTube](https://www.youtube.com/watch?v=wcIRPqTR3Kc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=9&t=0s)
+- [Trực Quan Hóa BST](https://www.cs.usfca.edu/~galles/visualization/BST.html)
diff --git a/src/data-structures/tree/fenwick-tree/README.en-EN.md b/src/data-structures/tree/fenwick-tree/README.en-EN.md
new file mode 100644
index 0000000000..6092b632a9
--- /dev/null
+++ b/src/data-structures/tree/fenwick-tree/README.en-EN.md
@@ -0,0 +1,40 @@
+# Fenwick Tree / Binary Indexed Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **Fenwick tree** or **binary indexed tree** is a data
+structure that can efficiently update elements and
+calculate prefix sums in a table of numbers.
+
+When compared with a flat array of numbers, the Fenwick tree achieves a
+much better balance between two operations: element update and prefix sum
+calculation. In a flat array of `n` numbers, you can either store the elements,
+or the prefix sums. In the first case, computing prefix sums requires linear
+time; in the second case, updating the array elements requires linear time
+(in both cases, the other operation can be performed in constant time).
+Fenwick trees allow both operations to be performed in `O(log n)` time.
+This is achieved by representing the numbers as a tree, where the value of
+each node is the sum of the numbers in that subtree. The tree structure allows
+operations to be performed using only `O(log n)` node accesses.
+
+## Implementation Notes
+
+Binary Indexed Tree is represented as an array. Each node of Binary Indexed Tree
+stores sum of some elements of given array. Size of Binary Indexed Tree is equal
+to `n` where `n` is size of input array. In current implementation we have used
+size as `n+1` for ease of implementation. All the indexes are 1-based.
+
+![Binary Indexed Tree](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)
+
+On the picture below you may see animated example of
+creation of binary indexed tree for the
+array `[1, 2, 3, 4, 5]` by inserting one by one.
+
+![Fenwick Tree](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Fenwick_tree)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)
+- [YouTube](https://www.youtube.com/watch?v=CWDQJGaN1gY&index=18&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/tree/fenwick-tree/README.md b/src/data-structures/tree/fenwick-tree/README.md
index 14129caa7c..6af99f3318 100644
--- a/src/data-structures/tree/fenwick-tree/README.md
+++ b/src/data-structures/tree/fenwick-tree/README.md
@@ -1,39 +1,23 @@
-# Fenwick Tree / Binary Indexed Tree
+# Cây Fenwick / Cây Nhị Phân Đánh Dấu
 
-_Read this in other languages:_
-[_Português_](README.pt-BR.md) 
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-A **Fenwick tree** or **binary indexed tree** is a data 
-structure that can efficiently update elements and 
-calculate prefix sums in a table of numbers.
+Cây Fenwick hoặc cây nhị phân đánh dấu là một cấu trúc dữ liệu có thể cập nhật các phần tử và tính tổng tiền tố một cách hiệu quả trong một bảng số.
 
-When compared with a flat array of numbers, the Fenwick tree achieves a 
-much better balance between two operations: element update and prefix sum 
-calculation. In a flat array of `n` numbers, you can either store the elements, 
-or the prefix sums. In the first case, computing prefix sums requires linear 
-time; in the second case, updating the array elements requires linear time 
-(in both cases, the other operation can be performed in constant time). 
-Fenwick trees allow both operations to be performed in `O(log n)` time. 
-This is achieved by representing the numbers as a tree, where the value of 
-each node is the sum of the numbers in that subtree. The tree structure allows 
-operations to be performed using only `O(log n)` node accesses.
+So với một mảng phẳng của các số, cây Fenwick đạt được sự cân bằng tốt hơn giữa hai thao tác: cập nhật phần tử và tính tổng tiền tố. Trong một mảng phẳng của `n` số, bạn có thể lưu trữ các phần tử hoặc tổng tiền tố. Trong trường hợp đầu tiên, việc tính toán tổng tiền tố đòi hỏi thời gian tuyến tính; trong trường hợp thứ hai, việc cập nhật các phần tử mảng đòi hỏi thời gian tuyến tính (trong cả hai trường hợp, thao tác còn lại có thể được thực hiện trong thời gian hằng số). Cây Fenwick cho phép cả hai thao tác được thực hiện trong thời gian `O(log n)`. Điều này được đạt được bằng cách đại diện cho các số như một cây, trong đó giá trị của mỗi nút là tổng của các số trong cây con đó. Cấu trúc cây cho phép các thao tác được thực hiện chỉ bằng cách truy cập vào các nút `O(log n)`.
 
-## Implementation Notes
+## Ghi chú về Triển khai
 
-Binary Indexed Tree is represented as an array. Each node of Binary Indexed Tree 
-stores sum of some elements of given array. Size of Binary Indexed Tree is equal 
-to `n` where `n` is size of input array. In current implementation we have used 
-size as `n+1` for ease of implementation. All the indexes are 1-based.
+Cây Nhị Phân Đánh Dấu được đại diện dưới dạng một mảng. Mỗi nút của Cây Nhị Phân Đánh Dấu lưu trữ tổng của một số phần tử của mảng được cho. Kích thước của Cây Nhị Phân Đánh Dấu bằng với `n` nơi `n` là kích thước của mảng đầu vào. Trong triển khai hiện tại, chúng ta đã sử dụng kích thước là `n+1` để dễ triển khai. Tất cả các chỉ số được đánh số từ 1.
 
-![Binary Indexed Tree](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)
+![Cây Nhị Phân Đánh Dấu](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)
 
-On the picture below you may see animated example of 
-creation of binary indexed tree for the 
-array `[1, 2, 3, 4, 5]` by inserting one by one.
+Trên hình dưới đây, bạn có thể thấy ví dụ minh họa động về việc tạo cây nhị phân đánh dấu cho mảng `[1, 2, 3, 4, 5]` bằng cách chèn từng phần tử một.
 
-![Fenwick Tree](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)
+![Cây Fenwick](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Fenwick_tree)
 - [GeeksForGeeks](https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)
diff --git a/src/data-structures/tree/fenwick-tree/README.pt-BR.md b/src/data-structures/tree/fenwick-tree/README.pt-BR.md
deleted file mode 100644
index b76bbc0f97..0000000000
--- a/src/data-structures/tree/fenwick-tree/README.pt-BR.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Árvore Fenwick / Árvore Binária Indexada (Fenwick Tree / Binary Indexed Tree)
-
-Uma **árvore Fenwick** ou **árvore binária indexada** é um tipo de
-estrutura de dados que consegue eficiemente atualizar elementos e
-calcular soma dos prefixos em uma tabela de números.
-
-Quando comparado com um _flat array_ de números, a árvore Fenwick
-alcança um balanceamento muito melhor entre duas operações: atualização
-(_update_) do elemento e cálculo da soma do prefíxo. Em uma _flar array_
-de `n` números, você pode tanto armazenar elementos quando a soma dos
-prefixos. Em ambos os casos, computar a soma dos prefixos requer ou 
-atualizar um array de elementos também requerem um tempo linear, contudo,
-a demais operações podem ser realizadas com tempo constante.
-A árvore Fenwick permite ambas as operações serem realizadas com tempo
-`O(log n)`.
-
-Isto é possível devido a representação dos números como uma árvore, aonde
-os valores de cada nó é a soma dos números naquela sub-árvore. A estrutura
-de árvore permite operações a serem realizadas consumindo somente acessos
-a nós em `O(log n)`.
-
-## Implementação de Nós
-
-Árvore Binária Indexada é representada como um _array_. Em cada nó da Árvore
-Binária Indexada armazena a soma de alguns dos elementos de uma _array_
-fornecida. O tamanho da Árvore Binária Indexada é igual a `n` aonde `n` é o
-tamanho do _array_ de entrada. Na presente implementação nós utilizados o
-tamanho `n+1` para uma implementação fácil. Todos os índices são baseados em 1. 
-
-![Binary Indexed Tree](https://www.geeksforgeeks.org/wp-content/uploads/BITSum.png)
-
-Na imagem abaixo você pode ver o exemplo animado da criação de uma árvore
-binária indexada para o _array_ `[1, 2, 3, 4, 5]`, sendo inseridos um após
-o outro.
-
-![Fenwick Tree](https://upload.wikimedia.org/wikipedia/commons/d/dc/BITDemo.gif)
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Fenwick_tree)
-- [GeeksForGeeks](https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)
-- [YouTube](https://www.youtube.com/watch?v=CWDQJGaN1gY&index=18&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/tree/red-black-tree/README.en-EN.md b/src/data-structures/tree/red-black-tree/README.en-EN.md
new file mode 100644
index 0000000000..1406f0e422
--- /dev/null
+++ b/src/data-structures/tree/red-black-tree/README.en-EN.md
@@ -0,0 +1,97 @@
+# Red–Black Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+A **red–black tree** is a kind of self-balancing binary search
+tree in computer science. Each node of the binary tree has
+an extra bit, and that bit is often interpreted as the
+color (red or black) of the node. These color bits are used
+to ensure the tree remains approximately balanced during
+insertions and deletions.
+
+Balance is preserved by painting each node of the tree with
+one of two colors in a way that satisfies certain properties,
+which collectively constrain how unbalanced the tree can
+become in the worst case. When the tree is modified, the
+new tree is subsequently rearranged and repainted to
+restore the coloring properties. The properties are
+designed in such a way that this rearranging and recoloring
+can be performed efficiently.
+
+The balancing of the tree is not perfect, but it is good
+enough to allow it to guarantee searching in `O(log n)` time,
+where `n` is the total number of elements in the tree.
+The insertion and deletion operations, along with the tree
+rearrangement and recoloring, are also performed
+in `O(log n)` time.
+
+An example of a red–black tree:
+
+![red-black tree](https://upload.wikimedia.org/wikipedia/commons/6/66/Red-black_tree_example.svg)
+
+## Properties
+
+In addition to the requirements imposed on a binary search
+tree the following must be satisfied by a red–black tree:
+
+- Each node is either red or black.
+- The root is black. This rule is sometimes omitted.
+  Since the root can always be changed from red to black,
+  but not necessarily vice versa, this rule has little
+  effect on analysis.
+- All leaves (NIL) are black.
+- If a node is red, then both its children are black.
+- Every path from a given node to any of its descendant
+  NIL nodes contains the same number of black nodes.
+
+Some definitions: the number of black nodes from the root
+to a node is the node's **black depth**; the uniform
+number of black nodes in all paths from root to the leaves
+is called the **black-height** of the red–black tree.
+
+These constraints enforce a critical property of red–black
+trees: _the path from the root to the farthest leaf is no more than twice as long as the path from the root to the nearest leaf_.
+The result is that the tree is roughly height-balanced.
+Since operations such as inserting, deleting, and finding
+values require worst-case time proportional to the height
+of the tree, this theoretical upper bound on the height
+allows red–black trees to be efficient in the worst case,
+unlike ordinary binary search trees.
+
+## Balancing during insertion
+
+### If uncle is RED
+
+![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)
+
+### If uncle is BLACK
+
+- Left Left Case (`p` is left child of `g` and `x` is left child of `p`)
+- Left Right Case (`p` is left child of `g` and `x` is right child of `p`)
+- Right Right Case (`p` is right child of `g` and `x` is right child of `p`)
+- Right Left Case (`p` is right child of `g` and `x` is left child of `p`)
+
+#### Left Left Case (See g, p and x)
+
+![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)
+
+#### Left Right Case (See g, p and x)
+
+![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)
+
+#### Right Right Case (See g, p and x)
+
+![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)
+
+#### Right Left Case (See g, p and x)
+
+![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
+- [Red Black Tree Insertion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)
+- [Red Black Tree Deletion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)
+- [Red Black Tree Insertion on GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)
+- [Red Black Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
diff --git a/src/data-structures/tree/red-black-tree/README.md b/src/data-structures/tree/red-black-tree/README.md
index 566089f976..744d2166bc 100644
--- a/src/data-structures/tree/red-black-tree/README.md
+++ b/src/data-structures/tree/red-black-tree/README.md
@@ -1,96 +1,65 @@
-# Red–Black Tree
-
-_Read this in other languages:_
-[_Português_](README.pt-BR.md) 
-
-A **red–black tree** is a kind of self-balancing binary search 
-tree in computer science. Each node of the binary tree has 
-an extra bit, and that bit is often interpreted as the 
-color (red or black) of the node. These color bits are used 
-to ensure the tree remains approximately balanced during 
-insertions and deletions.
-
-Balance is preserved by painting each node of the tree with 
-one of two colors in a way that satisfies certain properties,
-which collectively constrain how unbalanced the tree can 
-become in the worst case. When the tree is modified, the 
-new tree is subsequently rearranged and repainted to 
-restore the coloring properties. The properties are 
-designed in such a way that this rearranging and recoloring 
-can be performed efficiently.
-
-The balancing of the tree is not perfect, but it is good 
-enough to allow it to guarantee searching in `O(log n)` time,
-where `n` is the total number of elements in the tree. 
-The insertion and deletion operations, along with the tree 
-rearrangement and recoloring, are also performed 
-in `O(log n)` time.
-
-An example of a red–black tree:
+# Cây Đỏ-Đen
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+**Cây đỏ-đen** là một loại cây tìm kiếm nhị phân cân bằng tự động trong khoa học máy tính. Mỗi nút của cây nhị phân có một bit bổ sung, và bit này thường được hiểu là màu (đỏ hoặc đen) của nút. Các bit màu này được sử dụng để đảm bảo rằng cây vẫn cân bằng một cách xấp xỉ trong quá trình chèn và xóa.
+
+Sự cân bằng được bảo tồn bằng cách sơn mỗi nút của cây bằng một trong hai màu một cách thỏa mãn các thuộc tính nhất định, những thuộc tính này hạn chế tỉ lệ mất cân bằng của cây trong trường hợp xấu nhất. Khi cây bị thay đổi, cây mới sau đó được sắp xếp lại và sơn lại để khôi phục các thuộc tính về màu sắc. Các thuộc tính được thiết kế sao cho việc sắp xếp lại và sơn lại này có thể được thực hiện một cách hiệu quả.
+
+Việc cân bằng của cây không hoàn hảo, nhưng đủ tốt để cho phép nó đảm bảo tìm kiếm trong thời gian `O(log n)`, trong đó `n` là tổng số phần tử trong cây. Các thao tác chèn và xóa, cùng với việc sắp xếp lại và sơn lại cây, cũng được thực hiện trong thời gian `O(log n)`.
+
+Một ví dụ về cây đỏ-đen:
 
 ![red-black tree](https://upload.wikimedia.org/wikipedia/commons/6/66/Red-black_tree_example.svg)
 
-## Properties
+## Thuộc tính
+
+Ngoài các yêu cầu được đặt ra cho một cây tìm kiếm nhị phân, các yêu cầu sau phải được đáp ứng bởi một cây đỏ-đen:
 
-In addition to the requirements imposed on a binary search 
-tree the following must be satisfied by a red–black tree:
+- Mỗi nút có màu đỏ hoặc đen.
+- Gốc của cây là màu đen. Quy tắc này đôi khi được bỏ qua. Vì gốc luôn có thể được thay đổi từ màu đỏ thành màu đen, nhưng không nhất thiết phải ngược lại, quy tắc này không ảnh hưởng nhiều đến phân tích.
+- Tất cả các lá (NIL) đều là màu đen.
+- Nếu một nút có màu đỏ, thì cả hai con của nó đều là màu đen.
+- Mọi đường từ một nút cụ thể đến bất kỳ nút lá con NIL nào của nó đều chứa cùng số lượng nút đen.
 
-- Each node is either red or black.
-- The root is black. This rule is sometimes omitted. 
-Since the root can always be changed from red to black, 
-but not necessarily vice versa, this rule has little 
-effect on analysis.
-- All leaves (NIL) are black.
-- If a node is red, then both its children are black.
-- Every path from a given node to any of its descendant 
-NIL nodes contains the same number of black nodes.
+Một số định nghĩa: số lượng nút đen từ gốc đến một nút là **độ sâu đen** của nút đó; số lượng đều nhau của các nút đen trên tất cả các đường từ gốc đến các lá được gọi là **chiều cao đen** của cây đỏ-đen.
 
-Some definitions: the number of black nodes from the root 
-to a node is the node's **black depth**; the uniform 
-number of black nodes in all paths from root to the leaves 
-is called the **black-height** of the red–black tree.
+Những ràng buộc này áp dụng một tính chất quan trọng của cây đỏ-đen: _đường từ gốc đến lá xa nhất không dài hơn gấp đôi đường từ gốc đến lá gần nhất_. Kết quả là cây xấp xỉ cân bằng chiều cao. Vì các thao tác như chèn, xóa và tìm kiếm giá trị đều yêu cầu thời gian tối đa tỉ lệ thuận với chiều cao của cây, giới hạn trên lý thuyết này về chiều cao cho phép cây đỏ-đen là hiệu quả trong trường hợp xấu nhất, khác với cây tìm kiếm nhị phân thông thường.
 
-These constraints enforce a critical property of red–black 
-trees: _the path from the root to the farthest leaf is no more than twice as long as the path from the root to the nearest leaf_. 
-The result is that the tree is roughly height-balanced. 
-Since operations such as inserting, deleting, and finding 
-values require worst-case time proportional to the height 
-of the tree, this theoretical upper bound on the height 
-allows red–black trees to be efficient in the worst case, 
-unlike ordinary binary search trees.
+## Cân bằng trong quá trình chèn
 
-## Balancing during insertion
+### Nếu cậu là MÀU ĐỎ
 
-### If uncle is RED
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)
+![Cân bằng cây Đỏ-Đen](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)
 
-### If uncle is BLACK
+### Nếu cậu là MÀU ĐEN
 
-- Left Left Case (`p` is left child of `g` and `x` is left child of `p`)
-- Left Right Case (`p` is left child of `g` and `x` is right child of `p`)
-- Right Right Case (`p` is right child of `g` and `x` is right child of `p`)
-- Right Left Case (`p` is right child of `g` and `x` is left child of `p`)
+- Trường hợp Trái Trái (`p` là con trái của `g` và `x` là con trái của `p`)
+- Trường hợp Trái Phải (`p` là con trái của `g` và `x` là con phải của `p`)
+- Trường hợp Phải Phải (`p` là con phải của `g` và `x` là con phải của `p`)
+- Trường hợp Phải Trái (`p` là con phải của `g` và `x` là con trái của `p`)
 
-#### Left Left Case (See g, p and x)
+#### Trường hợp Trái Trái (Xem g, p và x)
 
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)
+![Cân bằng cây Đỏ-Đen](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)
 
-#### Left Right Case (See g, p and x)
+#### Trường hợp Trái Phải (Xem g, p và x)
 
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)
+![Cân bằng cây Đỏ-Đen](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)
 
-#### Right Right Case (See g, p and x)
+#### Trường hợp Phải Phải (Xem g, p và x)
 
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)
+![Cân bằng cây Đỏ-Đen](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)
 
-#### Right Left Case (See g, p and x)
+#### Trường hợp Phải Trái (Xem g, p và x)
 
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)
+![Cân bằng cây Đỏ-Đen](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
-- [Red Black Tree Insertion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)
-- [Red Black Tree Deletion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)
-- [Red Black Tree Insertion on GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)
-- [Red Black Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
+- [Chèn Cây Đỏ-Đen bởi Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)
+- [Xóa Cây Đỏ-Đen bởi Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)
+- [Chèn Cây Đỏ-Đen trên GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)
+- [Trực quan hóa Cây Đỏ-Đen](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
diff --git a/src/data-structures/tree/red-black-tree/README.pt-BR.md b/src/data-structures/tree/red-black-tree/README.pt-BR.md
deleted file mode 100644
index 6c80def9cd..0000000000
--- a/src/data-structures/tree/red-black-tree/README.pt-BR.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# Árvore Vermelha-Preta (Red-Black Tree)
-
-Uma **árvore vermelha-preta** é um tipo de árvore de pesquisa
-binária auto balanceada na ciência da computação. Cada nó da 
-árvore binária possui um _bit_ extra, e este _bit_ é frequentemente
-interpretado com a cor (vermelho ou preto) do nó. Estas cores de _bits_
-são utilizadas para garantir que a árvore permanece aproximadamente
-equilibrada durante as operações de inserções e remoções.
-
-O equilíbrio é preservado através da pintura de cada nó da árvore com
-uma das duas cores, de maneira que satisfaça certas propriedades, das
-quais restringe nos piores dos casos, o quão desequilibrada a árvore
-pode se tornar. Quando a árvore é modificada, a nova árvore é
-subsequentemente reorganizada e repintada para restaurar as
-propriedades de coloração. As propriedades são designadas de tal modo que
-esta reorganização e nova pintura podem ser realizadas eficientemente.
-
-O balanceamento de uma árvore não é perfeito, mas é suficientemente bom
-para permitir e garantir uma pesquisa no tempo `O(log n)`, aonde `n` é o
-número total de elementos na árvore.
-Operações de inserções e remoções, juntamente com a reorganização e 
-repintura da árvore, também são executados no tempo `O (log n)`.
-
-Um exemplo de uma árvore vermalha-preta:
-
-![red-black tree](https://upload.wikimedia.org/wikipedia/commons/6/66/Red-black_tree_example.svg)
-
-## Propriedades
-
-Em adição aos requerimentos impostos pela árvore de pesquisa binária,
-as seguintes condições devem ser satisfeitas pela árvore vermelha-preta:
-
-- Cada nó é tanto vermelho ou preto.
-- O nó raíz é preto. Esta regra algumas vezes é omitida.
-Tendo em vista que a raíz pode sempre ser alterada de vermelho para preto,
-mas não de preto para vermelho, esta regra tem pouco efeito na análise.
-- Todas as folhas (Nulo/NIL) são pretas.
-- Caso um nó é vermelho, então seus filhos serão pretos.
-- Cada caminho de um determinado nó para qualquer um dos seus nós nulos (NIL)
-descendentes contém o mesmo número de nós pretos.
-
-Algumas definições: o número de nós pretos da raiz até um nó é a
-**profundidade preta**(_black depth_) do nó; o número uniforme de nós pretos
-em todos os caminhos da raíz até as folhas são chamados de **altura negra**
-(_black-height_) da árvore vermelha-preta.
-
-Essas restrições impõem uma propriedade crítica de árvores vermelhas e pretas:
-_o caminho da raiz até a folha mais distante não possui mais que o dobro do
-comprimento do caminho da raiz até a folha mais próxima_.
-O resultado é que a árvore é grosseiramente balanceada na altura.
-
-Tendo em vista que operações como inserções, remoção e pesquisa de valores
-requerem nos piores dos casos um tempo proporcional a altura da ávore,
-este limite superior teórico na altura permite que as árvores vermelha-preta
-sejam eficientes no pior dos casos, ao contrário das árvores de busca binária
-comuns.
-
-## Balanceamento durante a inserção
-
-### Se o tio é VERMELHO
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase2.png)
-
-### Se o tio é PRETO
-
-- Caso Esquerda Esquerda (`p` é o filho a esquerda de `g` e `x`, é o filho a esquerda de `p`)
-- Caso Esquerda Direita (`p` é o filho a esquerda de `g` e `x`, é o filho a direita de `p`)
-- Caso Direita Direita (`p` é o filho a direita de `g` e `x`, é o filho da direita de `p`)
-- Caso Direita Esqueda (`p` é o filho a direita de `g` e `x`, é o filho a esquerda de `p`)
-
-#### Caso Esquerda Esquerda (Veja g, p e x)
-
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3a1.png)
-
-#### Caso Esquerda Direita (Veja g, p e x)
-
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3b.png)
-
-#### Caso Direita Direita (Veja g, p e x)
-
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3c.png)
-
-#### Caso Direita Esquerda (Veja g, p e x)
-
-![Red Black Tree Balancing](https://www.geeksforgeeks.org/wp-content/uploads/redBlackCase3d.png)
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
-- [Red Black Tree Insertion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=UaLIHuR1t8Q&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=63)
-- [Red Black Tree Deletion by Tushar Roy (YouTube)](https://www.youtube.com/watch?v=CTvfzU_uNKE&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=64)
-- [Red Black Tree Insertion on GeeksForGeeks](https://www.geeksforgeeks.org/red-black-tree-set-2-insert/)
-- [Red Black Tree Interactive Visualisations](https://www.cs.usfca.edu/~galles/visualization/RedBlack.html)
diff --git a/src/data-structures/tree/segment-tree/README.en-EN.md b/src/data-structures/tree/segment-tree/README.en-EN.md
new file mode 100644
index 0000000000..efeb371cad
--- /dev/null
+++ b/src/data-structures/tree/segment-tree/README.en-EN.md
@@ -0,0 +1,53 @@
+# Segment Tree
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **segment tree** also known as a statistic tree
+is a tree data structure used for storing information about intervals,
+or segments. It allows querying which of the stored segments contain
+a given point. It is, in principle, a static structure; that is,
+it's a structure that cannot be modified once it's built. A similar
+data structure is the interval tree.
+
+A segment tree is a binary tree. The root of the tree represents the
+whole array. The two children of the root represent the
+first and second halves of the array. Similarly, the
+children of each node corresponds to the two halves of
+the array corresponding to the node.
+
+We build the tree bottom up, with the value of each node
+being the "minimum" (or any other function) of its children's values. This will
+take `O(n log n)` time. The number
+of operations done is the height of the tree, which
+is `O(log n)`. To do range queries, each node splits the
+query into two parts, one sub-query for each child.
+If a query contains the whole subarray of a node, we
+can use the precomputed value at the node. Using this
+optimisation, we can prove that only `O(log n)` minimum
+operations are done.
+
+![Min Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/RangeMinimumQuery.png)
+
+![Sum Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/segment-tree1.png)
+
+## Application
+
+A segment tree is a data structure designed to perform
+certain array operations efficiently - especially those
+involving range queries.
+
+Applications of the segment tree are in the areas of computational geometry,
+and geographic information systems.
+
+Current implementation of Segment Tree implies that you may
+pass any binary (with two input params) function to it and
+thus you're able to do range query for variety of functions.
+In tests you may find examples of doing `min`, `max` and `sum` range
+queries on SegmentTree.
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Segment_tree)
+- [YouTube](https://www.youtube.com/watch?v=ZBHKZF5w4YU&index=65&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+- [GeeksForGeeks](https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/)
diff --git a/src/data-structures/tree/segment-tree/README.md b/src/data-structures/tree/segment-tree/README.md
index 7c332b0262..16699f910a 100644
--- a/src/data-structures/tree/segment-tree/README.md
+++ b/src/data-structures/tree/segment-tree/README.md
@@ -1,52 +1,23 @@
-# Segment Tree
-
-_Read this in other languages:_
-[_Português_](README.pt-BR.md) 
-
-In computer science, a **segment tree** also known as a statistic tree 
-is a tree data structure used for storing information about intervals, 
-or segments. It allows querying which of the stored segments contain 
-a given point. It is, in principle, a static structure; that is, 
-it's a structure that cannot be modified once it's built. A similar 
-data structure is the interval tree.
-
-A segment tree is a binary tree. The root of the tree represents the 
-whole array. The two children of the root represent the 
-first and second halves of the array. Similarly, the 
-children of each node corresponds to the two halves of 
-the array corresponding to the node.
-
-We build the tree bottom up, with the value of each node 
-being the "minimum" (or any other function) of its children's values. This will 
-take `O(n log n)` time. The number 
-of operations done is the height of the tree, which 
-is `O(log n)`. To do range queries, each node splits the 
-query into two parts, one sub-query for each child. 
-If a query contains the whole subarray of a node, we 
-can use the precomputed value at the node. Using this 
-optimisation, we can prove that only `O(log n)` minimum 
-operations are done.
-
-![Min Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/RangeMinimumQuery.png)
-
-![Sum Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/segment-tree1.png)
-
-## Application
-
-A segment tree is a data structure designed to perform 
-certain array operations efficiently - especially those 
-involving range queries.
-
-Applications of the segment tree are in the areas of computational geometry, 
-and geographic information systems.
-
-Current implementation of Segment Tree implies that you may
-pass any binary (with two input params) function to it and 
-thus you're able to do range query for variety of functions.
-In tests you may find examples of doing `min`, `max` and `sum` range
-queries on SegmentTree.
- 
-## References
+# Cây Đoạn
+
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
+
+Trong khoa học máy tính, một **cây đoạn** còn được gọi là cây thống kê là một cấu trúc dữ liệu cây được sử dụng để lưu trữ thông tin về các đoạn hoặc khoảng. Nó cho phép truy vấn xem đoạn được lưu trữ nào chứa một điểm cụ thể. Nó, về cơ bản, là một cấu trúc tĩnh; có nghĩa là, đó là một cấu trúc không thể được sửa đổi sau khi được xây dựng. Một cấu trúc dữ liệu tương tự là cây khoảng.
+
+Một cây đoạn là một cây nhị phân. Gốc của cây đại diện cho toàn bộ mảng. Hai con của gốc đại diện cho nửa đầu tiên và nửa thứ hai của mảng. Tương tự, các con của mỗi nút tương ứng với hai nửa của mảng tương ứng với nút đó.
+
+Chúng ta xây dựng cây từ dưới lên, với giá trị của mỗi nút là "tối thiểu" (hoặc bất kỳ hàm khác) của giá trị của các con của nó. Điều này sẽ mất thời gian `O(n log n)`. Số lượng thao tác được thực hiện là chiều cao của cây, là `O(log n)`. Để thực hiện truy vấn phạm vi, mỗi nút chia truy vấn thành hai phần, một phần con cho mỗi con. Nếu một truy vấn chứa toàn bộ mảng con của một nút, chúng ta có thể sử dụng giá trị được tính toán trước ở nút. Sử dụng tối ưu hóa này, chúng ta có thể chứng minh rằng chỉ có `O(log n)` thao tác tối thiểu được thực hiện.
+
+## Ứng dụng
+
+Một cây đoạn là một cấu trúc dữ liệu được thiết kế để thực hiện một số phép toán mảng cụ thể một cách hiệu quả - đặc biệt là những phép toán liên quan đến truy vấn phạm vi.
+
+Các ứng dụng của cây đoạn nằm trong các lĩnh vực của hình học tính toán và hệ thống thông tin địa lý.
+
+Hiện tại, cài đặt của Cây Đoạn ngụ ý rằng bạn có thể truyền bất kỳ hàm nhị phân nào (với hai tham số đầu vào) vào và do đó bạn có thể thực hiện truy vấn phạm vi cho nhiều loại hàm khác nhau. Trong các bài kiểm tra, bạn có thể tìm thấy ví dụ về việc thực hiện truy vấn phạm vi `min`, `max` và `sum` trên Cây Đoạn.
+
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Segment_tree)
 - [YouTube](https://www.youtube.com/watch?v=ZBHKZF5w4YU&index=65&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
diff --git a/src/data-structures/tree/segment-tree/README.pt-BR.md b/src/data-structures/tree/segment-tree/README.pt-BR.md
deleted file mode 100644
index 729a35c4ab..0000000000
--- a/src/data-structures/tree/segment-tree/README.pt-BR.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Árvore de Segmento (Segment Tree)
-
-Na ciência da computação, uma **árvore de segmento** também conhecida como
-árvore estatística é uma árvore de estrutura de dados utilizadas para
-armazenar informações sobre intervalores ou segmentos. Ela permite pesquisas
-no qual os segmentos armazenados contém um ponto fornecido. Isto é,
-em princípio, uma estrutura estática; ou seja, é uma estrutura que não pode
-ser modificada depois de inicializada. Uma estrutura de dados similar é a
-árvore de intervalos.
-
-Uma árvore de segmento é uma árvore binária. A raíz da árvore representa a
-_array_ inteira. Os dois filhos da raíz representam a primeira e a segunda
-metade da _array_. Similarmente, os filhos de cada nó correspondem ao número
-das duas metadas da _array_ correspondente do nó.
-
-Nós construímos a árvore debaixo para cima, com o valor de cada nó sendo o 
-"mínimo" (ou qualquer outra função) dos valores de seus filhos. Isto consumirá
-tempo `O(n log n)`. O número de oprações realizadas é equivalente a altura da
-árvore, pela qual consome tempo `O(log n)`. Para fazer consultas de intervalos,
-cada nó divide a consulta em duas partes, sendo uma sub consulta para cada filho.
-Se uma pesquisa contém todo o _subarray_ de um nó, nós podemos utilizar do valor
-pré-calculado do nó. Utilizando esta otimização, nós podemos provar que somente
-operações mínimas `O(log n)` são realizadas.
-
-![Min Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/RangeMinimumQuery.png)
-
-![Sum Segment Tree](https://www.geeksforgeeks.org/wp-content/uploads/segment-tree1.png)
-
-## Aplicação
-
-Uma árvore de segmento é uma estrutura de dados designada a realizar
-certas operações de _array_ eficientemente, especialmente aquelas envolvendo
-consultas de intervalos.
-
-Aplicações da árvore de segmentos são nas áreas de computação geométrica e
-sistemas de informação geográficos.
-
-A implementação atual da Árvore de Segmentos implica que você pode passar
-qualquer função binária (com dois parâmetros de entradas) e então, você
-será capaz de realizar consultas de intervalos para uma variedade de funções.
-Nos testes você poderá encontrar exemplos realizando `min`, `max` e consultas de
-intervalo `sum` na árvore segmentada (SegmentTree).
- 
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Segment_tree)
-- [YouTube](https://www.youtube.com/watch?v=ZBHKZF5w4YU&index=65&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
-- [GeeksForGeeks](https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/)
diff --git a/src/data-structures/trie/README.en-EN.md b/src/data-structures/trie/README.en-EN.md
new file mode 100644
index 0000000000..8b5066b0f3
--- /dev/null
+++ b/src/data-structures/trie/README.en-EN.md
@@ -0,0 +1,28 @@
+# Trie
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+In computer science, a **trie**, also called digital tree and sometimes
+radix tree or prefix tree (as they can be searched by prefixes),
+is a kind of search tree—an ordered tree data structure that is
+used to store a dynamic set or associative array where the keys
+are usually strings. Unlike a binary search tree, no node in the
+tree stores the key associated with that node; instead, its
+position in the tree defines the key with which it is associated.
+All the descendants of a node have a common prefix of the string
+associated with that node, and the root is associated with the
+empty string. Values are not necessarily associated with every
+node. Rather, values tend only to be associated with leaves,
+and with some inner nodes that correspond to keys of interest.
+For the space-optimized presentation of prefix tree, see compact
+prefix tree.
+
+![Trie](./images/trie.jpg)
+
+_Made with [okso.app](https://okso.app)_
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Trie)
+- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/data-structures/trie/README.ko-KO.md b/src/data-structures/trie/README.ko-KO.md
deleted file mode 100644
index e57142ece4..0000000000
--- a/src/data-structures/trie/README.ko-KO.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Trie
-
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_Português_](README.pt-BR.md),
-[_Українська_](README.uk-UA.md),
-[_한국어_](README.ko-KO.md)
-
-컴퓨터 과학에서 **트라이**는 디지털 트리라고도 불리며 때로는 기수 트리 또는 접두사 트리(접두사로 검색할 수 있기 때문에)라고도 불리며 일종의 검색 트리입니다. 키가 보통 문자열인 동적 집합 또는 연관 배열을 저장하는 데 사용되는 순서가 지정된 트리 데이터 구조입니다. 이진 검색 트리와 달리 트리의 어떤 노드도 해당 노드와 연결된 키를 저장하지 않으며 대신 트리의 위치가 해당 노드와 연결된 키를 정의합니다. 노드의 모든 하위 항목은 해당 노드와 연결된 문자열의 공통 접두사를 가지며 루트는 빈 문자열과 연결됩니다. 값은 모든 노드와 반드시 연결되지는 않습니다. 오히려 값은 나뭇잎과 관심 있는 키에 해당하는 일부 내부 노드에만 연결되는 경향이 있습니다. 접두사 트리의 공간에 최적화된 표현은 콤팩트 접두사 트리를 참조하십시오.
-
-![Trie](./images/trie.jpg)
-
-_Made with [okso.app](https://okso.app)_
-
-## 참조
-
-- [Wikipedia](<https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%9D%BC%EC%9D%B4_(%EC%BB%B4%ED%93%A8%ED%8C%85)>)
-- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/data-structures/trie/README.md b/src/data-structures/trie/README.md
index b3bba5de1e..fe9342e139 100644
--- a/src/data-structures/trie/README.md
+++ b/src/data-structures/trie/README.md
@@ -1,32 +1,15 @@
 # Trie
 
-_Read this in other languages:_
-[_简体中文_](README.zh-CN.md),
-[_Русский_](README.ru-RU.md),
-[_Português_](README.pt-BR.md),
-[_Українська_](README.uk-UA.md),
-[_한국어_](README.ko-KO.md)
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-In computer science, a **trie**, also called digital tree and sometimes
-radix tree or prefix tree (as they can be searched by prefixes),
-is a kind of search tree—an ordered tree data structure that is
-used to store a dynamic set or associative array where the keys
-are usually strings. Unlike a binary search tree, no node in the
-tree stores the key associated with that node; instead, its
-position in the tree defines the key with which it is associated.
-All the descendants of a node have a common prefix of the string
-associated with that node, and the root is associated with the
-empty string. Values are not necessarily associated with every
-node. Rather, values tend only to be associated with leaves,
-and with some inner nodes that correspond to keys of interest.
-For the space-optimized presentation of prefix tree, see compact
-prefix tree.
+Trong khoa học máy tính, một **trie**, còn được gọi là cây số và đôi khi là cây tiền tố (vì chúng có thể được tìm kiếm bằng các tiền tố), là một loại cây tìm kiếm — một cấu trúc dữ liệu cây có thứ tự được sử dụng để lưu trữ một tập hợp động hoặc mảng liên kết mà các khóa thường là chuỗi. Không giống như một cây tìm kiếm nhị phân, không có nút nào trong cây lưu trữ khóa được liên kết với nút đó; thay vào đó, vị trí của nó trong cây xác định khóa mà nó được liên kết. Tất cả các nút con của một nút có một tiền tố chung của chuỗi được liên kết với nút đó, và gốc được liên kết với chuỗi rỗng. Giá trị không nhất thiết phải được liên kết với mỗi nút. Thay vào đó, các giá trị thường chỉ được liên kết với các lá, và với một số nút trong căn cứ có thể được coi là các khóa quan trọng. Đối với cách trình bày tối ưu không gian của cây tiền tố, xem cây tiền tố gọn.
 
 ![Trie](./images/trie.jpg)
 
-*Made with [okso.app](https://okso.app)*
+_Tạo bởi [okso.app](https://okso.app)_
 
-## References
+## Tham khảo
 
 - [Wikipedia](https://en.wikipedia.org/wiki/Trie)
 - [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/data-structures/trie/README.pt-BR.md b/src/data-structures/trie/README.pt-BR.md
deleted file mode 100644
index 50a294b77c..0000000000
--- a/src/data-structures/trie/README.pt-BR.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Árvore de Prefixos (Trie)
-
-Na ciência da computação, uma **trie**, também chamada de árvore digital (digital tree)
-e algumas vezes de _radix tree_ ou _prefix tree_ (tendo em vista que eles
-podem ser pesquisados por prefixos), é um tipo de árvore de pesquisa, uma 
-estrutura de dados de árvore ordenada que é usado para armazenar um
-conjunto dinâmico ou matriz associativa onde as chaves são geralmente _strings_.
-Ao contrário de uma árvore de pesquisa binária (binary search tree),
-nenhum nó na árvore armazena a chave associada a esse nó; em vez disso,
-sua posição na árvore define a chave com a qual ela está associada.
-Todos os descendentes de um nó possuem em comum o prefixo de uma _string_
-associada com aquele nó, e a raiz é associada com uma _string_ vazia.
-Valores não são necessariamente associados a todos nós. Em vez disso,
-os valores tendem a ser associados apenas a folhas e com alguns nós
-internos que correspondem a chaves de interesse.
-
-Para a apresentação otimizada do espaço da árvore de prefixo (_prefix tree_),
-veja árvore de prefixo compacto.
-
-![Trie](./images/trie.jpg)
-
-*Made with [okso.app](https://okso.app)*
-
-## Referências
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Trie)
-- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/data-structures/trie/README.ru-RU.md b/src/data-structures/trie/README.ru-RU.md
deleted file mode 100644
index 30a4536383..0000000000
--- a/src/data-structures/trie/README.ru-RU.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Префиксное дерево
-
-**Префиксное дерево** (также бор, луч, нагруженное или суффиксное дерево) в информатике - упорядоченная древовидная
-структура данных, которая используется для хранения динамических множеств или ассоциативных массивов, где
-ключом обычно выступают строки. Дерево называется префиксным, потому что поиск осуществляется по префиксам.
-
-В отличие от бинарного дерева, узлы не содержат ключи, соответствующие узлу. Представляет собой корневое дерево, каждое
-ребро которого помечено каким-то символом так, что для любого узла все рёбра, соединяющие этот узел с его сыновьями,
-помечены разными символами. Некоторые узлы префиксного дерева выделены (на рисунке они подписаны цифрами) и считается,
-что префиксное дерево содержит данную строку-ключ тогда и только тогда, когда эту строку можно прочитать на пути из
-корня до некоторого выделенного узла.
-
-Таким образом, в отличие от бинарных деревьев поиска, ключ, идентифицирующий конкретный узел дерева, не явно хранится в
-данном узле, а неявно задаётся положением данного узла в дереве. Получить ключ можно выписыванием подряд символов,
-помечающих рёбра на пути от корня до узла. Ключ корня дерева — пустая строка. Часто в выделенных узлах хранят
-дополнительную информацию, связанную с ключом, и обычно выделенными являются только листья и, возможно, некоторые
-внутренние узлы.
-
-![Префиксное дерево](./images/trie.jpg)
-
-*Made with [okso.app](https://okso.app)*
-
-На рисунке представлено префиксное дерево, содержащее ключи «A», «to», «tea», «ted», «ten», «i», «in», «inn».
-
-## Ссылки
-
-- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81%D0%BD%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE)
-- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/data-structures/trie/README.uk-UA.md b/src/data-structures/trie/README.uk-UA.md
deleted file mode 100644
index 3b1f01f0aa..0000000000
--- a/src/data-structures/trie/README.uk-UA.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Префіксне дерево
-
-**Префіксне дерево** (Також промінь, навантажене або суфіксне дерево) в інформатиці - впорядкована деревоподібна
-структура даних, яка використовується для зберігання динамічних множин або асоціативних масивів, де
-ключем зазвичай виступають рядки. Дерево називається префіксним, тому що пошук здійснюється за префіксами.
-
-На відміну від бінарного дерева, вузли не містять ключів, що відповідають вузлу. Являє собою кореневе дерево, кожне
-ребро якого позначено якимось символом так, що для будь-якого вузла всі ребра, що з'єднують цей вузол з його синами,
-позначені різними символами. Деякі вузли префіксного дерева виділені (на малюнку вони підписані цифрами) і вважається,
-що префіксне дерево містить цей рядок-ключ тоді і тільки тоді, коли цей рядок можна прочитати на шляху з
-кореня до певного виділеного вузла.
-
-Таким чином, на відміну від бінарних дерев пошуку, ключ, що ідентифікує конкретний вузол дерева, не явно зберігається в
-цьому вузлі, а неявно задається положенням цього вузла в дереві. Отримати ключ можна виписуванням поспіль символів,
-помічають ребра по дорозі від кореня до вузла. Ключ кореня дерева - порожній рядок. Часто у виділених вузлах зберігають
-додаткову інформацію, пов'язану з ключем, і зазвичай виділеними є тільки листя і, можливо, деякі
-внутрішні вузли.
-
-![Префіксне дерево](./images/trie.jpg)
-
-*Made with [okso.app](https://okso.app)*
-
-На малюнку представлено префіксне дерево, що містить ключі. «A», «to», «tea», «ted», «ten», «i», «in», «inn».
-
-## Посилання
-
-- [Wikipedia](https://uk.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D1%84%D1%96%D0%BA%D1%81%D0%BD%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE)
diff --git a/src/data-structures/trie/README.zh-CN.md b/src/data-structures/trie/README.zh-CN.md
deleted file mode 100644
index e812f57523..0000000000
--- a/src/data-structures/trie/README.zh-CN.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# 字典树
-
-在计算机科学中, **字典树(trie,中文又被称为”单词查找树“或 ”键树“)**, 也称为数字树,有时候也被称为基数树或前缀树（因为它们可以通过前缀搜索）,它是一种搜索树--一种已排序的数据结构,通常用于存储动态集或键为字符串的关联数组。
-
-与二叉搜索树不同, 树上没有节点存储与该节点关联的键; 相反,节点在树上的位置定义了与之关联的键。一个节点的全部后代节点都有一个与该节点关联的通用的字符串前缀, 与根节点关联的是空字符串。
-
-值对于字典树中关联的节点来说,不是必需的,相反,值往往和相关的叶子相关,以及与一些键相关的内部节点相关。
-
-有关字典树的空间优化示意,请参阅紧凑前缀树
-
-![Trie](./images/trie.jpg)
-
-*Made with [okso.app](https://okso.app)*
-
-## 参考
-
-- [Wikipedia](https://en.wikipedia.org/wiki/Trie)
-- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
diff --git a/src/playground/README.en-EN.md b/src/playground/README.en-EN.md
new file mode 100644
index 0000000000..db188271bf
--- /dev/null
+++ b/src/playground/README.en-EN.md
@@ -0,0 +1,14 @@
+# Playground
+
+_Read this in other languages:_
+[_Tiếng Việt_](README.md)
+
+You may use `playground.js` file to play with data
+structures and algorithms. The code from `playground.js` may
+be tested in `./__test__/playground.test.js` file.
+
+To run tests simply run:
+
+```
+npm test -- -t 'playground'
+```
diff --git a/src/playground/README.md b/src/playground/README.md
index 7307a6b58d..631c2ac504 100644
--- a/src/playground/README.md
+++ b/src/playground/README.md
@@ -1,10 +1,13 @@
-# Playground
+# Playground - Sân chơi
 
-You may use `playground.js` file to play with data
-structures and algorithms. The code from `playground.js` may
-be tested in `./__test__/playground.test.js` file.
+_Nhấn vào đây để đọc bằng ngôn ngữ khác:_
+[_English_](README.en-EN.md)
 
-To run tests simply run:
+Bạn có thể sử dụng tệp `playground.js` để chơi với các cấu trúc
+dữ liệu và thuật toán. Mã từ tệp `playground.js` có thể
+được kiểm tra trong tệp `./__test__/playground.test.js`.
+
+Để chạy các bài kiểm tra, chỉ cần chạy:
 
 ```
 npm test -- -t 'playground'
